/*
* 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 android.os.Parcel;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.skyscreamer.jsonassert.JSONCompareMode;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION)
public class ParseRelationTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
//region testConstructor
@Test
public void testConstructorWithParentAndKey() {
ParseObject parent = mock(ParseObject.class);
String key = "test";
ParseRelation relation = new ParseRelation(parent, key);
assertEquals(key, relation.getKey());
assertSame(parent, relation.getParent());
assertNull(relation.getTargetClass());
}
@Test
public void testConstructorWithTargetClass() {
String targetClass = "Test";
ParseRelation relation = new ParseRelation(targetClass);
assertNull(relation.getKey());
assertNull(relation.getParent());
assertEquals(targetClass, relation.getTargetClass());
}
@Test
public void testConstructorWithJSONAndDecoder() throws Exception {
// Make ParseRelation JSONArray
ParseObject object = mock(ParseObject.class);
when(object.getClassName()).thenReturn("Test");
when(object.getObjectId()).thenReturn("objectId");
object.setObjectId("objectId");
JSONArray objectJSONArray = new JSONArray();
objectJSONArray.put(PointerEncoder.get().encode(object));
JSONObject relationJSON = new JSONObject();
relationJSON.put("className", "Test");
relationJSON.put("objects", objectJSONArray);
ParseRelation relationFromJSON = new ParseRelation(relationJSON, ParseDecoder.get());
assertEquals("Test", relationFromJSON.getTargetClass());
assertEquals(1, relationFromJSON.getKnownObjects().size());
Object[] objects = relationFromJSON.getKnownObjects().toArray();
assertEquals("objectId", ((ParseObject) objects[0]).getObjectId());
}
//endregion
//region testParcelable
@Test
public void testParcelable() throws Exception {
ParseFieldOperations.registerDefaultDecoders();
ParseRelation<ParseObject> relation = new ParseRelation<>("Test");
ParseObject parent = new ParseObject("Parent");
parent.setObjectId("parentId");
relation.ensureParentAndKey(parent, "key");
ParseObject inner = new ParseObject("Test");
inner.setObjectId("innerId");
relation.add(inner);
Parcel parcel = Parcel.obtain();
relation.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
//noinspection unchecked
ParseRelation<ParseObject> newRelation = ParseRelation.CREATOR.createFromParcel(parcel);
assertEquals(newRelation.getTargetClass(), "Test");
assertEquals(newRelation.getKey(), "key");
assertEquals(newRelation.getParent().getClassName(), "Parent");
assertEquals(newRelation.getParent().getObjectId(), "parentId");
assertEquals(newRelation.getKnownObjects().size(), 1);
// This would fail assertTrue(newRelation.hasKnownObject(inner)).
// That is because ParseRelation uses == to check for known objects.
}
//endregion
//region testEnsureParentAndKey
@Test
public void testEnsureParentAndKey() throws Exception {
ParseRelation relation = new ParseRelation("Test");
ParseObject parent = mock(ParseObject.class);
relation.ensureParentAndKey(parent, "key");
assertEquals(parent, relation.getParent());
assertEquals("key", relation.getKey());
}
@Test
public void testEnsureParentAndKeyWithDifferentParent() throws Exception {
ParseRelation relation = new ParseRelation(mock(ParseObject.class), "key");
thrown.expect(IllegalStateException.class);
thrown.expectMessage(
"Internal error. One ParseRelation retrieved from two different ParseObjects.");
relation.ensureParentAndKey(new ParseObject("Parent"), "key");
}
@Test
public void testEnsureParentAndKeyWithDifferentKey() throws Exception {
ParseObject parent = mock(ParseObject.class);
ParseRelation relation = new ParseRelation(parent, "key");
thrown.expect(IllegalStateException.class);
thrown.expectMessage(
"Internal error. One ParseRelation retrieved from two different keys.");
relation.ensureParentAndKey(parent, "keyAgain");
}
//endregion
//region testAdd
@Test
public void testAdd() throws Exception {
ParseObject parent = new ParseObject("Parent");
ParseRelation relation = new ParseRelation(parent, "key");
ParseObject object = new ParseObject("Test");
relation.add(object);
// Make sure targetClass is updated
assertEquals("Test", relation.getTargetClass());
// Make sure object is added to knownObjects
assertTrue(relation.hasKnownObject(object));
// Make sure parent is updated
ParseRelation relationInParent = parent.getRelation("key");
assertEquals("Test", relationInParent.getTargetClass());
assertTrue(relationInParent.hasKnownObject(object));
}
//endregion
//region testRemove
@Test
public void testRemove() throws Exception {
ParseObject parent = new ParseObject("Parent");
ParseRelation relation = new ParseRelation(parent, "key");
ParseObject object = new ParseObject("Test");
relation.add(object);
relation.remove(object);
// Make sure targetClass does not change
assertEquals("Test", relation.getTargetClass());
// Make sure object is removed from knownObjects
assertFalse(relation.hasKnownObject(object));
// Make sure parent is updated
ParseRelation relationInParent = parent.getRelation("key");
assertEquals("Test", relationInParent.getTargetClass());
assertFalse(relation.hasKnownObject(object));
}
//endregion
//region testGetQuery
@Test
public void testGetQueryWithNoTargetClass() throws Exception {
ParseObject parent = new ParseObject("Parent");
ParseRelation relation = new ParseRelation(parent, "key");
ParseQuery query = relation.getQuery();
// Make sure className is correct
assertEquals("Parent", query.getClassName());
ParseQuery.State state = query.getBuilder().build();
// Make sure redirectClassNameForKey is set
assertEquals("key", state.extraOptions().get("redirectClassNameForKey"));
// Make sure where condition is set
ParseQuery.RelationConstraint relationConstraint =
(ParseQuery.RelationConstraint) state.constraints().get("$relatedTo");
assertEquals("key", relationConstraint.getKey());
assertSame(parent, relationConstraint.getObject());
}
@Test
public void testGetQueryWithTargetClass() throws Exception {
ParseObject parent = new ParseObject("Parent");
ParseRelation relation = new ParseRelation(parent, "key");
relation.setTargetClass("targetClass");
ParseQuery query = relation.getQuery();
// Make sure className is correct
assertEquals("targetClass", query.getClassName());
ParseQuery.State state = query.getBuilder().build();
// Make sure where condition is set
ParseQuery.RelationConstraint relationConstraint =
(ParseQuery.RelationConstraint) state.constraints().get("$relatedTo");
assertEquals("key", relationConstraint.getKey());
assertSame(parent, relationConstraint.getObject());
}
//endregion
//region testToJSON
@Test
public void testEncodeToJSON() throws Exception {
ParseObject parent = new ParseObject("Parent");
ParseRelation relation = new ParseRelation(parent, "key");
relation.setTargetClass("Test");
ParseObject object = new ParseObject("Test");
object.setObjectId("objectId");
relation.addKnownObject(object);
JSONObject json = relation.encodeToJSON(PointerEncoder.get());
assertEquals("Relation", json.getString("__type"));
assertEquals("Test", json.getString("className"));
JSONArray knownObjectsArray = json.getJSONArray("objects");
assertEquals(
(JSONObject) PointerEncoder.get().encode(object),
knownObjectsArray.getJSONObject(0),
JSONCompareMode.NON_EXTENSIBLE);
}
//endregion
}