• 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/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 = "*&#25";
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 = "[*&#25]";
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': *&#25}";
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