001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.json.client;
017:
018: import com.google.gwt.junit.client.GWTTestCase;
019:
020: /**
021: * TODO: document me.
022: */
023: public class JSONTest extends GWTTestCase {
024: static final String menuTest = "{\"menu\": {\n"
025: + " \"id\": \"file\",\n"
026: + " \"value\": \"File:\",\n"
027: + " \"popup\": {\n"
028: + " \"menuitem\": [\n"
029: + " {\"value\": \"New\", \"onclick\": \"CreateNewDoc()\"},\n"
030: + " {\"value\": \"Open\", \"onclick\": \"OpenDoc()\"},\n"
031: + " {\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}\n"
032: + " ]\n" + " }\n" + "}}\n" + "";
033:
034: static final String widgetTest = "{\"widget\": {\n"
035: + " \"debug\": \"on\",\n"
036: + " \"window\": {\n"
037: + " \"title\": \"Sample Konfabulator Widget\", \"name\": \"main_window\", \"width\": 500, \"height\": 500\n"
038: + " }, \"image\": { \n"
039: + " \"src\": \"Images/Sun.png\",\n"
040: + " \"name\": \"sun1\", \"hOffset\": 250, \"vOffset\": 250, \"alignment\": \"center\"\n"
041: + " }, \"text\": {\n"
042: + " \"data\": \"Click Here\",\n"
043: + " \"size\": 36,\n"
044: + " \"style\": \"bold\", \"name\": \"text1\", \"hOffset\": 250, \"vOffset\": 100, \"alignment\": \"center\",\n"
045: + " \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n"
046: + " }\n" + "}} \n" + "";
047:
048: /**
049: * Returns the module name for GWT unit test running.
050: */
051: public String getModuleName() {
052: return "com.google.gwt.json.JSON";
053: }
054:
055: public void testArrayBasics() {
056: JSONArray a = new JSONArray();
057: JSONString s = new JSONString("s");
058: JSONBoolean b = JSONBoolean.getInstance(false);
059: JSONNumber n = new JSONNumber(4);
060: assertNull(a.get(3));
061: assertNull(a.get(-4));
062: a.set(3, s);
063: assertEquals(s, a.get(3));
064: a.set(-4, b);
065: assertEquals(b, a.get(-4));
066: a.set(2, b);
067: assertEquals(b, a.get(2));
068: a.set(1, n);
069: assertEquals(n, a.get(1));
070: }
071:
072: /**
073: * Test deep recursion of arrays.
074: */
075: public void testArrayOfArraysOfArrays() {
076: JSONArray array = populateRecursiveArray(3, 5);
077: assertEquals(
078: "[[[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]],[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]],[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]]],[[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]],[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]],[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]]],[[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]],[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]],[[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]],[[[],[],[]],[[],[],[]],[[],[],[]]]]]]",
079: array.toString());
080: // now to access
081: for (int i = 0; i < 5; i++) {
082: array = (JSONArray) array.get(0);
083: }
084: }
085:
086: /**
087: * Tests an array of raw numbers, like [1,2,3].
088: */
089: public void testArrayOfNumbers() {
090: JSONArray arr = new JSONArray();
091: for (int i = 0; i < 10; i++) {
092: arr.set(i, new JSONNumber(i));
093: }
094: String s = arr.toString();
095: JSONValue v = JSONParser.parse(s);
096: JSONArray array = v.isArray();
097: assertTrue("v must be an array", array != null);
098: assertEquals("Array size must be 10", 10, array.size());
099: for (int i = 0; i < 10; i++) {
100: assertEquals("Array value at " + i + " must be " + i, array
101: .get(i).isNumber().getValue(), i, 0.001);
102: }
103: }
104:
105: public void testBooleanBasics() {
106: assertTrue(JSONBoolean.getInstance(true).booleanValue());
107: assertFalse(JSONBoolean.getInstance(false).booleanValue());
108:
109: JSONValue trueVal = JSONParser.parse("true");
110: assertEquals(trueVal, trueVal.isBoolean());
111: assertTrue(trueVal.isBoolean().booleanValue());
112:
113: JSONValue falseVal = JSONParser.parse("false");
114: assertEquals(falseVal, falseVal.isBoolean());
115: assertFalse(falseVal.isBoolean().booleanValue());
116: }
117:
118: // Null characters do not work in hosted mode
119: public void testEscaping() {
120: JSONObject o = new JSONObject();
121: char[] charsToEscape = new char[40];
122: for (char i = 1; i < 32; i++) {
123: charsToEscape[i] = i;
124: }
125: charsToEscape[32] = '"';
126: charsToEscape[33] = '\\';
127: charsToEscape[34] = '\b';
128: charsToEscape[35] = '\f';
129: charsToEscape[36] = '\n';
130: charsToEscape[37] = '\r';
131: charsToEscape[38] = '\t';
132: charsToEscape[39] = '/';
133: for (int i = 1; i < 40; i++) {
134: o.put("c" + i, new JSONString(new Character(
135: charsToEscape[i]).toString()));
136: }
137: assertEquals(
138: "{\"c1\":\"\\u0001\", \"c2\":\"\\u0002\", "
139: + "\"c3\":\"\\u0003\", \"c4\":\"\\u0004\", \"c5\":\"\\u0005\", "
140: + "\"c6\":\"\\u0006\", \"c7\":\"\\u0007\", \"c8\":\"\\b\", "
141: + "\"c9\":\"\\t\", \"c10\":\"\\n\", \"c11\":\"\\u000B\", "
142: + "\"c12\":\"\\f\", \"c13\":\"\\r\", \"c14\":\"\\u000E\", "
143: + "\"c15\":\"\\u000F\", \"c16\":\"\\u0010\", \"c17\":\"\\u0011\", "
144: + "\"c18\":\"\\u0012\", \"c19\":\"\\u0013\", \"c20\":\"\\u0014\", "
145: + "\"c21\":\"\\u0015\", \"c22\":\"\\u0016\", \"c23\":\"\\u0017\", "
146: + "\"c24\":\"\\u0018\", \"c25\":\"\\u0019\", \"c26\":\"\\u001A\", "
147: + "\"c27\":\"\\u001B\", \"c28\":\"\\u001C\", \"c29\":\"\\u001D\", "
148: + "\"c30\":\"\\u001E\", \"c31\":\"\\u001F\", \"c32\":\"\\\"\", "
149: + "\"c33\":\"\\\\\", \"c34\":\"\\b\", \"c35\":\"\\f\", "
150: + "\"c36\":\"\\n\", \"c37\":\"\\r\", \"c38\":\"\\t\", "
151: + "\"c39\":\"/\"}", o.toString());
152: }
153:
154: public void testLargeArrays() {
155: JSONArray arr = null;
156: for (int j = 1; j < 500; j *= 2) {
157: arr = createLargeArray(j);
158: assertEquals("size j" + j, j, arr.size());
159: }
160: }
161:
162: public void testMenu() {
163: JSONObject v = (JSONObject) JSONParser.parse(menuTest);
164: assertTrue(v.containsKey("menu"));
165: JSONObject menu = ((JSONObject) v.get("menu"));
166: assertEquals(3, menu.keySet().size());
167: }
168:
169: public void testNested() {
170: JSONObject obj = new JSONObject();
171: nestedAux(obj, 3);
172: String s1 = obj.toString();
173: String s2 = JSONParser.parse(s1).toString();
174: assertEquals(s1, s2);
175: assertEquals(
176: "{\"string3\":\"s3\", \"Number3\":3.1, \"Boolean3\":false, "
177: + "\"Null3\":null, \"object3\":{\"string2\":\"s2\", \"Number2\":2.1, "
178: + "\"Boolean2\":true, \"Null2\":null, \"object2\":{\"string1\":\"s1\","
179: + " \"Number1\":1.1, \"Boolean1\":false, \"Null1\":null, \"object1\":{"
180: + "\"string0\":\"s0\", \"Number0\":0.1, \"Boolean0\":true, "
181: + "\"Null0\":null, \"object0\":{}, "
182: + "\"Array0\":[\"s0\",0.1,true,null,{}]}, "
183: + "\"Array1\":[\"s1\",1.1,false,null,{\"string0\":\"s0\", "
184: + "\"Number0\":0.1, \"Boolean0\":true, \"Null0\":null, \"object0\":{}, "
185: + "\"Array0\":[\"s0\",0.1,true,null,{}]}]}, "
186: + "\"Array2\":[\"s2\",2.1,true,null,{\"string1\":\"s1\", "
187: + "\"Number1\":1.1, \"Boolean1\":false, \"Null1\":null, "
188: + "\"object1\":{\"string0\":\"s0\", \"Number0\":0.1, "
189: + "\"Boolean0\":true, \"Null0\":null, \"object0\":{}, "
190: + "\"Array0\":[\"s0\",0.1,true,null,{}]}, "
191: + "\"Array1\":[\"s1\",1.1,false,null,{\"string0\":\"s0\", "
192: + "\"Number0\":0.1, \"Boolean0\":true, \"Null0\":null, "
193: + "\"object0\":{}, \"Array0\":[\"s0\",0.1,true,null,{}]}]}]}, "
194: + "\"Array3\":[\"s3\",3.1,false,null,{\"string2\":\"s2\", "
195: + "\"Number2\":2.1, \"Boolean2\":true, \"Null2\":null, "
196: + "\"object2\":{\"string1\":\"s1\", \"Number1\":1.1, "
197: + "\"Boolean1\":false, \"Null1\":null, \"object1\":{\"string0\":\"s0\","
198: + " \"Number0\":0.1, \"Boolean0\":true, \"Null0\":null, \"object0\":{}, "
199: + "\"Array0\":[\"s0\",0.1,true,null,{}]}, "
200: + "\"Array1\":[\"s1\",1.1,false,null,{\"string0\":\"s0\", "
201: + "\"Number0\":0.1, \"Boolean0\":true, \"Null0\":null, "
202: + "\"object0\":{}, \"Array0\":[\"s0\",0.1,true,null,{}]}]}, "
203: + "\"Array2\":[\"s2\",2.1,true,null,{\"string1\":\"s1\", "
204: + "\"Number1\":1.1, \"Boolean1\":false, \"Null1\":null, "
205: + "\"object1\":{\"string0\":\"s0\", \"Number0\":0.1, "
206: + "\"Boolean0\":true, \"Null0\":null, \"object0\":{}, "
207: + "\"Array0\":[\"s0\",0.1,true,null,{}]}, "
208: + "\"Array1\":[\"s1\",1.1,false,null,{\"string0\":\"s0\", "
209: + "\"Number0\":0.1, \"Boolean0\":true, \"Null0\":null, \"object0\":{},"
210: + " \"Array0\":[\"s0\",0.1,true,null,{}]}]}]}]}",
211: obj.toString());
212: }
213:
214: public void testNumberBasics() {
215: JSONNumber n0 = new JSONNumber(1000);
216: assertEquals(1000, n0.getValue(), .000001);
217: assertTrue(n0.isNumber() == n0);
218: assertNull(n0.isObject());
219:
220: JSONNumber n1 = new JSONNumber(Integer.MAX_VALUE);
221: assertEquals(Integer.MAX_VALUE, n1.getValue(), .00001);
222: assertTrue(n1.isNumber() == n1);
223: assertNull(n1.isObject());
224:
225: JSONNumber n2 = new JSONNumber(Integer.MIN_VALUE);
226: assertEquals(Integer.MIN_VALUE, n2.getValue(), .00001);
227: assertTrue(n2.isNumber() == n2);
228: assertNull(n2.isObject());
229: }
230:
231: public void testObjectBasics() {
232: JSONObject s = new JSONObject();
233: assertNull(s.get("buba"));
234: s.put("a", new JSONString("A"));
235: s.put("a", new JSONString("AA"));
236: assertEquals("\"AA\"", s.get("a").toString());
237: }
238:
239: /**
240: * Tests an object whose keys are filled out with numbers, like {"a":1}.
241: */
242: public void testObjectOfNumbers() {
243: JSONObject obj = new JSONObject();
244: for (int i = 0; i < 10; i++) {
245: obj.put("Object " + i, new JSONNumber(i));
246: }
247: String s = obj.toString();
248: JSONValue v = JSONParser.parse(s);
249: JSONObject objIn = v.isObject();
250: assertTrue("v must be an object", objIn != null);
251: assertEquals("Object size must be 10", 10, objIn.keySet()
252: .size());
253: for (int i = 0; i < 10; i++) {
254: assertEquals("Object value at 'Object " + i + "' must be "
255: + i,
256: objIn.get("Object " + i).isNumber().getValue(), i,
257: 0.001);
258: }
259: }
260:
261: /**
262: * Tests generic parsing.
263: */
264: public void testParse() {
265: try {
266: new JSONString(null);
267: fail();
268: } catch (NullPointerException t) {
269: }
270: try {
271: JSONParser.parse(null);
272: fail();
273: } catch (NullPointerException t) {
274: }
275: try {
276: JSONParser.parse("");
277: fail();
278: } catch (IllegalArgumentException t) {
279: }
280: try {
281: JSONParser
282: .parse("{\"menu\": {\n" + " \"id\": \"file\",\n");
283: fail();
284: } catch (JSONException e) {
285: }
286: assertEquals("\"null\" should be null JSONValue", JSONNull
287: .getInstance(), JSONParser.parse("null"));
288: assertEquals("5 should be JSONNumber 5", 5d, JSONParser.parse(
289: "5").isNumber().getValue(), 0.001);
290: assertEquals("\"null\" should be null JSONValue", JSONNull
291: .getInstance(), JSONParser.parse("null"));
292: JSONValue somethingHello = JSONParser
293: .parse("[{\"something\":\"hello\"}]");
294: JSONArray somethingHelloArray = somethingHello.isArray();
295: assertTrue("somethingHello must be a JSONArray",
296: somethingHelloArray != null);
297: assertTrue("somethingHello size must be one",
298: somethingHelloArray.size() == 1);
299: JSONObject somethingHelloObject = somethingHelloArray.get(0)
300: .isObject();
301: assertTrue("somethingHello element 0 must be a JSONObject",
302: somethingHelloObject != null);
303: assertTrue(
304: "somethingHello element 0 must have hello for key something",
305: somethingHelloObject.get("something").isString()
306: .stringValue().equals("hello"));
307: }
308:
309: public void testSimpleNested() {
310: JSONObject j1 = new JSONObject();
311: j1.put("test1", new JSONString(""));
312:
313: JSONObject j2 = new JSONObject();
314: j2.put("test1", new JSONString(""));
315:
316: JSONObject j22 = new JSONObject();
317: j22.put("test12", new JSONString(""));
318: j2.put("j22", j22);
319:
320: JSONObject j3 = new JSONObject();
321: j3.put("j1", j1);
322: j3.put("j2", j2);
323:
324: assertEquals(
325: "{\"j1\":{\"test1\":\"\"}, \"j2\":{\"test1\":\"\", \"j22\":{\"test12\":\"\"}}}",
326: j3.toString());
327: }
328:
329: public void testStringBasics() {
330: JSONString arr = new JSONString("");
331: assertEquals("\"\"", arr.toString());
332: JSONString s = new JSONString(menuTest);
333: assertEquals(menuTest, s.stringValue());
334: }
335:
336: public void testStringEscaping() {
337: checkRoundTripJsonText("\"hello\"", "hello");
338: checkRoundTripJsonText("\"hel\\\"lo\"", "hel\"lo");
339: checkRoundTripJsonText("\"hel\\\\lo\"", "hel\\lo");
340: checkRoundTripJsonText("\"hel\\\\\\\"lo\"", "hel\\\"lo");
341: }
342:
343: public void testStringTypes() {
344: JSONObject object = JSONParser.parse(
345: "{\"a\":\"b\",\"null\":\"foo\"}").isObject();
346: assertNotNull(object);
347:
348: assertEquals("b", object.get(stringAsPrimitive("a")).isString()
349: .stringValue());
350: assertEquals("b", object.get(stringAsObject("a")).isString()
351: .stringValue());
352: assertEquals("foo", object.get(stringAsPrimitive("null"))
353: .isString().stringValue());
354: assertEquals("foo", object.get(stringAsObject("null"))
355: .isString().stringValue());
356: assertNull(object.get(null));
357: }
358:
359: public void testWidget() {
360: JSONObject v = (JSONObject) JSONParser.parse(widgetTest);
361: JSONObject widget = (JSONObject) v.get("widget");
362: JSONObject window = (JSONObject) widget.get("window");
363: JSONValue title = window.get("title");
364: assertNotNull(title.isString());
365: JSONValue hOffSet = window.get("width");
366: assertNotNull(hOffSet.isNumber());
367: }
368:
369: private void checkRoundTripJsonText(String jsonText,
370: String normaltext) {
371: JSONString parsed = JSONParser.parse(jsonText).isString();
372: assertEquals(normaltext, parsed.stringValue());
373: assertEquals(jsonText, parsed.toString());
374: }
375:
376: private JSONArray createLargeArray(int size) {
377: JSONArray arr = new JSONArray();
378: for (int i = 0; i < size; i++) {
379: arr.set(i, new JSONNumber(i));
380: }
381: return arr;
382: }
383:
384: private void nestedAux(JSONObject obj, int i) {
385: JSONArray array = new JSONArray();
386: JSONString str = new JSONString("s" + i);
387: array.set(0, str);
388: obj.put("string" + i, str);
389: JSONNumber num = new JSONNumber(((double) i) + 0.1);
390: array.set(1, num);
391: obj.put("Number" + i, num);
392: JSONBoolean b = JSONBoolean.getInstance((i % 2) == 0);
393: array.set(2, b);
394: obj.put("Boolean" + i, b);
395: JSONNull nul = JSONNull.getInstance();
396: array.set(3, nul);
397: obj.put("Null" + i, nul);
398: JSONObject newObj = new JSONObject();
399: obj.put("object" + i, newObj);
400: if (i != 0) {
401: nestedAux(newObj, i - 1);
402: }
403: array.set(4, newObj);
404: obj.put("Array" + i, array);
405: }
406:
407: private JSONArray populateRecursiveArray(int numElements,
408: int recursion) {
409: JSONArray newArray = new JSONArray();
410: if (recursion <= 0) {
411: return newArray;
412: }
413:
414: for (int i = 0; i < numElements; i++) {
415: JSONArray childArray = populateRecursiveArray(numElements,
416: recursion - 1);
417: newArray.set(i, childArray);
418: }
419: return newArray;
420: }
421:
422: private native String stringAsObject(String str) /*-{
423: return new String(str);
424: }-*/;
425:
426: private native String stringAsPrimitive(String str) /*-{
427: return String(str);
428: }-*/;
429: }
|