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