1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 package com.google.crypto.tink.internal; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.gson.JsonArray; 23 import com.google.gson.JsonElement; 24 import com.google.gson.JsonNull; 25 import com.google.gson.JsonObject; 26 import com.google.gson.JsonPrimitive; 27 import java.io.ByteArrayOutputStream; 28 import java.io.IOException; 29 import java.io.NotSerializableException; 30 import java.io.ObjectOutputStream; 31 import java.math.BigInteger; 32 import org.junit.Test; 33 import org.junit.experimental.theories.DataPoints; 34 import org.junit.experimental.theories.FromDataPoints; 35 import org.junit.experimental.theories.Theories; 36 import org.junit.experimental.theories.Theory; 37 import org.junit.runner.RunWith; 38 39 /** 40 * Tests for Tink's internal {@link JsonParser}. 41 */ 42 @RunWith(Theories.class) 43 public final class JsonParserTest { 44 45 public static final class TestCase { 46 public final String name; 47 public final String input; 48 public final JsonElement expected; 49 TestCase(String name, String input, JsonElement expected)50 public TestCase(String name, String input, JsonElement expected) { 51 this.name = name; 52 this.input = input; 53 this.expected = expected; 54 } 55 TestCase(String name, String input)56 public TestCase(String name, String input) { 57 this.name = name; 58 this.input = input; 59 this.expected = null; 60 } 61 62 @Override toString()63 public String toString() { 64 return name; 65 } 66 } 67 jsonArray(JsonElement... elements)68 public static JsonArray jsonArray(JsonElement... elements) { 69 JsonArray output = new JsonArray(); 70 for (JsonElement element : elements) { 71 output.add(element); 72 } 73 return output; 74 } 75 jsonObject(String name, JsonElement value)76 public static JsonObject jsonObject(String name, JsonElement value) { 77 JsonObject output = new JsonObject(); 78 output.add(name, value); 79 return output; 80 } 81 82 @DataPoints("testCasesSuccess") 83 public static final TestCase[] TEST_CASES_SUCCESS = { 84 new TestCase("string", "\"xyz\"", new JsonPrimitive("xyz")), 85 new TestCase("number", "42", new JsonPrimitive(42)), 86 new TestCase("negative_number", "-42", new JsonPrimitive(-42)), 87 new TestCase("float", "42.42", new JsonPrimitive(42.42)), 88 new TestCase("negative_float", "-42.42", new JsonPrimitive(-42.42)), 89 new TestCase("true", "true", new JsonPrimitive(true)), 90 new TestCase("false", "false", new JsonPrimitive(false)), 91 new TestCase("null", "null", JsonNull.INSTANCE), 92 new TestCase( 93 "array", "[\"a\",\"b\"]", jsonArray(new JsonPrimitive("a"), new JsonPrimitive("b"))), 94 new TestCase("map", "{\"a\":\"b\"}", jsonObject("a", new JsonPrimitive("b"))), 95 new TestCase("empty_string", "\"\"", new JsonPrimitive("")), 96 new TestCase("empty_array", "[]", new JsonArray()), 97 new TestCase("array_with_newline", "[\n]", new JsonArray()), 98 new TestCase("array_with_tab", "[\t]", new JsonArray()), 99 new TestCase("empty_map", "{}", new JsonObject()), 100 new TestCase("map_with_empty_key", "{\"\":\"a\"}", jsonObject("", new JsonPrimitive("a"))), 101 new TestCase( 102 "nested_arrays", 103 "[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]", 104 jsonArray( 105 jsonArray( 106 jsonArray( 107 jsonArray( 108 jsonArray( 109 jsonArray( 110 jsonArray( 111 jsonArray( 112 jsonArray( 113 jsonArray( 114 jsonArray( 115 jsonArray( 116 jsonArray( 117 jsonArray( 118 jsonArray( 119 jsonArray())))))))))))))))), 120 new TestCase( 121 "nested_maps", 122 "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{}}}}}}}}}}}", 123 jsonObject( 124 "a", 125 jsonObject( 126 "a", 127 jsonObject( 128 "a", 129 jsonObject( 130 "a", 131 jsonObject( 132 "a", 133 jsonObject( 134 "a", 135 jsonObject( 136 "a", 137 jsonObject( 138 "a", 139 jsonObject("a", jsonObject("a", new JsonObject()))))))))))), 140 new TestCase("tRuE", "tRuE", new JsonPrimitive(true)), 141 new TestCase("fAlSe", "fAlSe", new JsonPrimitive(false)), 142 new TestCase("nUlL", "nUlL", JsonNull.INSTANCE), 143 new TestCase( 144 "mixed_array", 145 "[\"a\", null, 1, 0.1, true, {\"a\":0}, [4]]", 146 jsonArray( 147 new JsonPrimitive("a"), 148 JsonNull.INSTANCE, 149 new JsonPrimitive(1), 150 new JsonPrimitive(0.1), 151 new JsonPrimitive(true), 152 jsonObject("a", new JsonPrimitive(0)), 153 jsonArray(new JsonPrimitive(4)))), 154 new TestCase("tailing_newline", "\"a\"\n", new JsonPrimitive("a")), 155 new TestCase( 156 "whitespace", " { \"a\"\n: \n\"b\" \n } \n ", jsonObject("a", new JsonPrimitive("b"))), 157 new TestCase("string_with_comment", "\"a/*b*/c\"", new JsonPrimitive("a/*b*/c")), 158 new TestCase("string_with_excaped_unicode", "\"\\uA66D\"", new JsonPrimitive("ꙭ")), 159 new TestCase("valid_utf16", "\"\\uD83D\\uDC69\"", new JsonPrimitive("")), 160 new TestCase("valid_UTF8_1", "\"\\u002c\"", new JsonPrimitive(",")), 161 new TestCase("valid_UTF8_3", "\"\\u0123\"", new JsonPrimitive("ģ")), 162 new TestCase("escapes", "\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", new JsonPrimitive("\"\\/\b\f\n\r\t")), 163 new TestCase("newline", "\"a\\u000Ab\"", new JsonPrimitive("a\nb")), 164 new TestCase("backslash", "\"\\u005C\"", new JsonPrimitive("\\")), 165 new TestCase("double_quote", "\"\\u0022\"", new JsonPrimitive("\"")), 166 new TestCase( 167 "escaped_double_quote_in_key", 168 "{\"\\\"\\\"\": 42}", 169 jsonObject("\"\"", new JsonPrimitive(42))), 170 new TestCase("escaped_null", "\"\\u0000\"", new JsonPrimitive("" + (char) 0x00)), 171 new TestCase( 172 "escaped_null_in_key", 173 "{\"a\\u0000b\": 42}", 174 jsonObject("a\u0000b", new JsonPrimitive(42))), 175 new TestCase("invalid_UTF8", "\"日ш\"", new JsonPrimitive("日ш")), 176 177 new TestCase("long_max_value", "9223372036854775807", new JsonPrimitive(9223372036854775807L)), 178 new TestCase("big_float", "60911552482230981.0", new JsonPrimitive(6.0911552482230984e16)), 179 new TestCase("exp", "4e+42", new JsonPrimitive(4e+42)), 180 new TestCase("exp2", "4e42", new JsonPrimitive(4e+42)), 181 new TestCase("Exp", "4E42", new JsonPrimitive(4e+42)), 182 new TestCase("-exp", "-4e-42", new JsonPrimitive(-4e-42)), 183 new TestCase("number_tailing_space", "42 ", new JsonPrimitive(42)), 184 new TestCase("number_tailing_newline", "42\n", new JsonPrimitive(42)), 185 new TestCase("number_tailing_formfeed", "42\f", new JsonPrimitive(42)), 186 new TestCase( 187 "float_close_to_zero", 188 "0.000000000000000000000000000000001", 189 new JsonPrimitive(0.000000000000000000000000000000001)), 190 new TestCase( 191 "-float_close_to_zero", 192 "-0.000000000000000000000000000000001", 193 new JsonPrimitive(-0.000000000000000000000000000000001)), 194 new TestCase( 195 "huge_number", 196 "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 197 new JsonPrimitive(1e87)), 198 new TestCase( 199 "-huge_number", 200 "-999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 201 new JsonPrimitive(-1e87)), 202 new TestCase("string_with_tailing_comma", "\"a\",", new JsonPrimitive("a")), 203 new TestCase("number_with_tailing_comma", "42,", new JsonPrimitive(42)), 204 new TestCase("true_with_tailing_comma", "true,", new JsonPrimitive(true)), 205 new TestCase("string_with_tailing_comment", "\"a\"/*comment*/", new JsonPrimitive("a")), 206 new TestCase("map_with_tailing_comma", "{\"a\":1},", jsonObject("a", new JsonPrimitive(1))), 207 new TestCase( 208 "map_with_tailing_comment", "{\"a\":1}/*comment*/", jsonObject("a", new JsonPrimitive(1))), 209 new TestCase( 210 "map_with_tailing_open_comment", 211 "{\"a\":1}/*comment", 212 jsonObject("a", new JsonPrimitive(1))), 213 new TestCase("map_with_tailing_#", "{\"a\":1}#", jsonObject("a", new JsonPrimitive(1))), 214 new TestCase("map_with_tailing_]", "{\"a\":1}]", jsonObject("a", new JsonPrimitive(1))), 215 new TestCase("map_with_tailing_}", "{\"a\":1}}", jsonObject("a", new JsonPrimitive(1))), 216 new TestCase("array_with_tailing_comma", "[\"a\"],", jsonArray(new JsonPrimitive("a"))), 217 new TestCase( 218 "array_with_tailing_comment", "[\"a\"]/*comment*/", jsonArray(new JsonPrimitive("a"))), 219 new TestCase( 220 "array_with_tailing_open_comment", "[\"a\"]/*comment", jsonArray(new JsonPrimitive("a"))), 221 new TestCase("array_with_tailing_#", "[\"a\"]#", jsonArray(new JsonPrimitive("a"))), 222 new TestCase("array_with_tailing_]", "[\"a\"]]", jsonArray(new JsonPrimitive("a"))), 223 new TestCase("array_with_tailing_}", "[\"a\"]}", jsonArray(new JsonPrimitive("a"))), 224 new TestCase("double_array", "[][]", new JsonArray()), 225 new TestCase("number_with_space", "42 000", new JsonPrimitive(42)), 226 new TestCase("float_with_space", "42 000.0", new JsonPrimitive(42)), 227 }; 228 229 @Theory parse_asExpected( @romDataPoints"testCasesSuccess") TestCase testCase)230 public void parse_asExpected( 231 @FromDataPoints("testCasesSuccess") TestCase testCase) throws Exception { 232 JsonElement output = JsonParser.parse(testCase.input); 233 234 assertThat(output).isEqualTo(testCase.expected); 235 } 236 237 @Test parsedElementWithNumberToString_doesNotLoosePrecision()238 public void parsedElementWithNumberToString_doesNotLoosePrecision() throws Exception { 239 JsonElement element = JsonParser.parse("{ \"a\": 9223372036854775807 }"); 240 assertThat(element.toString()).isEqualTo("{\"a\":9223372036854775807}"); 241 } 242 243 @Test parsedNumberSerializeDeserialize_returnsBigDecimal()244 public void parsedNumberSerializeDeserialize_returnsBigDecimal() throws Exception { 245 JsonElement numElement = JsonParser.parse("42"); 246 Number num = numElement.getAsNumber(); 247 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 248 ObjectOutputStream out = new ObjectOutputStream(bytes); 249 assertThrows(NotSerializableException.class, () -> out.writeObject(num)); 250 } 251 252 @Test parsedNumberGetValue()253 public void parsedNumberGetValue() throws Exception { 254 JsonElement numElement = JsonParser.parse("42.42"); 255 assertThat(numElement.getAsInt()).isEqualTo(42); 256 assertThat(numElement.getAsLong()).isEqualTo(42); 257 assertThat(numElement.getAsFloat()).isEqualTo(42.42f); 258 assertThat(numElement.getAsDouble()).isEqualTo(42.42); 259 Number number = numElement.getAsNumber(); 260 assertThat(number.intValue()).isEqualTo(42); 261 assertThat(number.longValue()).isEqualTo(42); 262 assertThat(number.floatValue()).isEqualTo(42.42f); 263 assertThat(number.doubleValue()).isEqualTo(42.42); 264 } 265 266 @Test parsedNumberGetAsLong_discardsAllBut64LowestOrderBits()267 public void parsedNumberGetAsLong_discardsAllBut64LowestOrderBits() throws Exception { 268 // It would be preferable if JsonElement.getAsLong would throw a NumberFormatException exception 269 // if the number it contains does not fit into a long, similar to what Long.parseLong does. 270 271 // Instead, the method never throws an exception, and follows the "narrowing primitive 272 // conversion" of the Java Language Specification section 5.1.3, which means that all but the 32 273 // lowest order bits are discarded. 274 275 JsonElement numElement = JsonParser.parse("9223372036854775809"); // 2^63 + 1 276 assertThat(numElement.getAsLong()).isEqualTo(-9223372036854775807L); 277 } 278 279 @Test parsedNumberGetAsInt_discardsAllBut32LowestOrderBits()280 public void parsedNumberGetAsInt_discardsAllBut32LowestOrderBits() throws Exception { 281 // It would be preferable if JsonElement.getAsInt would throw a NumberFormatException exception 282 // if the number it contains does not fit into a long, similar to what Int.parseInt does. 283 284 // Instead, the method never throws an exception, and follows the "narrowing primitive 285 // conversion" of the Java Language Specification section 5.1.3, which means that all but the 32 286 // lowest order bits are discarded. 287 288 JsonElement numElement = JsonParser.parse("2147483649"); // 2^31 + 1 289 assertThat(numElement.getAsInt()).isEqualTo(-2147483647); 290 } 291 292 @DataPoints("longs") 293 public static final String[] LONGS = 294 new String[] { 295 "0", 296 "42", 297 "-42", 298 "2147483647", // 2^31 - 1 299 "-2147483648", // - 2^31 300 "2147483649", // 2^31 + 1 301 "44444444444444444", 302 "9223372036854775807", // 2^63 - 1 303 "-9223372036854775808", // - 2^63 304 }; 305 306 @DataPoints("biggerThanLongs") 307 public static final String[] BIGGER_THAN_LONGS = 308 new String[] { 309 "9223372036854775809", // 2^63 + 1 310 "18446744073709551658", // 2^64 + 42 311 "9999999999999999999999999999999999999999999999999999999999999999", 312 "-9999999999999999999999999999999999999999999999999999999999999999", 313 }; 314 315 @Theory parsedNumberGetAsLong_validLong_sameAsParseLong( @romDataPoints"longs") String numString)316 public void parsedNumberGetAsLong_validLong_sameAsParseLong( 317 @FromDataPoints("longs") String numString) throws Exception { 318 JsonElement parsed = JsonParser.parse(numString); 319 assertThat(parsed.getAsLong()).isEqualTo(Long.parseLong(numString)); 320 } 321 322 @Theory parsedNumberGetAsLong_biggerThanLong_sameAsBigIntegerLongValue( @romDataPoints"biggerThanLongs") String numString)323 public void parsedNumberGetAsLong_biggerThanLong_sameAsBigIntegerLongValue( 324 @FromDataPoints("biggerThanLongs") String numString) throws Exception { 325 JsonElement parsed = JsonParser.parse(numString); 326 assertThat(parsed.getAsLong()).isEqualTo(new BigInteger(numString).longValue()); 327 } 328 329 @Theory parsedNumberGetAsInt_validLong_sameAsBigIntegerIntValue( @romDataPoints"longs") String numString)330 public void parsedNumberGetAsInt_validLong_sameAsBigIntegerIntValue( 331 @FromDataPoints("longs") String numString) throws Exception { 332 JsonElement parsed = JsonParser.parse(numString); 333 assertThat(parsed.getAsInt()).isEqualTo(new BigInteger(numString).intValue()); 334 } 335 336 @Theory parsedNumberGetAsInt_biggerThanLong_sameAsBigIntegerIntValue( @romDataPoints"biggerThanLongs") String numString)337 public void parsedNumberGetAsInt_biggerThanLong_sameAsBigIntegerIntValue( 338 @FromDataPoints("biggerThanLongs") String numString) throws Exception { 339 JsonElement parsed = JsonParser.parse(numString); 340 assertThat(parsed.getAsInt()).isEqualTo(new BigInteger(numString).intValue()); 341 } 342 343 @Theory getParsedNumberAsLongOrThrow_validLong_sameAsParseLong( @romDataPoints"longs") String numString)344 public void getParsedNumberAsLongOrThrow_validLong_sameAsParseLong( 345 @FromDataPoints("longs") String numString) throws Exception { 346 Number parsed = JsonParser.parse(numString).getAsNumber(); 347 assertThat(JsonParser.getParsedNumberAsLongOrThrow(parsed)) 348 .isEqualTo(Long.parseLong(numString)); 349 } 350 351 @Theory getParsedNumberAsLongOrThrow_validLong_sameAsLongValue( @romDataPoints"longs") String numString)352 public void getParsedNumberAsLongOrThrow_validLong_sameAsLongValue( 353 @FromDataPoints("longs") String numString) throws Exception { 354 Number parsed = JsonParser.parse(numString).getAsNumber(); 355 assertThat(JsonParser.getParsedNumberAsLongOrThrow(parsed)).isEqualTo(parsed.longValue()); 356 } 357 358 @Theory getParsedNumberAsLongOrThrow_biggerThanLong_throws( @romDataPoints"biggerThanLongs") String numString)359 public void getParsedNumberAsLongOrThrow_biggerThanLong_throws( 360 @FromDataPoints("biggerThanLongs") String numString) throws Exception { 361 Number parsed = JsonParser.parse(numString).getAsNumber(); 362 assertThrows( 363 NumberFormatException.class, () -> JsonParser.getParsedNumberAsLongOrThrow(parsed)); 364 } 365 366 @Theory getParsedNumberAsLongOrThrow_nestedValue_success()367 public void getParsedNumberAsLongOrThrow_nestedValue_success() throws Exception { 368 JsonElement parsed = JsonParser.parse("{\"a\":{\"b\":9223372036854775807}}"); 369 Number parsedNumber = 370 parsed.getAsJsonObject().get("a").getAsJsonObject().get("b").getAsNumber(); 371 long output = JsonParser.getParsedNumberAsLongOrThrow(parsedNumber); 372 assertThat(output).isEqualTo(9223372036854775807L); 373 } 374 375 @Theory getParsedNumberAsLongOrThrow_notParsed_throws()376 public void getParsedNumberAsLongOrThrow_notParsed_throws() throws Exception { 377 Number notParsedJsonElementWithNumber = new JsonPrimitive(42).getAsNumber(); 378 assertThrows( 379 IllegalArgumentException.class, 380 () -> JsonParser.getParsedNumberAsLongOrThrow(notParsedJsonElementWithNumber)); 381 } 382 383 @Theory floatNumbersGetAsLong_getsTruncated()384 public void floatNumbersGetAsLong_getsTruncated() throws Exception { 385 assertThat(JsonParser.parse("42.0").getAsLong()).isEqualTo(42); 386 assertThat(JsonParser.parse("2.1e1").getAsLong()).isEqualTo(21); 387 388 assertThat(JsonParser.parse("42.1").getAsLong()).isEqualTo(42); 389 assertThat(JsonParser.parse("42.9999").getAsLong()).isEqualTo(42); 390 391 // 2^63 - 1 as float 392 assertThat(JsonParser.parse("9.223372036854775807e18").getAsLong()) 393 .isEqualTo(9223372036854775807L); 394 395 // - 2^63 as float 396 assertThat(JsonParser.parse("-9.223372036854775808e18").getAsLong()) 397 .isEqualTo(-9223372036854775808L); 398 } 399 400 @Theory floatNumbersGetAsInt_getsTruncated()401 public void floatNumbersGetAsInt_getsTruncated() throws Exception { 402 assertThat(JsonParser.parse("42.0").getAsInt()).isEqualTo(42); 403 assertThat(JsonParser.parse("2.1e1").getAsInt()).isEqualTo(21); 404 405 assertThat(JsonParser.parse("42.1").getAsInt()).isEqualTo(42); 406 assertThat(JsonParser.parse("42.9999").getAsInt()).isEqualTo(42); 407 408 // 2^31 - 1 as float 409 assertThat(JsonParser.parse("2.147483647e9").getAsInt()).isEqualTo(2147483647); 410 411 // - 2^31 as float 412 assertThat(JsonParser.parse("-2.147483648e9").getAsInt()).isEqualTo(-2147483648); 413 } 414 415 @Theory testNumbersToDouble()416 public void testNumbersToDouble() throws Exception { 417 assertThat(JsonParser.parse("60911552482230981.0").getAsDouble()) 418 .isEqualTo(6.0911552482230984e16); 419 assertThat(JsonParser.parse("4e+42").getAsDouble()).isEqualTo(4e42); 420 assertThat(JsonParser.parse("4e42").getAsDouble()).isEqualTo(4e42); 421 assertThat(JsonParser.parse("4E42").getAsDouble()).isEqualTo(4e42); 422 assertThat(JsonParser.parse("-4e-42").getAsDouble()).isEqualTo(-4e-42); 423 assertThat( 424 JsonParser.parse( 425 "9999999999999999999999999999999999999999999999999999999999999999999999999999" 426 + "99999999999") 427 .getAsDouble()) 428 .isEqualTo(1.0e87); 429 assertThat( 430 JsonParser.parse( 431 "-999999999999999999999999999999999999999999999999999999999999999999999999999" 432 + "999999999999") 433 .getAsDouble()) 434 .isEqualTo(-1.0e87); 435 assertThat( 436 JsonParser.parse("99999999999999999999999999.99e+99999999999999999999999999") 437 .getAsDouble()) 438 .isPositiveInfinity(); 439 assertThat( 440 JsonParser.parse("-99999999999999999999999999.99e+99999999999999999999999999") 441 .getAsDouble()) 442 .isNegativeInfinity(); 443 assertThat( 444 JsonParser.parse("99999999999999999999999999.99e-99999999999999999999999999") 445 .getAsDouble()) 446 .isEqualTo(0.0); 447 assertThat(JsonParser.parse("0.000000000000000000000000000000001").getAsDouble()) 448 .isEqualTo(0.000000000000000000000000000000001); 449 assertThat(JsonParser.parse("-0.000000000000000000000000000000001").getAsDouble()) 450 .isEqualTo(-0.000000000000000000000000000000001); 451 assertThat(JsonParser.parse("42").getAsInt()).isEqualTo(42); 452 assertThat(JsonParser.parse("42\n").getAsInt()).isEqualTo(42); 453 assertThat(JsonParser.parse("42\f").getAsInt()).isEqualTo(42); 454 } 455 456 @DataPoints("testCasesFail") 457 public static final TestCase[] TEST_CASES_FAIL = { 458 new TestCase("nested_empty_maps", "{{}}"), 459 new TestCase("open_map", "{\"\":{\"\":{\"\":{\"\":{\"\":{\"\":{\"\":"), 460 new TestCase("open_array_map", "[{\"\":[{\"\":[{\"\":[{\"\":[{\"\":[{\"\":[{\"\":["), 461 new TestCase("open_array", "["), 462 new TestCase("open_array_1", "[1"), 463 new TestCase("open_array_2", "[1,"), 464 new TestCase("open_arrays", "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["), 465 new TestCase("open_array_with_huge_negative_int", "[-2374623746732768942798327498324234"), 466 new TestCase("map_missing_value", "{\"a\":"), 467 new TestCase("string_not_closed", "\"a"), 468 new TestCase("empty_string_not_closed", "\""), 469 new TestCase("string_with_backslash_not_closed", "\"\\"), 470 new TestCase("number_dot", "42."), 471 new TestCase("-number_dot", "-42."), 472 new TestCase("number_dot_with_e1", "42.e1"), 473 new TestCase("number_dot_with_+e1", "42.e+1"), 474 new TestCase("number_dot_with_-e1", "42.e-1"), 475 new TestCase("number_with_e", "42e"), 476 new TestCase("number_with_e+", "42e+"), 477 new TestCase("number_with_E", "42E"), 478 new TestCase("number_with_E+", "42E+"), 479 new TestCase("float_with_e", "42.42e"), 480 new TestCase("float_with_e+", "42.42e+"), 481 new TestCase("float_with_E", "42.42E"), 482 new TestCase("float_with_E+", "42.42E+"), 483 new TestCase("+number", "+42"), 484 new TestCase("++number", "++42"), 485 new TestCase("Inf", "Inf"), 486 new TestCase("+Inf", "+Inf"), 487 new TestCase("-Inf", "-Inf"), 488 new TestCase("Infinity", "Infinity"), 489 new TestCase("+Infinity", "+Infinity"), 490 new TestCase("-Infinity", "-Infinity"), 491 new TestCase("NaN", "NaN"), 492 new TestCase("+NaN", "+NaN"), 493 new TestCase("-NaN", "-NaN"), 494 new TestCase("number_dot_minus_number", "42.-42"), 495 new TestCase("dot_minus_number", ".-42"), 496 new TestCase("dot_number", ".42"), 497 new TestCase("minus_dot_number", "-.42"), 498 new TestCase("number_with_leading_zero", "042"), 499 new TestCase("-number_with_leading_zero", "-042"), 500 new TestCase("number_two_dots", "42.43.44"), 501 new TestCase("number_two_dots_2", ".42.43"), 502 new TestCase("number_two_dots_3", "42.43."), 503 new TestCase("number_ee", "42ee42"), 504 new TestCase("number_eE", "42eE42"), 505 new TestCase("number_e_plus_minus", "42e+-42"), 506 new TestCase("number_with_trailing_garbage", "2@"), 507 new TestCase("number_with_tailing_comment", "42/*comment*/"), 508 new TestCase("number_garbage_after_e", "1ea"), 509 new TestCase("number_with_a", "1.2a-3"), 510 new TestCase("number_with_h", "1.8011670033376514H-308"), 511 new TestCase("hex1", "0x1"), 512 new TestCase("hex2", "0x42"), 513 new TestCase("number_with_tailing_a", "42a"), 514 new TestCase("float_with_tailing_a", "42.42a"), 515 new TestCase("minus_number_with_tailing_a", "-42a"), 516 new TestCase("number_tailing_excaped_newline", "42\\n"), 517 new TestCase("minus_a", "-a"), 518 new TestCase("minus", "-"), 519 new TestCase("addition", "1+2"), 520 new TestCase("subtraction", "2-1"), 521 new TestCase("multiplication", "2*1"), 522 new TestCase("array_with_number_with_space", "[1 000]"), 523 new TestCase("array_with_float_with_space", "[1 000.0]"), 524 new TestCase("array_with_minus_space_number", "[- 42]"), 525 new TestCase("key_without_quotes", "{a:0}"), 526 new TestCase("key_single_quote", "{'a':0}"), 527 new TestCase("array_element_without_quotes", "[a,0]"), 528 new TestCase("array_element_single_quotes", "['a',0]"), 529 new TestCase("map_with_trailing_comma", "{\"a\":0,}"), 530 new TestCase("map_with_two_commas", "{\"a\":0,,\"b\":1}"), 531 new TestCase("array_with_trailing_comma", "[\"a\",]"), 532 new TestCase("map_with_comment", "{\"a\":/*comment*/\"b\"}"), 533 new TestCase("map_with_null_key", "{null:0}"), 534 new TestCase("map_with_number_key", "{1:1}"), 535 new TestCase("map_with_huge_float_key", "{9999E9999:1}"), 536 new TestCase("map_missing_colon", "{\"a\" \"b\"}"), 537 new TestCase("map_missing_key", "{:\"b\"}"), 538 new TestCase("map_with_comma", "{\"a\", \"b\"}"), 539 new TestCase("map_double_colon", "{\"x\"::\"b\"}"), 540 new TestCase("map_with_garbage", "{\"a\":\"b\" c}"), 541 new TestCase("map_with_single_string", "{ \"a\" : \"b\", \"c\" }"), 542 new TestCase("array_leading_comma", "[,1]"), 543 new TestCase("array_double_comma", "[1,,2]"), 544 new TestCase("array_double_tailing_comma", "[1,,]"), 545 new TestCase("array_comma", "[,]"), 546 new TestCase("nested_arrays_no_comma", "[3[4]]"), 547 new TestCase("array_without_comma", "[1 2]"), 548 new TestCase("array__with_colon", "[\"a\": 1]"), 549 new TestCase("incomplete_false", "fals"), 550 new TestCase("incomplete_null", "nul"), 551 new TestCase("incomplete_true", "tru"), 552 new TestCase("unquoted_string", "a"), 553 new TestCase("star", "*"), 554 new TestCase("angle_bracket_dot", "<.>"), 555 new TestCase("string_escape_x", "\"\\x00\""), 556 new TestCase("escaped_emoji", "\"\\\""), 557 new TestCase("invalid_backslash_escape", "\"\\a\""), 558 new TestCase("unicode_with_capital_u", "\"\\UA66D\""), 559 new TestCase("invalid_unicode_escape", "\"\\uqqqq\""), 560 new TestCase("incomplete_surrogate", "\"\\uD834\\uDd\""), 561 new TestCase("1_surrogate_then_escape_u", "[\"\\uD800\\u\"]"), 562 new TestCase("2_incomplete_surrogate_escape_invalid", "[\"\\uD800\\uD800\\x\"]"), 563 new TestCase("array_with_formfeed", "[\f]"), 564 new TestCase("array_with_tailing_formfeed", "[\"a\"\f]"), 565 new TestCase("array_with_leading_uescaped_thinspace", "[\\u0020\"a\"]"), 566 new TestCase("array_with_escaped_new_line", "[\\n]"), 567 new TestCase("array_with_escaped_tab", "[\\t]"), 568 569 new TestCase("duplicated_key", "{\"a\":\"b\",\"a\":\"c\"}"), 570 new TestCase("duplicated_key_and_value", "{\"a\":\"b\",\"a\":\"b\"}"), 571 new TestCase("empty", ""), 572 new TestCase("single_space", " "), 573 new TestCase("nested_with_duplicated_key", "{\"x\":{\"a\":\"b\",\"a\":\"c\"}}"), 574 new TestCase("split_array", "{ \"a\" : [1,2,3], \"b\" : 0, \"a\" : [4,5,6]}"), 575 576 // invalid characters in strings 577 new TestCase("invalid_utf16", "\"\\uD834\"", null), 578 new TestCase("invalid_utf16_in_key", "{\"\\ud800\\ud800key\":\"value\"}", null), 579 new TestCase( 580 "invalid_utf16_in_key_2", "{\"key\":\"value1\",\"\\ud800\\ud800key\":\"value2\"}", null), 581 new TestCase("invalid_utf16_in_value", "{\"key\":\"value\\ud800\\ud800\"}", null), 582 new TestCase("invalid_surrogate_1", "\"\\uDADA\"", null), 583 new TestCase("invalid_surrogate_2", "\"\\ud800\"", null), 584 new TestCase("invalid_surrogate_3", "\"\\uDd1ea\"", null), 585 new TestCase("invalid_surrogate_4", "\"\\uDFAA\"", null), 586 new TestCase("invalid_surrogate_5", "\"\\uD888\\u1234\"", null), 587 new TestCase("invalid_surrogate_6", "\"\\uD800\\uD800\\n\"", null), 588 new TestCase("invalid_surrogate_7", "\"\\uDd1e\\uD834\"", null), 589 new TestCase("invalid_surrogate_in_map_key", "{\"\\uDFAA\":0}", null), 590 new TestCase("invalid_surrogate_in_map_value", "{\"a\": \"\\uDFAA\"}", null), 591 }; 592 593 @Test tooManyRecursions_fail()594 public void tooManyRecursions_fail() throws Exception { 595 int recursionNum = 150; 596 StringBuilder sb = new StringBuilder(); 597 for (int i = 0; i < recursionNum; i++) { 598 sb.append("{\"a\":"); 599 } 600 sb.append("1"); 601 for (int i = 0; i < recursionNum; i++) { 602 sb.append("}"); 603 } 604 assertThrows(IOException.class, () -> JsonParser.parse(sb.toString())); 605 } 606 607 @Theory parse_fail( @romDataPoints"testCasesFail") TestCase testCase)608 public void parse_fail( 609 @FromDataPoints("testCasesFail") TestCase testCase) throws Exception { 610 assertThrows(IOException.class, () -> JsonParser.parse(testCase.input)); 611 } 612 613 } 614