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
43 namespace google {
44 namespace protobuf {
45 namespace util {
46 using util::Status;
47 namespace error {
48 using util::error::INVALID_ARGUMENT;
49 } // namespace error
50 namespace converter {
51
52 using 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.
84 class JsonStreamParserTest : public ::testing::Test {
85 protected:
JsonStreamParserTest()86 JsonStreamParserTest() : mock_(), ow_(&mock_) {}
~JsonStreamParserTest()87 virtual ~JsonStreamParserTest() {}
88
RunTest(StringPiece json,int split,bool coerce_utf8=false)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
DoTest(StringPiece json,int split,bool coerce_utf8=false)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
DoErrorTest(StringPiece json,int split,StringPiece error_prefix,bool coerce_utf8=false)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
TEST_F(JsonStreamParserTest,SimpleTrue)144 TEST_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
TEST_F(JsonStreamParserTest,SimpleFalse)152 TEST_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
TEST_F(JsonStreamParserTest,SimpleNull)160 TEST_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.
TEST_F(JsonStreamParserTest,EmptyObject)169 TEST_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
TEST_F(JsonStreamParserTest,EmptyList)177 TEST_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
TEST_F(JsonStreamParserTest,SimpleDouble)186 TEST_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
TEST_F(JsonStreamParserTest,ScientificDouble)194 TEST_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
TEST_F(JsonStreamParserTest,SimpleNegativeDouble)202 TEST_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
TEST_F(JsonStreamParserTest,SimpleInt)210 TEST_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
TEST_F(JsonStreamParserTest,SimpleNegativeInt)218 TEST_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
TEST_F(JsonStreamParserTest,SimpleUnsignedInt)226 TEST_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
TEST_F(JsonStreamParserTest,OctalNumberIsInvalid)234 TEST_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
TEST_F(JsonStreamParserTest,HexNumberIsInvalid)245 TEST_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
TEST_F(JsonStreamParserTest,EmptyDoubleQuotedString)261 TEST_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
TEST_F(JsonStreamParserTest,EmptySingleQuotedString)269 TEST_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
TEST_F(JsonStreamParserTest,SimpleDoubleQuotedString)277 TEST_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
TEST_F(JsonStreamParserTest,SimpleSingleQuotedString)285 TEST_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
TEST_F(JsonStreamParserTest,ObjectKeyTypes)294 TEST_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)
TEST_F(JsonStreamParserTest,ArrayValues)312 TEST_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)
TEST_F(JsonStreamParserTest,ObjectValues)339 TEST_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
TEST_F(JsonStreamParserTest,RejectNonUtf8WhenNotCoerced)369 TEST_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
TEST_F(JsonStreamParserTest,UnicodeEscaping)382 TEST_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
TEST_F(JsonStreamParserTest,UnicodeSurrogatePairEscaping)393 TEST_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
TEST_F(JsonStreamParserTest,UnicodeEscapingInvalidCodePointWhenNotCoerced)407 TEST_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
TEST_F(JsonStreamParserTest,UnicodeEscapingMissingLowSurrogateWhenNotCoerced)415 TEST_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)
TEST_F(JsonStreamParserTest,AsciiEscaping)439 TEST_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.
TEST_F(JsonStreamParserTest,TrailingCommas)455 TEST_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
TEST_F(JsonStreamParserTest,ExtraTextAfterTrue)474 TEST_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
TEST_F(JsonStreamParserTest,InvalidNumberDashOnly)482 TEST_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
TEST_F(JsonStreamParserTest,InvalidNumberDashName)489 TEST_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
TEST_F(JsonStreamParserTest,InvalidLiteralInArray)496 TEST_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
TEST_F(JsonStreamParserTest,InvalidLiteralInObject)504 TEST_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
TEST_F(JsonStreamParserTest,MismatchedSingleQuotedLiteral)513 TEST_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
TEST_F(JsonStreamParserTest,MismatchedDoubleQuotedLiteral)520 TEST_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
TEST_F(JsonStreamParserTest,UnterminatedLiteralString)528 TEST_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
TEST_F(JsonStreamParserTest,UnterminatedStringEscape)535 TEST_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
TEST_F(JsonStreamParserTest,UnterminatedStringInArray)542 TEST_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
TEST_F(JsonStreamParserTest,UnterminatedStringInObject)550 TEST_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
TEST_F(JsonStreamParserTest,UnterminatedObject)558 TEST_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
TEST_F(JsonStreamParserTest,MismatchedCloseObject)568 TEST_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
TEST_F(JsonStreamParserTest,MismatchedCloseArray)576 TEST_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.
TEST_F(JsonStreamParserTest,InvalidNumericObjectKey)585 TEST_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
TEST_F(JsonStreamParserTest,InvalidLiteralObjectInObject)593 TEST_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
TEST_F(JsonStreamParserTest,InvalidLiteralArrayInObject)601 TEST_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
TEST_F(JsonStreamParserTest,InvalidLiteralValueInObject)609 TEST_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
TEST_F(JsonStreamParserTest,MissingColonAfterStringInObject)617 TEST_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
TEST_F(JsonStreamParserTest,MissingColonAfterKeyInObject)625 TEST_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
TEST_F(JsonStreamParserTest,EndOfTextAfterKeyInObject)633 TEST_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
TEST_F(JsonStreamParserTest,MissingValueAfterColonInObject)641 TEST_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
TEST_F(JsonStreamParserTest,MissingCommaBetweenObjectEntries)649 TEST_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
TEST_F(JsonStreamParserTest,InvalidLiteralAsObjectKey)657 TEST_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
TEST_F(JsonStreamParserTest,ExtraCharactersAfterObject)665 TEST_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
TEST_F(JsonStreamParserTest,PositiveNumberTooBig)674 TEST_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
TEST_F(JsonStreamParserTest,NegativeNumberTooBig)682 TEST_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 /*
691 TODO(sven): Fail parsing when parsing a double that is too large.
692
693 TEST_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.
TEST_F(JsonStreamParserTest,UnfinishedEscape)703 TEST_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.
TEST_F(JsonStreamParserTest,UnfinishedUnicodeEscape)711 TEST_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.
TEST_F(JsonStreamParserTest,UnicodeEscapeCutOff)719 TEST_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).
TEST_F(JsonStreamParserTest,BracketedUnicodeEscape)727 TEST_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
TEST_F(JsonStreamParserTest,UnicodeEscapeInvalidCharacters)735 TEST_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.
TEST_F(JsonStreamParserTest,UnicodeEscapeLowHalfSurrogateInvalidCharacters)743 TEST_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.
TEST_F(JsonStreamParserTest,ExtraCommaInObject)751 TEST_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
TEST_F(JsonStreamParserTest,ExtraCommaInArray)759 TEST_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.
TEST_F(JsonStreamParserTest,ExtraTextAfterLiteral)768 TEST_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
TEST_F(JsonStreamParserTest,ExtraTextAfterObject)776 TEST_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
TEST_F(JsonStreamParserTest,ExtraTextAfterArray)784 TEST_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.
TEST_F(JsonStreamParserTest,UnknownCharactersAsValue)793 TEST_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
TEST_F(JsonStreamParserTest,UnknownCharactersInArray)800 TEST_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
TEST_F(JsonStreamParserTest,UnknownCharactersInObject)808 TEST_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