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