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.Arrays; 20 import java.util.Collection; 21 import java.util.Collections; 22 import java.util.List; 23 import junit.framework.TestCase; 24 25 import org.json.JSONArray; 26 import org.json.JSONException; 27 import org.json.JSONObject; 28 import org.json.JSONTokener; 29 30 /** 31 * This black box test was written without inspecting the non-free org.json sourcecode. 32 */ 33 public class JSONArrayTest extends TestCase { 34 testEmptyArray()35 public void testEmptyArray() throws JSONException { 36 JSONArray array = new JSONArray(); 37 assertEquals(0, array.length()); 38 assertEquals("", array.join(" AND ")); 39 try { 40 array.get(0); 41 fail(); 42 } catch (JSONException e) { 43 } 44 try { 45 array.getBoolean(0); 46 fail(); 47 } catch (JSONException e) { 48 } 49 50 assertEquals("[]", array.toString()); 51 assertEquals("[]", array.toString(4)); 52 53 // out of bounds is co-opted with defaulting 54 assertTrue(array.isNull(0)); 55 assertNull(array.opt(0)); 56 assertFalse(array.optBoolean(0)); 57 assertTrue(array.optBoolean(0, true)); 58 59 // bogus (but documented) behaviour: returns null rather than an empty object! 60 assertNull(array.toJSONObject(new JSONArray())); 61 } 62 testEqualsAndHashCode()63 public void testEqualsAndHashCode() throws JSONException { 64 JSONArray a = new JSONArray(); 65 JSONArray b = new JSONArray(); 66 assertTrue(a.equals(b)); 67 assertEquals("equals() not consistent with hashCode()", a.hashCode(), b.hashCode()); 68 69 a.put(true); 70 a.put(false); 71 b.put(true); 72 b.put(false); 73 assertTrue(a.equals(b)); 74 assertEquals(a.hashCode(), b.hashCode()); 75 76 b.put(true); 77 assertFalse(a.equals(b)); 78 assertTrue(a.hashCode() != b.hashCode()); 79 } 80 testBooleans()81 public void testBooleans() throws JSONException { 82 JSONArray array = new JSONArray(); 83 array.put(true); 84 array.put(false); 85 array.put(2, false); 86 array.put(3, false); 87 array.put(2, true); 88 assertEquals("[true,false,true,false]", array.toString()); 89 assertEquals(4, array.length()); 90 assertEquals(Boolean.TRUE, array.get(0)); 91 assertEquals(Boolean.FALSE, array.get(1)); 92 assertEquals(Boolean.TRUE, array.get(2)); 93 assertEquals(Boolean.FALSE, array.get(3)); 94 assertFalse(array.isNull(0)); 95 assertFalse(array.isNull(1)); 96 assertFalse(array.isNull(2)); 97 assertFalse(array.isNull(3)); 98 assertEquals(true, array.optBoolean(0)); 99 assertEquals(false, array.optBoolean(1, true)); 100 assertEquals(true, array.optBoolean(2, false)); 101 assertEquals(false, array.optBoolean(3)); 102 assertEquals("true", array.getString(0)); 103 assertEquals("false", array.getString(1)); 104 assertEquals("true", array.optString(2)); 105 assertEquals("false", array.optString(3, "x")); 106 assertEquals("[\n true,\n false,\n true,\n false\n]", array.toString(5)); 107 108 JSONArray other = new JSONArray(); 109 other.put(true); 110 other.put(false); 111 other.put(true); 112 other.put(false); 113 assertTrue(array.equals(other)); 114 other.put(true); 115 assertFalse(array.equals(other)); 116 117 other = new JSONArray(); 118 other.put("true"); 119 other.put("false"); 120 other.put("truE"); 121 other.put("FALSE"); 122 assertFalse(array.equals(other)); 123 assertFalse(other.equals(array)); 124 assertEquals(true, other.getBoolean(0)); 125 assertEquals(false, other.optBoolean(1, true)); 126 assertEquals(true, other.optBoolean(2)); 127 assertEquals(false, other.getBoolean(3)); 128 } 129 130 // http://code.google.com/p/android/issues/detail?id=16411 testCoerceStringToBoolean()131 public void testCoerceStringToBoolean() throws JSONException { 132 JSONArray array = new JSONArray(); 133 array.put("maybe"); 134 try { 135 array.getBoolean(0); 136 fail(); 137 } catch (JSONException expected) { 138 } 139 assertEquals(false, array.optBoolean(0)); 140 assertEquals(true, array.optBoolean(0, true)); 141 } 142 testNulls()143 public void testNulls() throws JSONException { 144 JSONArray array = new JSONArray(); 145 array.put(3, (Collection) null); 146 array.put(0, JSONObject.NULL); 147 assertEquals(4, array.length()); 148 assertEquals("[null,null,null,null]", array.toString()); 149 150 // there's 2 ways to represent null; each behaves differently! 151 assertEquals(JSONObject.NULL, array.get(0)); 152 try { 153 array.get(1); 154 fail(); 155 } catch (JSONException e) { 156 } 157 try { 158 array.get(2); 159 fail(); 160 } catch (JSONException e) { 161 } 162 try { 163 array.get(3); 164 fail(); 165 } catch (JSONException e) { 166 } 167 assertEquals(JSONObject.NULL, array.opt(0)); 168 assertEquals(null, array.opt(1)); 169 assertEquals(null, array.opt(2)); 170 assertEquals(null, array.opt(3)); 171 assertTrue(array.isNull(0)); 172 assertTrue(array.isNull(1)); 173 assertTrue(array.isNull(2)); 174 assertTrue(array.isNull(3)); 175 assertEquals("null", array.optString(0)); 176 assertEquals("", array.optString(1)); 177 assertEquals("", array.optString(2)); 178 assertEquals("", array.optString(3)); 179 } 180 181 /** 182 * Our behaviour is questioned by this bug: 183 * http://code.google.com/p/android/issues/detail?id=7257 184 */ testParseNullYieldsJSONObjectNull()185 public void testParseNullYieldsJSONObjectNull() throws JSONException { 186 JSONArray array = new JSONArray("[\"null\",null]"); 187 array.put((Collection) null); 188 assertEquals("null", array.get(0)); 189 assertEquals(JSONObject.NULL, array.get(1)); 190 try { 191 array.get(2); 192 fail(); 193 } catch (JSONException e) { 194 } 195 assertEquals("null", array.getString(0)); 196 assertEquals("null", array.getString(1)); 197 try { 198 array.getString(2); 199 fail(); 200 } catch (JSONException e) { 201 } 202 } 203 testNumbers()204 public void testNumbers() throws JSONException { 205 JSONArray array = new JSONArray(); 206 array.put(Double.MIN_VALUE); 207 array.put(9223372036854775806L); 208 array.put(Double.MAX_VALUE); 209 array.put(-0d); 210 assertEquals(4, array.length()); 211 212 // toString() and getString(int) return different values for -0d 213 assertEquals("[4.9E-324,9223372036854775806,1.7976931348623157E308,-0]", array.toString()); 214 215 assertEquals(Double.MIN_VALUE, array.get(0)); 216 assertEquals(9223372036854775806L, array.get(1)); 217 assertEquals(Double.MAX_VALUE, array.get(2)); 218 assertEquals(-0d, array.get(3)); 219 assertEquals(Double.MIN_VALUE, array.getDouble(0)); 220 assertEquals(9.223372036854776E18, array.getDouble(1)); 221 assertEquals(Double.MAX_VALUE, array.getDouble(2)); 222 assertEquals(-0d, array.getDouble(3)); 223 assertEquals(0, array.getLong(0)); 224 assertEquals(9223372036854775806L, array.getLong(1)); 225 assertEquals(Long.MAX_VALUE, array.getLong(2)); 226 assertEquals(0, array.getLong(3)); 227 assertEquals(0, array.getInt(0)); 228 assertEquals(-2, array.getInt(1)); 229 assertEquals(Integer.MAX_VALUE, array.getInt(2)); 230 assertEquals(0, array.getInt(3)); 231 assertEquals(Double.MIN_VALUE, array.opt(0)); 232 assertEquals(Double.MIN_VALUE, array.optDouble(0)); 233 assertEquals(0, array.optLong(0, 1L)); 234 assertEquals(0, array.optInt(0, 1)); 235 assertEquals("4.9E-324", array.getString(0)); 236 assertEquals("9223372036854775806", array.getString(1)); 237 assertEquals("1.7976931348623157E308", array.getString(2)); 238 assertEquals("-0.0", array.getString(3)); 239 240 JSONArray other = new JSONArray(); 241 other.put(Double.MIN_VALUE); 242 other.put(9223372036854775806L); 243 other.put(Double.MAX_VALUE); 244 other.put(-0d); 245 assertTrue(array.equals(other)); 246 other.put(0, 0L); 247 assertFalse(array.equals(other)); 248 } 249 testStrings()250 public void testStrings() throws JSONException { 251 JSONArray array = new JSONArray(); 252 array.put("true"); 253 array.put("5.5"); 254 array.put("9223372036854775806"); 255 array.put("null"); 256 array.put("5\"8' tall"); 257 assertEquals(5, array.length()); 258 assertEquals("[\"true\",\"5.5\",\"9223372036854775806\",\"null\",\"5\\\"8' tall\"]", 259 array.toString()); 260 261 // although the documentation doesn't mention it, join() escapes text and wraps 262 // strings in quotes 263 assertEquals("\"true\" \"5.5\" \"9223372036854775806\" \"null\" \"5\\\"8' tall\"", 264 array.join(" ")); 265 266 assertEquals("true", array.get(0)); 267 assertEquals("null", array.getString(3)); 268 assertEquals("5\"8' tall", array.getString(4)); 269 assertEquals("true", array.opt(0)); 270 assertEquals("5.5", array.optString(1)); 271 assertEquals("9223372036854775806", array.optString(2, null)); 272 assertEquals("null", array.optString(3, "-1")); 273 assertFalse(array.isNull(0)); 274 assertFalse(array.isNull(3)); 275 276 assertEquals(true, array.getBoolean(0)); 277 assertEquals(true, array.optBoolean(0)); 278 assertEquals(true, array.optBoolean(0, false)); 279 assertEquals(0, array.optInt(0)); 280 assertEquals(-2, array.optInt(0, -2)); 281 282 assertEquals(5.5d, array.getDouble(1)); 283 assertEquals(5L, array.getLong(1)); 284 assertEquals(5, array.getInt(1)); 285 assertEquals(5, array.optInt(1, 3)); 286 287 // The last digit of the string is a 6 but getLong returns a 7. It's probably parsing as a 288 // double and then converting that to a long. This is consistent with JavaScript. 289 assertEquals(9223372036854775807L, array.getLong(2)); 290 assertEquals(9.223372036854776E18, array.getDouble(2)); 291 assertEquals(Integer.MAX_VALUE, array.getInt(2)); 292 293 assertFalse(array.isNull(3)); 294 try { 295 array.getDouble(3); 296 fail(); 297 } catch (JSONException e) { 298 } 299 assertEquals(Double.NaN, array.optDouble(3)); 300 assertEquals(-1.0d, array.optDouble(3, -1.0d)); 301 } 302 testJoin()303 public void testJoin() throws JSONException { 304 JSONArray array = new JSONArray(); 305 array.put((Collection) null); 306 assertEquals("null", array.join(" & ")); 307 array.put("\""); 308 assertEquals("null & \"\\\"\"", array.join(" & ")); 309 array.put(5); 310 assertEquals("null & \"\\\"\" & 5", array.join(" & ")); 311 array.put(true); 312 assertEquals("null & \"\\\"\" & 5 & true", array.join(" & ")); 313 array.put(new JSONArray(Arrays.asList(true, false))); 314 assertEquals("null & \"\\\"\" & 5 & true & [true,false]", array.join(" & ")); 315 array.put(new JSONObject(Collections.singletonMap("x", 6))); 316 assertEquals("null & \"\\\"\" & 5 & true & [true,false] & {\"x\":6}", array.join(" & ")); 317 } 318 testJoinWithNull()319 public void testJoinWithNull() throws JSONException { 320 JSONArray array = new JSONArray(Arrays.asList(5, 6)); 321 assertEquals("5null6", array.join(null)); 322 } 323 testJoinWithSpecialCharacters()324 public void testJoinWithSpecialCharacters() throws JSONException { 325 JSONArray array = new JSONArray(Arrays.asList(5, 6)); 326 assertEquals("5\"6", array.join("\"")); 327 } 328 testToJSONObject()329 public void testToJSONObject() throws JSONException { 330 JSONArray keys = new JSONArray(); 331 keys.put("a"); 332 keys.put("b"); 333 334 JSONArray values = new JSONArray(); 335 values.put(5.5d); 336 values.put(false); 337 338 JSONObject object = values.toJSONObject(keys); 339 assertEquals(5.5d, object.get("a")); 340 assertEquals(false, object.get("b")); 341 342 keys.put(0, "a"); 343 values.put(0, 11.0d); 344 assertEquals(5.5d, object.get("a")); 345 } 346 testToJSONObjectWithNulls()347 public void testToJSONObjectWithNulls() throws JSONException { 348 JSONArray keys = new JSONArray(); 349 keys.put("a"); 350 keys.put("b"); 351 352 JSONArray values = new JSONArray(); 353 values.put(5.5d); 354 values.put((Collection) null); 355 356 // null values are stripped! 357 JSONObject object = values.toJSONObject(keys); 358 assertEquals(1, object.length()); 359 assertFalse(object.has("b")); 360 assertEquals("{\"a\":5.5}", object.toString()); 361 } 362 testToJSONObjectMoreNamesThanValues()363 public void testToJSONObjectMoreNamesThanValues() throws JSONException { 364 JSONArray keys = new JSONArray(); 365 keys.put("a"); 366 keys.put("b"); 367 JSONArray values = new JSONArray(); 368 values.put(5.5d); 369 JSONObject object = values.toJSONObject(keys); 370 assertEquals(1, object.length()); 371 assertEquals(5.5d, object.get("a")); 372 } 373 testToJSONObjectMoreValuesThanNames()374 public void testToJSONObjectMoreValuesThanNames() throws JSONException { 375 JSONArray keys = new JSONArray(); 376 keys.put("a"); 377 JSONArray values = new JSONArray(); 378 values.put(5.5d); 379 values.put(11.0d); 380 JSONObject object = values.toJSONObject(keys); 381 assertEquals(1, object.length()); 382 assertEquals(5.5d, object.get("a")); 383 } 384 testToJSONObjectNullKey()385 public void testToJSONObjectNullKey() throws JSONException { 386 JSONArray keys = new JSONArray(); 387 keys.put(JSONObject.NULL); 388 JSONArray values = new JSONArray(); 389 values.put(5.5d); 390 JSONObject object = values.toJSONObject(keys); 391 assertEquals(1, object.length()); 392 assertEquals(5.5d, object.get("null")); 393 } 394 testPutUnsupportedNumbers()395 public void testPutUnsupportedNumbers() throws JSONException { 396 JSONArray array = new JSONArray(); 397 398 try { 399 array.put(Double.NaN); 400 fail(); 401 } catch (JSONException e) { 402 } 403 try { 404 array.put(0, Double.NEGATIVE_INFINITY); 405 fail(); 406 } catch (JSONException e) { 407 } 408 try { 409 array.put(0, Double.POSITIVE_INFINITY); 410 fail(); 411 } catch (JSONException e) { 412 } 413 } 414 testPutUnsupportedNumbersAsObject()415 public void testPutUnsupportedNumbersAsObject() throws JSONException { 416 JSONArray array = new JSONArray(); 417 array.put(Double.valueOf(Double.NaN)); 418 array.put(Double.valueOf(Double.NEGATIVE_INFINITY)); 419 array.put(Double.valueOf(Double.POSITIVE_INFINITY)); 420 assertEquals(null, array.toString()); 421 } 422 423 /** 424 * Although JSONArray is usually defensive about which numbers it accepts, 425 * it doesn't check inputs in its constructor. 426 */ testCreateWithUnsupportedNumbers()427 public void testCreateWithUnsupportedNumbers() throws JSONException { 428 JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN)); 429 assertEquals(2, array.length()); 430 assertEquals(5.5, array.getDouble(0)); 431 assertEquals(Double.NaN, array.getDouble(1)); 432 } 433 testToStringWithUnsupportedNumbers()434 public void testToStringWithUnsupportedNumbers() throws JSONException { 435 // when the array contains an unsupported number, toString returns null! 436 JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN)); 437 assertNull(array.toString()); 438 } 439 testListConstructorCopiesContents()440 public void testListConstructorCopiesContents() throws JSONException { 441 List<Object> contents = Arrays.<Object>asList(5); 442 JSONArray array = new JSONArray(contents); 443 contents.set(0, 10); 444 assertEquals(5, array.get(0)); 445 } 446 testTokenerConstructor()447 public void testTokenerConstructor() throws JSONException { 448 JSONArray object = new JSONArray(new JSONTokener("[false]")); 449 assertEquals(1, object.length()); 450 assertEquals(false, object.get(0)); 451 } 452 testTokenerConstructorWrongType()453 public void testTokenerConstructorWrongType() throws JSONException { 454 try { 455 new JSONArray(new JSONTokener("{\"foo\": false}")); 456 fail(); 457 } catch (JSONException e) { 458 } 459 } 460 testTokenerConstructorNull()461 public void testTokenerConstructorNull() throws JSONException { 462 try { 463 new JSONArray((JSONTokener) null); 464 fail(); 465 } catch (NullPointerException e) { 466 } 467 } 468 testTokenerConstructorParseFail()469 public void testTokenerConstructorParseFail() { 470 try { 471 new JSONArray(new JSONTokener("[")); 472 fail(); 473 } catch (JSONException e) { 474 } catch (StackOverflowError e) { 475 fail("Stack overflowed on input: \"[\""); 476 } 477 } 478 testStringConstructor()479 public void testStringConstructor() throws JSONException { 480 JSONArray object = new JSONArray("[false]"); 481 assertEquals(1, object.length()); 482 assertEquals(false, object.get(0)); 483 } 484 testStringConstructorWrongType()485 public void testStringConstructorWrongType() throws JSONException { 486 try { 487 new JSONArray("{\"foo\": false}"); 488 fail(); 489 } catch (JSONException e) { 490 } 491 } 492 testStringConstructorNull()493 public void testStringConstructorNull() throws JSONException { 494 try { 495 new JSONArray((String) null); 496 fail(); 497 } catch (NullPointerException e) { 498 } 499 } 500 testStringConstructorParseFail()501 public void testStringConstructorParseFail() { 502 try { 503 new JSONArray("["); 504 fail(); 505 } catch (JSONException e) { 506 } catch (StackOverflowError e) { 507 fail("Stack overflowed on input: \"[\""); 508 } 509 } 510 testCreate()511 public void testCreate() throws JSONException { 512 JSONArray array = new JSONArray(Arrays.asList(5.5, true)); 513 assertEquals(2, array.length()); 514 assertEquals(5.5, array.getDouble(0)); 515 assertEquals(true, array.get(1)); 516 assertEquals("[5.5,true]", array.toString()); 517 } 518 testAccessOutOfBounds()519 public void testAccessOutOfBounds() throws JSONException { 520 JSONArray array = new JSONArray(); 521 array.put("foo"); 522 assertEquals(null, array.opt(3)); 523 assertEquals(null, array.opt(-3)); 524 assertEquals("", array.optString(3)); 525 assertEquals("", array.optString(-3)); 526 try { 527 array.get(3); 528 fail(); 529 } catch (JSONException e) { 530 } 531 try { 532 array.get(-3); 533 fail(); 534 } catch (JSONException e) { 535 } 536 try { 537 array.getString(3); 538 fail(); 539 } catch (JSONException e) { 540 } 541 try { 542 array.getString(-3); 543 fail(); 544 } catch (JSONException e) { 545 } 546 } 547 test_remove()548 public void test_remove() throws Exception { 549 JSONArray a = new JSONArray(); 550 assertEquals(null, a.remove(-1)); 551 assertEquals(null, a.remove(0)); 552 553 a.put("hello"); 554 assertEquals(null, a.remove(-1)); 555 assertEquals(null, a.remove(1)); 556 assertEquals("hello", a.remove(0)); 557 assertEquals(null, a.remove(0)); 558 } 559 560 enum MyEnum { A, B, C; } 561 562 // https://code.google.com/p/android/issues/detail?id=62539 testEnums()563 public void testEnums() throws Exception { 564 // This works because it's in java.* and any class in there falls back to toString. 565 JSONArray a1 = new JSONArray(java.lang.annotation.RetentionPolicy.values()); 566 assertEquals("[\"SOURCE\",\"CLASS\",\"RUNTIME\"]", a1.toString()); 567 568 // This doesn't because it's not. 569 JSONArray a2 = new JSONArray(MyEnum.values()); 570 assertEquals("[null,null,null]", a2.toString()); 571 } 572 } 573