http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/test/java/org/json/JSONObjectTest.java ---------------------------------------------------------------------- diff --git a/geode-json/src/test/java/org/json/JSONObjectTest.java b/geode-json/src/test/java/org/json/JSONObjectTest.java new file mode 100755 index 0000000..393a2d0 --- /dev/null +++ b/geode-json/src/test/java/org/json/JSONObjectTest.java @@ -0,0 +1,1198 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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 org.json; + +import org.junit.Test; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; + +/** + * This black box test was written without inspecting the non-free org.json sourcecode. + */ +public class JSONObjectTest { + @Test + public void testKeyset() throws Exception { + JSONObject x = new JSONObject("{'a':1, 'b':2, 'c':3}"); + Set<String> k = new TreeSet<String>(); + for (String kx : Arrays.asList("a", "b", "c")) { + k.add(kx); + } + assertEquals(x.keySet(), k); + x = new JSONObject("{}"); + assertEquals(x.keySet().size(), 0); + } + + @Test + public void testEmptyObject() throws JSONException { + JSONObject object = new JSONObject(); + assertEquals(0, object.length()); + + // bogus (but documented) behaviour: returns null rather than the empty object! + assertNull(object.names()); + + // returns null rather than an empty array! + assertNull(object.toJSONArray(new JSONArray())); + assertEquals("{}", object.toString()); + assertEquals("{}", object.toString(5)); + try { + object.get("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getBoolean("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getDouble("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getInt("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getJSONArray("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getJSONObject("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getLong("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getString("foo"); + fail(); + } catch (JSONException ignored) { + } + assertFalse(object.has("foo")); + assertTrue(object.isNull("foo")); // isNull also means "is not present" + assertNull(object.opt("foo")); + assertEquals(false, object.optBoolean("foo")); + assertEquals(true, object.optBoolean("foo", true)); + assertEquals(Double.NaN, object.optDouble("foo"), 0); + assertEquals(5.0, object.optDouble("foo", 5.0), 0); + assertEquals(0, object.optInt("foo")); + assertEquals(5, object.optInt("foo", 5)); + assertEquals(null, object.optJSONArray("foo")); + assertEquals(null, object.optJSONObject("foo")); + assertEquals(0, object.optLong("foo")); + assertEquals(Long.MAX_VALUE - 1, object.optLong("foo", Long.MAX_VALUE - 1)); + assertEquals("", object.optString("foo")); // empty string is default! + assertEquals("bar", object.optString("foo", "bar")); + assertNull(object.remove("foo")); + } + + @Test + public void testEqualsAndHashCode() throws JSONException { + JSONObject a = new JSONObject(); + JSONObject b = new JSONObject(); + + // JSON object doesn't override either equals or hashCode (!) + assertFalse(a.equals(b)); + assertEquals(a.hashCode(), System.identityHashCode(a)); + } + + @Test + public void testGet() throws JSONException { + JSONObject object = new JSONObject(); + Object value = new Object(); + object.put("foo", value); + object.put("bar", new Object()); + object.put("baz", new Object()); + assertSame(value, object.get("foo")); + try { + object.get("FOO"); + fail(); + } catch (JSONException ignored) { + } + try { + object.put(null, value); + fail(); + } catch (JSONException ignored) { + } + try { + object.get(null); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testPut() throws JSONException { + JSONObject object = new JSONObject(); + assertSame(object, object.put("foo", true)); + object.put("foo", false); + assertEquals(false, object.get("foo")); + + object.put("foo", 5.0d); + assertEquals(5.0d, object.get("foo")); + object.put("foo", 0); + assertEquals(0, object.get("foo")); + object.put("bar", Long.MAX_VALUE - 1); + assertEquals(Long.MAX_VALUE - 1, object.get("bar")); + object.put("baz", "x"); + assertEquals("x", object.get("baz")); + object.put("bar", JSONObject.NULL); + assertSame(JSONObject.NULL, object.get("bar")); + } + + @Test + public void testPutNullRemoves() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "bar"); + object.put("foo", null); + assertEquals(0, object.length()); + assertFalse(object.has("foo")); + try { + object.get("foo"); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testPutOpt() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "bar"); + object.putOpt("foo", null); + assertEquals("bar", object.get("foo")); + object.putOpt(null, null); + assertEquals(1, object.length()); + object.putOpt(null, "bar"); + assertEquals(1, object.length()); + } + + @Test + public void testPutOptUnsupportedNumbers() throws JSONException { + JSONObject object = new JSONObject(); + try { + object.putOpt("foo", Double.NaN); + fail(); + } catch (JSONException ignored) { + } + try { + object.putOpt("foo", Double.NEGATIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + try { + object.putOpt("foo", Double.POSITIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testRemove() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "bar"); + assertEquals(null, object.remove(null)); + assertEquals(null, object.remove("")); + assertEquals(null, object.remove("bar")); + assertEquals("bar", object.remove("foo")); + assertEquals(null, object.remove("foo")); + } + + @Test + public void testBooleans() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", true); + object.put("bar", false); + object.put("baz", "true"); + object.put("quux", "false"); + assertEquals(4, object.length()); + assertEquals(true, object.getBoolean("foo")); + assertEquals(false, object.getBoolean("bar")); + assertEquals(true, object.getBoolean("baz")); + assertEquals(false, object.getBoolean("quux")); + assertFalse(object.isNull("foo")); + assertFalse(object.isNull("quux")); + assertTrue(object.has("foo")); + assertTrue(object.has("quux")); + assertFalse(object.has("missing")); + assertEquals(true, object.optBoolean("foo")); + assertEquals(false, object.optBoolean("bar")); + assertEquals(true, object.optBoolean("baz")); + assertEquals(false, object.optBoolean("quux")); + assertEquals(false, object.optBoolean("missing")); + assertEquals(true, object.optBoolean("foo", true)); + assertEquals(false, object.optBoolean("bar", true)); + assertEquals(true, object.optBoolean("baz", true)); + assertEquals(false, object.optBoolean("quux", true)); + assertEquals(true, object.optBoolean("missing", true)); + + object.put("foo", "truE"); + object.put("bar", "FALSE"); + assertEquals(true, object.getBoolean("foo")); + assertEquals(false, object.getBoolean("bar")); + assertEquals(true, object.optBoolean("foo")); + assertEquals(false, object.optBoolean("bar")); + assertEquals(true, object.optBoolean("foo", false)); + assertEquals(false, object.optBoolean("bar", false)); + } + + // http://code.google.com/p/android/issues/detail?id=16411 + @Test + public void testCoerceStringToBoolean() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "maybe"); + try { + object.getBoolean("foo"); + fail(); + } catch (JSONException ignored) { + } + assertEquals(false, object.optBoolean("foo")); + assertEquals(true, object.optBoolean("foo", true)); + } + + @Test + public void testNumbers() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", Double.MIN_VALUE); + object.put("bar", 9223372036854775806L); + object.put("baz", Double.MAX_VALUE); + object.put("quux", -0d); + assertEquals(4, object.length()); + + String toString = object.toString(); + assertTrue(toString, toString.contains("\"foo\":4.9E-324")); + assertTrue(toString, toString.contains("\"bar\":9223372036854775806")); + assertTrue(toString, toString.contains("\"baz\":1.7976931348623157E308")); + + // toString() and getString() return different values for -0d! + assertTrue(toString, toString.contains("\"quux\":-0}") // no trailing decimal point + || toString.contains("\"quux\":-0,")); + + assertEquals(Double.MIN_VALUE, object.get("foo")); + assertEquals(9223372036854775806L, object.get("bar")); + assertEquals(Double.MAX_VALUE, object.get("baz")); + assertEquals(-0d, object.get("quux")); + assertEquals(Double.MIN_VALUE, object.getDouble("foo"), 0); + assertEquals(9.223372036854776E18, object.getDouble("bar"), 0); + assertEquals(Double.MAX_VALUE, object.getDouble("baz"), 0); + assertEquals(-0d, object.getDouble("quux"), 0); + assertEquals(0, object.getLong("foo")); + assertEquals(9223372036854775806L, object.getLong("bar")); + assertEquals(Long.MAX_VALUE, object.getLong("baz")); + assertEquals(0, object.getLong("quux")); + assertEquals(0, object.getInt("foo")); + assertEquals(-2, object.getInt("bar")); + assertEquals(Integer.MAX_VALUE, object.getInt("baz")); + assertEquals(0, object.getInt("quux")); + assertEquals(Double.MIN_VALUE, object.opt("foo")); + assertEquals(9223372036854775806L, object.optLong("bar")); + assertEquals(Double.MAX_VALUE, object.optDouble("baz"), 0); + assertEquals(0, object.optInt("quux")); + assertEquals(Double.MIN_VALUE, object.opt("foo")); + assertEquals(9223372036854775806L, object.optLong("bar")); + assertEquals(Double.MAX_VALUE, object.optDouble("baz"), 0); + assertEquals(0, object.optInt("quux")); + assertEquals(Double.MIN_VALUE, object.optDouble("foo", 5.0d), 0); + assertEquals(9223372036854775806L, object.optLong("bar", 1L)); + assertEquals(Long.MAX_VALUE, object.optLong("baz", 1L)); + assertEquals(0, object.optInt("quux", -1)); + assertEquals("4.9E-324", object.getString("foo")); + assertEquals("9223372036854775806", object.getString("bar")); + assertEquals("1.7976931348623157E308", object.getString("baz")); + assertEquals("-0.0", object.getString("quux")); + } + + @Test + public void testFloats() throws JSONException { + JSONObject object = new JSONObject(); + try { + object.put("foo", (Float) Float.NaN); + fail(); + } catch (JSONException ignored) { + } + try { + object.put("foo", (Float) Float.NEGATIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + try { + object.put("foo", (Float) Float.POSITIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testOtherNumbers() throws JSONException { + Number nan = new Number() { + public int intValue() { + throw new UnsupportedOperationException(); + } + + public long longValue() { + throw new UnsupportedOperationException(); + } + + public float floatValue() { + throw new UnsupportedOperationException(); + } + + public double doubleValue() { + return Double.NaN; + } + + @Override + public String toString() { + return "x"; + } + }; + + JSONObject object = new JSONObject(); + try { + object.put("foo", nan); + fail("Object.put() accepted a NaN (via a custom Number class)"); + } catch (JSONException ignored) { + } + } + + @Test + public void testForeignObjects() throws JSONException { + Object foreign = new Object() { + @Override + public String toString() { + return "x"; + } + }; + + // foreign object types are accepted and treated as Strings! + JSONObject object = new JSONObject(); + object.put("foo", foreign); + assertEquals("{\"foo\":\"x\"}", object.toString()); + } + + @Test + public void testNullKeys() { + try { + new JSONObject().put(null, false); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONObject().put(null, 0.0d); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONObject().put(null, 5); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONObject().put(null, 5L); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONObject().put(null, "foo"); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testStrings() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "true"); + object.put("bar", "5.5"); + object.put("baz", "9223372036854775806"); + object.put("quux", "null"); + object.put("height", "5\"8' tall"); + + assertTrue(object.toString().contains("\"foo\":\"true\"")); + assertTrue(object.toString().contains("\"bar\":\"5.5\"")); + assertTrue(object.toString().contains("\"baz\":\"9223372036854775806\"")); + assertTrue(object.toString().contains("\"quux\":\"null\"")); + assertTrue(object.toString().contains("\"height\":\"5\\\"8' tall\"")); + + assertEquals("true", object.get("foo")); + assertEquals("null", object.getString("quux")); + assertEquals("5\"8' tall", object.getString("height")); + assertEquals("true", object.opt("foo")); + assertEquals("5.5", object.optString("bar")); + assertEquals("true", object.optString("foo", "x")); + assertFalse(object.isNull("foo")); + + assertEquals(true, object.getBoolean("foo")); + assertEquals(true, object.optBoolean("foo")); + assertEquals(true, object.optBoolean("foo", false)); + assertEquals(0, object.optInt("foo")); + assertEquals(-2, object.optInt("foo", -2)); + + assertEquals(5.5d, object.getDouble("bar"), 0); + assertEquals(5L, object.getLong("bar")); + assertEquals(5, object.getInt("bar")); + assertEquals(5, object.optInt("bar", 3)); + + // The last digit of the string is a 6 but getLong returns a 7. It's probably parsing as a + // double and then converting that to a long. This is consistent with JavaScript. + assertEquals(9223372036854775807L, object.getLong("baz")); + assertEquals(9.223372036854776E18, object.getDouble("baz"), 0); + assertEquals(Integer.MAX_VALUE, object.getInt("baz")); + + assertFalse(object.isNull("quux")); + try { + object.getDouble("quux"); + fail(); + } catch (JSONException e) { + // expected + } + assertEquals(Double.NaN, object.optDouble("quux"), 0); + assertEquals(-1.0d, object.optDouble("quux", -1.0d), 0); + + object.put("foo", "TRUE"); + assertEquals(true, object.getBoolean("foo")); + } + + @Test + public void testJSONObjects() throws JSONException { + JSONObject object = new JSONObject(); + + JSONArray a = new JSONArray(); + JSONObject b = new JSONObject(); + object.put("foo", a); + object.put("bar", b); + + assertSame(a, object.getJSONArray("foo")); + assertSame(b, object.getJSONObject("bar")); + try { + object.getJSONObject("foo"); + fail(); + } catch (JSONException ignored) { + } + try { + object.getJSONArray("bar"); + fail(); + } catch (JSONException ignored) { + } + assertEquals(a, object.optJSONArray("foo")); + assertEquals(b, object.optJSONObject("bar")); + assertEquals(null, object.optJSONArray("bar")); + assertEquals(null, object.optJSONObject("foo")); + } + + @Test + public void testNullCoercionToString() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", JSONObject.NULL); + assertEquals("null", object.getString("foo")); + } + + @Test + public void testArrayCoercion() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "[true]"); + try { + object.getJSONArray("foo"); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testObjectCoercion() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "{}"); + try { + object.getJSONObject("foo"); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testAccumulateValueChecking() throws JSONException { + JSONObject object = new JSONObject(); + try { + object.accumulate("foo", Double.NaN); + fail(); + } catch (JSONException ignored) { + } + object.accumulate("foo", 1); + try { + object.accumulate("foo", Double.NaN); + fail(); + } catch (JSONException ignored) { + } + object.accumulate("foo", 2); + try { + object.accumulate("foo", Double.NaN); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testToJSONArray() throws JSONException { + JSONObject object = new JSONObject(); + Object value = new Object(); + object.put("foo", true); + object.put("bar", 5.0d); + object.put("baz", -0.0d); + object.put("quux", value); + + JSONArray names = new JSONArray(); + names.put("baz"); + names.put("quux"); + names.put("foo"); + + JSONArray array = object.toJSONArray(names); + assertEquals(-0.0d, array.get(0)); + assertEquals(value, array.get(1)); + assertEquals(true, array.get(2)); + + object.put("foo", false); + assertEquals(true, array.get(2)); + } + + @Test + public void testToJSONArrayMissingNames() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", true); + object.put("bar", 5.0d); + object.put("baz", JSONObject.NULL); + + JSONArray names = new JSONArray(); + names.put("bar"); + names.put("foo"); + names.put("quux"); + names.put("baz"); + + JSONArray array = object.toJSONArray(names); + assertEquals(4, array.length()); + + assertEquals(5.0d, array.get(0)); + assertEquals(true, array.get(1)); + try { + array.get(2); + fail(); + } catch (JSONException ignored) { + } + assertEquals(JSONObject.NULL, array.get(3)); + } + + @Test + public void testToJSONArrayNull() throws JSONException { + JSONObject object = new JSONObject(); + assertEquals(null, object.toJSONArray(null)); + object.put("foo", 5); + try { + object.toJSONArray(null); + } catch (JSONException ignored) { + } + } + + @Test + public void testToJSONArrayEndsUpEmpty() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + JSONArray array = new JSONArray(); + array.put("bar"); + assertEquals(1, object.toJSONArray(array).length()); + } + + @Test + public void testToJSONArrayNonString() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + object.put("null", 10); + object.put("false", 15); + + JSONArray names = new JSONArray(); + names.put(JSONObject.NULL); + names.put(false); + names.put("foo"); + + // array elements are converted to strings to do name lookups on the map! + JSONArray array = object.toJSONArray(names); + assertEquals(3, array.length()); + assertEquals(10, array.get(0)); + assertEquals(15, array.get(1)); + assertEquals(5, array.get(2)); + } + + @Test + public void testPutUnsupportedNumbers() throws JSONException { + JSONObject object = new JSONObject(); + try { + object.put("foo", Double.NaN); + fail(); + } catch (JSONException ignored) { + } + try { + object.put("foo", Double.NEGATIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + try { + object.put("foo", Double.POSITIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testPutUnsupportedNumbersAsObjects() throws JSONException { + JSONObject object = new JSONObject(); + try { + object.put("foo", (Double) Double.NaN); + fail(); + } catch (JSONException ignored) { + } + try { + object.put("foo", (Double) Double.NEGATIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + try { + object.put("foo", (Double) Double.POSITIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + } + + /** + * Although JSONObject is usually defensive about which numbers it accepts, + * it doesn't check inputs in its constructor. + */ + @Test + public void testCreateWithUnsupportedNumbers() throws JSONException { + Map<String, Object> contents = new HashMap<String, Object>(); + contents.put("foo", Double.NaN); + contents.put("bar", Double.NEGATIVE_INFINITY); + contents.put("baz", Double.POSITIVE_INFINITY); + + JSONObject object = new JSONObject(contents); + assertEquals(Double.NaN, object.get("foo")); + assertEquals(Double.NEGATIVE_INFINITY, object.get("bar")); + assertEquals(Double.POSITIVE_INFINITY, object.get("baz")); + } + + @Test + public void testToStringWithUnsupportedNumbers() { + // when the object contains an unsupported number, toString returns null! + JSONObject object = new JSONObject(Collections.singletonMap("foo", Double.NaN)); + assertEquals(null, object.toString()); + } + + @Test + public void testMapConstructorCopiesContents() throws JSONException { + Map<String, Object> contents = new HashMap<String, Object>(); + contents.put("foo", 5); + JSONObject object = new JSONObject(contents); + contents.put("foo", 10); + assertEquals(5, object.get("foo")); + } + + @Test + public void testMapConstructorWithBogusEntries() { + Map<Object, Object> contents = new HashMap<Object, Object>(); + contents.put(5, 5); + + try { + new JSONObject(contents); + fail("JSONObject constructor doesn't validate its input!"); + } catch (Exception ignored) { + } + } + + @Test + public void testTokenerConstructor() throws JSONException { + JSONObject object = new JSONObject(new JSONTokener("{\"foo\": false}")); + assertEquals(1, object.length()); + assertEquals(false, object.get("foo")); + } + + @Test + public void testTokenerConstructorWrongType() throws JSONException { + try { + new JSONObject(new JSONTokener("[\"foo\", false]")); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testTokenerConstructorNull() throws JSONException { + try { + new JSONObject((JSONTokener) null); + fail(); + } catch (NullPointerException ignored) { + } + } + + @Test + public void testTokenerConstructorParseFail() { + try { + new JSONObject(new JSONTokener("{")); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testStringConstructor() throws JSONException { + JSONObject object = new JSONObject("{\"foo\": false}"); + assertEquals(1, object.length()); + assertEquals(false, object.get("foo")); + } + + @Test + public void testStringConstructorWrongType() throws JSONException { + try { + new JSONObject("[\"foo\", false]"); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testStringConstructorNull() throws JSONException { + try { + new JSONObject((String) null); + fail(); + } catch (NullPointerException ignored) { + } + } + + @Test + public void testStringConstructorParseFail() { + try { + new JSONObject("{"); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testCopyConstructor() throws JSONException { + JSONObject source = new JSONObject(); + source.put("a", JSONObject.NULL); + source.put("b", false); + source.put("c", 5); + + JSONObject copy = new JSONObject(source, new String[]{"a", "c"}); + assertEquals(2, copy.length()); + assertEquals(JSONObject.NULL, copy.get("a")); + assertEquals(5, copy.get("c")); + assertEquals(null, copy.opt("b")); + } + + @Test + public void testCopyConstructorMissingName() throws JSONException { + JSONObject source = new JSONObject(); + source.put("a", JSONObject.NULL); + source.put("b", false); + source.put("c", 5); + + JSONObject copy = new JSONObject(source, new String[]{"a", "c", "d"}); + assertEquals(2, copy.length()); + assertEquals(JSONObject.NULL, copy.get("a")); + assertEquals(5, copy.get("c")); + assertEquals(0, copy.optInt("b")); + } + + @Test + public void testAccumulateMutatesInPlace() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + object.accumulate("foo", 6); + JSONArray array = object.getJSONArray("foo"); + assertEquals("[5,6]", array.toString()); + object.accumulate("foo", 7); + assertEquals("[5,6,7]", array.toString()); + } + + @Test + public void testAccumulateExistingArray() throws JSONException { + JSONArray array = new JSONArray(); + JSONObject object = new JSONObject(); + object.put("foo", array); + object.accumulate("foo", 5); + assertEquals("[5]", array.toString()); + } + + @Test + public void testAccumulatePutArray() throws JSONException { + JSONObject object = new JSONObject(); + object.accumulate("foo", 5); + assertEquals("{\"foo\":5}", object.toString()); + object.accumulate("foo", new JSONArray()); + assertEquals("{\"foo\":[5,[]]}", object.toString()); + } + + @Test + public void testAccumulateNull() { + JSONObject object = new JSONObject(); + try { + object.accumulate(null, 5); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testEmptyStringKey() throws JSONException { + JSONObject object = new JSONObject(); + object.put("", 5); + assertEquals(5, object.get("")); + assertEquals("{\"\":5}", object.toString()); + } + + @Test + public void testNullValue() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", JSONObject.NULL); + object.put("bar", null); + + // there are two ways to represent null; each behaves differently! + assertTrue(object.has("foo")); + assertFalse(object.has("bar")); + assertTrue(object.isNull("foo")); + assertTrue(object.isNull("bar")); + } + + @Test + public void testNullValue_equalsAndHashCode() { + //noinspection ObjectEqualsNull + assertTrue(JSONObject.NULL.equals(null)); // guaranteed by javadoc + // not guaranteed by javadoc, but seems like a good idea + assertEquals(Objects.hashCode(null), JSONObject.NULL.hashCode()); + } + + @Test + public void testHas() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + assertTrue(object.has("foo")); + assertFalse(object.has("bar")); + assertFalse(object.has(null)); + } + + @Test + public void testOptNull() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", "bar"); + assertEquals(null, object.opt(null)); + assertEquals(false, object.optBoolean(null)); + assertEquals(Double.NaN, object.optDouble(null), 0); + assertEquals(0, object.optInt(null)); + assertEquals(0L, object.optLong(null)); + assertEquals(null, object.optJSONArray(null)); + assertEquals(null, object.optJSONObject(null)); + assertEquals("", object.optString(null)); + assertEquals(true, object.optBoolean(null, true)); + assertEquals(0.0d, object.optDouble(null, 0.0d), 0); + assertEquals(1, object.optInt(null, 1)); + assertEquals(1L, object.optLong(null, 1L)); + assertEquals("baz", object.optString(null, "baz")); + } + + @Test + public void testToStringWithIndentFactor() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", new JSONArray(Arrays.asList(5, 6))); + object.put("bar", new JSONObject()); + String foobar = "{\n" + + " \"foo\": [\n" + + " 5,\n" + + " 6\n" + + " ],\n" + + " \"bar\": {}\n" + + "}"; + String barfoo = "{\n" + + " \"bar\": {},\n" + + " \"foo\": [\n" + + " 5,\n" + + " 6\n" + + " ]\n" + + "}"; + String string = object.toString(5); + assertTrue(string, foobar.equals(string) || barfoo.equals(string)); + } + + @Test + public void testNames() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + object.put("bar", 6); + object.put("baz", 7); + JSONArray array = object.names(); + assertTrue(array.toString().contains("foo")); + assertTrue(array.toString().contains("bar")); + assertTrue(array.toString().contains("baz")); + } + + @Test + public void testKeysEmptyObject() { + JSONObject object = new JSONObject(); + assertFalse(object.keys().hasNext()); + try { + object.keys().next(); + fail(); + } catch (NoSuchElementException ignored) { + } + } + + @Test + public void testKeys() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + object.put("bar", 6); + object.put("foo", 7); + + @SuppressWarnings("unchecked") + Iterator<String> keys = object.keys(); + Set<String> result = new HashSet<String>(); + assertTrue(keys.hasNext()); + result.add(keys.next()); + assertTrue(keys.hasNext()); + result.add(keys.next()); + assertFalse(keys.hasNext()); + assertEquals(new HashSet<String>(Arrays.asList("foo", "bar")), result); + + try { + keys.next(); + fail(); + } catch (NoSuchElementException ignored) { + } + } + + @Test + public void testMutatingKeysMutatesObject() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + Iterator keys = object.keys(); + keys.next(); + keys.remove(); + assertEquals(0, object.length()); + } + + @Test + public void testQuote() { + // covered by JSONStringerTest.testEscaping + } + + @Test + public void testQuoteNull() throws JSONException { + assertEquals("\"\"", JSONObject.quote(null)); + } + + @Test + public void testNumberToString() throws JSONException { + assertEquals("5", JSONObject.numberToString(5)); + assertEquals("-0", JSONObject.numberToString(-0.0d)); + assertEquals("9223372036854775806", JSONObject.numberToString(9223372036854775806L)); + assertEquals("4.9E-324", JSONObject.numberToString(Double.MIN_VALUE)); + assertEquals("1.7976931348623157E308", JSONObject.numberToString(Double.MAX_VALUE)); + try { + JSONObject.numberToString(Double.NaN); + fail(); + } catch (JSONException ignored) { + } + try { + JSONObject.numberToString(Double.NEGATIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + try { + JSONObject.numberToString(Double.POSITIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + assertEquals("0.001", JSONObject.numberToString(new BigDecimal("0.001"))); + assertEquals("9223372036854775806", + JSONObject.numberToString(new BigInteger("9223372036854775806"))); + try { + JSONObject.numberToString(null); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void test_wrap() throws Exception { + assertEquals(JSONObject.NULL, JSONObject.wrap(null)); + + JSONArray a = new JSONArray(); + assertEquals(a, JSONObject.wrap(a)); + + JSONObject o = new JSONObject(); + assertEquals(o, JSONObject.wrap(o)); + + assertEquals(JSONObject.NULL, JSONObject.wrap(JSONObject.NULL)); + + assertTrue(JSONObject.wrap(new byte[0]) instanceof JSONArray); + assertTrue(JSONObject.wrap(new ArrayList<String>()) instanceof JSONArray); + assertTrue(JSONObject.wrap(new HashMap<String, String>()) instanceof JSONObject); + assertTrue(JSONObject.wrap(0.0) instanceof Double); + assertTrue(JSONObject.wrap("hello") instanceof String); + } + + // https://code.google.com/p/android/issues/detail?id=55114 + @Test + public void test_toString_listAsMapValue() throws Exception { + ArrayList<Object> list = new ArrayList<Object>(); + list.add("a"); + list.add(new ArrayList<String>()); + Map<String, Object> map = new TreeMap<String, Object>(); + map.put("x", "l"); + map.put("y", list); + assertEquals("{\"x\":\"l\",\"y\":[\"a\",[]]}", new JSONObject(map).toString()); + } + + @Test + public void testAppendExistingInvalidKey() throws JSONException { + JSONObject object = new JSONObject(); + object.put("foo", 5); + try { + object.append("foo", 6); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testAppendExistingArray() throws JSONException { + JSONArray array = new JSONArray(); + JSONObject object = new JSONObject(); + object.put("foo", array); + object.append("foo", 5); + assertEquals("[5]", array.toString()); + } + + @Test + public void testAppendPutArray() throws JSONException { + JSONObject object = new JSONObject(); + object.append("foo", 5); + assertEquals("{\"foo\":[5]}", object.toString()); + object.append("foo", new JSONArray()); + assertEquals("{\"foo\":[5,[]]}", object.toString()); + } + + @Test + public void testAppendNull() { + JSONObject object = new JSONObject(); + try { + object.append(null, 5); + fail(); + } catch (JSONException ignored) { + } + } + + // https://code.google.com/p/android/issues/detail?id=103641 + @Test + public void testInvalidUnicodeEscape() { + try { + new JSONObject("{\"q\":\"\\u\", \"r\":[]}"); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testBeanThings() throws IllegalAccessException, IntrospectionException, InvocationTargetException { + Foo f = new Foo(); + assertEquals("{\"a\":1,\"b\":1,\"c\":\"c\",\"d\":[{\"e\":\"echo\"}]}", new JSONObject(f).toString()); + } + + @Test + public void testGetNames() throws Exception { + assertArrayEquals(new String[]{"a", "b", "c", "d"}, JSONObject.getNames(new JSONObject(new Foo()))); + } + + private static class Foo { + public double getA() { + return 1.0; + } + + public int getB() { + return 1; + } + + public String getC() { + return "c"; + } + + public List<Bar> getD() { + ArrayList<Bar> r = new ArrayList<Bar>(); + r.add(new Bar()); + return r; + } + } + + private static class Bar { + public String getE() { + return "echo"; + } + } + + @Test + public void testEnumWrapper() throws Exception { + Object y = JSONObject.wrap(E.A); + assertEquals("A", y); + assertTrue(y instanceof String); + } + + enum E { + A { + int key() { + return 1; + } + }, B { + int key() { + return 2; + } + }; + int key() { + return -1; + } + } +}
http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/test/java/org/json/JSONStringerTest.java ---------------------------------------------------------------------- diff --git a/geode-json/src/test/java/org/json/JSONStringerTest.java b/geode-json/src/test/java/org/json/JSONStringerTest.java new file mode 100755 index 0000000..7c7362d --- /dev/null +++ b/geode-json/src/test/java/org/json/JSONStringerTest.java @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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 org.json; + +import org.junit.Test; + +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; + +/** + * This black box test was written without inspecting the non-free org.json sourcecode. + */ +public class JSONStringerTest { + + @Test + public void testJSONFunctionHackTest() { + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.key("key"); + stringer.value(new JSONFunctionTestObject("window.test('foo' + \"bar\")")); + stringer.endObject(); + assertEquals("{\"key\":window.test('foo' + \"bar\")}", stringer.toString()); + } + + @Test + public void testEmptyStringer() { + // why isn't this the empty string? + assertNull(new JSONStringer().toString()); + } + + @Test + public void testValueJSONNull() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(JSONObject.NULL); + stringer.endArray(); + assertEquals("[null]", stringer.toString()); + } + + @Test + public void testEmptyObject() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.endObject(); + assertEquals("{}", stringer.toString()); + } + + @Test + public void testEmptyArray() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.endArray(); + assertEquals("[]", stringer.toString()); + } + + @Test + public void testArray() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(false); + stringer.value(5.0); + stringer.value(5L); + stringer.value("five"); + stringer.value(null); + stringer.endArray(); + assertEquals("[false,5,5,\"five\",null]", stringer.toString()); + } + + @Test + public void testValueObjectMethods() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(Boolean.FALSE); + stringer.value(Double.valueOf(5.0)); + stringer.value(Long.valueOf(5L)); + stringer.endArray(); + assertEquals("[false,5,5]", stringer.toString()); + } + + @Test + public void testKeyValue() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.key("a").value(false); + stringer.key("b").value(5.0); + stringer.key("c").value(5L); + stringer.key("d").value("five"); + stringer.key("e").value(null); + stringer.endObject(); + assertEquals("{\"a\":false," + + "\"b\":5," + + "\"c\":5," + + "\"d\":\"five\"," + + "\"e\":null}", stringer.toString()); + } + + /** + * Test what happens when extreme values are emitted. Such values are likely + * to be rounded during parsing. + */ + @Test + public void testNumericRepresentations() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(Long.MAX_VALUE); + stringer.value(Double.MIN_VALUE); + stringer.endArray(); + assertEquals("[9223372036854775807,4.9E-324]", stringer.toString()); + } + + @Test + public void testWeirdNumbers() throws JSONException { + try { + new JSONStringer().array().value(Double.NaN); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().array().value(Double.NEGATIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().array().value(Double.POSITIVE_INFINITY); + fail(); + } catch (JSONException ignored) { + } + + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(-0.0d); + stringer.value(0.0d); + stringer.endArray(); + assertEquals("[-0,0]", stringer.toString()); + } + + @Test + public void testMismatchedScopes() { + try { + new JSONStringer().key("a"); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().value("a"); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().endObject(); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().endArray(); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().array().endObject(); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().object().endArray(); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().object().key("a").key("a"); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONStringer().object().value(false); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testNullKey() { + try { + new JSONStringer().object().key(null); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testRepeatedKey() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.key("a").value(true); + stringer.key("a").value(false); + stringer.endObject(); + // JSONStringer doesn't attempt to detect duplicates + assertEquals("{\"a\":true,\"a\":false}", stringer.toString()); + } + + @Test + public void testEmptyKey() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.key("").value(false); + stringer.endObject(); + assertEquals("{\"\":false}", stringer.toString()); // legit behaviour! + } + + @Test + public void testEscaping() throws JSONException { + assertEscapedAllWays("a", "a"); + assertEscapedAllWays("a\\\"", "a\""); + assertEscapedAllWays("\\\"", "\""); + assertEscapedAllWays(":", ":"); + assertEscapedAllWays(",", ","); + assertEscapedAllWays("\\b", "\b"); + assertEscapedAllWays("\\f", "\f"); + assertEscapedAllWays("\\n", "\n"); + assertEscapedAllWays("\\r", "\r"); + assertEscapedAllWays("\\t", "\t"); + assertEscapedAllWays(" ", " "); + assertEscapedAllWays("\\\\", "\\"); + assertEscapedAllWays("{", "{"); + assertEscapedAllWays("}", "}"); + assertEscapedAllWays("[", "["); + assertEscapedAllWays("]", "]"); + assertEscapedAllWays("\\u0000", "\0"); + assertEscapedAllWays("\\u0019", "\u0019"); + assertEscapedAllWays(" ", "\u0020"); + assertEscapedAllWays("<\\/foo>", "</foo>"); + } + + private void assertEscapedAllWays(String escaped, String original) throws JSONException { + assertEquals("{\"" + escaped + "\":false}", + new JSONStringer().object().key(original).value(false).endObject().toString()); + assertEquals("{\"a\":\"" + escaped + "\"}", + new JSONStringer().object().key("a").value(original).endObject().toString()); + assertEquals("[\"" + escaped + "\"]", + new JSONStringer().array().value(original).endArray().toString()); + assertEquals("\"" + escaped + "\"", JSONObject.quote(original)); + } + + @Test + public void testJSONArrayAsValue() throws JSONException { + JSONArray array = new JSONArray(); + array.put(false); + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(array); + stringer.endArray(); + assertEquals("[[false]]", stringer.toString()); + } + + @Test + public void testJSONObjectAsValue() throws JSONException { + JSONObject object = new JSONObject(); + object.put("a", false); + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.key("b").value(object); + stringer.endObject(); + assertEquals("{\"b\":{\"a\":false}}", stringer.toString()); + } + + @Test + public void testArrayNestingMaxDepthSupports20() throws JSONException { + JSONStringer stringer = new JSONStringer(); + for (int i = 0; i < 20; i++) { + stringer.array(); + } + for (int i = 0; i < 20; i++) { + stringer.endArray(); + } + assertEquals("[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]", stringer.toString()); + + stringer = new JSONStringer(); + for (int i = 0; i < 20; i++) { + stringer.array(); + } + } + + @Test + public void testObjectNestingMaxDepthSupports20() throws JSONException { + JSONStringer stringer = new JSONStringer(); + for (int i = 0; i < 20; i++) { + stringer.object(); + stringer.key("a"); + } + stringer.value(false); + for (int i = 0; i < 20; i++) { + stringer.endObject(); + } + assertEquals("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":" + + "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":false" + + "}}}}}}}}}}}}}}}}}}}}", stringer.toString()); + + stringer = new JSONStringer(); + for (int i = 0; i < 20; i++) { + stringer.object(); + stringer.key("a"); + } + } + + @Test + public void testMixedMaxDepthSupports20() throws JSONException { + JSONStringer stringer = new JSONStringer(); + for (int i = 0; i < 20; i += 2) { + stringer.array(); + stringer.object(); + stringer.key("a"); + } + stringer.value(false); + for (int i = 0; i < 20; i += 2) { + stringer.endObject(); + stringer.endArray(); + } + assertEquals("[{\"a\":[{\"a\":[{\"a\":[{\"a\":[{\"a\":" + + "[{\"a\":[{\"a\":[{\"a\":[{\"a\":[{\"a\":false" + + "}]}]}]}]}]}]}]}]}]}]", stringer.toString()); + + stringer = new JSONStringer(); + for (int i = 0; i < 20; i += 2) { + stringer.array(); + stringer.object(); + stringer.key("a"); + } + } + + @Test + public void testMaxDepthWithArrayValue() throws JSONException { + JSONArray array = new JSONArray(); + array.put(false); + + JSONStringer stringer = new JSONStringer(); + for (int i = 0; i < 20; i++) { + stringer.array(); + } + stringer.value(array); + for (int i = 0; i < 20; i++) { + stringer.endArray(); + } + assertEquals("[[[[[[[[[[[[[[[[[[[[[false]]]]]]]]]]]]]]]]]]]]]", stringer.toString()); + } + + @Test + public void testMaxDepthWithObjectValue() throws JSONException { + JSONObject object = new JSONObject(); + object.put("a", false); + JSONStringer stringer = new JSONStringer(); + for (int i = 0; i < 20; i++) { + stringer.object(); + stringer.key("b"); + } + stringer.value(object); + for (int i = 0; i < 20; i++) { + stringer.endObject(); + } + assertEquals("{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":" + + "{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":" + + "{\"a\":false}}}}}}}}}}}}}}}}}}}}}", stringer.toString()); + } + + @Test + public void testMultipleRoots() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.endArray(); + try { + stringer.object(); + fail(); + } catch (JSONException ignored) { + } + } + + @Test + public void testEnums() { + JSONObject x = new JSONObject(); + x.put("a", TimeUnit.SECONDS); + x.put("b", "xyx"); + JSONStringer s = new JSONStringer(); + s.array(); + s.value(x); + s.endArray(); + assertEquals("[{\"a\":\"SECONDS\",\"b\":\"xyx\"}]", s.toString()); + } + + @Test + public void testJsonString() { + JSONObject x = new JSONObject(); + x.put("a", new Goo()); + JSONStringer s = new JSONStringer(); + s.array(); + s.value(x); + s.endArray(); + // note lack of quotes + assertEquals("[{\"a\":fffooo}]", s.toString()); + } + + private static class Goo implements JSONString { + @Override + public String toJSONString() { + return "fffooo"; + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/test/java/org/json/JSONTokenerTest.java ---------------------------------------------------------------------- diff --git a/geode-json/src/test/java/org/json/JSONTokenerTest.java b/geode-json/src/test/java/org/json/JSONTokenerTest.java new file mode 100755 index 0000000..9975177 --- /dev/null +++ b/geode-json/src/test/java/org/json/JSONTokenerTest.java @@ -0,0 +1,621 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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 org.json; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +/** + * This black box test was written without inspecting the non-free org.json sourcecode. + */ +public class JSONTokenerTest extends TestCase { + + public void testNulls() throws JSONException { + // JSONTokener accepts null, only to fail later on almost all APIs! + new JSONTokener((String) null).back(); + + try { + new JSONTokener((String) null).more(); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).next(); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).next(3); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).next('A'); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).nextClean(); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).nextString('"'); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).nextTo('A'); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).nextTo("ABC"); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).nextValue(); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).skipPast("ABC"); + fail(); + } catch (NullPointerException ignored) { + } + + try { + new JSONTokener((String) null).skipTo('A'); + fail(); + } catch (NullPointerException ignored) { + } + + //noinspection ThrowableResultOfMethodCallIgnored + assertEquals("foo! at character 0 of null", + new JSONTokener((String) null).syntaxError("foo!").getMessage()); + + assertEquals(" at character 0 of null", new JSONTokener((String) null).toString()); + } + + public void testEmptyString() throws JSONException { + JSONTokener backTokener = new JSONTokener(""); + backTokener.back(); + assertEquals(" at character 0 of ", backTokener.toString()); + assertFalse(new JSONTokener("").more()); + assertEquals('\0', new JSONTokener("").next()); + try { + new JSONTokener("").next(3); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONTokener("").next('A'); + fail(); + } catch (JSONException ignored) { + } + assertEquals('\0', new JSONTokener("").nextClean()); + try { + new JSONTokener("").nextString('"'); + fail(); + } catch (JSONException ignored) { + } + assertEquals("", new JSONTokener("").nextTo('A')); + assertEquals("", new JSONTokener("").nextTo("ABC")); + try { + new JSONTokener("").nextValue(); + fail(); + } catch (JSONException ignored) { + } + new JSONTokener("").skipPast("ABC"); + assertEquals('\0', new JSONTokener("").skipTo('A')); + //noinspection ThrowableResultOfMethodCallIgnored + assertEquals("foo! at character 0 of ", + new JSONTokener("").syntaxError("foo!").getMessage()); + assertEquals(" at character 0 of ", new JSONTokener("").toString()); + } + + public void testCharacterNavigation() throws JSONException { + JSONTokener abcdeTokener = new JSONTokener("ABCDE"); + assertEquals('A', abcdeTokener.next()); + assertEquals('B', abcdeTokener.next('B')); + assertEquals("CD", abcdeTokener.next(2)); + try { + abcdeTokener.next(2); + fail(); + } catch (JSONException ignored) { + } + assertEquals('E', abcdeTokener.nextClean()); + assertEquals('\0', abcdeTokener.next()); + assertFalse(abcdeTokener.more()); + abcdeTokener.back(); + assertTrue(abcdeTokener.more()); + assertEquals('E', abcdeTokener.next()); + } + + public void testBackNextAndMore() throws JSONException { + JSONTokener abcTokener = new JSONTokener("ABC"); + assertTrue(abcTokener.more()); + abcTokener.next(); + abcTokener.next(); + assertTrue(abcTokener.more()); + abcTokener.next(); + assertFalse(abcTokener.more()); + abcTokener.back(); + assertTrue(abcTokener.more()); + abcTokener.next(); + assertFalse(abcTokener.more()); + abcTokener.back(); + abcTokener.back(); + abcTokener.back(); + abcTokener.back(); // you can back up before the beginning of a String! + assertEquals('A', abcTokener.next()); + } + + public void testNextMatching() throws JSONException { + JSONTokener abcdTokener = new JSONTokener("ABCD"); + assertEquals('A', abcdTokener.next('A')); + try { + abcdTokener.next('C'); // although it failed, this op consumes a character of input + fail(); + } catch (JSONException ignored) { + } + assertEquals('C', abcdTokener.next('C')); + assertEquals('D', abcdTokener.next('D')); + try { + abcdTokener.next('E'); + fail(); + } catch (JSONException ignored) { + } + } + + public void testNextN() throws JSONException { + JSONTokener abcdeTokener = new JSONTokener("ABCDEF"); + assertEquals("", abcdeTokener.next(0)); + try { + abcdeTokener.next(7); + fail(); + } catch (JSONException ignored) { + } + assertEquals("ABC", abcdeTokener.next(3)); + try { + abcdeTokener.next(4); + fail(); + } catch (JSONException ignored) { + } + } + + public void testNextNWithAllRemaining() throws JSONException { + JSONTokener tokener = new JSONTokener("ABCDEF"); + tokener.next(3); + try { + tokener.next(3); + } catch (JSONException e) { + AssertionFailedError error = new AssertionFailedError("off-by-one error?"); + error.initCause(e); + throw error; + } + } + + public void testNext0() throws JSONException { + JSONTokener tokener = new JSONTokener("ABCDEF"); + tokener.next(5); + tokener.next(); + try { + tokener.next(0); + } catch (JSONException e) { + Error error = new AssertionFailedError("Returning an empty string should be valid"); + error.initCause(e); + throw error; + } + } + + public void testNextCleanComments() throws JSONException { + JSONTokener tokener = new JSONTokener( + " A /*XX*/B/*XX//XX\n//XX\nXX*/C//X//X//X\nD/*X*///X\n"); + assertEquals('A', tokener.nextClean()); + assertEquals('B', tokener.nextClean()); + assertEquals('C', tokener.nextClean()); + assertEquals('D', tokener.nextClean()); + assertEquals('\0', tokener.nextClean()); + } + + public void testNextCleanNestedCStyleComments() throws JSONException { + JSONTokener tokener = new JSONTokener("A /* B /* C */ D */ E"); + assertEquals('A', tokener.nextClean()); + assertEquals('D', tokener.nextClean()); + assertEquals('*', tokener.nextClean()); + assertEquals('/', tokener.nextClean()); + assertEquals('E', tokener.nextClean()); + } + + /** + * Some applications rely on parsing '#' to lead an end-of-line comment. + * http://b/2571423 + */ + public void testNextCleanHashComments() throws JSONException { + JSONTokener tokener = new JSONTokener("A # B */ /* C */ \nD #"); + assertEquals('A', tokener.nextClean()); + assertEquals('D', tokener.nextClean()); + assertEquals('\0', tokener.nextClean()); + } + + public void testNextCleanCommentsTrailingSingleSlash() throws JSONException { + JSONTokener tokener = new JSONTokener(" / S /"); + assertEquals('/', tokener.nextClean()); + assertEquals('S', tokener.nextClean()); + assertEquals('/', tokener.nextClean()); + assertEquals("nextClean doesn't consume a trailing slash", + '\0', tokener.nextClean()); + } + + public void testNextCleanTrailingOpenComment() throws JSONException { + try { + new JSONTokener(" /* ").nextClean(); + fail(); + } catch (JSONException ignored) { + } + assertEquals('\0', new JSONTokener(" // ").nextClean()); + } + + public void testNextCleanNewlineDelimiters() throws JSONException { + assertEquals('B', new JSONTokener(" // \r\n B ").nextClean()); + assertEquals('B', new JSONTokener(" // \n B ").nextClean()); + assertEquals('B', new JSONTokener(" // \r B ").nextClean()); + } + + public void testNextCleanSkippedWhitespace() throws JSONException { + assertEquals("character tabulation", 'A', new JSONTokener("\tA").nextClean()); + assertEquals("line feed", 'A', new JSONTokener("\nA").nextClean()); + assertEquals("carriage return", 'A', new JSONTokener("\rA").nextClean()); + assertEquals("space", 'A', new JSONTokener(" A").nextClean()); + } + + /** + * Tests which characters tokener treats as ignorable whitespace. See Kevin Bourrillion's + * <a href="https://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">list + * of whitespace characters</a>. + */ + public void testNextCleanRetainedWhitespace() throws JSONException { + assertNotClean("null", '\u0000'); + assertNotClean("next line", '\u0085'); + assertNotClean("non-breaking space", '\u00a0'); + assertNotClean("ogham space mark", '\u1680'); + assertNotClean("mongolian vowel separator", '\u180e'); + assertNotClean("en quad", '\u2000'); + assertNotClean("em quad", '\u2001'); + assertNotClean("en space", '\u2002'); + assertNotClean("em space", '\u2003'); + assertNotClean("three-per-em space", '\u2004'); + assertNotClean("four-per-em space", '\u2005'); + assertNotClean("six-per-em space", '\u2006'); + assertNotClean("figure space", '\u2007'); + assertNotClean("punctuation space", '\u2008'); + assertNotClean("thin space", '\u2009'); + assertNotClean("hair space", '\u200a'); + assertNotClean("zero-width space", '\u200b'); + assertNotClean("left-to-right mark", '\u200e'); + assertNotClean("right-to-left mark", '\u200f'); + assertNotClean("line separator", '\u2028'); + assertNotClean("paragraph separator", '\u2029'); + assertNotClean("narrow non-breaking space", '\u202f'); + assertNotClean("medium mathematical space", '\u205f'); + assertNotClean("ideographic space", '\u3000'); + assertNotClean("line tabulation", '\u000b'); + assertNotClean("form feed", '\u000c'); + assertNotClean("information separator 4", '\u001c'); + assertNotClean("information separator 3", '\u001d'); + assertNotClean("information separator 2", '\u001e'); + assertNotClean("information separator 1", '\u001f'); + } + + private void assertNotClean(String name, char c) throws JSONException { + assertEquals("The character " + name + " is not whitespace according to the JSON spec.", + c, new JSONTokener(new String(new char[] { c, 'A' })).nextClean()); + } + + public void testNextString() throws JSONException { + assertEquals("", new JSONTokener("'").nextString('\'')); + assertEquals("", new JSONTokener("\"").nextString('\"')); + assertEquals("ABC", new JSONTokener("ABC'DEF").nextString('\'')); + assertEquals("ABC", new JSONTokener("ABC'''DEF").nextString('\'')); + + // nextString permits slash-escaping of arbitrary characters! + assertEquals("ABC", new JSONTokener("A\\B\\C'DEF").nextString('\'')); + + JSONTokener tokener = new JSONTokener(" 'abc' 'def' \"ghi\""); + tokener.next(); + assertEquals('\'', tokener.next()); + assertEquals("abc", tokener.nextString('\'')); + tokener.next(); + assertEquals('\'', tokener.next()); + assertEquals("def", tokener.nextString('\'')); + tokener.next(); + assertEquals('"', tokener.next()); + assertEquals("ghi", tokener.nextString('\"')); + assertFalse(tokener.more()); + } + + public void testNextStringNoDelimiter() throws JSONException { + try { + new JSONTokener("").nextString('\''); + fail(); + } catch (JSONException ignored) { + } + + JSONTokener tokener = new JSONTokener(" 'abc"); + tokener.next(); + tokener.next(); + try { + tokener.next('\''); + fail(); + } catch (JSONException ignored) { + } + } + + public void testNextStringEscapedQuote() throws JSONException { + try { + new JSONTokener("abc\\").nextString('"'); + fail(); + } catch (JSONException ignored) { + } + + // we're mixing Java escaping like \" and JavaScript escaping like \\\" + // which makes these tests extra tricky to read! + assertEquals("abc\"def", new JSONTokener("abc\\\"def\"ghi").nextString('"')); + assertEquals("abc\\def", new JSONTokener("abc\\\\def\"ghi").nextString('"')); + assertEquals("abc/def", new JSONTokener("abc\\/def\"ghi").nextString('"')); + assertEquals("abc\bdef", new JSONTokener("abc\\bdef\"ghi").nextString('"')); + assertEquals("abc\fdef", new JSONTokener("abc\\fdef\"ghi").nextString('"')); + assertEquals("abc\ndef", new JSONTokener("abc\\ndef\"ghi").nextString('"')); + assertEquals("abc\rdef", new JSONTokener("abc\\rdef\"ghi").nextString('"')); + assertEquals("abc\tdef", new JSONTokener("abc\\tdef\"ghi").nextString('"')); + } + + public void testNextStringUnicodeEscaped() throws JSONException { + // we're mixing Java escaping like \\ and JavaScript escaping like \\u + assertEquals("abc def", new JSONTokener("abc\\u0020def\"ghi").nextString('"')); + assertEquals("abcU0020def", new JSONTokener("abc\\U0020def\"ghi").nextString('"')); + + // JSON requires 4 hex characters after a unicode escape + try { + new JSONTokener("abc\\u002\"").nextString('"'); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONTokener("abc\\u").nextString('"'); + fail(); + } catch (JSONException ignored) { + } + try { + new JSONTokener("abc\\u \"").nextString('"'); + fail(); + } catch (JSONException ignored) { + } + assertEquals("abc\"def", new JSONTokener("abc\\u0022def\"ghi").nextString('"')); + try { + new JSONTokener("abc\\u000G\"").nextString('"'); + fail(); + } catch (JSONException ignored) { + } + } + + public void testNextStringNonQuote() throws JSONException { + assertEquals("AB", new JSONTokener("ABC").nextString('C')); + assertEquals("ABCD", new JSONTokener("AB\\CDC").nextString('C')); + assertEquals("AB\nC", new JSONTokener("AB\\nCn").nextString('n')); + } + + public void testNextTo() throws JSONException { + assertEquals("ABC", new JSONTokener("ABCDEFG").nextTo("DHI")); + assertEquals("ABCDEF", new JSONTokener("ABCDEF").nextTo("")); + + JSONTokener tokener = new JSONTokener("ABC\rDEF\nGHI\r\nJKL"); + assertEquals("ABC", tokener.nextTo("M")); + assertEquals('\r', tokener.next()); + assertEquals("DEF", tokener.nextTo("M")); + assertEquals('\n', tokener.next()); + assertEquals("GHI", tokener.nextTo("M")); + assertEquals('\r', tokener.next()); + assertEquals('\n', tokener.next()); + assertEquals("JKL", tokener.nextTo("M")); + + tokener = new JSONTokener("ABCDEFGHI"); + assertEquals("ABC", tokener.nextTo("DEF")); + assertEquals("", tokener.nextTo("DEF")); + assertEquals('D', tokener.next()); + assertEquals("", tokener.nextTo("DEF")); + assertEquals('E', tokener.next()); + assertEquals("", tokener.nextTo("DEF")); + assertEquals('F', tokener.next()); + assertEquals("GHI", tokener.nextTo("DEF")); + assertEquals("", tokener.nextTo("DEF")); + + tokener = new JSONTokener(" \t \fABC \t DEF"); + assertEquals("ABC", tokener.nextTo("DEF")); + assertEquals('D', tokener.next()); + + tokener = new JSONTokener(" \t \fABC \n DEF"); + assertEquals("ABC", tokener.nextTo("\n")); + assertEquals("", tokener.nextTo("\n")); + + tokener = new JSONTokener(""); + try { + tokener.nextTo(null); + fail(); + } catch (NullPointerException ignored) { + } + } + + public void testNextToTrimming() { + assertEquals("ABC", new JSONTokener("\t ABC \tDEF").nextTo("DE")); + assertEquals("ABC", new JSONTokener("\t ABC \tDEF").nextTo('D')); + } + + public void testNextToTrailing() { + assertEquals("ABC DEF", new JSONTokener("\t ABC DEF \t").nextTo("G")); + assertEquals("ABC DEF", new JSONTokener("\t ABC DEF \t").nextTo('G')); + } + + public void testNextToDoesntStopOnNull() { + String message = "nextTo() shouldn't stop after \\0 characters"; + JSONTokener tokener = new JSONTokener(" \0\t \fABC \n DEF"); + assertEquals(message, "ABC", tokener.nextTo("D")); + assertEquals(message, '\n', tokener.next()); + assertEquals(message, "", tokener.nextTo("D")); + } + + public void testNextToConsumesNull() { + String message = "nextTo shouldn't consume \\0."; + JSONTokener tokener = new JSONTokener("ABC\0DEF"); + assertEquals(message, "ABC", tokener.nextTo("\0")); + assertEquals(message, '\0', tokener.next()); + assertEquals(message, "DEF", tokener.nextTo("\0")); + } + + public void testSkipPast() { + JSONTokener tokener = new JSONTokener("ABCDEF"); + tokener.skipPast("ABC"); + assertEquals('D', tokener.next()); + tokener.skipPast("EF"); + assertEquals('\0', tokener.next()); + + tokener = new JSONTokener("ABCDEF"); + tokener.skipPast("ABCDEF"); + assertEquals('\0', tokener.next()); + + tokener = new JSONTokener("ABCDEF"); + tokener.skipPast("G"); + assertEquals('\0', tokener.next()); + + tokener = new JSONTokener("ABC\0ABC"); + tokener.skipPast("ABC"); + assertEquals('\0', tokener.next()); + assertEquals('A', tokener.next()); + + tokener = new JSONTokener("\0ABC"); + tokener.skipPast("ABC"); + assertEquals('\0', tokener.next()); + + tokener = new JSONTokener("ABC\nDEF"); + tokener.skipPast("DEF"); + assertEquals('\0', tokener.next()); + + tokener = new JSONTokener("ABC"); + tokener.skipPast("ABCDEF"); + assertEquals('\0', tokener.next()); + + tokener = new JSONTokener("ABCDABCDABCD"); + tokener.skipPast("ABC"); + assertEquals('D', tokener.next()); + tokener.skipPast("ABC"); + assertEquals('D', tokener.next()); + tokener.skipPast("ABC"); + assertEquals('D', tokener.next()); + + tokener = new JSONTokener(""); + try { + tokener.skipPast(null); + fail(); + } catch (NullPointerException ignored) { + } + } + + public void testSkipTo() { + JSONTokener tokener = new JSONTokener("ABCDEF"); + tokener.skipTo('A'); + assertEquals('A', tokener.next()); + tokener.skipTo('D'); + assertEquals('D', tokener.next()); + tokener.skipTo('G'); + assertEquals('E', tokener.next()); + tokener.skipTo('A'); + assertEquals('F', tokener.next()); + + tokener = new JSONTokener("ABC\nDEF"); + tokener.skipTo('F'); + assertEquals('F', tokener.next()); + + tokener = new JSONTokener("ABCfDEF"); + tokener.skipTo('F'); + assertEquals('F', tokener.next()); + + tokener = new JSONTokener("ABC/* DEF */"); + tokener.skipTo('D'); + assertEquals('D', tokener.next()); + } + + public void testSkipToStopsOnNull() { + JSONTokener tokener = new JSONTokener("ABC\0DEF"); + tokener.skipTo('F'); + assertEquals("skipTo shouldn't stop when it sees '\\0'", 'F', tokener.next()); + } + + public void testBomIgnoredAsFirstCharacterOfDocument() throws JSONException { + JSONTokener tokener = new JSONTokener("\ufeff[]"); + JSONArray array = (JSONArray) tokener.nextValue(); + assertEquals(0, array.length()); + } + + public void testBomTreatedAsCharacterInRestOfDocument() throws JSONException { + JSONTokener tokener = new JSONTokener("[\ufeff]"); + JSONArray array = (JSONArray) tokener.nextValue(); + assertEquals(1, array.length()); + } + + public void testDehexchar() { + assertEquals( 0, JSONTokener.dehexchar('0')); + assertEquals( 1, JSONTokener.dehexchar('1')); + assertEquals( 2, JSONTokener.dehexchar('2')); + assertEquals( 3, JSONTokener.dehexchar('3')); + assertEquals( 4, JSONTokener.dehexchar('4')); + assertEquals( 5, JSONTokener.dehexchar('5')); + assertEquals( 6, JSONTokener.dehexchar('6')); + assertEquals( 7, JSONTokener.dehexchar('7')); + assertEquals( 8, JSONTokener.dehexchar('8')); + assertEquals( 9, JSONTokener.dehexchar('9')); + assertEquals(10, JSONTokener.dehexchar('A')); + assertEquals(11, JSONTokener.dehexchar('B')); + assertEquals(12, JSONTokener.dehexchar('C')); + assertEquals(13, JSONTokener.dehexchar('D')); + assertEquals(14, JSONTokener.dehexchar('E')); + assertEquals(15, JSONTokener.dehexchar('F')); + assertEquals(10, JSONTokener.dehexchar('a')); + assertEquals(11, JSONTokener.dehexchar('b')); + assertEquals(12, JSONTokener.dehexchar('c')); + assertEquals(13, JSONTokener.dehexchar('d')); + assertEquals(14, JSONTokener.dehexchar('e')); + assertEquals(15, JSONTokener.dehexchar('f')); + + for (int c = 0; c <= 0xFFFF; c++) { + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) { + continue; + } + assertEquals("dehexchar " + c, -1, JSONTokener.dehexchar((char) c)); + } + } +}
