diff options
author | Jesse Wilson <jessewilson@google.com> | 2010-02-16 13:50:32 -0800 |
---|---|---|
committer | Jesse Wilson <jessewilson@google.com> | 2010-02-17 10:02:32 -0800 |
commit | 67f4459a2fcc50cb3378c302b6c663af48f60ff0 (patch) | |
tree | b5084003279d4ac4121f2ae839fda1071f93ded6 /json/src/test | |
parent | 6c231cf6815ba6427035e8e47fc36f9d1139d2fb (diff) | |
download | libcore-67f4459a2fcc50cb3378c302b6c663af48f60ff0.zip libcore-67f4459a2fcc50cb3378c302b6c663af48f60ff0.tar.gz libcore-67f4459a2fcc50cb3378c302b6c663af48f60ff0.tar.bz2 |
First round of tests for the subset of the org.json in Android.
Diffstat (limited to 'json/src/test')
-rw-r--r-- | json/src/test/java/org/json/AllTests.java | 30 | ||||
-rw-r--r-- | json/src/test/java/org/json/JSONArrayTest.java | 343 | ||||
-rw-r--r-- | json/src/test/java/org/json/JSONStringerTest.java | 361 | ||||
-rw-r--r-- | json/src/test/java/org/json/JSONTokenerTest.java | 567 |
4 files changed, 1301 insertions, 0 deletions
diff --git a/json/src/test/java/org/json/AllTests.java b/json/src/test/java/org/json/AllTests.java new file mode 100644 index 0000000..8261a4d --- /dev/null +++ b/json/src/test/java/org/json/AllTests.java @@ -0,0 +1,30 @@ +/* + * 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.Test; +import junit.framework.TestSuite; + +public class AllTests { + public static Test suite() { + TestSuite suite = tests.TestSuiteFactory.createTestSuite(); + suite.addTestSuite(JSONArrayTest.class); + suite.addTestSuite(JSONStringerTest.class); + suite.addTestSuite(JSONStringerTest.class); + return suite; + } +} diff --git a/json/src/test/java/org/json/JSONArrayTest.java b/json/src/test/java/org/json/JSONArrayTest.java new file mode 100644 index 0000000..e0c7164 --- /dev/null +++ b/json/src/test/java/org/json/JSONArrayTest.java @@ -0,0 +1,343 @@ +/** + * 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 android; + +import junit.framework.TestCase; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; + +/** + * This black box test was written without inspecting the non-free org.json sourcecode. + */ +public class JSONArrayTest extends TestCase { + + public void testEmptyArray() throws JSONException { + JSONArray array = new JSONArray(); + assertEquals(0, array.length()); + assertEquals("", array.join(" AND ")); + try { + array.get(0); + fail(); + } catch (JSONException e) { + } + try { + array.getBoolean(0); + fail(); + } catch (JSONException e) { + } + + assertEquals("[]", array.toString()); + assertEquals("[]", array.toString(4)); + + // out of bounds is co-opted with defaulting + assertTrue(array.isNull(0)); + assertNull(array.opt(0)); + assertFalse(array.optBoolean(0)); + assertTrue(array.optBoolean(0, true)); + + // bogus (but documented) behaviour: returns null rather than an empty object + assertNull(array.toJSONObject(new JSONArray())); + } + + public void testEqualsAndHashCode() throws JSONException { + JSONArray a = new JSONArray(); + JSONArray b = new JSONArray(); + assertTrue(a.equals(b)); + // bogus behavior: JSONArray overrides equals() but not hashCode(). + assertEquals(a.hashCode(), b.hashCode()); + + a.put(true); + a.put(false); + b.put(true); + b.put(false); + assertTrue(a.equals(b)); + assertEquals(a.hashCode(), b.hashCode()); + + b.put(true); + assertFalse(a.equals(b)); + assertTrue(a.hashCode() != b.hashCode()); + } + + public void testBooleans() throws JSONException { + JSONArray array = new JSONArray(); + array.put(true); + array.put(false); + array.put(2, false); + array.put(3, false); + array.put(2, true); + assertEquals("[true,false,true,false]", array.toString()); + assertEquals(4, array.length()); + assertEquals(Boolean.TRUE, array.get(0)); + assertEquals(Boolean.FALSE, array.get(1)); + assertEquals(Boolean.TRUE, array.get(2)); + assertEquals(Boolean.FALSE, array.get(3)); + assertFalse(array.isNull(0)); + assertFalse(array.isNull(1)); + assertFalse(array.isNull(2)); + assertFalse(array.isNull(3)); + assertEquals(true, array.optBoolean(0)); + assertEquals(false, array.optBoolean(1, true)); + assertEquals(true, array.optBoolean(2, false)); + assertEquals(false, array.optBoolean(3)); + assertEquals("true", array.getString(0)); + assertEquals("false", array.getString(1)); + assertEquals("true", array.optString(2)); + assertEquals("false", array.optString(3, "x")); + assertEquals("[\n true,\n false,\n true,\n false\n]", array.toString(5)); + + JSONArray other = new JSONArray(); + other.put(true); + other.put(false); + other.put(true); + other.put(false); + assertTrue(array.equals(other)); + other.put(true); + assertFalse(array.equals(other)); + + other = new JSONArray(); + other.put("true"); + other.put("false"); + other.put("truE"); + other.put("FALSE"); + assertFalse(array.equals(other)); + assertFalse(other.equals(array)); + assertEquals(true, other.getBoolean(0)); + assertEquals(false, other.optBoolean(1, true)); + assertEquals(true, other.optBoolean(2)); + assertEquals(false, other.getBoolean(3)); + } + + public void testNulls() throws JSONException { + JSONArray array = new JSONArray(); + array.put(3, null); + array.put(0, JSONObject.NULL); + assertEquals(4, array.length()); + assertEquals("[null,null,null,null]", array.toString()); + + // bogus behaviour: there's 2 ways to represent null; each behaves differently! + assertEquals(JSONObject.NULL, array.get(0)); + try { + assertEquals(null, array.get(1)); + fail(); + } catch (JSONException e) { + } + try { + assertEquals(null, array.get(2)); + fail(); + } catch (JSONException e) { + } + try { + assertEquals(null, array.get(3)); + fail(); + } catch (JSONException e) { + } + assertEquals(JSONObject.NULL, array.opt(0)); + assertEquals(null, array.opt(1)); + assertEquals(null, array.opt(2)); + assertEquals(null, array.opt(3)); + assertTrue(array.isNull(0)); + assertTrue(array.isNull(1)); + assertTrue(array.isNull(2)); + assertTrue(array.isNull(3)); + assertEquals("null", array.optString(0)); + assertEquals("", array.optString(1)); + assertEquals("", array.optString(2)); + assertEquals("", array.optString(3)); + } + + public void testNumbers() throws JSONException { + JSONArray array = new JSONArray(); + array.put(Double.MIN_VALUE); + array.put(9223372036854775806L); + array.put(Double.MAX_VALUE); + array.put(-0d); + assertEquals(4, array.length()); + + // bogus behaviour: toString() and getString(int) return different values for -0d + assertEquals("[4.9E-324,9223372036854775806,1.7976931348623157E308,-0]", array.toString()); + + assertEquals(Double.MIN_VALUE, array.get(0)); + assertEquals(9223372036854775806L, array.get(1)); + assertEquals(Double.MAX_VALUE, array.get(2)); + assertEquals(-0d, array.get(3)); + assertEquals(Double.MIN_VALUE, array.getDouble(0)); + assertEquals(9.223372036854776E18, array.getDouble(1)); + assertEquals(Double.MAX_VALUE, array.getDouble(2)); + assertEquals(-0d, array.getDouble(3)); + assertEquals(0, array.getLong(0)); + assertEquals(9223372036854775806L, array.getLong(1)); + assertEquals(Long.MAX_VALUE, array.getLong(2)); + assertEquals(0, array.getLong(3)); + assertEquals(0, array.getInt(0)); + assertEquals(-2, array.getInt(1)); + assertEquals(Integer.MAX_VALUE, array.getInt(2)); + assertEquals(0, array.getInt(3)); + assertEquals(Double.MIN_VALUE, array.opt(0)); + assertEquals(Double.MIN_VALUE, array.optDouble(0)); + assertEquals(0, array.optLong(0, 1L)); + assertEquals(0, array.optInt(0, 1)); + assertEquals("4.9E-324", array.getString(0)); + assertEquals("9223372036854775806", array.getString(1)); + assertEquals("1.7976931348623157E308", array.getString(2)); + assertEquals("-0.0", array.getString(3)); + + JSONArray other = new JSONArray(); + other.put(Double.MIN_VALUE); + other.put(9223372036854775806L); + other.put(Double.MAX_VALUE); + other.put(-0d); + assertTrue(array.equals(other)); + other.put(0, 0L); + assertFalse(array.equals(other)); + } + + public void testStrings() throws JSONException { + JSONArray array = new JSONArray(); + array.put("true"); + array.put("5.5"); + array.put("9223372036854775806"); + array.put("null"); + array.put("5\"8' tall"); + assertEquals(5, array.length()); + assertEquals("[\"true\",\"5.5\",\"9223372036854775806\",\"null\",\"5\\\"8' tall\"]", + array.toString()); + + // although the documentation doesn't mention it, join() escapes text and wraps + // strings in quotes + assertEquals("\"true\" \"5.5\" \"9223372036854775806\" \"null\" \"5\\\"8' tall\"", + array.join(" ")); + + assertEquals("true", array.get(0)); + assertEquals("null", array.getString(3)); + assertEquals("5\"8' tall", array.getString(4)); + assertEquals("true", array.opt(0)); + assertEquals("5.5", array.optString(1)); + assertEquals("9223372036854775806", array.optString(2, null)); + assertEquals("null", array.optString(3, "-1")); + assertFalse(array.isNull(0)); + assertFalse(array.isNull(3)); + + assertEquals(true, array.getBoolean(0)); + assertEquals(true, array.optBoolean(0)); + assertEquals(true, array.optBoolean(0, false)); + assertEquals(0, array.optInt(0)); + assertEquals(-2, array.optInt(0, -2)); + + assertEquals(5.5d, array.getDouble(1)); + assertEquals(5, array.getLong(1)); + assertEquals(5, array.getInt(1)); + assertEquals(5, array.optInt(1, 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, array.getLong(2)); + assertEquals(9.223372036854776E18, array.getDouble(2)); + assertEquals(Integer.MAX_VALUE, array.getInt(2)); + + assertFalse(array.isNull(3)); + try { + array.getDouble(3); + fail(); + } catch (JSONException e) { + } + assertEquals(Double.NaN, array.optDouble(3)); + assertEquals(-1.0d, array.optDouble(3, -1.0d)); + } + + public void testToJSONObject() throws JSONException { + JSONArray keys = new JSONArray(); + keys.put("a"); + keys.put("b"); + + JSONArray values = new JSONArray(); + values.put(5.5d); + values.put(false); + + JSONObject object = values.toJSONObject(keys); + assertEquals(5.5d, object.get("a")); + assertEquals(false, object.get("b")); + + keys.put(0, "a"); + values.put(0, 11.0d); + assertEquals(5.5d, object.get("a")); + } + + public void testToJSONObjectWithNulls() throws JSONException { + JSONArray keys = new JSONArray(); + keys.put("a"); + keys.put("b"); + + JSONArray values = new JSONArray(); + values.put(5.5d); + values.put(null); + + // bogus behaviour: null values are stripped + JSONObject object = values.toJSONObject(keys); + assertEquals(1, object.length()); + assertFalse(object.has("b")); + assertEquals("{\"a\":5.5}", object.toString()); + } + + public void testPutUnsupportedNumbers() throws JSONException { + JSONArray array = new JSONArray(); + + try { + array.put(Double.NaN); + fail(); + } catch (JSONException e) { + } + try { + array.put(0, Double.NEGATIVE_INFINITY); + fail(); + } catch (JSONException e) { + } + try { + array.put(0, Double.POSITIVE_INFINITY); + fail(); + } catch (JSONException e) { + } + } + + public void testCreateWithUnsupportedNumbers() throws JSONException { + JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN)); + assertEquals(2, array.length()); + assertEquals(5.5, array.getDouble(0)); + assertEquals(Double.NaN, array.getDouble(1)); + } + + public void testToStringWithUnsupportedNumbers() throws JSONException { + // bogus behaviour: when the array contains an unsupported number, toString returns null + JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN)); + assertNull(array.toString()); + } + + public void testCreate() throws JSONException { + JSONArray array = new JSONArray(Arrays.asList(5.5, true)); + assertEquals(2, array.length()); + assertEquals(5.5, array.getDouble(0)); + assertEquals(true, array.get(1)); + assertEquals("[5.5,true]", array.toString()); + } + + public void testParsingConstructor() { + fail("TODO"); + } +} diff --git a/json/src/test/java/org/json/JSONStringerTest.java b/json/src/test/java/org/json/JSONStringerTest.java new file mode 100644 index 0000000..e9b4e51 --- /dev/null +++ b/json/src/test/java/org/json/JSONStringerTest.java @@ -0,0 +1,361 @@ +/** + * 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 android; + +import junit.framework.TestCase; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; + +/** + * This black box test was written without inspecting the non-free org.json sourcecode. + */ +public class JSONStringerTest extends TestCase { + + public void testEmptyStringer() { + // bogus behaviour: why isn't this the empty string? + assertNull(new JSONStringer().toString()); + } + + public void testValueJSONNull() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(JSONObject.NULL); + stringer.endArray(); + assertEquals("[null]", stringer.toString()); + } + + public void testEmptyObject() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.endObject(); + assertEquals("{}", stringer.toString()); + } + + public void testEmptyArray() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.endArray(); + assertEquals("[]", stringer.toString()); + } + + 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()); + } + + 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. + */ + 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()); + } + + public void testWeirdNumbers() throws JSONException { + try { + new JSONStringer().array().value(Double.NaN); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().array().value(Double.NEGATIVE_INFINITY); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().array().value(Double.POSITIVE_INFINITY); + fail(); + } catch (JSONException e) { + } + + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.value(-0.0d); + stringer.value(0.0d); + stringer.endArray(); + assertEquals("[-0,0]", stringer.toString()); + } + + public void testMismatchedScopes() { + try { + new JSONStringer().key("a"); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().value("a"); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().endObject(); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().endArray(); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().array().endObject(); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().object().endArray(); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().object().key("a").key("a"); + fail(); + } catch (JSONException e) { + } + try { + new JSONStringer().object().value(false); + fail(); + } catch (JSONException e) { + } + } + + public void testNullKey() { + try { + new JSONStringer().object().key(null); + fail(); + } catch (JSONException e) { + } + } + + 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()); + } + + public void testEmptyKey() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.object(); + stringer.key("").value(false); + stringer.endObject(); + assertEquals("{\"\":false}", stringer.toString()); // legit behaviour! + } + + public void testEscaping() throws JSONException { + assertEscapedAllWays("a", "a"); + assertEscapedAllWays("a\"", "a\\\""); + assertEscapedAllWays("\"", "\\\""); + assertEscapedAllWays(":", ":"); + assertEscapedAllWays(",", ","); + assertEscapedAllWays("\n", "\\n"); + assertEscapedAllWays("\t", "\\t"); + assertEscapedAllWays(" ", " "); + assertEscapedAllWays("\\", "\\\\"); + assertEscapedAllWays("{", "{"); + assertEscapedAllWays("}", "}"); + assertEscapedAllWays("[", "["); + assertEscapedAllWays("]", "]"); + + // how does it decide which characters to escape? + assertEscapedAllWays("\0", "\\u0000"); + assertEscapedAllWays("\u0019", "\\u0019"); + assertEscapedAllWays("\u0020", " "); + } + + private void assertEscapedAllWays(String original, String escaped) 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()); + } + + 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()); + } + + 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()); + } + + public void testArrayNestingMaxDepthIs20() 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(); + } + try { + stringer.array(); + fail(); + } catch (JSONException e) { + } + } + + public void testObjectNestingMaxDepthIs20() 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"); + } + try { + stringer.object(); + fail(); + } catch (JSONException e) { + } + } + + public void testMixedMaxDepth() 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"); + } + try { + stringer.array(); + fail(); + } catch (JSONException e) { + } + } + + 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()); + } + + 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()); + } + + public void testMultipleRoots() throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.array(); + stringer.endArray(); + try { + stringer.object(); + fail(); + } catch (JSONException e) { + } + } +} diff --git a/json/src/test/java/org/json/JSONTokenerTest.java b/json/src/test/java/org/json/JSONTokenerTest.java new file mode 100644 index 0000000..7d947e3 --- /dev/null +++ b/json/src/test/java/org/json/JSONTokenerTest.java @@ -0,0 +1,567 @@ +/** + * 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 android; + +import junit.framework.TestCase; +import org.json.JSONException; +import org.json.JSONTokener; + +/** + * This black box test was written without inspecting the non-free org.json sourcecode. + */ +public class JSONTokenerTest extends TestCase { + + public void testNulls() throws JSONException { + // bogus behaviour: JSONTokener accepts null, only to fail later on almost all APIs. + new JSONTokener(null).back(); + + try { + new JSONTokener(null).more(); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).next(); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).next(3); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).next('A'); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).nextClean(); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).nextString('"'); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).nextTo('A'); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).nextTo("ABC"); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).nextValue(); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).skipPast("ABC"); + fail(); + } catch (NullPointerException e) { + } + + try { + new JSONTokener(null).skipTo('A'); + fail(); + } catch (NullPointerException e) { + } + + assertEquals("foo! at character 0 of null", + new JSONTokener(null).syntaxError("foo!").getMessage()); + + assertEquals(" at character 0 of null", new JSONTokener(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 expected) { + } + try { + new JSONTokener("").next('A'); + fail(); + } catch (JSONException e) { + } + assertEquals('\0', new JSONTokener("").nextClean()); + try { + new JSONTokener("").nextString('"'); + fail(); + } catch (JSONException e) { + } + assertEquals("", new JSONTokener("").nextTo('A')); + assertEquals("", new JSONTokener("").nextTo("ABC")); + try { + new JSONTokener("").nextValue(); + fail(); + } catch (JSONException e) { + } + new JSONTokener("").skipPast("ABC"); + assertEquals('\0', new JSONTokener("").skipTo('A')); + 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 e) { + } + assertEquals('E', abcdeTokener.nextClean()); + assertEquals('\0', abcdeTokener.next()); + try { + // bogus behaviour: returning an empty string should be valid + abcdeTokener.next(0); + fail(); + } catch (JSONException e) { + } + 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(); // bogus behaviour: 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 e) { + } + assertEquals('C', abcdTokener.next('C')); + assertEquals('D', abcdTokener.next('D')); + try { + abcdTokener.next('E'); + fail(); + } catch (JSONException e) { + } + } + + public void testNextN() throws JSONException { + JSONTokener abcdeTokener = new JSONTokener("ABCDEF"); + assertEquals("", abcdeTokener.next(0)); + try { + abcdeTokener.next(7); + fail(); + } catch (JSONException e) { + } + assertEquals("ABC", abcdeTokener.next(3)); + try { + abcdeTokener.next(4); + fail(); + } catch (JSONException e) { + } + try { + // bogus behaviour: there should be 3 characters left, but there must be an off-by-one + // error in the implementation. + assertEquals("DEF", abcdeTokener.next(3)); + fail(); + } catch (JSONException e) { + } + assertEquals("DE", abcdeTokener.next(2)); + assertEquals('F', abcdeTokener.next()); + try { + // bogus behaviour: returning an empty string should be valid + abcdeTokener.next(0); + fail(); + } catch (JSONException e) { + } + abcdeTokener.back(); + abcdeTokener.back(); + abcdeTokener.back(); + assertEquals("DE", abcdeTokener.next(2)); + assertEquals('F', abcdeTokener.next()); + } + + 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 testNextCleanTrailingOpenComment() throws JSONException { + try { + new JSONTokener(" /* ").nextClean(); + fail(); + } catch (JSONException e) { + } + 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()); + } + + /** + * 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 testNextCleanWhitespace() throws JSONException { + // This behaviour contradicts the JSON spec. It claims the only space + // characters are space, tab, newline and carriage return. But it treats + // many characters like whitespace! These are the same whitespace + // characters used by String.trim(), with the exception of '\0'. + assertEquals("character tabulation", 'A', new JSONTokener("\u0009A").nextClean()); + assertEquals("line feed", 'A', new JSONTokener("\nA").nextClean()); + assertEquals("line tabulation", 'A', new JSONTokener("\u000bA").nextClean()); + assertEquals("form feed", 'A', new JSONTokener("\u000cA").nextClean()); + assertEquals("carriage return", 'A', new JSONTokener("\rA").nextClean()); + assertEquals("information separator 4", 'A', new JSONTokener("\u001cA").nextClean()); + assertEquals("information separator 3", 'A', new JSONTokener("\u001dA").nextClean()); + assertEquals("information separator 2", 'A', new JSONTokener("\u001eA").nextClean()); + assertEquals("information separator 1", 'A', new JSONTokener("\u001fA").nextClean()); + assertEquals("space", 'A', new JSONTokener("\u0020A").nextClean()); + for (char c = '\u0002'; c < ' '; c++) { + assertEquals('A', new JSONTokener(new String(new char[] { ' ', c, 'A' })).nextClean()); + } + + // These characters are neither whitespace in the JSON spec nor the implementation + assertEquals("null", '\u0000', new JSONTokener("\u0000A").nextClean()); + assertEquals("next line", '\u0085', new JSONTokener("\u0085A").nextClean()); + assertEquals("non-breaking space", '\u00a0', new JSONTokener("\u00a0A").nextClean()); + assertEquals("ogham space mark", '\u1680', new JSONTokener("\u1680A").nextClean()); + assertEquals("mongolian vowel separator", '\u180e', new JSONTokener("\u180eA").nextClean()); + assertEquals("en quad", '\u2000', new JSONTokener("\u2000A").nextClean()); + assertEquals("em quad", '\u2001', new JSONTokener("\u2001A").nextClean()); + assertEquals("en space", '\u2002', new JSONTokener("\u2002A").nextClean()); + assertEquals("em space", '\u2003', new JSONTokener("\u2003A").nextClean()); + assertEquals("three-per-em space", '\u2004', new JSONTokener("\u2004A").nextClean()); + assertEquals("four-per-em space", '\u2005', new JSONTokener("\u2005A").nextClean()); + assertEquals("six-per-em space", '\u2006', new JSONTokener("\u2006A").nextClean()); + assertEquals("figure space", '\u2007', new JSONTokener("\u2007A").nextClean()); + assertEquals("punctuation space", '\u2008', new JSONTokener("\u2008A").nextClean()); + assertEquals("thin space", '\u2009', new JSONTokener("\u2009A").nextClean()); + assertEquals("hair space", '\u200a', new JSONTokener("\u200aA").nextClean()); + assertEquals("zero-width space", '\u200b', new JSONTokener("\u200bA").nextClean()); + assertEquals("left-to-right mark", '\u200e', new JSONTokener("\u200eA").nextClean()); + assertEquals("right-to-left mark", '\u200f', new JSONTokener("\u200fA").nextClean()); + assertEquals("line separator", '\u2028', new JSONTokener("\u2028A").nextClean()); + assertEquals("paragraph separator", '\u2029', new JSONTokener("\u2029A").nextClean()); + assertEquals("narrow non-breaking space", '\u202f', new JSONTokener("\u202fA").nextClean()); + assertEquals("medium mathematical space", '\u205f', new JSONTokener("\u205fA").nextClean()); + assertEquals("ideographic space", '\u3000', new JSONTokener("\u3000A").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 e) { + } + + JSONTokener tokener = new JSONTokener(" 'abc"); + tokener.next(); + tokener.next(); + try { + tokener.next('\''); + fail(); + } catch (JSONException e) { + } + } + + public void testNextStringEscapedQuote() throws JSONException { + try { + new JSONTokener("abc\\").nextString('"'); + fail(); + } catch (JSONException e) { + } + + // 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 e) { + } + try { + new JSONTokener("abc\\u").nextString('"'); + fail(); + } catch (JSONException e) { + } + try { + new JSONTokener("abc\\u \"").nextString('"'); + fail(); + } catch (NumberFormatException e) { + } + assertEquals("abc\"def", new JSONTokener("abc\\u0022def\"ghi").nextString('"')); + try { + new JSONTokener("abc\\u000G\"").nextString('"'); + fail(); + } catch (NumberFormatException e) { + } + } + + 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")); + + // Bogus behaviour: the tokener stops after \0 always + tokener = new JSONTokener(" \0\t \fABC \n DEF"); + assertEquals("", tokener.nextTo("D")); + assertEquals('\t', tokener.next()); + assertEquals("ABC", tokener.nextTo("D")); + tokener = new JSONTokener("ABC\0DEF"); + assertEquals("ABC", tokener.nextTo("\0")); + assertEquals("DEF", tokener.nextTo("\0")); + + tokener = new JSONTokener(""); + try { + tokener.nextTo(null); + fail(); + } catch (NullPointerException e) { + } + } + + 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 e) { + } + } + + 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\0DEF"); + tokener.skipTo('F'); + // bogus behaviour: skipTo gives up when it sees '\0' + assertEquals('A', 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 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)); + } + } + + public void testNextValue() { + fail("TODO"); + } +} |