diff --git a/gson/src/main/java/com/google/gson/JsonArray.java b/gson/src/main/java/com/google/gson/JsonArray.java index 5a0c77e88d..e9ce580c68 100644 --- a/gson/src/main/java/com/google/gson/JsonArray.java +++ b/gson/src/main/java/com/google/gson/JsonArray.java @@ -16,6 +16,7 @@ package com.google.gson; +import com.google.gson.internal.NonNullElementWrapperList; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; @@ -28,11 +29,14 @@ * elements are added is preserved. This class does not support {@code null} values. If {@code null} * is provided as element argument to any of the methods, it is converted to a {@link JsonNull}. * + *

{@code JsonArray} only implements the {@link Iterable} interface but not the {@link List} + * interface. A {@code List} view of it can be obtained with {@link #asList()}. + * * @author Inderjeet Singh * @author Joel Leitch */ public final class JsonArray extends JsonElement implements Iterable { - private final List elements; + private final ArrayList elements; /** * Creates an empty JsonArray. @@ -393,6 +397,20 @@ public boolean getAsBoolean() { return getAsSingleElement().getAsBoolean(); } + /** + * Returns a mutable {@link List} view of this {@code JsonArray}. Changes to the {@code List} + * are visible in this {@code JsonArray} and the other way around. + * + *

The {@code List} does not permit {@code null} elements. Unlike {@code JsonArray}'s + * {@code null} handling, a {@link NullPointerException} is thrown when trying to add {@code null}. + * Use {@link JsonNull} for JSON null values. + * + * @return mutable {@code List} view + */ + public List asList() { + return new NonNullElementWrapperList<>(elements); + } + /** * Returns whether the other object is equal to this. This method only considers * the other object to be equal if it is an instance of {@code JsonArray} and has diff --git a/gson/src/main/java/com/google/gson/JsonObject.java b/gson/src/main/java/com/google/gson/JsonObject.java index 428861a60d..0c36ef24b3 100644 --- a/gson/src/main/java/com/google/gson/JsonObject.java +++ b/gson/src/main/java/com/google/gson/JsonObject.java @@ -27,6 +27,9 @@ * This class does not support {@code null} values. If {@code null} is provided as value argument * to any of the methods, it is converted to a {@link JsonNull}. * + *

{@code JsonObject} does not implement the {@link Map} interface, but a {@code Map} view + * of it can be obtained with {@link #asMap()}. + * * @author Inderjeet Singh * @author Joel Leitch */ @@ -208,6 +211,21 @@ public JsonObject getAsJsonObject(String memberName) { return (JsonObject) members.get(memberName); } + /** + * Returns a mutable {@link Map} view of this {@code JsonObject}. Changes to the {@code Map} + * are visible in this {@code JsonObject} and the other way around. + * + *

The {@code Map} does not permit {@code null} keys or values. Unlike {@code JsonObject}'s + * {@code null} handling, a {@link NullPointerException} is thrown when trying to add {@code null}. + * Use {@link JsonNull} for JSON null values. + * + * @return mutable {@code Map} view + */ + public Map asMap() { + // It is safe to expose the underlying map because it disallows null keys and values + return members; + } + /** * Returns whether the other object is equal to this. This method only considers * the other object to be equal if it is an instance of {@code JsonObject} and has diff --git a/gson/src/main/java/com/google/gson/internal/NonNullElementWrapperList.java b/gson/src/main/java/com/google/gson/internal/NonNullElementWrapperList.java new file mode 100644 index 0000000000..b301743047 --- /dev/null +++ b/gson/src/main/java/com/google/gson/internal/NonNullElementWrapperList.java @@ -0,0 +1,98 @@ +package com.google.gson.internal; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.RandomAccess; + +/** + * {@link List} which wraps another {@code List} but prevents insertion of + * {@code null} elements. Methods which only perform checks with the element + * argument (e.g. {@link #contains(Object)}) do not throw exceptions for + * {@code null} arguments. + */ +public class NonNullElementWrapperList extends AbstractList implements RandomAccess { + // Explicitly specify ArrayList as type to guarantee that delegate implements RandomAccess + private final ArrayList delegate; + + public NonNullElementWrapperList(ArrayList delegate) { + this.delegate = Objects.requireNonNull(delegate); + } + + @Override public E get(int index) { + return delegate.get(index); + } + + @Override public int size() { + return delegate.size(); + } + + private E nonNull(E element) { + if (element == null) { + throw new NullPointerException("Element must be non-null"); + } + return element; + } + + @Override public E set(int index, E element) { + return delegate.set(index, nonNull(element)); + } + + @Override public void add(int index, E element) { + delegate.add(index, nonNull(element)); + } + + @Override public E remove(int index) { + return delegate.remove(index); + } + + /* The following methods are overridden because their default implementation is inefficient */ + + @Override public void clear() { + delegate.clear(); + } + + @Override public boolean remove(Object o) { + return delegate.remove(o); + } + + @Override public boolean removeAll(Collection c) { + return delegate.removeAll(c); + } + + @Override public boolean retainAll(Collection c) { + return delegate.retainAll(c); + } + + @Override public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override public int indexOf(Object o) { + return delegate.indexOf(o); + } + + @Override public int lastIndexOf(Object o) { + return delegate.lastIndexOf(o); + } + + @Override public Object[] toArray() { + return delegate.toArray(); + } + + @Override public T[] toArray(T[] a) { + return delegate.toArray(a); + } + + @Override public boolean equals(Object o) { + return delegate.equals(o); + } + + @Override public int hashCode() { + return delegate.hashCode(); + } + + // TODO: Once Gson targets Java 8 also override List.sort +} diff --git a/gson/src/test/java/com/google/gson/JsonArrayAsListTest.java b/gson/src/test/java/com/google/gson/JsonArrayAsListTest.java new file mode 100644 index 0000000000..36d671f9e1 --- /dev/null +++ b/gson/src/test/java/com/google/gson/JsonArrayAsListTest.java @@ -0,0 +1,285 @@ +package com.google.gson; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.google.gson.common.MoreAsserts; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Test; + +/** + * Tests for {@link JsonArray#asList()}. + */ +public class JsonArrayAsListTest { + @Test + public void testGet() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + assertEquals(new JsonPrimitive(1), list.get(0)); + + try { + list.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + } + + try { + list.get(2); + fail(); + } catch (IndexOutOfBoundsException e) { + } + + a.add((JsonElement) null); + assertEquals(JsonNull.INSTANCE, list.get(1)); + } + + @Test + public void testSize() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + assertEquals(1, list.size()); + list.add(new JsonPrimitive(2)); + assertEquals(2, list.size()); + } + + @Test + public void testSet() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + JsonElement old = list.set(0, new JsonPrimitive(2)); + assertEquals(new JsonPrimitive(1), old); + assertEquals(new JsonPrimitive(2), list.get(0)); + assertEquals(new JsonPrimitive(2), a.get(0)); + + try { + list.set(-1, new JsonPrimitive(1)); + fail(); + } catch (IndexOutOfBoundsException e) { + } + + try { + list.set(2, new JsonPrimitive(1)); + fail(); + } catch (IndexOutOfBoundsException e) { + } + + try { + list.set(0, null); + fail(); + } catch (NullPointerException e) { + assertEquals("Element must be non-null", e.getMessage()); + } + } + + @Test + public void testAdd() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + list.add(0, new JsonPrimitive(2)); + list.add(1, new JsonPrimitive(3)); + assertTrue(list.add(new JsonPrimitive(4))); + assertTrue(list.add(JsonNull.INSTANCE)); + + List expectedList = Arrays.asList( + new JsonPrimitive(2), + new JsonPrimitive(3), + new JsonPrimitive(1), + new JsonPrimitive(4), + JsonNull.INSTANCE + ); + assertEquals(expectedList, list); + + try { + list.set(-1, new JsonPrimitive(1)); + fail(); + } catch (IndexOutOfBoundsException e) { + } + + try { + list.set(list.size(), new JsonPrimitive(1)); + fail(); + } catch (IndexOutOfBoundsException e) { + } + + try { + list.add(0, null); + fail(); + } catch (NullPointerException e) { + assertEquals("Element must be non-null", e.getMessage()); + } + try { + list.add(null); + fail(); + } catch (NullPointerException e) { + assertEquals("Element must be non-null", e.getMessage()); + } + } + + @Test + public void testAddAll() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + list.addAll(Arrays.asList(new JsonPrimitive(2), new JsonPrimitive(3))); + + List expectedList = Arrays.asList( + new JsonPrimitive(1), + new JsonPrimitive(2), + new JsonPrimitive(3) + ); + assertEquals(expectedList, list); + + try { + list.addAll(0, Collections.singletonList(null)); + fail(); + } catch (NullPointerException e) { + assertEquals("Element must be non-null", e.getMessage()); + } + try { + list.addAll(Collections.singletonList(null)); + fail(); + } catch (NullPointerException e) { + assertEquals("Element must be non-null", e.getMessage()); + } + } + + @Test + public void testRemoveIndex() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + assertEquals(new JsonPrimitive(1), list.remove(0)); + assertEquals(0, list.size()); + assertEquals(0, a.size()); + + try { + list.remove(0); + fail(); + } catch (IndexOutOfBoundsException e) { + } + } + + @Test + public void testRemoveElement() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + assertTrue(list.remove(new JsonPrimitive(1))); + assertEquals(0, list.size()); + assertEquals(0, a.size()); + + assertFalse(list.remove(new JsonPrimitive(1))); + assertFalse(list.remove(null)); + } + + @Test + public void testClear() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + list.clear(); + assertEquals(0, list.size()); + assertEquals(0, a.size()); + } + + @Test + public void testContains() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + assertTrue(list.contains(new JsonPrimitive(1))); + assertFalse(list.contains(new JsonPrimitive(2))); + assertFalse(list.contains(null)); + + @SuppressWarnings("unlikely-arg-type") + boolean containsInt = list.contains(1); // should only contain JsonPrimitive(1) + assertFalse(containsInt); + } + + @Test + public void testIndexOf() { + JsonArray a = new JsonArray(); + // Add the same value twice to test indexOf vs. lastIndexOf + a.add(1); + a.add(1); + + List list = a.asList(); + assertEquals(0, list.indexOf(new JsonPrimitive(1))); + assertEquals(-1, list.indexOf(new JsonPrimitive(2))); + assertEquals(-1, list.indexOf(null)); + + @SuppressWarnings("unlikely-arg-type") + int indexOfInt = list.indexOf(1); // should only contain JsonPrimitive(1) + assertEquals(-1, indexOfInt); + + assertEquals(1, list.lastIndexOf(new JsonPrimitive(1))); + assertEquals(-1, list.lastIndexOf(new JsonPrimitive(2))); + assertEquals(-1, list.lastIndexOf(null)); + } + + @Test + public void testToArray() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + assertArrayEquals(new Object[] {new JsonPrimitive(1)}, list.toArray()); + + JsonElement[] array = list.toArray(new JsonElement[0]); + assertArrayEquals(new Object[] {new JsonPrimitive(1)}, array); + + array = new JsonElement[1]; + assertSame(array, list.toArray(array)); + assertArrayEquals(new Object[] {new JsonPrimitive(1)}, array); + + array = new JsonElement[] {null, new JsonPrimitive(2)}; + assertSame(array, list.toArray(array)); + // Should have set existing array element to null + assertArrayEquals(new Object[] {new JsonPrimitive(1), null}, array); + } + + @Test + public void testEqualsHashCode() { + JsonArray a = new JsonArray(); + a.add(1); + + List list = a.asList(); + MoreAsserts.assertEqualsAndHashCode(list, Collections.singletonList(new JsonPrimitive(1))); + assertFalse(list.equals(Collections.emptyList())); + assertFalse(list.equals(Collections.singletonList(new JsonPrimitive(2)))); + } + + /** Verify that {@code JsonArray} updates are visible to view and vice versa */ + @Test + public void testViewUpdates() { + JsonArray a = new JsonArray(); + List list = a.asList(); + + a.add(1); + assertEquals(1, list.size()); + assertEquals(new JsonPrimitive(1), list.get(0)); + + list.add(new JsonPrimitive(2)); + assertEquals(2, a.size()); + assertEquals(new JsonPrimitive(2), a.get(1)); + } +} diff --git a/gson/src/test/java/com/google/gson/JsonArrayTest.java b/gson/src/test/java/com/google/gson/JsonArrayTest.java index 703984605c..45070e3f33 100644 --- a/gson/src/test/java/com/google/gson/JsonArrayTest.java +++ b/gson/src/test/java/com/google/gson/JsonArrayTest.java @@ -16,18 +16,26 @@ package com.google.gson; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import com.google.gson.common.MoreAsserts; -import junit.framework.TestCase; +import java.math.BigInteger; +import org.junit.Test; /** * @author Jesse Wilson */ -public final class JsonArrayTest extends TestCase { +public final class JsonArrayTest { + @Test public void testEqualsOnEmptyArray() { MoreAsserts.assertEqualsAndHashCode(new JsonArray(), new JsonArray()); } + @Test public void testEqualsNonEmptyArray() { JsonArray a = new JsonArray(); JsonArray b = new JsonArray(); @@ -50,6 +58,7 @@ public void testEqualsNonEmptyArray() { assertFalse(b.equals(a)); } + @Test public void testRemove() { JsonArray array = new JsonArray(); try { @@ -67,6 +76,7 @@ public void testRemove() { assertTrue(array.contains(a)); } + @Test public void testSet() { JsonArray array = new JsonArray(); try { @@ -91,6 +101,7 @@ public void testSet() { assertEquals(1, array.size()); } + @Test public void testDeepCopy() { JsonArray original = new JsonArray(); JsonArray firstEntry = new JsonArray(); @@ -106,6 +117,7 @@ public void testDeepCopy() { assertEquals(0, copy.get(0).getAsJsonArray().size()); } + @Test public void testIsEmpty() { JsonArray array = new JsonArray(); assertTrue(array.isEmpty()); @@ -118,6 +130,7 @@ public void testIsEmpty() { assertTrue(array.isEmpty()); } + @Test public void testFailedGetArrayValues() { JsonArray jsonArray = new JsonArray(); jsonArray.add(JsonParser.parseString("{" + "\"key1\":\"value1\"," + "\"key2\":\"value2\"," + "\"key3\":\"value3\"," + "\"key4\":\"value4\"" + "}")); @@ -182,6 +195,7 @@ public void testFailedGetArrayValues() { } } + @Test public void testGetAs_WrongArraySize() { JsonArray jsonArray = new JsonArray(); try { @@ -200,4 +214,160 @@ public void testGetAs_WrongArraySize() { assertEquals("Array must have size 1, but has size 2", e.getMessage()); } } + + @Test + public void testStringPrimitiveAddition() { + JsonArray jsonArray = new JsonArray(); + + jsonArray.add("Hello"); + jsonArray.add("Goodbye"); + jsonArray.add("Thank you"); + jsonArray.add((String) null); + jsonArray.add("Yes"); + + assertEquals("[\"Hello\",\"Goodbye\",\"Thank you\",null,\"Yes\"]", jsonArray.toString()); + } + + @Test + public void testIntegerPrimitiveAddition() { + JsonArray jsonArray = new JsonArray(); + + int x = 1; + jsonArray.add(x); + + x = 2; + jsonArray.add(x); + + x = -3; + jsonArray.add(x); + + jsonArray.add((Integer) null); + + x = 4; + jsonArray.add(x); + + x = 0; + jsonArray.add(x); + + assertEquals("[1,2,-3,null,4,0]", jsonArray.toString()); + } + + @Test + public void testDoublePrimitiveAddition() { + JsonArray jsonArray = new JsonArray(); + + double x = 1.0; + jsonArray.add(x); + + x = 2.13232; + jsonArray.add(x); + + x = 0.121; + jsonArray.add(x); + + jsonArray.add((Double) null); + + x = -0.00234; + jsonArray.add(x); + + jsonArray.add((Double) null); + + assertEquals("[1.0,2.13232,0.121,null,-0.00234,null]", jsonArray.toString()); + } + + @Test + public void testBooleanPrimitiveAddition() { + JsonArray jsonArray = new JsonArray(); + + jsonArray.add(true); + jsonArray.add(true); + jsonArray.add(false); + jsonArray.add(false); + jsonArray.add((Boolean) null); + jsonArray.add(true); + + assertEquals("[true,true,false,false,null,true]", jsonArray.toString()); + } + + @Test + public void testCharPrimitiveAddition() { + JsonArray jsonArray = new JsonArray(); + + jsonArray.add('a'); + jsonArray.add('e'); + jsonArray.add('i'); + jsonArray.add((char) 111); + jsonArray.add((Character) null); + jsonArray.add('u'); + jsonArray.add("and sometimes Y"); + + assertEquals("[\"a\",\"e\",\"i\",\"o\",null,\"u\",\"and sometimes Y\"]", jsonArray.toString()); + } + + @Test + public void testMixedPrimitiveAddition() { + JsonArray jsonArray = new JsonArray(); + + jsonArray.add('a'); + jsonArray.add("apple"); + jsonArray.add(12121); + jsonArray.add((char) 111); + + jsonArray.add((Boolean) null); + assertEquals(JsonNull.INSTANCE, jsonArray.get(jsonArray.size() - 1)); + + jsonArray.add((Character) null); + assertEquals(JsonNull.INSTANCE, jsonArray.get(jsonArray.size() - 1)); + + jsonArray.add(12.232); + jsonArray.add(BigInteger.valueOf(2323)); + + assertEquals("[\"a\",\"apple\",12121,\"o\",null,null,12.232,2323]", jsonArray.toString()); + } + + @Test + public void testNullPrimitiveAddition() { + JsonArray jsonArray = new JsonArray(); + + jsonArray.add((Character) null); + jsonArray.add((Boolean) null); + jsonArray.add((Integer) null); + jsonArray.add((Double) null); + jsonArray.add((Float) null); + jsonArray.add((BigInteger) null); + jsonArray.add((String) null); + jsonArray.add((Boolean) null); + jsonArray.add((Number) null); + + assertEquals("[null,null,null,null,null,null,null,null,null]", jsonArray.toString()); + for (int i = 0; i < jsonArray.size(); i++) { + // Verify that they are actually a JsonNull and not a Java null + assertEquals(JsonNull.INSTANCE, jsonArray.get(i)); + } + } + + @Test + public void testNullJsonElementAddition() { + JsonArray jsonArray = new JsonArray(); + jsonArray.add((JsonElement) null); + assertEquals(JsonNull.INSTANCE, jsonArray.get(0)); + } + + @Test + public void testSameAddition() { + JsonArray jsonArray = new JsonArray(); + + jsonArray.add('a'); + jsonArray.add('a'); + jsonArray.add(true); + jsonArray.add(true); + jsonArray.add(1212); + jsonArray.add(1212); + jsonArray.add(34.34); + jsonArray.add(34.34); + jsonArray.add((Boolean) null); + jsonArray.add((Boolean) null); + + assertEquals("[\"a\",\"a\",true,true,1212,1212,34.34,34.34,null,null]", jsonArray.toString()); + } } diff --git a/gson/src/test/java/com/google/gson/JsonObjectAsMapTest.java b/gson/src/test/java/com/google/gson/JsonObjectAsMapTest.java new file mode 100644 index 0000000000..7f17538936 --- /dev/null +++ b/gson/src/test/java/com/google/gson/JsonObjectAsMapTest.java @@ -0,0 +1,287 @@ +package com.google.gson; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.google.gson.common.MoreAsserts; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.junit.Test; + +/** + * Tests for {@link JsonObject#asMap()}. + */ +public class JsonObjectAsMapTest { + @Test + public void testSize() { + JsonObject o = new JsonObject(); + assertEquals(0, o.asMap().size()); + + o.addProperty("a", 1); + Map map = o.asMap(); + assertEquals(1, map.size()); + + map.clear(); + assertEquals(0, map.size()); + assertEquals(0, o.size()); + } + + @Test + public void testContainsKey() { + JsonObject o = new JsonObject(); + o.addProperty("a", 1); + + Map map = o.asMap(); + assertTrue(map.containsKey("a")); + assertFalse(map.containsKey("b")); + assertFalse(map.containsKey(null)); + } + + @Test + public void testContainsValue() { + JsonObject o = new JsonObject(); + o.addProperty("a", 1); + o.add("b", JsonNull.INSTANCE); + + Map map = o.asMap(); + assertTrue(map.containsValue(new JsonPrimitive(1))); + assertFalse(map.containsValue(new JsonPrimitive(2))); + assertFalse(map.containsValue(null)); + + @SuppressWarnings("unlikely-arg-type") + boolean containsInt = map.containsValue(1); // should only contain JsonPrimitive(1) + assertFalse(containsInt); + } + + @Test + public void testGet() { + JsonObject o = new JsonObject(); + o.addProperty("a", 1); + + Map map = o.asMap(); + assertEquals(new JsonPrimitive(1), map.get("a")); + assertNull(map.get("b")); + assertNull(map.get(null)); + } + + @Test + public void testPut() { + JsonObject o = new JsonObject(); + Map map = o.asMap(); + + assertNull(map.put("a", new JsonPrimitive(1))); + assertEquals(1, map.size()); + assertEquals(new JsonPrimitive(1), map.get("a")); + + JsonElement old = map.put("a", new JsonPrimitive(2)); + assertEquals(new JsonPrimitive(1), old); + assertEquals(1, map.size()); + assertEquals(new JsonPrimitive(2), map.get("a")); + assertEquals(new JsonPrimitive(2), o.get("a")); + + assertNull(map.put("b", JsonNull.INSTANCE)); + assertEquals(JsonNull.INSTANCE, map.get("b")); + + try { + map.put(null, new JsonPrimitive(1)); + fail(); + } catch (NullPointerException e) { + assertEquals("key == null", e.getMessage()); + } + + try { + map.put("a", null); + fail(); + } catch (NullPointerException e) { + assertEquals("value == null", e.getMessage()); + } + } + + @Test + public void testRemove() { + JsonObject o = new JsonObject(); + o.addProperty("a", 1); + + Map map = o.asMap(); + assertNull(map.remove("b")); + assertEquals(1, map.size()); + + JsonElement old = map.remove("a"); + assertEquals(new JsonPrimitive(1), old); + assertEquals(0, map.size()); + + assertNull(map.remove("a")); + assertEquals(0, map.size()); + assertEquals(0, o.size()); + + assertNull(map.remove(null)); + } + + @Test + public void testPutAll() { + JsonObject o = new JsonObject(); + o.addProperty("a", 1); + + Map otherMap = new HashMap<>(); + otherMap.put("a", new JsonPrimitive(2)); + otherMap.put("b", new JsonPrimitive(3)); + + Map map = o.asMap(); + map.putAll(otherMap); + assertEquals(2, map.size()); + assertEquals(new JsonPrimitive(2), map.get("a")); + assertEquals(new JsonPrimitive(3), map.get("b")); + + try { + map.putAll(Collections.singletonMap(null, new JsonPrimitive(1))); + fail(); + } catch (NullPointerException e) { + assertEquals("key == null", e.getMessage()); + } + + try { + map.putAll(Collections.singletonMap("a", null)); + fail(); + } catch (NullPointerException e) { + assertEquals("value == null", e.getMessage()); + } + } + + @Test + public void testClear() { + JsonObject o = new JsonObject(); + o.addProperty("a", 1); + + Map map = o.asMap(); + map.clear(); + assertEquals(0, map.size()); + assertEquals(0, o.size()); + } + + @Test + public void testKeySet() { + JsonObject o = new JsonObject(); + o.addProperty("b", 1); + o.addProperty("a", 2); + + Map map = o.asMap(); + Set keySet = map.keySet(); + // Should contain keys in same order + assertEquals(Arrays.asList("b", "a"), new ArrayList<>(keySet)); + + // Key set doesn't support insertions + try { + keySet.add("c"); + fail(); + } catch (UnsupportedOperationException e) { + } + + assertTrue(keySet.remove("a")); + assertEquals(Collections.singleton("b"), map.keySet()); + assertEquals(Collections.singleton("b"), o.keySet()); + } + + @Test + public void testValues() { + JsonObject o = new JsonObject(); + o.addProperty("a", 2); + o.addProperty("b", 1); + + Map map = o.asMap(); + Collection values = map.values(); + // Should contain values in same order + assertEquals(Arrays.asList(new JsonPrimitive(2), new JsonPrimitive(1)), new ArrayList<>(values)); + + // Values collection doesn't support insertions + try { + values.add(new JsonPrimitive(3)); + fail(); + } catch (UnsupportedOperationException e) { + } + + assertTrue(values.remove(new JsonPrimitive(2))); + assertEquals(Collections.singletonList(new JsonPrimitive(1)), new ArrayList<>(map.values())); + assertEquals(1, o.size()); + assertEquals(new JsonPrimitive(1), o.get("b")); + } + + @Test + public void testEntrySet() { + JsonObject o = new JsonObject(); + o.addProperty("b", 2); + o.addProperty("a", 1); + + Map map = o.asMap(); + Set> entrySet = map.entrySet(); + + List> expectedEntrySet = Arrays.>asList( + new SimpleEntry<>("b", new JsonPrimitive(2)), + new SimpleEntry<>("a", new JsonPrimitive(1)) + ); + // Should contain entries in same order + assertEquals(expectedEntrySet, new ArrayList<>(entrySet)); + + try { + entrySet.add(new SimpleEntry("c", new JsonPrimitive(3))); + fail(); + } catch (UnsupportedOperationException e) { + } + + assertTrue(entrySet.remove(new SimpleEntry<>("a", new JsonPrimitive(1)))); + assertEquals(Collections.singleton(new SimpleEntry<>("b", new JsonPrimitive(2))), map.entrySet()); + assertEquals(Collections.singleton(new SimpleEntry<>("b", new JsonPrimitive(2))), o.entrySet()); + + // Should return false because entry has already been removed + assertFalse(entrySet.remove(new SimpleEntry<>("a", new JsonPrimitive(1)))); + + Entry entry = entrySet.iterator().next(); + JsonElement old = entry.setValue(new JsonPrimitive(3)); + assertEquals(new JsonPrimitive(2), old); + assertEquals(Collections.singleton(new SimpleEntry<>("b", new JsonPrimitive(3))), map.entrySet()); + assertEquals(Collections.singleton(new SimpleEntry<>("b", new JsonPrimitive(3))), o.entrySet()); + + try { + entry.setValue(null); + fail(); + } catch (NullPointerException e) { + assertEquals("value == null", e.getMessage()); + } + } + + @Test + public void testEqualsHashCode() { + JsonObject o = new JsonObject(); + o.addProperty("a", 1); + + Map map = o.asMap(); + MoreAsserts.assertEqualsAndHashCode(map, Collections.singletonMap("a", new JsonPrimitive(1))); + assertFalse(map.equals(Collections.emptyMap())); + assertFalse(map.equals(Collections.singletonMap("a", new JsonPrimitive(2)))); + } + + /** Verify that {@code JsonObject} updates are visible to view and vice versa */ + @Test + public void testViewUpdates() { + JsonObject o = new JsonObject(); + Map map = o.asMap(); + + o.addProperty("a", 1); + assertEquals(1, map.size()); + assertEquals(new JsonPrimitive(1), map.get("a")); + + map.put("b", new JsonPrimitive(2)); + assertEquals(2, o.size()); + assertEquals(new JsonPrimitive(2), o.get("b")); + } +} diff --git a/gson/src/test/java/com/google/gson/JsonObjectTest.java b/gson/src/test/java/com/google/gson/JsonObjectTest.java index d12d12d898..a0109ba863 100644 --- a/gson/src/test/java/com/google/gson/JsonObjectTest.java +++ b/gson/src/test/java/com/google/gson/JsonObjectTest.java @@ -16,6 +16,13 @@ package com.google.gson; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import com.google.gson.common.MoreAsserts; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayDeque; @@ -27,15 +34,16 @@ import java.util.List; import java.util.Map.Entry; import java.util.Set; -import junit.framework.TestCase; +import org.junit.Test; /** * Unit test for the {@link JsonObject} class. * * @author Joel Leitch */ -public class JsonObjectTest extends TestCase { +public class JsonObjectTest { + @Test public void testAddingAndRemovingObjectProperties() throws Exception { JsonObject jsonObj = new JsonObject(); String propertyName = "property"; @@ -54,6 +62,7 @@ public void testAddingAndRemovingObjectProperties() throws Exception { assertNull(jsonObj.remove(propertyName)); } + @Test public void testAddingNullPropertyValue() throws Exception { String propertyName = "property"; JsonObject jsonObj = new JsonObject(); @@ -66,6 +75,7 @@ public void testAddingNullPropertyValue() throws Exception { assertTrue(jsonElement.isJsonNull()); } + @Test public void testAddingNullOrEmptyPropertyName() throws Exception { JsonObject jsonObj = new JsonObject(); try { @@ -77,6 +87,7 @@ public void testAddingNullOrEmptyPropertyName() throws Exception { jsonObj.add(" \t", JsonNull.INSTANCE); } + @Test public void testAddingBooleanProperties() throws Exception { String propertyName = "property"; JsonObject jsonObj = new JsonObject(); @@ -89,6 +100,7 @@ public void testAddingBooleanProperties() throws Exception { assertTrue(jsonElement.getAsBoolean()); } + @Test public void testAddingStringProperties() throws Exception { String propertyName = "property"; String value = "blah"; @@ -103,6 +115,7 @@ public void testAddingStringProperties() throws Exception { assertEquals(value, jsonElement.getAsString()); } + @Test public void testAddingCharacterProperties() throws Exception { String propertyName = "property"; char value = 'a'; @@ -124,6 +137,7 @@ public void testAddingCharacterProperties() throws Exception { /** * From bug report http://code.google.com/p/google-gson/issues/detail?id=182 */ + @Test public void testPropertyWithQuotes() { JsonObject jsonObj = new JsonObject(); jsonObj.add("a\"b", new JsonPrimitive("c\"d")); @@ -134,6 +148,7 @@ public void testPropertyWithQuotes() { /** * From issue 227. */ + @Test public void testWritePropertyWithEmptyStringName() { JsonObject jsonObj = new JsonObject(); jsonObj.add("", new JsonPrimitive(true)); @@ -141,15 +156,18 @@ public void testWritePropertyWithEmptyStringName() { } + @Test public void testReadPropertyWithEmptyStringName() { JsonObject jsonObj = JsonParser.parseString("{\"\":true}").getAsJsonObject(); assertEquals(true, jsonObj.get("").getAsBoolean()); } + @Test public void testEqualsOnEmptyObject() { MoreAsserts.assertEqualsAndHashCode(new JsonObject(), new JsonObject()); } + @Test public void testEqualsNonEmptyObject() { JsonObject a = new JsonObject(); JsonObject b = new JsonObject(); @@ -172,6 +190,7 @@ public void testEqualsNonEmptyObject() { assertFalse(b.equals(a)); } + @Test public void testEqualsHashCodeIgnoringOrder() { JsonObject a = new JsonObject(); JsonObject b = new JsonObject(); @@ -188,6 +207,7 @@ public void testEqualsHashCodeIgnoringOrder() { MoreAsserts.assertEqualsAndHashCode(a, b); } + @Test public void testSize() { JsonObject o = new JsonObject(); assertEquals(0, o.size()); @@ -202,6 +222,7 @@ public void testSize() { assertEquals(1, o.size()); } + @Test public void testDeepCopy() { JsonObject original = new JsonObject(); JsonArray firstEntry = new JsonArray(); @@ -217,6 +238,7 @@ public void testDeepCopy() { /** * From issue 941 */ + @Test public void testKeySet() { JsonObject a = new JsonObject(); assertEquals(0, a.keySet().size()); @@ -250,6 +272,7 @@ public void testKeySet() { } } + @Test public void testEntrySet() { JsonObject o = new JsonObject(); assertEquals(0, o.entrySet().size()); diff --git a/gson/src/test/java/com/google/gson/functional/JsonArrayTest.java b/gson/src/test/java/com/google/gson/functional/JsonArrayTest.java deleted file mode 100644 index 410a081750..0000000000 --- a/gson/src/test/java/com/google/gson/functional/JsonArrayTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.gson.functional; - -import com.google.gson.JsonArray; -import java.math.BigInteger; -import junit.framework.TestCase; - -/** - * Functional tests for adding primitives to a JsonArray. - * - * @author Dillon Dixon - */ -public class JsonArrayTest extends TestCase { - - public void testStringPrimitiveAddition() { - JsonArray jsonArray = new JsonArray(); - - jsonArray.add("Hello"); - jsonArray.add("Goodbye"); - jsonArray.add("Thank you"); - jsonArray.add((String) null); - jsonArray.add("Yes"); - - assertEquals("[\"Hello\",\"Goodbye\",\"Thank you\",null,\"Yes\"]", jsonArray.toString()); - } - - public void testIntegerPrimitiveAddition() { - JsonArray jsonArray = new JsonArray(); - - int x = 1; - jsonArray.add(x); - - x = 2; - jsonArray.add(x); - - x = -3; - jsonArray.add(x); - - jsonArray.add((Integer) null); - - x = 4; - jsonArray.add(x); - - x = 0; - jsonArray.add(x); - - assertEquals("[1,2,-3,null,4,0]", jsonArray.toString()); - } - - public void testDoublePrimitiveAddition() { - JsonArray jsonArray = new JsonArray(); - - double x = 1.0; - jsonArray.add(x); - - x = 2.13232; - jsonArray.add(x); - - x = 0.121; - jsonArray.add(x); - - jsonArray.add((Double) null); - - x = -0.00234; - jsonArray.add(x); - - jsonArray.add((Double) null); - - assertEquals("[1.0,2.13232,0.121,null,-0.00234,null]", jsonArray.toString()); - } - - public void testBooleanPrimitiveAddition() { - JsonArray jsonArray = new JsonArray(); - - jsonArray.add(true); - jsonArray.add(true); - jsonArray.add(false); - jsonArray.add(false); - jsonArray.add((Boolean) null); - jsonArray.add(true); - - assertEquals("[true,true,false,false,null,true]", jsonArray.toString()); - } - - public void testCharPrimitiveAddition() { - JsonArray jsonArray = new JsonArray(); - - jsonArray.add('a'); - jsonArray.add('e'); - jsonArray.add('i'); - jsonArray.add((char) 111); - jsonArray.add((Character) null); - jsonArray.add('u'); - jsonArray.add("and sometimes Y"); - - assertEquals("[\"a\",\"e\",\"i\",\"o\",null,\"u\",\"and sometimes Y\"]", jsonArray.toString()); - } - - public void testMixedPrimitiveAddition() { - JsonArray jsonArray = new JsonArray(); - - jsonArray.add('a'); - jsonArray.add("apple"); - jsonArray.add(12121); - jsonArray.add((char) 111); - jsonArray.add((Boolean) null); - jsonArray.add((Character) null); - jsonArray.add(12.232); - jsonArray.add(BigInteger.valueOf(2323)); - - assertEquals("[\"a\",\"apple\",12121,\"o\",null,null,12.232,2323]", jsonArray.toString()); - } - - public void testNullPrimitiveAddition() { - JsonArray jsonArray = new JsonArray(); - - jsonArray.add((Character) null); - jsonArray.add((Boolean) null); - jsonArray.add((Integer) null); - jsonArray.add((Double) null); - jsonArray.add((Float) null); - jsonArray.add((BigInteger) null); - jsonArray.add((String) null); - jsonArray.add((Boolean) null); - jsonArray.add((Number) null); - - assertEquals("[null,null,null,null,null,null,null,null,null]", jsonArray.toString()); - } - - public void testSameAddition() { - JsonArray jsonArray = new JsonArray(); - - jsonArray.add('a'); - jsonArray.add('a'); - jsonArray.add(true); - jsonArray.add(true); - jsonArray.add(1212); - jsonArray.add(1212); - jsonArray.add(34.34); - jsonArray.add(34.34); - jsonArray.add((Boolean) null); - jsonArray.add((Boolean) null); - - assertEquals("[\"a\",\"a\",true,true,1212,1212,34.34,34.34,null,null]", jsonArray.toString()); - } -}