1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31#include <google/protobuf/util/internal/json_stream_parser.h> 32 33#include <google/protobuf/stubs/logging.h> 34#include <google/protobuf/stubs/common.h> 35#include <google/protobuf/stubs/time.h> 36#include <google/protobuf/util/internal/expecting_objectwriter.h> 37#include <google/protobuf/util/internal/object_writer.h> 38#include <google/protobuf/stubs/strutil.h> 39#include <gtest/gtest.h> 40#include <google/protobuf/stubs/status.h> 41 42 43namespace google { 44namespace protobuf { 45namespace util { 46using util::Status; 47namespace error { 48using util::error::INVALID_ARGUMENT; 49} // namespace error 50namespace converter { 51 52using util::Status; 53 54// Tests for the JSON Stream Parser. These tests are intended to be 55// comprehensive and cover the following: 56// 57// Positive tests: 58// - true, false, null 59// - empty object or array. 60// - negative and positive double and int, unsigned int 61// - single and double quoted strings 62// - string key, unquoted key, numeric key 63// - array containing array, object, value 64// - object containing array, object, value 65// - unicode handling in strings 66// - ascii escaping (\b, \f, \n, \r, \t, \v) 67// - trailing commas 68// 69// Negative tests: 70// - illegal literals 71// - mismatched quotes failure on strings 72// - unterminated string failure 73// - unexpected end of string failure 74// - mismatched object and array closing 75// - Failure to close array or object 76// - numbers too large 77// - invalid unicode escapes. 78// - invalid unicode sequences. 79// - numbers as keys 80// 81// For each test we split the input string on every possible character to ensure 82// the parser is able to handle arbitrarily split input for all cases. We also 83// do a final test of the entire test case one character at a time. 84class JsonStreamParserTest : public ::testing::Test { 85 protected: 86 JsonStreamParserTest() : mock_(), ow_(&mock_) {} 87 virtual ~JsonStreamParserTest() {} 88 89 util::Status RunTest(StringPiece json, int split, bool coerce_utf8 = false) { 90 JsonStreamParser parser(&mock_); 91 92 // Special case for split == length, test parsing one character at a time. 93 if (split == json.length()) { 94 GOOGLE_LOG(INFO) << "Testing split every char: " << json; 95 for (int i = 0; i < json.length(); ++i) { 96 StringPiece single = json.substr(i, 1); 97 util::Status result = parser.Parse(single); 98 if (!result.ok()) { 99 return result; 100 } 101 } 102 return parser.FinishParse(); 103 } 104 105 // Normal case, split at the split point and parse two substrings. 106 StringPiece first = json.substr(0, split); 107 StringPiece rest = json.substr(split); 108 GOOGLE_LOG(INFO) << "Testing split: " << first << "><" << rest; 109 util::Status result = parser.Parse(first); 110 if (result.ok()) { 111 result = parser.Parse(rest); 112 if (result.ok()) { 113 result = parser.FinishParse(); 114 } 115 } 116 return result; 117 } 118 119 void DoTest(StringPiece json, int split, bool coerce_utf8 = false) { 120 util::Status result = RunTest(json, split, coerce_utf8); 121 if (!result.ok()) { 122 GOOGLE_LOG(WARNING) << result; 123 } 124 EXPECT_OK(result); 125 } 126 127 void DoErrorTest(StringPiece json, int split, StringPiece error_prefix, 128 bool coerce_utf8 = false) { 129 util::Status result = RunTest(json, split, coerce_utf8); 130 EXPECT_EQ(util::error::INVALID_ARGUMENT, result.error_code()); 131 StringPiece error_message(result.error_message()); 132 EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size())); 133 } 134 135 136 MockObjectWriter mock_; 137 ExpectingObjectWriter ow_; 138}; 139 140 141// Positive tests 142 143// - true, false, null 144TEST_F(JsonStreamParserTest, SimpleTrue) { 145 StringPiece str = "true"; 146 for (int i = 0; i <= str.length(); ++i) { 147 ow_.RenderBool("", true); 148 DoTest(str, i); 149 } 150} 151 152TEST_F(JsonStreamParserTest, SimpleFalse) { 153 StringPiece str = "false"; 154 for (int i = 0; i <= str.length(); ++i) { 155 ow_.RenderBool("", false); 156 DoTest(str, i); 157 } 158} 159 160TEST_F(JsonStreamParserTest, SimpleNull) { 161 StringPiece str = "null"; 162 for (int i = 0; i <= str.length(); ++i) { 163 ow_.RenderNull(""); 164 DoTest(str, i); 165 } 166} 167 168// - empty object and array. 169TEST_F(JsonStreamParserTest, EmptyObject) { 170 StringPiece str = "{}"; 171 for (int i = 0; i <= str.length(); ++i) { 172 ow_.StartObject("")->EndObject(); 173 DoTest(str, i); 174 } 175} 176 177TEST_F(JsonStreamParserTest, EmptyList) { 178 StringPiece str = "[]"; 179 for (int i = 0; i <= str.length(); ++i) { 180 ow_.StartList("")->EndList(); 181 DoTest(str, i); 182 } 183} 184 185// - negative and positive double and int, unsigned int 186TEST_F(JsonStreamParserTest, SimpleDouble) { 187 StringPiece str = "42.5"; 188 for (int i = 0; i <= str.length(); ++i) { 189 ow_.RenderDouble("", 42.5); 190 DoTest(str, i); 191 } 192} 193 194TEST_F(JsonStreamParserTest, ScientificDouble) { 195 StringPiece str = "1.2345e-10"; 196 for (int i = 0; i < str.length(); ++i) { 197 ow_.RenderDouble("", 1.2345e-10); 198 DoTest(str, i); 199 } 200} 201 202TEST_F(JsonStreamParserTest, SimpleNegativeDouble) { 203 StringPiece str = "-1045.235"; 204 for (int i = 0; i <= str.length(); ++i) { 205 ow_.RenderDouble("", -1045.235); 206 DoTest(str, i); 207 } 208} 209 210TEST_F(JsonStreamParserTest, SimpleInt) { 211 StringPiece str = "123456"; 212 for (int i = 0; i <= str.length(); ++i) { 213 ow_.RenderUint64("", 123456); 214 DoTest(str, i); 215 } 216} 217 218TEST_F(JsonStreamParserTest, SimpleNegativeInt) { 219 StringPiece str = "-79497823553162765"; 220 for (int i = 0; i <= str.length(); ++i) { 221 ow_.RenderInt64("", -79497823553162765LL); 222 DoTest(str, i); 223 } 224} 225 226TEST_F(JsonStreamParserTest, SimpleUnsignedInt) { 227 StringPiece str = "11779497823553162765"; 228 for (int i = 0; i <= str.length(); ++i) { 229 ow_.RenderUint64("", 11779497823553162765ULL); 230 DoTest(str, i); 231 } 232} 233 234TEST_F(JsonStreamParserTest, OctalNumberIsInvalid) { 235 StringPiece str = "01234"; 236 for (int i = 0; i <= str.length(); ++i) { 237 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); 238 } 239 str = "-01234"; 240 for (int i = 0; i <= str.length(); ++i) { 241 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); 242 } 243} 244 245TEST_F(JsonStreamParserTest, HexNumberIsInvalid) { 246 StringPiece str = "0x1234"; 247 for (int i = 0; i <= str.length(); ++i) { 248 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); 249 } 250 str = "-0x1234"; 251 for (int i = 0; i <= str.length(); ++i) { 252 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); 253 } 254 str = "12x34"; 255 for (int i = 0; i <= str.length(); ++i) { 256 DoErrorTest(str, i, "Unable to parse number."); 257 } 258} 259 260// - single and double quoted strings 261TEST_F(JsonStreamParserTest, EmptyDoubleQuotedString) { 262 StringPiece str = "\"\""; 263 for (int i = 0; i <= str.length(); ++i) { 264 ow_.RenderString("", ""); 265 DoTest(str, i); 266 } 267} 268 269TEST_F(JsonStreamParserTest, EmptySingleQuotedString) { 270 StringPiece str = "''"; 271 for (int i = 0; i <= str.length(); ++i) { 272 ow_.RenderString("", ""); 273 DoTest(str, i); 274 } 275} 276 277TEST_F(JsonStreamParserTest, SimpleDoubleQuotedString) { 278 StringPiece str = "\"Some String\""; 279 for (int i = 0; i <= str.length(); ++i) { 280 ow_.RenderString("", "Some String"); 281 DoTest(str, i); 282 } 283} 284 285TEST_F(JsonStreamParserTest, SimpleSingleQuotedString) { 286 StringPiece str = "'Another String'"; 287 for (int i = 0; i <= str.length(); ++i) { 288 ow_.RenderString("", "Another String"); 289 DoTest(str, i); 290 } 291} 292 293// - string key, unquoted key, numeric key 294TEST_F(JsonStreamParserTest, ObjectKeyTypes) { 295 StringPiece str = 296 "{'s': true, \"d\": false, key: null, snake_key: [], camelKey: {}}"; 297 for (int i = 0; i <= str.length(); ++i) { 298 ow_.StartObject("") 299 ->RenderBool("s", true) 300 ->RenderBool("d", false) 301 ->RenderNull("key") 302 ->StartList("snake_key") 303 ->EndList() 304 ->StartObject("camelKey") 305 ->EndObject() 306 ->EndObject(); 307 DoTest(str, i); 308 } 309} 310 311// - array containing array, object, values (true, false, null, num, string) 312TEST_F(JsonStreamParserTest, ArrayValues) { 313 StringPiece str = 314 "[true, false, null, 'a string', \"another string\", [22, -127, 45.3, " 315 "-1056.4, 11779497823553162765], {'key': true}]"; 316 for (int i = 0; i <= str.length(); ++i) { 317 ow_.StartList("") 318 ->RenderBool("", true) 319 ->RenderBool("", false) 320 ->RenderNull("") 321 ->RenderString("", "a string") 322 ->RenderString("", "another string") 323 ->StartList("") 324 ->RenderUint64("", 22) 325 ->RenderInt64("", -127) 326 ->RenderDouble("", 45.3) 327 ->RenderDouble("", -1056.4) 328 ->RenderUint64("", 11779497823553162765ULL) 329 ->EndList() 330 ->StartObject("") 331 ->RenderBool("key", true) 332 ->EndObject() 333 ->EndList(); 334 DoTest(str, i); 335 } 336} 337 338// - object containing array, object, value (true, false, null, num, string) 339TEST_F(JsonStreamParserTest, ObjectValues) { 340 StringPiece str = 341 "{t: true, f: false, n: null, s: 'a string', d: \"another string\", pi: " 342 "22, ni: -127, pd: 45.3, nd: -1056.4, pl: 11779497823553162765, l: [[]], " 343 "o: {'key': true}}"; 344 for (int i = 0; i <= str.length(); ++i) { 345 ow_.StartObject("") 346 ->RenderBool("t", true) 347 ->RenderBool("f", false) 348 ->RenderNull("n") 349 ->RenderString("s", "a string") 350 ->RenderString("d", "another string") 351 ->RenderUint64("pi", 22) 352 ->RenderInt64("ni", -127) 353 ->RenderDouble("pd", 45.3) 354 ->RenderDouble("nd", -1056.4) 355 ->RenderUint64("pl", 11779497823553162765ULL) 356 ->StartList("l") 357 ->StartList("") 358 ->EndList() 359 ->EndList() 360 ->StartObject("o") 361 ->RenderBool("key", true) 362 ->EndObject() 363 ->EndObject(); 364 DoTest(str, i); 365 } 366} 367 368 369TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) { 370 StringPiece json = "{\"address\":\xFF\"חרושת 23, רעננה, ישראל\"}"; 371 for (int i = 0; i <= json.length(); ++i) { 372 DoErrorTest(json, i, "Encountered non UTF-8 code points."); 373 } 374 json = "{\"address\": \"חרושת 23,\xFFרעננה, ישראל\"}"; 375 for (int i = 0; i <= json.length(); ++i) { 376 DoErrorTest(json, i, "Encountered non UTF-8 code points."); 377 } 378 DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points."); 379} 380 381// - unicode handling in strings 382TEST_F(JsonStreamParserTest, UnicodeEscaping) { 383 StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]"; 384 for (int i = 0; i <= str.length(); ++i) { 385 ow_.StartList("") 386 ->RenderString("", "\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x89") 387 ->EndList(); 388 DoTest(str, i); 389 } 390} 391 392// - unicode UTF-16 surrogate pair handling in strings 393TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) { 394 StringPiece str = 395 "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\\uD83C\\uDF6F\"]"; 396 for (int i = 0; i <= str.length(); ++i) { 397 ow_.StartList("") 398 ->RenderString("", 399 "\xE0\xAF\xAE\xF0\x90\x87\xB1\xF0\x93\x86\xA4\xF0" 400 "\x9F\x90\x9D\xF0\x9F\x8D\xAF") 401 ->EndList(); 402 DoTest(str, i); 403 } 404} 405 406 407TEST_F(JsonStreamParserTest, UnicodeEscapingInvalidCodePointWhenNotCoerced) { 408 // A low surrogate alone. 409 StringPiece str = "[\"\\ude36\"]"; 410 for (int i = 0; i <= str.length(); ++i) { 411 DoErrorTest(str, i, "Invalid unicode code point."); 412 } 413} 414 415TEST_F(JsonStreamParserTest, UnicodeEscapingMissingLowSurrogateWhenNotCoerced) { 416 // A high surrogate alone. 417 StringPiece str = "[\"\\ud83d\"]"; 418 for (int i = 0; i <= str.length(); ++i) { 419 DoErrorTest(str, i, "Missing low surrogate."); 420 } 421 // A high surrogate with some trailing characters. 422 str = "[\"\\ud83d|ude36\"]"; 423 for (int i = 0; i <= str.length(); ++i) { 424 DoErrorTest(str, i, "Missing low surrogate."); 425 } 426 // A high surrogate with half a low surrogate. 427 str = "[\"\\ud83d\\ude--\"]"; 428 for (int i = 0; i <= str.length(); ++i) { 429 DoErrorTest(str, i, "Invalid escape sequence."); 430 } 431 // Two high surrogates. 432 str = "[\"\\ud83d\\ud83d\"]"; 433 for (int i = 0; i <= str.length(); ++i) { 434 DoErrorTest(str, i, "Invalid low surrogate."); 435 } 436} 437 438// - ascii escaping (\b, \f, \n, \r, \t, \v) 439TEST_F(JsonStreamParserTest, AsciiEscaping) { 440 StringPiece str = 441 "[\"\\b\", \"\\ning\", \"test\\f\", \"\\r\\t\", \"test\\\\\\ving\"]"; 442 for (int i = 0; i <= str.length(); ++i) { 443 ow_.StartList("") 444 ->RenderString("", "\b") 445 ->RenderString("", "\ning") 446 ->RenderString("", "test\f") 447 ->RenderString("", "\r\t") 448 ->RenderString("", "test\\\ving") 449 ->EndList(); 450 DoTest(str, i); 451 } 452} 453 454// - trailing commas, we support a single trailing comma but no internal commas. 455TEST_F(JsonStreamParserTest, TrailingCommas) { 456 StringPiece str = "[['a',true,], {b: null,},]"; 457 for (int i = 0; i <= str.length(); ++i) { 458 ow_.StartList("") 459 ->StartList("") 460 ->RenderString("", "a") 461 ->RenderBool("", true) 462 ->EndList() 463 ->StartObject("") 464 ->RenderNull("b") 465 ->EndObject() 466 ->EndList(); 467 DoTest(str, i); 468 } 469} 470 471// Negative tests 472 473// illegal literals 474TEST_F(JsonStreamParserTest, ExtraTextAfterTrue) { 475 StringPiece str = "truee"; 476 for (int i = 0; i <= str.length(); ++i) { 477 ow_.RenderBool("", true); 478 DoErrorTest(str, i, "Parsing terminated before end of input."); 479 } 480} 481 482TEST_F(JsonStreamParserTest, InvalidNumberDashOnly) { 483 StringPiece str = "-"; 484 for (int i = 0; i <= str.length(); ++i) { 485 DoErrorTest(str, i, "Unable to parse number."); 486 } 487} 488 489TEST_F(JsonStreamParserTest, InvalidNumberDashName) { 490 StringPiece str = "-foo"; 491 for (int i = 0; i <= str.length(); ++i) { 492 DoErrorTest(str, i, "Unable to parse number."); 493 } 494} 495 496TEST_F(JsonStreamParserTest, InvalidLiteralInArray) { 497 StringPiece str = "[nule]"; 498 for (int i = 0; i <= str.length(); ++i) { 499 ow_.StartList(""); 500 DoErrorTest(str, i, "Unexpected token."); 501 } 502} 503 504TEST_F(JsonStreamParserTest, InvalidLiteralInObject) { 505 StringPiece str = "{123false}"; 506 for (int i = 0; i <= str.length(); ++i) { 507 ow_.StartObject(""); 508 DoErrorTest(str, i, "Expected an object key or }."); 509 } 510} 511 512// mismatched quotes failure on strings 513TEST_F(JsonStreamParserTest, MismatchedSingleQuotedLiteral) { 514 StringPiece str = "'Some str\""; 515 for (int i = 0; i <= str.length(); ++i) { 516 DoErrorTest(str, i, "Closing quote expected in string."); 517 } 518} 519 520TEST_F(JsonStreamParserTest, MismatchedDoubleQuotedLiteral) { 521 StringPiece str = "\"Another string that ends poorly!'"; 522 for (int i = 0; i <= str.length(); ++i) { 523 DoErrorTest(str, i, "Closing quote expected in string."); 524 } 525} 526 527// unterminated strings 528TEST_F(JsonStreamParserTest, UnterminatedLiteralString) { 529 StringPiece str = "\"Forgot the rest of i"; 530 for (int i = 0; i <= str.length(); ++i) { 531 DoErrorTest(str, i, "Closing quote expected in string."); 532 } 533} 534 535TEST_F(JsonStreamParserTest, UnterminatedStringEscape) { 536 StringPiece str = "\"Forgot the rest of \\"; 537 for (int i = 0; i <= str.length(); ++i) { 538 DoErrorTest(str, i, "Closing quote expected in string."); 539 } 540} 541 542TEST_F(JsonStreamParserTest, UnterminatedStringInArray) { 543 StringPiece str = "[\"Forgot to close the string]"; 544 for (int i = 0; i <= str.length(); ++i) { 545 ow_.StartList(""); 546 DoErrorTest(str, i, "Closing quote expected in string."); 547 } 548} 549 550TEST_F(JsonStreamParserTest, UnterminatedStringInObject) { 551 StringPiece str = "{f: \"Forgot to close the string}"; 552 for (int i = 0; i <= str.length(); ++i) { 553 ow_.StartObject(""); 554 DoErrorTest(str, i, "Closing quote expected in string."); 555 } 556} 557 558TEST_F(JsonStreamParserTest, UnterminatedObject) { 559 StringPiece str = "{"; 560 for (int i = 0; i <= str.length(); ++i) { 561 ow_.StartObject(""); 562 DoErrorTest(str, i, "Unexpected end of string."); 563 } 564} 565 566 567// mismatched object and array closing 568TEST_F(JsonStreamParserTest, MismatchedCloseObject) { 569 StringPiece str = "{'key': true]"; 570 for (int i = 0; i <= str.length(); ++i) { 571 ow_.StartObject("")->RenderBool("key", true); 572 DoErrorTest(str, i, "Expected , or } after key:value pair."); 573 } 574} 575 576TEST_F(JsonStreamParserTest, MismatchedCloseArray) { 577 StringPiece str = "[true, null}"; 578 for (int i = 0; i <= str.length(); ++i) { 579 ow_.StartList("")->RenderBool("", true)->RenderNull(""); 580 DoErrorTest(str, i, "Expected , or ] after array value."); 581 } 582} 583 584// Invalid object keys. 585TEST_F(JsonStreamParserTest, InvalidNumericObjectKey) { 586 StringPiece str = "{42: true}"; 587 for (int i = 0; i <= str.length(); ++i) { 588 ow_.StartObject(""); 589 DoErrorTest(str, i, "Expected an object key or }."); 590 } 591} 592 593TEST_F(JsonStreamParserTest, InvalidLiteralObjectInObject) { 594 StringPiece str = "{{bob: true}}"; 595 for (int i = 0; i <= str.length(); ++i) { 596 ow_.StartObject(""); 597 DoErrorTest(str, i, "Expected an object key or }."); 598 } 599} 600 601TEST_F(JsonStreamParserTest, InvalidLiteralArrayInObject) { 602 StringPiece str = "{[null]}"; 603 for (int i = 0; i <= str.length(); ++i) { 604 ow_.StartObject(""); 605 DoErrorTest(str, i, "Expected an object key or }."); 606 } 607} 608 609TEST_F(JsonStreamParserTest, InvalidLiteralValueInObject) { 610 StringPiece str = "{false}"; 611 for (int i = 0; i <= str.length(); ++i) { 612 ow_.StartObject(""); 613 DoErrorTest(str, i, "Expected an object key or }."); 614 } 615} 616 617TEST_F(JsonStreamParserTest, MissingColonAfterStringInObject) { 618 StringPiece str = "{\"key\"}"; 619 for (int i = 0; i <= str.length(); ++i) { 620 ow_.StartObject(""); 621 DoErrorTest(str, i, "Expected : between key:value pair."); 622 } 623} 624 625TEST_F(JsonStreamParserTest, MissingColonAfterKeyInObject) { 626 StringPiece str = "{key}"; 627 for (int i = 0; i <= str.length(); ++i) { 628 ow_.StartObject(""); 629 DoErrorTest(str, i, "Expected : between key:value pair."); 630 } 631} 632 633TEST_F(JsonStreamParserTest, EndOfTextAfterKeyInObject) { 634 StringPiece str = "{key"; 635 for (int i = 0; i <= str.length(); ++i) { 636 ow_.StartObject(""); 637 DoErrorTest(str, i, "Unexpected end of string."); 638 } 639} 640 641TEST_F(JsonStreamParserTest, MissingValueAfterColonInObject) { 642 StringPiece str = "{key:}"; 643 for (int i = 0; i <= str.length(); ++i) { 644 ow_.StartObject(""); 645 DoErrorTest(str, i, "Unexpected token."); 646 } 647} 648 649TEST_F(JsonStreamParserTest, MissingCommaBetweenObjectEntries) { 650 StringPiece str = "{key:20 'hello': true}"; 651 for (int i = 0; i <= str.length(); ++i) { 652 ow_.StartObject("")->RenderUint64("key", 20); 653 DoErrorTest(str, i, "Expected , or } after key:value pair."); 654 } 655} 656 657TEST_F(JsonStreamParserTest, InvalidLiteralAsObjectKey) { 658 StringPiece str = "{false: 20}"; 659 for (int i = 0; i <= str.length(); ++i) { 660 ow_.StartObject(""); 661 DoErrorTest(str, i, "Expected an object key or }."); 662 } 663} 664 665TEST_F(JsonStreamParserTest, ExtraCharactersAfterObject) { 666 StringPiece str = "{}}"; 667 for (int i = 0; i <= str.length(); ++i) { 668 ow_.StartObject("")->EndObject(); 669 DoErrorTest(str, i, "Parsing terminated before end of input."); 670 } 671} 672 673// numbers too large 674TEST_F(JsonStreamParserTest, PositiveNumberTooBig) { 675 StringPiece str = "[18446744073709551616]"; // 2^64 676 for (int i = 0; i <= str.length(); ++i) { 677 ow_.StartList(""); 678 DoErrorTest(str, i, "Unable to parse number."); 679 } 680} 681 682TEST_F(JsonStreamParserTest, NegativeNumberTooBig) { 683 StringPiece str = "[-18446744073709551616]"; 684 for (int i = 0; i <= str.length(); ++i) { 685 ow_.StartList(""); 686 DoErrorTest(str, i, "Unable to parse number."); 687 } 688} 689 690/* 691TODO(sven): Fail parsing when parsing a double that is too large. 692 693TEST_F(JsonStreamParserTest, DoubleTooBig) { 694 StringPiece str = "[184464073709551232321616.45]"; 695 for (int i = 0; i <= str.length(); ++i) { 696 ow_.StartList(""); 697 DoErrorTest(str, i, "Unable to parse number"); 698 } 699} 700*/ 701 702// invalid bare backslash. 703TEST_F(JsonStreamParserTest, UnfinishedEscape) { 704 StringPiece str = "\"\\"; 705 for (int i = 0; i <= str.length(); ++i) { 706 DoErrorTest(str, i, "Closing quote expected in string."); 707 } 708} 709 710// invalid bare backslash u. 711TEST_F(JsonStreamParserTest, UnfinishedUnicodeEscape) { 712 StringPiece str = "\"\\u"; 713 for (int i = 0; i <= str.length(); ++i) { 714 DoErrorTest(str, i, "Illegal hex string."); 715 } 716} 717 718// invalid unicode sequence. 719TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) { 720 StringPiece str = "\"\\u12"; 721 for (int i = 0; i <= str.length(); ++i) { 722 DoErrorTest(str, i, "Illegal hex string."); 723 } 724} 725 726// invalid unicode sequence (valid in modern EcmaScript but not in JSON). 727TEST_F(JsonStreamParserTest, BracketedUnicodeEscape) { 728 StringPiece str = "\"\\u{1f36f}\""; 729 for (int i = 0; i <= str.length(); ++i) { 730 DoErrorTest(str, i, "Invalid escape sequence."); 731 } 732} 733 734 735TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) { 736 StringPiece str = "\"\\u12$4hello"; 737 for (int i = 0; i <= str.length(); ++i) { 738 DoErrorTest(str, i, "Invalid escape sequence."); 739 } 740} 741 742// invalid unicode sequence in low half surrogate: g is not a hex digit. 743TEST_F(JsonStreamParserTest, UnicodeEscapeLowHalfSurrogateInvalidCharacters) { 744 StringPiece str = "\"\\ud800\\udcfg\""; 745 for (int i = 0; i <= str.length(); ++i) { 746 DoErrorTest(str, i, "Invalid escape sequence."); 747 } 748} 749 750// Extra commas with an object or array. 751TEST_F(JsonStreamParserTest, ExtraCommaInObject) { 752 StringPiece str = "{'k1': true,,'k2': false}"; 753 for (int i = 0; i <= str.length(); ++i) { 754 ow_.StartObject("")->RenderBool("k1", true); 755 DoErrorTest(str, i, "Expected an object key or }."); 756 } 757} 758 759TEST_F(JsonStreamParserTest, ExtraCommaInArray) { 760 StringPiece str = "[true,,false}"; 761 for (int i = 0; i <= str.length(); ++i) { 762 ow_.StartList("")->RenderBool("", true); 763 DoErrorTest(str, i, "Unexpected token."); 764 } 765} 766 767// Extra text beyond end of value. 768TEST_F(JsonStreamParserTest, ExtraTextAfterLiteral) { 769 StringPiece str = "'hello', 'world'"; 770 for (int i = 0; i <= str.length(); ++i) { 771 ow_.RenderString("", "hello"); 772 DoErrorTest(str, i, "Parsing terminated before end of input."); 773 } 774} 775 776TEST_F(JsonStreamParserTest, ExtraTextAfterObject) { 777 StringPiece str = "{'key': true} 'oops'"; 778 for (int i = 0; i <= str.length(); ++i) { 779 ow_.StartObject("")->RenderBool("key", true)->EndObject(); 780 DoErrorTest(str, i, "Parsing terminated before end of input."); 781 } 782} 783 784TEST_F(JsonStreamParserTest, ExtraTextAfterArray) { 785 StringPiece str = "[null] 'oops'"; 786 for (int i = 0; i <= str.length(); ++i) { 787 ow_.StartList("")->RenderNull("")->EndList(); 788 DoErrorTest(str, i, "Parsing terminated before end of input."); 789 } 790} 791 792// Random unknown text in the value. 793TEST_F(JsonStreamParserTest, UnknownCharactersAsValue) { 794 StringPiece str = "*"; 795 for (int i = 0; i <= str.length(); ++i) { 796 DoErrorTest(str, i, "Expected a value."); 797 } 798} 799 800TEST_F(JsonStreamParserTest, UnknownCharactersInArray) { 801 StringPiece str = "[*]"; 802 for (int i = 0; i <= str.length(); ++i) { 803 ow_.StartList(""); 804 DoErrorTest(str, i, "Expected a value or ] within an array."); 805 } 806} 807 808TEST_F(JsonStreamParserTest, UnknownCharactersInObject) { 809 StringPiece str = "{'key': *}"; 810 for (int i = 0; i <= str.length(); ++i) { 811 ow_.StartObject(""); 812 DoErrorTest(str, i, "Expected a value."); 813 } 814} 815 816} // namespace converter 817} // namespace util 818} // namespace protobuf 819} // namespace google 820