JSONObjectTest.java revision 661054f5a2f7f8f5f3ceffb97e803211b546e7fc
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 java.math.BigDecimal;
20import java.math.BigInteger;
21import java.util.Arrays;
22import java.util.Collections;
23import java.util.HashMap;
24import java.util.HashSet;
25import java.util.Iterator;
26import java.util.Map;
27import java.util.NoSuchElementException;
28import java.util.Set;
29import junit.framework.TestCase;
30
31/**
32 * This black box test was written without inspecting the non-free org.json sourcecode.
33 */
34public class JSONObjectTest extends TestCase {
35
36    public void testEmptyObject() throws JSONException {
37        JSONObject object = new JSONObject();
38        assertEquals(0, object.length());
39
40        // bogus (but documented) behaviour: returns null rather than the empty object!
41        assertNull(object.names());
42
43        // returns null rather than an empty array!
44        assertNull(object.toJSONArray(new JSONArray()));
45        assertEquals("{}", object.toString());
46        assertEquals("{}", object.toString(5));
47        try {
48            object.get("foo");
49            fail();
50        } catch (JSONException e) {
51        }
52        try {
53            object.getBoolean("foo");
54            fail();
55        } catch (JSONException e) {
56        }
57        try {
58            object.getDouble("foo");
59            fail();
60        } catch (JSONException e) {
61        }
62        try {
63            object.getInt("foo");
64            fail();
65        } catch (JSONException e) {
66        }
67        try {
68            object.getJSONArray("foo");
69            fail();
70        } catch (JSONException e) {
71        }
72        try {
73            object.getJSONObject("foo");
74            fail();
75        } catch (JSONException e) {
76        }
77        try {
78            object.getLong("foo");
79            fail();
80        } catch (JSONException e) {
81        }
82        try {
83            object.getString("foo");
84            fail();
85        } catch (JSONException e) {
86        }
87        assertFalse(object.has("foo"));
88        assertTrue(object.isNull("foo")); // isNull also means "is not present"
89        assertNull(object.opt("foo"));
90        assertEquals(false, object.optBoolean("foo"));
91        assertEquals(true, object.optBoolean("foo", true));
92        assertEquals(Double.NaN, object.optDouble("foo"));
93        assertEquals(5.0, object.optDouble("foo", 5.0));
94        assertEquals(0, object.optInt("foo"));
95        assertEquals(5, object.optInt("foo", 5));
96        assertEquals(null, object.optJSONArray("foo"));
97        assertEquals(null, object.optJSONObject("foo"));
98        assertEquals(0, object.optLong("foo"));
99        assertEquals(Long.MAX_VALUE-1, object.optLong("foo", Long.MAX_VALUE-1));
100        assertEquals("", object.optString("foo")); // empty string is default!
101        assertEquals("bar", object.optString("foo", "bar"));
102        assertNull(object.remove("foo"));
103    }
104
105    public void testEqualsAndHashCode() throws JSONException {
106        JSONObject a = new JSONObject();
107        JSONObject b = new JSONObject();
108
109        // JSON object doesn't override either equals or hashCode (!)
110        assertFalse(a.equals(b));
111        assertEquals(a.hashCode(), System.identityHashCode(a));
112    }
113
114    public void testGet() throws JSONException {
115        JSONObject object = new JSONObject();
116        Object value = new Object();
117        object.put("foo", value);
118        object.put("bar", new Object());
119        object.put("baz", new Object());
120        assertSame(value, object.get("foo"));
121        try {
122            object.get("FOO");
123            fail();
124        } catch (JSONException e) {
125        }
126        try {
127            object.put(null, value);
128            fail();
129        } catch (JSONException e) {
130        }
131        try {
132            object.get(null);
133            fail();
134        } catch (JSONException e) {
135        }
136    }
137
138    public void testPut() throws JSONException {
139        JSONObject object = new JSONObject();
140        assertSame(object, object.put("foo", true));
141        object.put("foo", false);
142        assertEquals(false, object.get("foo"));
143
144        object.put("foo", 5.0d);
145        assertEquals(5.0d, object.get("foo"));
146        object.put("foo", 0);
147        assertEquals(0, object.get("foo"));
148        object.put("bar", Long.MAX_VALUE - 1);
149        assertEquals(Long.MAX_VALUE - 1, object.get("bar"));
150        object.put("baz", "x");
151        assertEquals("x", object.get("baz"));
152        object.put("bar", JSONObject.NULL);
153        assertSame(JSONObject.NULL, object.get("bar"));
154    }
155
156    public void testPutNullRemoves() throws JSONException {
157        JSONObject object = new JSONObject();
158        object.put("foo", "bar");
159        object.put("foo", null);
160        assertEquals(0, object.length());
161        assertFalse(object.has("foo"));
162        try {
163            object.get("foo");
164            fail();
165        } catch (JSONException e) {
166        }
167    }
168
169    public void testPutOpt() throws JSONException {
170        JSONObject object = new JSONObject();
171        object.put("foo", "bar");
172        object.putOpt("foo", null);
173        assertEquals("bar", object.get("foo"));
174        object.putOpt(null, null);
175        assertEquals(1, object.length());
176        object.putOpt(null, "bar");
177        assertEquals(1, object.length());
178    }
179
180    public void testPutOptUnsupportedNumbers() throws JSONException {
181        JSONObject object = new JSONObject();
182        try {
183            object.putOpt("foo", Double.NaN);
184            fail();
185        } catch (JSONException e) {
186        }
187        try {
188            object.putOpt("foo", Double.NEGATIVE_INFINITY);
189            fail();
190        } catch (JSONException e) {
191        }
192        try {
193            object.putOpt("foo", Double.POSITIVE_INFINITY);
194            fail();
195        } catch (JSONException e) {
196        }
197    }
198
199    public void testRemove() throws JSONException {
200        JSONObject object = new JSONObject();
201        object.put("foo", "bar");
202        assertEquals(null, object.remove(null));
203        assertEquals(null, object.remove(""));
204        assertEquals(null, object.remove("bar"));
205        assertEquals("bar", object.remove("foo"));
206        assertEquals(null, object.remove("foo"));
207    }
208
209    public void testBooleans() throws JSONException {
210        JSONObject object = new JSONObject();
211        object.put("foo", true);
212        object.put("bar", false);
213        object.put("baz", "true");
214        object.put("quux", "false");
215        assertEquals(4, object.length());
216        assertEquals(true, object.getBoolean("foo"));
217        assertEquals(false, object.getBoolean("bar"));
218        assertEquals(true, object.getBoolean("baz"));
219        assertEquals(false, object.getBoolean("quux"));
220        assertFalse(object.isNull("foo"));
221        assertFalse(object.isNull("quux"));
222        assertTrue(object.has("foo"));
223        assertTrue(object.has("quux"));
224        assertFalse(object.has("missing"));
225        assertEquals(true, object.optBoolean("foo"));
226        assertEquals(false, object.optBoolean("bar"));
227        assertEquals(true, object.optBoolean("baz"));
228        assertEquals(false, object.optBoolean("quux"));
229        assertEquals(false, object.optBoolean("missing"));
230        assertEquals(true, object.optBoolean("foo", true));
231        assertEquals(false, object.optBoolean("bar", true));
232        assertEquals(true, object.optBoolean("baz", true));
233        assertEquals(false, object.optBoolean("quux", true));
234        assertEquals(true, object.optBoolean("missing", true));
235
236        object.put("foo", "truE");
237        object.put("bar", "FALSE");
238        assertEquals(true, object.getBoolean("foo"));
239        assertEquals(false, object.getBoolean("bar"));
240        assertEquals(true, object.optBoolean("foo"));
241        assertEquals(false, object.optBoolean("bar"));
242        assertEquals(true, object.optBoolean("foo", false));
243        assertEquals(false, object.optBoolean("bar", false));
244    }
245
246    // http://code.google.com/p/android/issues/detail?id=16411
247    public void testCoerceStringToBoolean() throws JSONException {
248        JSONObject object = new JSONObject();
249        object.put("foo", "maybe");
250        try {
251            object.getBoolean("foo");
252            fail();
253        } catch (JSONException expected) {
254        }
255        assertEquals(false, object.optBoolean("foo"));
256        assertEquals(true, object.optBoolean("foo", true));
257    }
258
259    public void testNumbers() throws JSONException {
260        JSONObject object = new JSONObject();
261        object.put("foo", Double.MIN_VALUE);
262        object.put("bar", 9223372036854775806L);
263        object.put("baz", Double.MAX_VALUE);
264        object.put("quux", -0d);
265        assertEquals(4, object.length());
266
267        String toString = object.toString();
268        assertTrue(toString, toString.contains("\"foo\":4.9E-324"));
269        assertTrue(toString, toString.contains("\"bar\":9223372036854775806"));
270        assertTrue(toString, toString.contains("\"baz\":1.7976931348623157E308"));
271
272        // toString() and getString() return different values for -0d!
273        assertTrue(toString, toString.contains("\"quux\":-0}") // no trailing decimal point
274                || toString.contains("\"quux\":-0,"));
275
276        assertEquals(Double.MIN_VALUE, object.get("foo"));
277        assertEquals(9223372036854775806L, object.get("bar"));
278        assertEquals(Double.MAX_VALUE, object.get("baz"));
279        assertEquals(-0d, object.get("quux"));
280        assertEquals(Double.MIN_VALUE, object.getDouble("foo"));
281        assertEquals(9.223372036854776E18, object.getDouble("bar"));
282        assertEquals(Double.MAX_VALUE, object.getDouble("baz"));
283        assertEquals(-0d, object.getDouble("quux"));
284        assertEquals(0, object.getLong("foo"));
285        assertEquals(9223372036854775806L, object.getLong("bar"));
286        assertEquals(Long.MAX_VALUE, object.getLong("baz"));
287        assertEquals(0, object.getLong("quux"));
288        assertEquals(0, object.getInt("foo"));
289        assertEquals(-2, object.getInt("bar"));
290        assertEquals(Integer.MAX_VALUE, object.getInt("baz"));
291        assertEquals(0, object.getInt("quux"));
292        assertEquals(Double.MIN_VALUE, object.opt("foo"));
293        assertEquals(9223372036854775806L, object.optLong("bar"));
294        assertEquals(Double.MAX_VALUE, object.optDouble("baz"));
295        assertEquals(0, object.optInt("quux"));
296        assertEquals(Double.MIN_VALUE, object.opt("foo"));
297        assertEquals(9223372036854775806L, object.optLong("bar"));
298        assertEquals(Double.MAX_VALUE, object.optDouble("baz"));
299        assertEquals(0, object.optInt("quux"));
300        assertEquals(Double.MIN_VALUE, object.optDouble("foo", 5.0d));
301        assertEquals(9223372036854775806L, object.optLong("bar", 1L));
302        assertEquals(Long.MAX_VALUE, object.optLong("baz", 1L));
303        assertEquals(0, object.optInt("quux", -1));
304        assertEquals("4.9E-324", object.getString("foo"));
305        assertEquals("9223372036854775806", object.getString("bar"));
306        assertEquals("1.7976931348623157E308", object.getString("baz"));
307        assertEquals("-0.0", object.getString("quux"));
308    }
309
310    public void testFloats() throws JSONException {
311        JSONObject object = new JSONObject();
312        try {
313            object.put("foo", (Float) Float.NaN);
314            fail();
315        } catch (JSONException e) {
316        }
317        try {
318            object.put("foo", (Float) Float.NEGATIVE_INFINITY);
319            fail();
320        } catch (JSONException e) {
321        }
322        try {
323            object.put("foo", (Float) Float.POSITIVE_INFINITY);
324            fail();
325        } catch (JSONException e) {
326        }
327    }
328
329    public void testOtherNumbers() throws JSONException {
330        Number nan = new Number() {
331            public int intValue() {
332                throw new UnsupportedOperationException();
333            }
334            public long longValue() {
335                throw new UnsupportedOperationException();
336            }
337            public float floatValue() {
338                throw new UnsupportedOperationException();
339            }
340            public double doubleValue() {
341                return Double.NaN;
342            }
343            @Override public String toString() {
344                return "x";
345            }
346        };
347
348        JSONObject object = new JSONObject();
349        try {
350            object.put("foo", nan);
351            fail("Object.put() accepted a NaN (via a custom Number class)");
352        } catch (JSONException e) {
353        }
354    }
355
356    public void testForeignObjects() throws JSONException {
357        Object foreign = new Object() {
358            @Override public String toString() {
359                return "x";
360            }
361        };
362
363        // foreign object types are accepted and treated as Strings!
364        JSONObject object = new JSONObject();
365        object.put("foo", foreign);
366        assertEquals("{\"foo\":\"x\"}", object.toString());
367    }
368
369    public void testNullKeys() {
370        try {
371            new JSONObject().put(null, false);
372            fail();
373        } catch (JSONException e) {
374        }
375        try {
376            new JSONObject().put(null, 0.0d);
377            fail();
378        } catch (JSONException e) {
379        }
380        try {
381            new JSONObject().put(null, 5);
382            fail();
383        } catch (JSONException e) {
384        }
385        try {
386            new JSONObject().put(null, 5L);
387            fail();
388        } catch (JSONException e) {
389        }
390        try {
391            new JSONObject().put(null, "foo");
392            fail();
393        } catch (JSONException e) {
394        }
395    }
396
397    public void testStrings() throws JSONException {
398        JSONObject object = new JSONObject();
399        object.put("foo", "true");
400        object.put("bar", "5.5");
401        object.put("baz", "9223372036854775806");
402        object.put("quux", "null");
403        object.put("height", "5\"8' tall");
404
405        assertTrue(object.toString().contains("\"foo\":\"true\""));
406        assertTrue(object.toString().contains("\"bar\":\"5.5\""));
407        assertTrue(object.toString().contains("\"baz\":\"9223372036854775806\""));
408        assertTrue(object.toString().contains("\"quux\":\"null\""));
409        assertTrue(object.toString().contains("\"height\":\"5\\\"8' tall\""));
410
411        assertEquals("true", object.get("foo"));
412        assertEquals("null", object.getString("quux"));
413        assertEquals("5\"8' tall", object.getString("height"));
414        assertEquals("true", object.opt("foo"));
415        assertEquals("5.5", object.optString("bar"));
416        assertEquals("true", object.optString("foo", "x"));
417        assertFalse(object.isNull("foo"));
418
419        assertEquals(true, object.getBoolean("foo"));
420        assertEquals(true, object.optBoolean("foo"));
421        assertEquals(true, object.optBoolean("foo", false));
422        assertEquals(0, object.optInt("foo"));
423        assertEquals(-2, object.optInt("foo", -2));
424
425        assertEquals(5.5d, object.getDouble("bar"));
426        assertEquals(5L, object.getLong("bar"));
427        assertEquals(5, object.getInt("bar"));
428        assertEquals(5, object.optInt("bar", 3));
429
430        // The last digit of the string is a 6 but getLong returns a 7. It's probably parsing as a
431        // double and then converting that to a long. This is consistent with JavaScript.
432        assertEquals(9223372036854775807L, object.getLong("baz"));
433        assertEquals(9.223372036854776E18, object.getDouble("baz"));
434        assertEquals(Integer.MAX_VALUE, object.getInt("baz"));
435
436        assertFalse(object.isNull("quux"));
437        try {
438            object.getDouble("quux");
439            fail();
440        } catch (JSONException e) {
441        }
442        assertEquals(Double.NaN, object.optDouble("quux"));
443        assertEquals(-1.0d, object.optDouble("quux", -1.0d));
444
445        object.put("foo", "TRUE");
446        assertEquals(true, object.getBoolean("foo"));
447    }
448
449    public void testJSONObjects() throws JSONException {
450        JSONObject object = new JSONObject();
451
452        JSONArray a = new JSONArray();
453        JSONObject b = new JSONObject();
454        object.put("foo", a);
455        object.put("bar", b);
456
457        assertSame(a, object.getJSONArray("foo"));
458        assertSame(b, object.getJSONObject("bar"));
459        try {
460            object.getJSONObject("foo");
461            fail();
462        } catch (JSONException e) {
463        }
464        try {
465            object.getJSONArray("bar");
466            fail();
467        } catch (JSONException e) {
468        }
469        assertEquals(a, object.optJSONArray("foo"));
470        assertEquals(b, object.optJSONObject("bar"));
471        assertEquals(null, object.optJSONArray("bar"));
472        assertEquals(null, object.optJSONObject("foo"));
473    }
474
475    public void testNullCoercionToString() throws JSONException {
476        JSONObject object = new JSONObject();
477        object.put("foo", JSONObject.NULL);
478        assertEquals("null", object.getString("foo"));
479    }
480
481    public void testArrayCoercion() throws JSONException {
482        JSONObject object = new JSONObject();
483        object.put("foo", "[true]");
484        try {
485            object.getJSONArray("foo");
486            fail();
487        } catch (JSONException e) {
488        }
489    }
490
491    public void testObjectCoercion() throws JSONException {
492        JSONObject object = new JSONObject();
493        object.put("foo", "{}");
494        try {
495            object.getJSONObject("foo");
496            fail();
497        } catch (JSONException e) {
498        }
499    }
500
501    public void testAccumulateValueChecking() throws JSONException {
502        JSONObject object = new JSONObject();
503        try {
504            object.accumulate("foo", Double.NaN);
505            fail();
506        } catch (JSONException e) {
507        }
508        object.accumulate("foo", 1);
509        try {
510            object.accumulate("foo", Double.NaN);
511            fail();
512        } catch (JSONException e) {
513        }
514        object.accumulate("foo", 2);
515        try {
516            object.accumulate("foo", Double.NaN);
517            fail();
518        } catch (JSONException e) {
519        }
520    }
521
522    public void testToJSONArray() throws JSONException {
523        JSONObject object = new JSONObject();
524        Object value = new Object();
525        object.put("foo", true);
526        object.put("bar", 5.0d);
527        object.put("baz", -0.0d);
528        object.put("quux", value);
529
530        JSONArray names = new JSONArray();
531        names.put("baz");
532        names.put("quux");
533        names.put("foo");
534
535        JSONArray array = object.toJSONArray(names);
536        assertEquals(-0.0d, array.get(0));
537        assertEquals(value, array.get(1));
538        assertEquals(true, array.get(2));
539
540        object.put("foo", false);
541        assertEquals(true, array.get(2));
542    }
543
544    public void testToJSONArrayMissingNames() throws JSONException {
545        JSONObject object = new JSONObject();
546        object.put("foo", true);
547        object.put("bar", 5.0d);
548        object.put("baz", JSONObject.NULL);
549
550        JSONArray names = new JSONArray();
551        names.put("bar");
552        names.put("foo");
553        names.put("quux");
554        names.put("baz");
555
556        JSONArray array = object.toJSONArray(names);
557        assertEquals(4, array.length());
558
559        assertEquals(5.0d, array.get(0));
560        assertEquals(true, array.get(1));
561        try {
562            array.get(2);
563            fail();
564        } catch (JSONException e) {
565        }
566        assertEquals(JSONObject.NULL, array.get(3));
567    }
568
569    public void testToJSONArrayNull() throws JSONException {
570        JSONObject object = new JSONObject();
571        assertEquals(null, object.toJSONArray(null));
572        object.put("foo", 5);
573        try {
574            object.toJSONArray(null);
575        } catch (JSONException e) {
576        }
577    }
578
579    public void testToJSONArrayEndsUpEmpty() throws JSONException {
580        JSONObject object = new JSONObject();
581        object.put("foo", 5);
582        JSONArray array = new JSONArray();
583        array.put("bar");
584        assertEquals(1, object.toJSONArray(array).length());
585    }
586
587    public void testToJSONArrayNonString() throws JSONException {
588        JSONObject object = new JSONObject();
589        object.put("foo", 5);
590        object.put("null", 10);
591        object.put("false", 15);
592
593        JSONArray names = new JSONArray();
594        names.put(JSONObject.NULL);
595        names.put(false);
596        names.put("foo");
597
598        // array elements are converted to strings to do name lookups on the map!
599        JSONArray array = object.toJSONArray(names);
600        assertEquals(3, array.length());
601        assertEquals(10, array.get(0));
602        assertEquals(15, array.get(1));
603        assertEquals(5, array.get(2));
604    }
605
606    public void testPutUnsupportedNumbers() throws JSONException {
607        JSONObject object = new JSONObject();
608        try {
609            object.put("foo", Double.NaN);
610            fail();
611        } catch (JSONException e) {
612        }
613        try {
614            object.put("foo", Double.NEGATIVE_INFINITY);
615            fail();
616        } catch (JSONException e) {
617        }
618        try {
619            object.put("foo", Double.POSITIVE_INFINITY);
620            fail();
621        } catch (JSONException e) {
622        }
623    }
624
625    public void testPutUnsupportedNumbersAsObjects() throws JSONException {
626        JSONObject object = new JSONObject();
627        try {
628            object.put("foo", (Double) Double.NaN);
629            fail();
630        } catch (JSONException e) {
631        }
632        try {
633            object.put("foo", (Double) Double.NEGATIVE_INFINITY);
634            fail();
635        } catch (JSONException e) {
636        }
637        try {
638            object.put("foo", (Double) Double.POSITIVE_INFINITY);
639            fail();
640        } catch (JSONException e) {
641        }
642    }
643
644    /**
645     * Although JSONObject is usually defensive about which numbers it accepts,
646     * it doesn't check inputs in its constructor.
647     */
648    public void testCreateWithUnsupportedNumbers() throws JSONException {
649        Map<String, Object> contents = new HashMap<String, Object>();
650        contents.put("foo", Double.NaN);
651        contents.put("bar", Double.NEGATIVE_INFINITY);
652        contents.put("baz", Double.POSITIVE_INFINITY);
653
654        JSONObject object = new JSONObject(contents);
655        assertEquals(Double.NaN, object.get("foo"));
656        assertEquals(Double.NEGATIVE_INFINITY, object.get("bar"));
657        assertEquals(Double.POSITIVE_INFINITY, object.get("baz"));
658    }
659
660    public void testToStringWithUnsupportedNumbers() {
661        // when the object contains an unsupported number, toString returns null!
662        JSONObject object = new JSONObject(Collections.singletonMap("foo", Double.NaN));
663        assertEquals(null, object.toString());
664    }
665
666    public void testMapConstructorCopiesContents() throws JSONException {
667        Map<String, Object> contents = new HashMap<String, Object>();
668        contents.put("foo", 5);
669        JSONObject object = new JSONObject(contents);
670        contents.put("foo", 10);
671        assertEquals(5, object.get("foo"));
672    }
673
674    public void testMapConstructorWithBogusEntries() {
675        Map<Object, Object> contents = new HashMap<Object, Object>();
676        contents.put(5, 5);
677
678        try {
679            new JSONObject(contents);
680            fail("JSONObject constructor doesn't validate its input!");
681        } catch (Exception e) {
682        }
683    }
684
685    public void testTokenerConstructor() throws JSONException {
686        JSONObject object = new JSONObject(new JSONTokener("{\"foo\": false}"));
687        assertEquals(1, object.length());
688        assertEquals(false, object.get("foo"));
689    }
690
691    public void testTokenerConstructorWrongType() throws JSONException {
692        try {
693            new JSONObject(new JSONTokener("[\"foo\", false]"));
694            fail();
695        } catch (JSONException e) {
696        }
697    }
698
699    public void testTokenerConstructorNull() throws JSONException {
700        try {
701            new JSONObject((JSONTokener) null);
702            fail();
703        } catch (NullPointerException e) {
704        }
705    }
706
707    public void testTokenerConstructorParseFail() {
708        try {
709            new JSONObject(new JSONTokener("{"));
710            fail();
711        } catch (JSONException e) {
712        }
713    }
714
715    public void testStringConstructor() throws JSONException {
716        JSONObject object = new JSONObject("{\"foo\": false}");
717        assertEquals(1, object.length());
718        assertEquals(false, object.get("foo"));
719    }
720
721    public void testStringConstructorWrongType() throws JSONException {
722        try {
723            new JSONObject("[\"foo\", false]");
724            fail();
725        } catch (JSONException e) {
726        }
727    }
728
729    public void testStringConstructorNull() throws JSONException {
730        try {
731            new JSONObject((String) null);
732            fail();
733        } catch (NullPointerException e) {
734        }
735    }
736
737    public void testStringonstructorParseFail() {
738        try {
739            new JSONObject("{");
740            fail();
741        } catch (JSONException e) {
742        }
743    }
744
745    public void testCopyConstructor() throws JSONException {
746        JSONObject source = new JSONObject();
747        source.put("a", JSONObject.NULL);
748        source.put("b", false);
749        source.put("c", 5);
750
751        JSONObject copy = new JSONObject(source, new String[] { "a", "c" });
752        assertEquals(2, copy.length());
753        assertEquals(JSONObject.NULL, copy.get("a"));
754        assertEquals(5, copy.get("c"));
755        assertEquals(null, copy.opt("b"));
756    }
757
758    public void testCopyConstructorMissingName() throws JSONException {
759        JSONObject source = new JSONObject();
760        source.put("a", JSONObject.NULL);
761        source.put("b", false);
762        source.put("c", 5);
763
764        JSONObject copy = new JSONObject(source, new String[]{ "a", "c", "d" });
765        assertEquals(2, copy.length());
766        assertEquals(JSONObject.NULL, copy.get("a"));
767        assertEquals(5, copy.get("c"));
768        assertEquals(0, copy.optInt("b"));
769    }
770
771    public void testAccumulateMutatesInPlace() throws JSONException {
772        JSONObject object = new JSONObject();
773        object.put("foo", 5);
774        object.accumulate("foo", 6);
775        JSONArray array = object.getJSONArray("foo");
776        assertEquals("[5,6]", array.toString());
777        object.accumulate("foo", 7);
778        assertEquals("[5,6,7]", array.toString());
779    }
780
781    public void testAccumulateExistingArray() throws JSONException {
782        JSONArray array = new JSONArray();
783        JSONObject object = new JSONObject();
784        object.put("foo", array);
785        object.accumulate("foo", 5);
786        assertEquals("[5]", array.toString());
787    }
788
789    public void testAccumulatePutArray() throws JSONException {
790        JSONObject object = new JSONObject();
791        object.accumulate("foo", 5);
792        assertEquals("{\"foo\":5}", object.toString());
793        object.accumulate("foo", new JSONArray());
794        assertEquals("{\"foo\":[5,[]]}", object.toString());
795    }
796
797    public void testAccumulateNull() {
798        JSONObject object = new JSONObject();
799        try {
800            object.accumulate(null, 5);
801            fail();
802        } catch (JSONException e) {
803        }
804    }
805
806    public void testEmptyStringKey() throws JSONException {
807        JSONObject object = new JSONObject();
808        object.put("", 5);
809        assertEquals(5, object.get(""));
810        assertEquals("{\"\":5}", object.toString());
811    }
812
813    public void testNullValue() throws JSONException {
814        JSONObject object = new JSONObject();
815        object.put("foo", JSONObject.NULL);
816        object.put("bar", null);
817
818        // there are two ways to represent null; each behaves differently!
819        assertTrue(object.has("foo"));
820        assertFalse(object.has("bar"));
821        assertTrue(object.isNull("foo"));
822        assertTrue(object.isNull("bar"));
823    }
824
825    public void testHas() throws JSONException {
826        JSONObject object = new JSONObject();
827        object.put("foo", 5);
828        assertTrue(object.has("foo"));
829        assertFalse(object.has("bar"));
830        assertFalse(object.has(null));
831    }
832
833    public void testOptNull() throws JSONException {
834        JSONObject object = new JSONObject();
835        object.put("foo", "bar");
836        assertEquals(null, object.opt(null));
837        assertEquals(false, object.optBoolean(null));
838        assertEquals(Double.NaN, object.optDouble(null));
839        assertEquals(0, object.optInt(null));
840        assertEquals(0L, object.optLong(null));
841        assertEquals(null, object.optJSONArray(null));
842        assertEquals(null, object.optJSONObject(null));
843        assertEquals("", object.optString(null));
844        assertEquals(true, object.optBoolean(null, true));
845        assertEquals(0.0d, object.optDouble(null, 0.0d));
846        assertEquals(1, object.optInt(null, 1));
847        assertEquals(1L, object.optLong(null, 1L));
848        assertEquals("baz", object.optString(null, "baz"));
849    }
850
851    public void testToStringWithIndentFactor() throws JSONException {
852        JSONObject object = new JSONObject();
853        object.put("foo", new JSONArray(Arrays.asList(5, 6)));
854        object.put("bar", new JSONObject());
855        String foobar = "{\n" +
856                "     \"foo\": [\n" +
857                "          5,\n" +
858                "          6\n" +
859                "     ],\n" +
860                "     \"bar\": {}\n" +
861                "}";
862        String barfoo = "{\n" +
863                "     \"bar\": {},\n" +
864                "     \"foo\": [\n" +
865                "          5,\n" +
866                "          6\n" +
867                "     ]\n" +
868                "}";
869        String string = object.toString(5);
870        assertTrue(string, foobar.equals(string) || barfoo.equals(string));
871    }
872
873    public void testNames() throws JSONException {
874        JSONObject object = new JSONObject();
875        object.put("foo", 5);
876        object.put("bar", 6);
877        object.put("baz", 7);
878        JSONArray array = object.names();
879        assertTrue(array.toString().contains("foo"));
880        assertTrue(array.toString().contains("bar"));
881        assertTrue(array.toString().contains("baz"));
882    }
883
884    public void testKeysEmptyObject() {
885        JSONObject object = new JSONObject();
886        assertFalse(object.keys().hasNext());
887        try {
888            object.keys().next();
889            fail();
890        } catch (NoSuchElementException e) {
891        }
892    }
893
894    public void testKeys() throws JSONException {
895        JSONObject object = new JSONObject();
896        object.put("foo", 5);
897        object.put("bar", 6);
898        object.put("foo", 7);
899
900        @SuppressWarnings("unchecked")
901        Iterator<String> keys = (Iterator<String>) object.keys();
902        Set<String> result = new HashSet<String>();
903        assertTrue(keys.hasNext());
904        result.add(keys.next());
905        assertTrue(keys.hasNext());
906        result.add(keys.next());
907        assertFalse(keys.hasNext());
908        assertEquals(new HashSet<String>(Arrays.asList("foo", "bar")), result);
909
910        try {
911            keys.next();
912            fail();
913        } catch (NoSuchElementException e) {
914        }
915    }
916
917    public void testMutatingKeysMutatesObject() throws JSONException {
918        JSONObject object = new JSONObject();
919        object.put("foo", 5);
920        Iterator keys = object.keys();
921        keys.next();
922        keys.remove();
923        assertEquals(0, object.length());
924    }
925
926    public void testQuote() {
927        // covered by JSONStringerTest.testEscaping
928    }
929
930    public void testQuoteNull() throws JSONException {
931        assertEquals("\"\"", JSONObject.quote(null));
932    }
933
934    public void testNumberToString() throws JSONException {
935        assertEquals("5", JSONObject.numberToString(5));
936        assertEquals("-0", JSONObject.numberToString(-0.0d));
937        assertEquals("9223372036854775806", JSONObject.numberToString(9223372036854775806L));
938        assertEquals("4.9E-324", JSONObject.numberToString(Double.MIN_VALUE));
939        assertEquals("1.7976931348623157E308", JSONObject.numberToString(Double.MAX_VALUE));
940        try {
941            JSONObject.numberToString(Double.NaN);
942            fail();
943        } catch (JSONException e) {
944        }
945        try {
946            JSONObject.numberToString(Double.NEGATIVE_INFINITY);
947            fail();
948        } catch (JSONException e) {
949        }
950        try {
951            JSONObject.numberToString(Double.POSITIVE_INFINITY);
952            fail();
953        } catch (JSONException e) {
954        }
955        assertEquals("0.001", JSONObject.numberToString(new BigDecimal("0.001")));
956        assertEquals("9223372036854775806",
957                JSONObject.numberToString(new BigInteger("9223372036854775806")));
958        try {
959            JSONObject.numberToString(null);
960            fail();
961        } catch (JSONException e) {
962        }
963    }
964}
965