ParsingTest.java revision 4558195b4a7ee014517f1aa3c59bc6c561baa2ef
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.json;
18
19import junit.framework.TestCase;
20import junit.framework.AssertionFailedError;
21
22import java.util.*;
23
24public class ParsingTest extends TestCase {
25
26    public void testParsingNoObjects() {
27        try {
28            new JSONTokener("").nextValue();
29            fail();
30        } catch (JSONException e) {
31        }
32    }
33
34    public void testParsingLiterals() throws JSONException {
35        assertParsed(Boolean.TRUE, "true");
36        assertParsed(Boolean.FALSE, "false");
37        assertParsed(JSONObject.NULL, "null");
38        assertParsed(JSONObject.NULL, "NULL");
39        assertParsed(Boolean.FALSE, "False");
40        assertParsed(Boolean.TRUE, "truE");
41    }
42
43    public void testParsingQuotedStrings() throws JSONException {
44        assertParsed("abc", "\"abc\"");
45        assertParsed("123", "\"123\"");
46        assertParsed("foo\nbar", "\"foo\\nbar\"");
47        assertParsed("foo bar", "\"foo\\u0020bar\"");
48        assertParsed("\"{}[]/\\:,=;#", "\"\\\"{}[]/\\\\:,=;#\"");
49    }
50
51    public void testParsingSingleQuotedStrings() throws JSONException {
52        assertParsed("abc", "'abc'");
53        assertParsed("123", "'123'");
54        assertParsed("foo\nbar", "'foo\\nbar'");
55        assertParsed("foo bar", "'foo\\u0020bar'");
56        assertParsed("\"{}[]/\\:,=;#", "'\\\"{}[]/\\\\:,=;#'");
57    }
58
59    public void testParsingUnquotedStrings() throws JSONException {
60        assertParsed("abc", "abc");
61        assertParsed("123abc", "123abc");
62        assertParsed("123e0x", "123e0x");
63        assertParsed("123e", "123e");
64        assertParsed("123ee21", "123ee21");
65        assertParsed("0xFFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFFF");
66    }
67
68    /**
69     * Unfortunately the original implementation attempts to figure out what
70     * Java number type best suits an input value.
71     */
72    public void testParsingNumbersThatAreBestRepresentedAsLongs() throws JSONException {
73        assertParsed(9223372036854775807L, "9223372036854775807");
74        assertParsed(9223372036854775806L, "9223372036854775806");
75        assertParsed(-9223372036854775808L, "-9223372036854775808");
76        assertParsed(-9223372036854775807L, "-9223372036854775807");
77    }
78
79    public void testParsingNumbersThatAreBestRepresentedAsIntegers() throws JSONException {
80        assertParsed(0, "0");
81        assertParsed(5, "5");
82        assertParsed(-2147483648, "-2147483648");
83        assertParsed(2147483647, "2147483647");
84    }
85
86    public void testParsingNegativeZero() throws JSONException {
87        assertParsed(0, "-0");
88    }
89
90    public void testParsingIntegersWithAdditionalPrecisionYieldDoubles() throws JSONException {
91        assertParsed(1d, "1.00");
92        assertParsed(1d, "1.0");
93        assertParsed(0d, "0.0");
94        assertParsed(-0d, "-0.0");
95    }
96
97    public void testParsingNumbersThatAreBestRepresentedAsDoubles() throws JSONException {
98        assertParsed(9.223372036854776E18, "9223372036854775808");
99        assertParsed(-9.223372036854776E18, "-9223372036854775809");
100        assertParsed(1.7976931348623157E308, "1.7976931348623157e308");
101        assertParsed(2.2250738585072014E-308, "2.2250738585072014E-308");
102        assertParsed(4.9E-324, "4.9E-324");
103        assertParsed(4.9E-324, "4.9e-324");
104    }
105
106    public void testParsingOctalNumbers() throws JSONException {
107        assertParsed(5, "05");
108        assertParsed(8, "010");
109        assertParsed(1046, "02026");
110    }
111
112    public void testParsingHexNumbers() throws JSONException {
113        assertParsed(5, "0x5");
114        assertParsed(16, "0x10");
115        assertParsed(8230, "0x2026");
116        assertParsed(180150010, "0xABCDEFA");
117        assertParsed(2077093803, "0x7BCDEFAB");
118    }
119
120    public void testParsingLargeHexValues() throws JSONException {
121        assertParsed(Integer.MAX_VALUE, "0x7FFFFFFF");
122        String message = "Hex values are parsed as Strings if their signed " +
123                "value is greater than Integer.MAX_VALUE.";
124        assertParsed(message, 0x80000000L, "0x80000000");
125    }
126
127    public void test64BitHexValues() throws JSONException {
128        assertParsed("Large hex longs shouldn't be yield ints or strings",
129                -1L, "0xFFFFFFFFFFFFFFFF");
130    }
131
132    public void testParsingWithCommentsAndWhitespace() throws JSONException {
133        assertParsed("baz", "  // foo bar \n baz");
134        assertParsed(5, "  /* foo bar \n baz */ 5");
135        assertParsed(5, "  /* foo bar \n baz */ 5 // quux");
136        assertParsed(5, "  5   ");
137        assertParsed(5, "  5  \r\n\t ");
138        assertParsed(5, "\r\n\t   5 ");
139    }
140
141    public void testParsingArrays() throws JSONException {
142        assertParsed(array(), "[]");
143        assertParsed(array(5, 6, true), "[5,6,true]");
144        assertParsed(array(5, 6, array()), "[5,6,[]]");
145        assertParsed(array(5, 6, 7), "[5;6;7]");
146        assertParsed(array(5, 6, 7), "[5  , 6 \t; \r\n 7\n]");
147        assertParsed(array(5, 6, 7, null), "[5,6,7,]");
148        assertParsed(array(null, null), "[,]");
149        assertParsed(array(5, null, null, null, 5), "[5,,,,5]");
150        assertParsed(array(null, 5), "[,5]");
151        assertParsed(array(null, null, null), "[,,]");
152        assertParsed(array(null, null, null, 5), "[,,,5]");
153    }
154
155    public void testParsingObjects() throws JSONException {
156        assertParsed(object("foo", 5), "{\"foo\": 5}");
157        assertParsed(object("foo", 5), "{foo: 5}");
158        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\": 5, \"bar\": \"baz\"}");
159        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\": 5; \"bar\": \"baz\"}");
160        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\"= 5; \"bar\"= \"baz\"}");
161        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\"=> 5; \"bar\"=> \"baz\"}");
162        assertParsed(object("foo", object(), "bar", array()), "{\"foo\"=> {}; \"bar\"=> []}");
163        assertParsed(object("foo", object("foo", array(5, 6))), "{\"foo\": {\"foo\": [5, 6]}}");
164        assertParsed(object("foo", object("foo", array(5, 6))), "{\"foo\":\n\t{\t \"foo\":[5,\r6]}}");
165    }
166
167    public void testSyntaxProblemUnterminatedObject() {
168        assertParseFail("{");
169        assertParseFail("{\"foo\"");
170        assertParseFail("{\"foo\":");
171        assertParseFail("{\"foo\":bar");
172        assertParseFail("{\"foo\":bar,");
173        assertParseFail("{\"foo\":bar,\"baz\"");
174        assertParseFail("{\"foo\":bar,\"baz\":");
175        assertParseFail("{\"foo\":bar,\"baz\":true");
176        assertParseFail("{\"foo\":bar,\"baz\":true,");
177    }
178
179    public void testSyntaxProblemEmptyString() {
180        assertParseFail("");
181    }
182
183    public void testSyntaxProblemUnterminatedArray() {
184        assertParseFail("[");
185        assertParseFail("[,");
186        assertParseFail("[,,");
187        assertParseFail("[true");
188        assertParseFail("[true,");
189        assertParseFail("[true,,");
190    }
191
192    public void testSyntaxProblemMalformedObject() {
193        assertParseFail("{:}");
194        assertParseFail("{\"key\":}");
195        assertParseFail("{:true}");
196        assertParseFail("{\"key\":true:}");
197        assertParseFail("{null:true}");
198        assertParseFail("{true:true}");
199        assertParseFail("{0xFF:true}");
200    }
201
202    private void assertParseFail(String malformedJson) {
203        try {
204            new JSONTokener(malformedJson).nextValue();
205            fail("Successfully parsed: \"" + malformedJson + "\"");
206        } catch (JSONException e) {
207        } catch (StackOverflowError e) {
208            fail("Stack overflowed on input: \"" + malformedJson + "\"");
209        }
210    }
211
212    private JSONArray array(Object... elements) {
213        return new JSONArray(Arrays.asList(elements));
214    }
215
216    private JSONObject object(Object... keyValuePairs) throws JSONException {
217        JSONObject result = new JSONObject();
218        for (int i = 0; i < keyValuePairs.length; i+=2) {
219            result.put((String) keyValuePairs[i], keyValuePairs[i+1]);
220        }
221        return result;
222    }
223
224    private void assertParsed(String message, Object expected, String json) throws JSONException {
225        Object actual = new JSONTokener(json).nextValue();
226        actual = canonicalize(actual);
227        expected = canonicalize(expected);
228        assertEquals("For input \"" + json + "\" " + message, expected, actual);
229    }
230
231    private void assertParsed(Object expected, String json) throws JSONException {
232        assertParsed("", expected, json);
233    }
234
235    /**
236     * Since they don't implement equals or hashCode properly, this recursively
237     * replaces JSONObjects with an equivalent HashMap, and JSONArrays with the
238     * equivalent ArrayList.
239     */
240    private Object canonicalize(Object input) throws JSONException {
241        if (input instanceof JSONArray) {
242            JSONArray array = (JSONArray) input;
243            List<Object> result = new ArrayList<Object>();
244            for (int i = 0; i < array.length(); i++) {
245                result.add(canonicalize(array.opt(i)));
246            }
247            return result;
248        } else if (input instanceof JSONObject) {
249            JSONObject object = (JSONObject) input;
250            Map<String, Object> result = new HashMap<String, Object>();
251            for (Iterator<?> i = object.keys(); i.hasNext(); ) {
252                String key = (String) i.next();
253                result.put(key, canonicalize(object.get(key)));
254            }
255            return result;
256        } else {
257            return input;
258        }
259    }
260}
261