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
41 #include <google/protobuf/stubs/status.h>
42
43
44 namespace google {
45 namespace protobuf {
46 namespace util {
47 using util::Status;
48 namespace error {
49 using util::error::INVALID_ARGUMENT;
50 } // namespace error
51 namespace converter {
52
53 using util::Status;
54
55 // Tests for the JSON Stream Parser. These tests are intended to be
56 // comprehensive and cover the following:
57 //
58 // Positive tests:
59 // - true, false, null
60 // - empty object or array.
61 // - negative and positive double and int, unsigned int
62 // - single and double quoted strings
63 // - string key, unquoted key, numeric key
64 // - array containing array, object, value
65 // - object containing array, object, value
66 // - unicode handling in strings
67 // - ascii escaping (\b, \f, \n, \r, \t, \v)
68 // - trailing commas
69 //
70 // Negative tests:
71 // - illegal literals
72 // - mismatched quotes failure on strings
73 // - unterminated string failure
74 // - unexpected end of string failure
75 // - mismatched object and array closing
76 // - Failure to close array or object
77 // - numbers too large
78 // - invalid unicode escapes.
79 // - invalid unicode sequences.
80 // - numbers as keys
81 //
82 // For each test we split the input string on every possible character to ensure
83 // the parser is able to handle arbitrarily split input for all cases. We also
84 // do a final test of the entire test case one character at a time.
85 //
86 // It is verified that expected calls to the mocked objects are in sequence.
87 class JsonStreamParserTest : public ::testing::Test {
88 protected:
JsonStreamParserTest()89 JsonStreamParserTest() : mock_(), ow_(&mock_) {}
~JsonStreamParserTest()90 virtual ~JsonStreamParserTest() {}
91
RunTest(StringPiece json,int split,bool coerce_utf8=false,bool allow_empty_null=false,bool loose_float_number_conversion=false)92 util::Status RunTest(StringPiece json, int split,
93 bool coerce_utf8 = false, bool allow_empty_null = false,
94 bool loose_float_number_conversion = false) {
95 JsonStreamParser parser(&mock_);
96
97 // Special case for split == length, test parsing one character at a time.
98 if (split == json.length()) {
99 GOOGLE_LOG(INFO) << "Testing split every char: " << json;
100 for (int i = 0; i < json.length(); ++i) {
101 StringPiece single = json.substr(i, 1);
102 util::Status result = parser.Parse(single);
103 if (!result.ok()) {
104 return result;
105 }
106 }
107 return parser.FinishParse();
108 }
109
110 // Normal case, split at the split point and parse two substrings.
111 StringPiece first = json.substr(0, split);
112 StringPiece rest = json.substr(split);
113 GOOGLE_LOG(INFO) << "Testing split: " << first << "><" << rest;
114 util::Status result = parser.Parse(first);
115 if (result.ok()) {
116 result = parser.Parse(rest);
117 if (result.ok()) {
118 result = parser.FinishParse();
119 }
120 }
121 if (result.ok()) {
122 EXPECT_EQ(parser.recursion_depth(), 0);
123 }
124 return result;
125 }
126
DoTest(StringPiece json,int split,bool coerce_utf8=false,bool allow_empty_null=false,bool loose_float_number_conversion=false)127 void DoTest(StringPiece json, int split, bool coerce_utf8 = false,
128 bool allow_empty_null = false,
129 bool loose_float_number_conversion = false) {
130 util::Status result = RunTest(json, split, coerce_utf8, allow_empty_null,
131 loose_float_number_conversion);
132 if (!result.ok()) {
133 GOOGLE_LOG(WARNING) << result;
134 }
135 EXPECT_OK(result);
136 }
137
DoErrorTest(StringPiece json,int split,StringPiece error_prefix,bool coerce_utf8=false,bool allow_empty_null=false)138 void DoErrorTest(StringPiece json, int split,
139 StringPiece error_prefix, bool coerce_utf8 = false,
140 bool allow_empty_null = false) {
141 util::Status result = RunTest(json, split, coerce_utf8, allow_empty_null);
142 EXPECT_EQ(util::error::INVALID_ARGUMENT, result.code());
143 StringPiece error_message(result.error_message());
144 EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size()));
145 }
146
147
148 #ifndef _MSC_VER
149 // TODO(xiaofeng): We have to disable InSequence check for MSVC because it
150 // causes stack overflow due to its use of a linked list that is desctructed
151 // recursively.
152 ::testing::InSequence in_sequence_;
153 #endif // !_MSC_VER
154 MockObjectWriter mock_;
155 ExpectingObjectWriter ow_;
156 };
157
158
159 // Positive tests
160
161 // - true, false, null
TEST_F(JsonStreamParserTest,SimpleTrue)162 TEST_F(JsonStreamParserTest, SimpleTrue) {
163 StringPiece str = "true";
164 for (int i = 0; i <= str.length(); ++i) {
165 ow_.RenderBool("", true);
166 DoTest(str, i);
167 }
168 }
169
TEST_F(JsonStreamParserTest,SimpleFalse)170 TEST_F(JsonStreamParserTest, SimpleFalse) {
171 StringPiece str = "false";
172 for (int i = 0; i <= str.length(); ++i) {
173 ow_.RenderBool("", false);
174 DoTest(str, i);
175 }
176 }
177
TEST_F(JsonStreamParserTest,SimpleNull)178 TEST_F(JsonStreamParserTest, SimpleNull) {
179 StringPiece str = "null";
180 for (int i = 0; i <= str.length(); ++i) {
181 ow_.RenderNull("");
182 DoTest(str, i);
183 }
184 }
185
186 // - empty object and array.
TEST_F(JsonStreamParserTest,EmptyObject)187 TEST_F(JsonStreamParserTest, EmptyObject) {
188 StringPiece str = "{}";
189 for (int i = 0; i <= str.length(); ++i) {
190 ow_.StartObject("")->EndObject();
191 DoTest(str, i);
192 }
193 }
194
TEST_F(JsonStreamParserTest,EmptyList)195 TEST_F(JsonStreamParserTest, EmptyList) {
196 StringPiece str = "[]";
197 for (int i = 0; i <= str.length(); ++i) {
198 ow_.StartList("")->EndList();
199 DoTest(str, i);
200 }
201 }
202
203 // - negative and positive double and int, unsigned int
TEST_F(JsonStreamParserTest,SimpleDouble)204 TEST_F(JsonStreamParserTest, SimpleDouble) {
205 StringPiece str = "42.5";
206 for (int i = 0; i <= str.length(); ++i) {
207 ow_.RenderDouble("", 42.5);
208 DoTest(str, i);
209 }
210 }
211
TEST_F(JsonStreamParserTest,ScientificDouble)212 TEST_F(JsonStreamParserTest, ScientificDouble) {
213 StringPiece str = "1.2345e-10";
214 for (int i = 0; i < str.length(); ++i) {
215 ow_.RenderDouble("", 1.2345e-10);
216 DoTest(str, i);
217 }
218 }
219
TEST_F(JsonStreamParserTest,SimpleNegativeDouble)220 TEST_F(JsonStreamParserTest, SimpleNegativeDouble) {
221 StringPiece str = "-1045.235";
222 for (int i = 0; i <= str.length(); ++i) {
223 ow_.RenderDouble("", -1045.235);
224 DoTest(str, i);
225 }
226 }
227
TEST_F(JsonStreamParserTest,SimpleInt)228 TEST_F(JsonStreamParserTest, SimpleInt) {
229 StringPiece str = "123456";
230 for (int i = 0; i <= str.length(); ++i) {
231 ow_.RenderUint64("", 123456);
232 DoTest(str, i);
233 }
234 }
235
TEST_F(JsonStreamParserTest,SimpleNegativeInt)236 TEST_F(JsonStreamParserTest, SimpleNegativeInt) {
237 StringPiece str = "-79497823553162765";
238 for (int i = 0; i <= str.length(); ++i) {
239 ow_.RenderInt64("", -79497823553162765LL);
240 DoTest(str, i);
241 }
242 }
243
TEST_F(JsonStreamParserTest,SimpleUnsignedInt)244 TEST_F(JsonStreamParserTest, SimpleUnsignedInt) {
245 StringPiece str = "11779497823553162765";
246 for (int i = 0; i <= str.length(); ++i) {
247 ow_.RenderUint64("", 11779497823553162765ULL);
248 DoTest(str, i);
249 }
250 }
251
TEST_F(JsonStreamParserTest,OctalNumberIsInvalid)252 TEST_F(JsonStreamParserTest, OctalNumberIsInvalid) {
253 StringPiece str = "01234";
254 for (int i = 0; i <= str.length(); ++i) {
255 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
256 }
257 str = "-01234";
258 for (int i = 0; i <= str.length(); ++i) {
259 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
260 }
261 }
262
TEST_F(JsonStreamParserTest,HexNumberIsInvalid)263 TEST_F(JsonStreamParserTest, HexNumberIsInvalid) {
264 StringPiece str = "0x1234";
265 for (int i = 0; i <= str.length(); ++i) {
266 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
267 }
268 str = "-0x1234";
269 for (int i = 0; i <= str.length(); ++i) {
270 DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
271 }
272 str = "12x34";
273 for (int i = 0; i <= str.length(); ++i) {
274 DoErrorTest(str, i, "Unable to parse number.");
275 }
276 }
277
278 // - single and double quoted strings
TEST_F(JsonStreamParserTest,EmptyDoubleQuotedString)279 TEST_F(JsonStreamParserTest, EmptyDoubleQuotedString) {
280 StringPiece str = "\"\"";
281 for (int i = 0; i <= str.length(); ++i) {
282 ow_.RenderString("", "");
283 DoTest(str, i);
284 }
285 }
286
TEST_F(JsonStreamParserTest,EmptySingleQuotedString)287 TEST_F(JsonStreamParserTest, EmptySingleQuotedString) {
288 StringPiece str = "''";
289 for (int i = 0; i <= str.length(); ++i) {
290 ow_.RenderString("", "");
291 DoTest(str, i);
292 }
293 }
294
TEST_F(JsonStreamParserTest,SimpleDoubleQuotedString)295 TEST_F(JsonStreamParserTest, SimpleDoubleQuotedString) {
296 StringPiece str = "\"Some String\"";
297 for (int i = 0; i <= str.length(); ++i) {
298 ow_.RenderString("", "Some String");
299 DoTest(str, i);
300 }
301 }
302
TEST_F(JsonStreamParserTest,SimpleSingleQuotedString)303 TEST_F(JsonStreamParserTest, SimpleSingleQuotedString) {
304 StringPiece str = "'Another String'";
305 for (int i = 0; i <= str.length(); ++i) {
306 ow_.RenderString("", "Another String");
307 DoTest(str, i);
308 }
309 }
310
311 // - string key, unquoted key, numeric key
TEST_F(JsonStreamParserTest,ObjectKeyTypes)312 TEST_F(JsonStreamParserTest, ObjectKeyTypes) {
313 StringPiece str =
314 "{'s': true, \"d\": false, key: null, snake_key: [], camelKey: {}}";
315 for (int i = 0; i <= str.length(); ++i) {
316 ow_.StartObject("")
317 ->RenderBool("s", true)
318 ->RenderBool("d", false)
319 ->RenderNull("key")
320 ->StartList("snake_key")
321 ->EndList()
322 ->StartObject("camelKey")
323 ->EndObject()
324 ->EndObject();
325 DoTest(str, i);
326 }
327 }
328
329 // - array containing primitive values (true, false, null, num, string)
TEST_F(JsonStreamParserTest,ArrayPrimitiveValues)330 TEST_F(JsonStreamParserTest, ArrayPrimitiveValues) {
331 StringPiece str = "[true, false, null, 'one', \"two\"]";
332 for (int i = 0; i <= str.length(); ++i) {
333 ow_.StartList("")
334 ->RenderBool("", true)
335 ->RenderBool("", false)
336 ->RenderNull("")
337 ->RenderString("", "one")
338 ->RenderString("", "two")
339 ->EndList();
340 DoTest(str, i);
341 }
342 }
343
344 // - array containing array, object
TEST_F(JsonStreamParserTest,ArrayComplexValues)345 TEST_F(JsonStreamParserTest, ArrayComplexValues) {
346 StringPiece str =
347 "[[22, -127, 45.3, -1056.4, 11779497823553162765], {'key': true}]";
348 for (int i = 0; i <= str.length(); ++i) {
349 ow_.StartList("")
350 ->StartList("")
351 ->RenderUint64("", 22)
352 ->RenderInt64("", -127)
353 ->RenderDouble("", 45.3)
354 ->RenderDouble("", -1056.4)
355 ->RenderUint64("", 11779497823553162765ULL)
356 ->EndList()
357 ->StartObject("")
358 ->RenderBool("key", true)
359 ->EndObject()
360 ->EndList();
361 DoTest(str, i);
362 }
363 }
364
365
366 // - object containing array, object, value (true, false, null, num, string)
TEST_F(JsonStreamParserTest,ObjectValues)367 TEST_F(JsonStreamParserTest, ObjectValues) {
368 StringPiece str =
369 "{t: true, f: false, n: null, s: 'a string', d: \"another string\", pi: "
370 "22, ni: -127, pd: 45.3, nd: -1056.4, pl: 11779497823553162765, l: [[]], "
371 "o: {'key': true}}";
372 for (int i = 0; i <= str.length(); ++i) {
373 ow_.StartObject("")
374 ->RenderBool("t", true)
375 ->RenderBool("f", false)
376 ->RenderNull("n")
377 ->RenderString("s", "a string")
378 ->RenderString("d", "another string")
379 ->RenderUint64("pi", 22)
380 ->RenderInt64("ni", -127)
381 ->RenderDouble("pd", 45.3)
382 ->RenderDouble("nd", -1056.4)
383 ->RenderUint64("pl", 11779497823553162765ULL)
384 ->StartList("l")
385 ->StartList("")
386 ->EndList()
387 ->EndList()
388 ->StartObject("o")
389 ->RenderBool("key", true)
390 ->EndObject()
391 ->EndObject();
392 DoTest(str, i);
393 }
394 }
395
396
TEST_F(JsonStreamParserTest,RejectNonUtf8WhenNotCoerced)397 TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) {
398 StringPiece json = "{\"address\":\xFF\"חרושת 23, רעננה, ישראל\"}";
399 for (int i = 0; i <= json.length(); ++i) {
400 DoErrorTest(json, i, "Encountered non UTF-8 code points.");
401 }
402 json = "{\"address\": \"חרושת 23,\xFFרעננה, ישראל\"}";
403 for (int i = 0; i <= json.length(); ++i) {
404 DoErrorTest(json, i, "Encountered non UTF-8 code points.");
405 }
406 DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points.");
407 }
408
409 // - unicode handling in strings
TEST_F(JsonStreamParserTest,UnicodeEscaping)410 TEST_F(JsonStreamParserTest, UnicodeEscaping) {
411 StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]";
412 for (int i = 0; i <= str.length(); ++i) {
413 ow_.StartList("")
414 ->RenderString("", "\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x89")
415 ->EndList();
416 DoTest(str, i);
417 }
418 }
419
420 // - unicode UTF-16 surrogate pair handling in strings
TEST_F(JsonStreamParserTest,UnicodeSurrogatePairEscaping)421 TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) {
422 StringPiece str =
423 "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\\uD83C\\uDF6F\"]";
424 for (int i = 0; i <= str.length(); ++i) {
425 ow_.StartList("")
426 ->RenderString("",
427 "\xE0\xAF\xAE\xF0\x90\x87\xB1\xF0\x93\x86\xA4\xF0"
428 "\x9F\x90\x9D\xF0\x9F\x8D\xAF")
429 ->EndList();
430 DoTest(str, i);
431 }
432 }
433
434
TEST_F(JsonStreamParserTest,UnicodeEscapingInvalidCodePointWhenNotCoerced)435 TEST_F(JsonStreamParserTest, UnicodeEscapingInvalidCodePointWhenNotCoerced) {
436 // A low surrogate alone.
437 StringPiece str = "[\"\\ude36\"]";
438 for (int i = 0; i <= str.length(); ++i) {
439 DoErrorTest(str, i, "Invalid unicode code point.");
440 }
441 }
442
TEST_F(JsonStreamParserTest,UnicodeEscapingMissingLowSurrogateWhenNotCoerced)443 TEST_F(JsonStreamParserTest, UnicodeEscapingMissingLowSurrogateWhenNotCoerced) {
444 // A high surrogate alone.
445 StringPiece str = "[\"\\ud83d\"]";
446 for (int i = 0; i <= str.length(); ++i) {
447 DoErrorTest(str, i, "Missing low surrogate.");
448 }
449 // A high surrogate with some trailing characters.
450 str = "[\"\\ud83d|ude36\"]";
451 for (int i = 0; i <= str.length(); ++i) {
452 DoErrorTest(str, i, "Missing low surrogate.");
453 }
454 // A high surrogate with half a low surrogate.
455 str = "[\"\\ud83d\\ude--\"]";
456 for (int i = 0; i <= str.length(); ++i) {
457 DoErrorTest(str, i, "Invalid escape sequence.");
458 }
459 // Two high surrogates.
460 str = "[\"\\ud83d\\ud83d\"]";
461 for (int i = 0; i <= str.length(); ++i) {
462 DoErrorTest(str, i, "Invalid low surrogate.");
463 }
464 }
465
466 // - ascii escaping (\b, \f, \n, \r, \t, \v)
TEST_F(JsonStreamParserTest,AsciiEscaping)467 TEST_F(JsonStreamParserTest, AsciiEscaping) {
468 StringPiece str =
469 "[\"\\b\", \"\\ning\", \"test\\f\", \"\\r\\t\", \"test\\\\\\ving\"]";
470 for (int i = 0; i <= str.length(); ++i) {
471 ow_.StartList("")
472 ->RenderString("", "\b")
473 ->RenderString("", "\ning")
474 ->RenderString("", "test\f")
475 ->RenderString("", "\r\t")
476 ->RenderString("", "test\\\ving")
477 ->EndList();
478 DoTest(str, i);
479 }
480 }
481
482 // - trailing commas, we support a single trailing comma but no internal commas.
TEST_F(JsonStreamParserTest,TrailingCommas)483 TEST_F(JsonStreamParserTest, TrailingCommas) {
484 StringPiece str = "[['a',true,], {b: null,},]";
485 for (int i = 0; i <= str.length(); ++i) {
486 ow_.StartList("")
487 ->StartList("")
488 ->RenderString("", "a")
489 ->RenderBool("", true)
490 ->EndList()
491 ->StartObject("")
492 ->RenderNull("b")
493 ->EndObject()
494 ->EndList();
495 DoTest(str, i);
496 }
497 }
498
499 // Negative tests
500
501 // illegal literals
TEST_F(JsonStreamParserTest,ExtraTextAfterTrue)502 TEST_F(JsonStreamParserTest, ExtraTextAfterTrue) {
503 StringPiece str = "truee";
504 for (int i = 0; i <= str.length(); ++i) {
505 ow_.RenderBool("", true);
506 DoErrorTest(str, i, "Parsing terminated before end of input.");
507 }
508 }
509
TEST_F(JsonStreamParserTest,InvalidNumberDashOnly)510 TEST_F(JsonStreamParserTest, InvalidNumberDashOnly) {
511 StringPiece str = "-";
512 for (int i = 0; i <= str.length(); ++i) {
513 DoErrorTest(str, i, "Unable to parse number.");
514 }
515 }
516
TEST_F(JsonStreamParserTest,InvalidNumberDashName)517 TEST_F(JsonStreamParserTest, InvalidNumberDashName) {
518 StringPiece str = "-foo";
519 for (int i = 0; i <= str.length(); ++i) {
520 DoErrorTest(str, i, "Unable to parse number.");
521 }
522 }
523
TEST_F(JsonStreamParserTest,InvalidLiteralInArray)524 TEST_F(JsonStreamParserTest, InvalidLiteralInArray) {
525 StringPiece str = "[nule]";
526 for (int i = 0; i <= str.length(); ++i) {
527 ow_.StartList("");
528 DoErrorTest(str, i, "Unexpected token.");
529 }
530 }
531
TEST_F(JsonStreamParserTest,InvalidLiteralInObject)532 TEST_F(JsonStreamParserTest, InvalidLiteralInObject) {
533 StringPiece str = "{123false}";
534 for (int i = 0; i <= str.length(); ++i) {
535 ow_.StartObject("");
536 DoErrorTest(str, i, "Expected an object key or }.");
537 }
538 }
539
540 // mismatched quotes failure on strings
TEST_F(JsonStreamParserTest,MismatchedSingleQuotedLiteral)541 TEST_F(JsonStreamParserTest, MismatchedSingleQuotedLiteral) {
542 StringPiece str = "'Some str\"";
543 for (int i = 0; i <= str.length(); ++i) {
544 DoErrorTest(str, i, "Closing quote expected in string.");
545 }
546 }
547
TEST_F(JsonStreamParserTest,MismatchedDoubleQuotedLiteral)548 TEST_F(JsonStreamParserTest, MismatchedDoubleQuotedLiteral) {
549 StringPiece str = "\"Another string that ends poorly!'";
550 for (int i = 0; i <= str.length(); ++i) {
551 DoErrorTest(str, i, "Closing quote expected in string.");
552 }
553 }
554
555 // unterminated strings
TEST_F(JsonStreamParserTest,UnterminatedLiteralString)556 TEST_F(JsonStreamParserTest, UnterminatedLiteralString) {
557 StringPiece str = "\"Forgot the rest of i";
558 for (int i = 0; i <= str.length(); ++i) {
559 DoErrorTest(str, i, "Closing quote expected in string.");
560 }
561 }
562
TEST_F(JsonStreamParserTest,UnterminatedStringEscape)563 TEST_F(JsonStreamParserTest, UnterminatedStringEscape) {
564 StringPiece str = "\"Forgot the rest of \\";
565 for (int i = 0; i <= str.length(); ++i) {
566 DoErrorTest(str, i, "Closing quote expected in string.");
567 }
568 }
569
TEST_F(JsonStreamParserTest,UnterminatedStringInArray)570 TEST_F(JsonStreamParserTest, UnterminatedStringInArray) {
571 StringPiece str = "[\"Forgot to close the string]";
572 for (int i = 0; i <= str.length(); ++i) {
573 ow_.StartList("");
574 DoErrorTest(str, i, "Closing quote expected in string.");
575 }
576 }
577
TEST_F(JsonStreamParserTest,UnterminatedStringInObject)578 TEST_F(JsonStreamParserTest, UnterminatedStringInObject) {
579 StringPiece str = "{f: \"Forgot to close the string}";
580 for (int i = 0; i <= str.length(); ++i) {
581 ow_.StartObject("");
582 DoErrorTest(str, i, "Closing quote expected in string.");
583 }
584 }
585
TEST_F(JsonStreamParserTest,UnterminatedObject)586 TEST_F(JsonStreamParserTest, UnterminatedObject) {
587 StringPiece str = "{";
588 for (int i = 0; i <= str.length(); ++i) {
589 ow_.StartObject("");
590 DoErrorTest(str, i, "Unexpected end of string.");
591 }
592 }
593
594
595 // mismatched object and array closing
TEST_F(JsonStreamParserTest,MismatchedCloseObject)596 TEST_F(JsonStreamParserTest, MismatchedCloseObject) {
597 StringPiece str = "{'key': true]";
598 for (int i = 0; i <= str.length(); ++i) {
599 ow_.StartObject("")->RenderBool("key", true);
600 DoErrorTest(str, i, "Expected , or } after key:value pair.");
601 }
602 }
603
TEST_F(JsonStreamParserTest,MismatchedCloseArray)604 TEST_F(JsonStreamParserTest, MismatchedCloseArray) {
605 StringPiece str = "[true, null}";
606 for (int i = 0; i <= str.length(); ++i) {
607 ow_.StartList("")->RenderBool("", true)->RenderNull("");
608 DoErrorTest(str, i, "Expected , or ] after array value.");
609 }
610 }
611
612 // Invalid object keys.
TEST_F(JsonStreamParserTest,InvalidNumericObjectKey)613 TEST_F(JsonStreamParserTest, InvalidNumericObjectKey) {
614 StringPiece str = "{42: true}";
615 for (int i = 0; i <= str.length(); ++i) {
616 ow_.StartObject("");
617 DoErrorTest(str, i, "Expected an object key or }.");
618 }
619 }
620
TEST_F(JsonStreamParserTest,InvalidLiteralObjectInObject)621 TEST_F(JsonStreamParserTest, InvalidLiteralObjectInObject) {
622 StringPiece str = "{{bob: true}}";
623 for (int i = 0; i <= str.length(); ++i) {
624 ow_.StartObject("");
625 DoErrorTest(str, i, "Expected an object key or }.");
626 }
627 }
628
TEST_F(JsonStreamParserTest,InvalidLiteralArrayInObject)629 TEST_F(JsonStreamParserTest, InvalidLiteralArrayInObject) {
630 StringPiece str = "{[null]}";
631 for (int i = 0; i <= str.length(); ++i) {
632 ow_.StartObject("");
633 DoErrorTest(str, i, "Expected an object key or }.");
634 }
635 }
636
TEST_F(JsonStreamParserTest,InvalidLiteralValueInObject)637 TEST_F(JsonStreamParserTest, InvalidLiteralValueInObject) {
638 StringPiece str = "{false}";
639 for (int i = 0; i <= str.length(); ++i) {
640 ow_.StartObject("");
641 DoErrorTest(str, i, "Expected an object key or }.");
642 }
643 }
644
TEST_F(JsonStreamParserTest,MissingColonAfterStringInObject)645 TEST_F(JsonStreamParserTest, MissingColonAfterStringInObject) {
646 StringPiece str = "{\"key\"}";
647 for (int i = 0; i <= str.length(); ++i) {
648 ow_.StartObject("");
649 DoErrorTest(str, i, "Expected : between key:value pair.");
650 }
651 }
652
TEST_F(JsonStreamParserTest,MissingColonAfterKeyInObject)653 TEST_F(JsonStreamParserTest, MissingColonAfterKeyInObject) {
654 StringPiece str = "{key}";
655 for (int i = 0; i <= str.length(); ++i) {
656 ow_.StartObject("");
657 DoErrorTest(str, i, "Expected : between key:value pair.");
658 }
659 }
660
TEST_F(JsonStreamParserTest,EndOfTextAfterKeyInObject)661 TEST_F(JsonStreamParserTest, EndOfTextAfterKeyInObject) {
662 StringPiece str = "{key";
663 for (int i = 0; i <= str.length(); ++i) {
664 ow_.StartObject("");
665 DoErrorTest(str, i, "Unexpected end of string.");
666 }
667 }
668
TEST_F(JsonStreamParserTest,MissingValueAfterColonInObject)669 TEST_F(JsonStreamParserTest, MissingValueAfterColonInObject) {
670 StringPiece str = "{key:}";
671 for (int i = 0; i <= str.length(); ++i) {
672 ow_.StartObject("");
673 DoErrorTest(str, i, "Unexpected token.");
674 }
675 }
676
TEST_F(JsonStreamParserTest,MissingCommaBetweenObjectEntries)677 TEST_F(JsonStreamParserTest, MissingCommaBetweenObjectEntries) {
678 StringPiece str = "{key:20 'hello': true}";
679 for (int i = 0; i <= str.length(); ++i) {
680 ow_.StartObject("")->RenderUint64("key", 20);
681 DoErrorTest(str, i, "Expected , or } after key:value pair.");
682 }
683 }
684
TEST_F(JsonStreamParserTest,InvalidLiteralAsObjectKey)685 TEST_F(JsonStreamParserTest, InvalidLiteralAsObjectKey) {
686 StringPiece str = "{false: 20}";
687 for (int i = 0; i <= str.length(); ++i) {
688 ow_.StartObject("");
689 DoErrorTest(str, i, "Expected an object key or }.");
690 }
691 }
692
TEST_F(JsonStreamParserTest,ExtraCharactersAfterObject)693 TEST_F(JsonStreamParserTest, ExtraCharactersAfterObject) {
694 StringPiece str = "{}}";
695 for (int i = 0; i <= str.length(); ++i) {
696 ow_.StartObject("")->EndObject();
697 DoErrorTest(str, i, "Parsing terminated before end of input.");
698 }
699 }
700
TEST_F(JsonStreamParserTest,PositiveNumberTooBigIsDouble)701 TEST_F(JsonStreamParserTest, PositiveNumberTooBigIsDouble) {
702 StringPiece str = "18446744073709551616"; // 2^64
703 for (int i = 0; i <= str.length(); ++i) {
704 ow_.RenderDouble("", 18446744073709552000.0);
705 DoTest(str, i);
706 }
707 }
708
TEST_F(JsonStreamParserTest,NegativeNumberTooBigIsDouble)709 TEST_F(JsonStreamParserTest, NegativeNumberTooBigIsDouble) {
710 StringPiece str = "-18446744073709551616";
711 for (int i = 0; i <= str.length(); ++i) {
712 ow_.RenderDouble("", -18446744073709551616.0);
713 DoTest(str, i);
714 }
715 }
716
TEST_F(JsonStreamParserTest,DoubleTooBig)717 TEST_F(JsonStreamParserTest, DoubleTooBig) {
718 StringPiece str = "[1.89769e+308]";
719 for (int i = 0; i <= str.length(); ++i) {
720 ow_.StartList("");
721 DoErrorTest(str, i, "Number exceeds the range of double.");
722 }
723 str = "[-1.89769e+308]";
724 for (int i = 0; i <= str.length(); ++i) {
725 ow_.StartList("");
726 DoErrorTest(str, i, "Number exceeds the range of double.");
727 }
728 }
729
730
731 // invalid bare backslash.
TEST_F(JsonStreamParserTest,UnfinishedEscape)732 TEST_F(JsonStreamParserTest, UnfinishedEscape) {
733 StringPiece str = "\"\\";
734 for (int i = 0; i <= str.length(); ++i) {
735 DoErrorTest(str, i, "Closing quote expected in string.");
736 }
737 }
738
739 // invalid bare backslash u.
TEST_F(JsonStreamParserTest,UnfinishedUnicodeEscape)740 TEST_F(JsonStreamParserTest, UnfinishedUnicodeEscape) {
741 StringPiece str = "\"\\u";
742 for (int i = 0; i <= str.length(); ++i) {
743 DoErrorTest(str, i, "Illegal hex string.");
744 }
745 }
746
747 // invalid unicode sequence.
TEST_F(JsonStreamParserTest,UnicodeEscapeCutOff)748 TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) {
749 StringPiece str = "\"\\u12";
750 for (int i = 0; i <= str.length(); ++i) {
751 DoErrorTest(str, i, "Illegal hex string.");
752 }
753 }
754
755 // invalid unicode sequence (valid in modern EcmaScript but not in JSON).
TEST_F(JsonStreamParserTest,BracketedUnicodeEscape)756 TEST_F(JsonStreamParserTest, BracketedUnicodeEscape) {
757 StringPiece str = "\"\\u{1f36f}\"";
758 for (int i = 0; i <= str.length(); ++i) {
759 DoErrorTest(str, i, "Invalid escape sequence.");
760 }
761 }
762
763
TEST_F(JsonStreamParserTest,UnicodeEscapeInvalidCharacters)764 TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) {
765 StringPiece str = "\"\\u12$4hello";
766 for (int i = 0; i <= str.length(); ++i) {
767 DoErrorTest(str, i, "Invalid escape sequence.");
768 }
769 }
770
771 // invalid unicode sequence in low half surrogate: g is not a hex digit.
TEST_F(JsonStreamParserTest,UnicodeEscapeLowHalfSurrogateInvalidCharacters)772 TEST_F(JsonStreamParserTest, UnicodeEscapeLowHalfSurrogateInvalidCharacters) {
773 StringPiece str = "\"\\ud800\\udcfg\"";
774 for (int i = 0; i <= str.length(); ++i) {
775 DoErrorTest(str, i, "Invalid escape sequence.");
776 }
777 }
778
779 // Extra commas with an object or array.
TEST_F(JsonStreamParserTest,ExtraCommaInObject)780 TEST_F(JsonStreamParserTest, ExtraCommaInObject) {
781 StringPiece str = "{'k1': true,,'k2': false}";
782 for (int i = 0; i <= str.length(); ++i) {
783 ow_.StartObject("")->RenderBool("k1", true);
784 DoErrorTest(str, i, "Expected an object key or }.");
785 }
786 }
787
TEST_F(JsonStreamParserTest,ExtraCommaInArray)788 TEST_F(JsonStreamParserTest, ExtraCommaInArray) {
789 StringPiece str = "[true,,false}";
790 for (int i = 0; i <= str.length(); ++i) {
791 ow_.StartList("")->RenderBool("", true);
792 DoErrorTest(str, i, "Unexpected token.");
793 }
794 }
795
796 // Extra text beyond end of value.
TEST_F(JsonStreamParserTest,ExtraTextAfterLiteral)797 TEST_F(JsonStreamParserTest, ExtraTextAfterLiteral) {
798 StringPiece str = "'hello', 'world'";
799 for (int i = 0; i <= str.length(); ++i) {
800 ow_.RenderString("", "hello");
801 DoErrorTest(str, i, "Parsing terminated before end of input.");
802 }
803 }
804
TEST_F(JsonStreamParserTest,ExtraTextAfterObject)805 TEST_F(JsonStreamParserTest, ExtraTextAfterObject) {
806 StringPiece str = "{'key': true} 'oops'";
807 for (int i = 0; i <= str.length(); ++i) {
808 ow_.StartObject("")->RenderBool("key", true)->EndObject();
809 DoErrorTest(str, i, "Parsing terminated before end of input.");
810 }
811 }
812
TEST_F(JsonStreamParserTest,ExtraTextAfterArray)813 TEST_F(JsonStreamParserTest, ExtraTextAfterArray) {
814 StringPiece str = "[null] 'oops'";
815 for (int i = 0; i <= str.length(); ++i) {
816 ow_.StartList("")->RenderNull("")->EndList();
817 DoErrorTest(str, i, "Parsing terminated before end of input.");
818 }
819 }
820
821 // Random unknown text in the value.
TEST_F(JsonStreamParserTest,UnknownCharactersAsValue)822 TEST_F(JsonStreamParserTest, UnknownCharactersAsValue) {
823 StringPiece str = "*";
824 for (int i = 0; i <= str.length(); ++i) {
825 DoErrorTest(str, i, "Expected a value.");
826 }
827 }
828
TEST_F(JsonStreamParserTest,UnknownCharactersInArray)829 TEST_F(JsonStreamParserTest, UnknownCharactersInArray) {
830 StringPiece str = "[*]";
831 for (int i = 0; i <= str.length(); ++i) {
832 ow_.StartList("");
833 DoErrorTest(str, i, "Expected a value or ] within an array.");
834 }
835 }
836
TEST_F(JsonStreamParserTest,UnknownCharactersInObject)837 TEST_F(JsonStreamParserTest, UnknownCharactersInObject) {
838 StringPiece str = "{'key': *}";
839 for (int i = 0; i <= str.length(); ++i) {
840 ow_.StartObject("");
841 DoErrorTest(str, i, "Expected a value.");
842 }
843 }
844
TEST_F(JsonStreamParserTest,DeepNestJsonNotExceedLimit)845 TEST_F(JsonStreamParserTest, DeepNestJsonNotExceedLimit) {
846 int count = 99;
847 std::string str;
848 for (int i = 0; i < count; ++i) {
849 StrAppend(&str, "{'a':");
850 }
851 StrAppend(&str, "{'nest64':'v1', 'nest64': false, 'nest64': ['v2']}");
852 for (int i = 0; i < count; ++i) {
853 StrAppend(&str, "}");
854 }
855 ow_.StartObject("");
856 for (int i = 0; i < count; ++i) {
857 ow_.StartObject("a");
858 }
859 ow_.RenderString("nest64", "v1")
860 ->RenderBool("nest64", false)
861 ->StartList("nest64")
862 ->RenderString("", "v2")
863 ->EndList();
864 for (int i = 0; i < count; ++i) {
865 ow_.EndObject();
866 }
867 ow_.EndObject();
868 DoTest(str, 0);
869 }
870
TEST_F(JsonStreamParserTest,DeepNestJsonExceedLimit)871 TEST_F(JsonStreamParserTest, DeepNestJsonExceedLimit) {
872 int count = 98;
873 std::string str;
874 for (int i = 0; i < count; ++i) {
875 StrAppend(&str, "{'a':");
876 }
877 // Supports trailing commas.
878 StrAppend(&str,
879 "{'nest11' : [{'nest12' : null,},],"
880 "'nest21' : {'nest22' : {'nest23' : false}}}");
881 for (int i = 0; i < count; ++i) {
882 StrAppend(&str, "}");
883 }
884 DoErrorTest(str, 0,
885 "Message too deep. Max recursion depth reached for key 'nest22'");
886 }
887
888 } // namespace converter
889 } // namespace util
890 } // namespace protobuf
891 } // namespace google
892