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