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