/*
* Copyright (c) 2015-present, Parse, LLC.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.parse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.lang.IllegalArgumentException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
public class SubclassTest extends ResetPluginsParseTest {
/**
* This is a subclass of ParseObject that will be used below. We're going to imagine a world in
* which every "Person" is an instance of "The Flash".
*/
@ParseClassName("Person")
public static class Person extends ParseObject {
public String getNickname() {
return getString("nickname");
}
public void setNickname(String name) {
put("nickname", name);
}
public String getRealName() {
return getString("realName");
}
public void setRealName(String name) {
put("realName", name);
}
@Override
void setDefaultValues() {
setNickname("The Flash");
}
public static ParseQuery<Person> getQuery() {
return ParseQuery.getQuery(Person.class);
}
}
@ParseClassName("NoDefaultConstructor")
public static class NoDefaultConstructor extends ParseObject {
public NoDefaultConstructor(Void argument) {
}
}
@ParseClassName("ClassWithDirtyingConstructor")
public static class ClassWithDirtyingConstructor extends ParseObject {
public ClassWithDirtyingConstructor() {
put("foo", "Bar");
}
}
@ParseClassName("UnregisteredClass")
public static class UnregisteredClass extends ParseObject {
}
public static class MyUser extends ParseUser {
}
public static class MyUser2 extends ParseUser {
}
@Before
public void setUp() throws Exception {
super.setUp();
ParseObject.registerParseSubclasses();
ParseObject.registerSubclass(Person.class);
ParseObject.registerSubclass(ClassWithDirtyingConstructor.class);
}
@After
public void tearDown() throws Exception {
super.tearDown();
ParseObject.unregisterParseSubclasses();
ParseObject.unregisterSubclass(Person.class);
ParseObject.unregisterSubclass(ClassWithDirtyingConstructor.class);
}
@SuppressWarnings("unused")
public void testUnregisteredConstruction() throws Exception {
Exception thrown = null;
try {
new UnregisteredClass();
} catch (Exception e) {
thrown = e;
}
assertNotNull(thrown);
ParseObject.registerSubclass(UnregisteredClass.class);
try {
new UnregisteredClass();
} finally {
ParseObject.unregisterSubclass(UnregisteredClass.class);
}
}
@Test
public void testSubclassPointers() throws Exception {
Person flashPointer = (Person) ParseObject.createWithoutData("Person", "someFakeObjectId");
assertFalse(flashPointer.isDirty());
}
@Test
public void testDirtyingConstructorsThrow() throws Exception {
ClassWithDirtyingConstructor dirtyObj = new ClassWithDirtyingConstructor();
assertTrue(dirtyObj.isDirty());
try {
ParseObject.createWithoutData("ClassWithDirtyingConstructor", "someFakeObjectId");
fail("Should throw due to subclass with dirtying constructor");
} catch (IllegalStateException e) {
// success
}
}
@Test
public void testRegisteringSubclassesUsesMostDescendantSubclass() throws Exception {
try {
// When we register a ParseUser subclass, we have to clear the cached currentParseUser, so
// we need to register a mock ParseUserController here, otherwise Parse.getCacheDir() will
// throw an exception in unit test environment.
ParseCurrentUserController controller = mock(ParseCurrentUserController.class);
ParseCorePlugins.getInstance().registerCurrentUserController(controller);
assertEquals(ParseUser.class, ParseObject.create("_User").getClass());
ParseObject.registerSubclass(MyUser.class);
assertEquals(MyUser.class, ParseObject.create("_User").getClass());
ParseObject.registerSubclass(ParseUser.class);
assertEquals(MyUser.class, ParseObject.create("_User").getClass());
// This is expected to fail as MyUser2 and MyUser are not directly related.
try {
ParseObject.registerSubclass(MyUser2.class);
fail();
} catch (IllegalArgumentException ex) {
/* expected */
}
assertEquals(MyUser.class, ParseObject.create("_User").getClass());
} finally {
ParseObject.unregisterSubclass(ParseUser.class);
ParseCorePlugins.getInstance().reset();
}
}
@Test
public void testRegisteringClassWithNoDefaultConstructorThrows() throws Exception {
Exception thrown = null;
try {
ParseObject.registerSubclass(NoDefaultConstructor.class);
} catch (Exception e) {
thrown = e;
}
assertNotNull(thrown);
}
}