1 #include <boost/property_tree/detail/json_parser/parser.hpp>
2 #include <boost/property_tree/detail/json_parser/narrow_encoding.hpp>
3 #include <boost/property_tree/detail/json_parser/wide_encoding.hpp>
4 #include <boost/property_tree/detail/json_parser/standard_callbacks.hpp>
5 #include "prefixing_callbacks.hpp"
6
7 #define BOOST_TEST_NO_MAIN
8 #include <boost/test/unit_test.hpp>
9 #include <boost/test/parameterized_test.hpp>
10
11 #include <boost/property_tree/ptree.hpp>
12 #include <boost/range/iterator_range.hpp>
13
14 #include <cassert>
15 #include <sstream>
16 #include <vector>
17
18 using namespace boost::property_tree;
19
20 template <typename Ch> struct encoding;
21 template <> struct encoding<char>
22 : json_parser::detail::utf8_utf8_encoding
23 {};
24 template <> struct encoding<wchar_t>
25 : json_parser::detail::wide_wide_encoding
26 {};
27
28 template <typename Callbacks, typename Ch>
29 struct test_parser
30 {
31 Callbacks callbacks;
32 ::encoding<Ch> encoding;
33 typedef std::basic_string<Ch> string;
34 typedef basic_ptree<string, string> tree;
35 json_parser::detail::parser<Callbacks, ::encoding<Ch>,
36 typename string::const_iterator,
37 typename string::const_iterator>
38 parser;
39
test_parsertest_parser40 test_parser() : parser(callbacks, encoding) {}
41
parse_nulltest_parser42 bool parse_null(const string& input, string& output) {
43 parser.set_input("", input);
44 bool result = parser.parse_null();
45 if (result) {
46 parser.finish();
47 output = callbacks.output().data();
48 }
49 return result;
50 }
51
parse_booleantest_parser52 bool parse_boolean(const string& input, string& output) {
53 parser.set_input("", input);
54 bool result = parser.parse_boolean();
55 if (result) {
56 parser.finish();
57 output = callbacks.output().data();
58 }
59 return result;
60 }
61
parse_numbertest_parser62 bool parse_number(const string& input, string& output) {
63 parser.set_input("", input);
64 bool result = parser.parse_number();
65 if (result) {
66 parser.finish();
67 output = callbacks.output().data();
68 }
69 return result;
70 }
71
parse_stringtest_parser72 bool parse_string(const string& input, string& output) {
73 parser.set_input("", input);
74 bool result = parser.parse_string();
75 if (result) {
76 parser.finish();
77 output = callbacks.output().data();
78 }
79 return result;
80 }
81
parse_arraytest_parser82 bool parse_array(const string& input, tree& output) {
83 parser.set_input("", input);
84 bool result = parser.parse_array();
85 if (result) {
86 parser.finish();
87 output = callbacks.output();
88 }
89 return result;
90 }
91
parse_objecttest_parser92 bool parse_object(const string& input, tree& output) {
93 parser.set_input("", input);
94 bool result = parser.parse_object();
95 if (result) {
96 parser.finish();
97 output = callbacks.output();
98 }
99 return result;
100 }
101
parse_valuetest_parser102 void parse_value(const string& input, tree& output) {
103 parser.set_input("", input);
104 parser.parse_value();
105 parser.finish();
106 output = callbacks.output();
107 }
108 };
109
110 template <typename Ch>
111 struct standard_parser
112 : test_parser<
113 json_parser::detail::standard_callbacks<
114 basic_ptree<std::basic_string<Ch>, std::basic_string<Ch> > >,
115 Ch>
116 {};
117
118 template <typename Ch>
119 struct prefixing_parser
120 : test_parser<
121 prefixing_callbacks<
122 basic_ptree<std::basic_string<Ch>, std::basic_string<Ch> > >,
123 Ch>
124 {};
125
126 namespace boost { namespace test_tools { namespace tt_detail {
127 template<>
128 struct print_log_value<std::wstring> {
operator ()boost::test_tools::tt_detail::print_log_value129 void operator()(std::ostream& os, const std::wstring& s) {
130 print_log_value<const wchar_t*>()(os, s.c_str());
131 }
132 };
133 }}}
134 BOOST_TEST_DONT_PRINT_LOG_VALUE(ptree::iterator)
BOOST_TEST_DONT_PRINT_LOG_VALUE(ptree::const_iterator)135 BOOST_TEST_DONT_PRINT_LOG_VALUE(ptree::const_iterator)
136 BOOST_TEST_DONT_PRINT_LOG_VALUE(wptree::iterator)
137 BOOST_TEST_DONT_PRINT_LOG_VALUE(wptree::const_iterator)
138
139 BOOST_AUTO_TEST_CASE(null_parse_result_is_input) {
140 std::string parsed;
141 standard_parser<char> p;
142 BOOST_REQUIRE(p.parse_null("null", parsed));
143 BOOST_CHECK_EQUAL("null", parsed);
144 }
145
BOOST_AUTO_TEST_CASE(uses_traits_from_null)146 BOOST_AUTO_TEST_CASE(uses_traits_from_null)
147 {
148 std::string parsed;
149 prefixing_parser<char> p;
150 BOOST_REQUIRE(p.parse_null("null", parsed));
151 BOOST_CHECK_EQUAL("_:null", parsed);
152 }
153
BOOST_AUTO_TEST_CASE(null_parse_result_is_input_w)154 BOOST_AUTO_TEST_CASE(null_parse_result_is_input_w) {
155 std::wstring parsed;
156 standard_parser<wchar_t> p;
157 BOOST_REQUIRE(p.parse_null(L"null", parsed));
158 BOOST_CHECK_EQUAL(L"null", parsed);
159 }
160
BOOST_AUTO_TEST_CASE(uses_traits_from_null_w)161 BOOST_AUTO_TEST_CASE(uses_traits_from_null_w)
162 {
163 std::wstring parsed;
164 prefixing_parser<wchar_t> p;
165 BOOST_REQUIRE(p.parse_null(L"null", parsed));
166 BOOST_CHECK_EQUAL(L"_:null", parsed);
167 }
168
boolean_parse_result_is_input_n(const char * param)169 void boolean_parse_result_is_input_n(const char* param) {
170 std::string parsed;
171 standard_parser<char> p;
172 BOOST_REQUIRE(p.parse_boolean(param, parsed));
173 BOOST_CHECK_EQUAL(param, parsed);
174 }
175
176 const char* const booleans_n[] = { "true", "false" };
177
BOOST_AUTO_TEST_CASE(uses_traits_from_boolean_n)178 BOOST_AUTO_TEST_CASE(uses_traits_from_boolean_n)
179 {
180 std::string parsed;
181 prefixing_parser<char> p;
182 BOOST_REQUIRE(p.parse_boolean("true", parsed));
183 BOOST_CHECK_EQUAL("b:true", parsed);
184 }
185
boolean_parse_result_is_input_w(const wchar_t * param)186 void boolean_parse_result_is_input_w(const wchar_t* param) {
187 std::wstring parsed;
188 standard_parser<wchar_t> p;
189 BOOST_REQUIRE(p.parse_boolean(param, parsed));
190 BOOST_CHECK_EQUAL(param, parsed);
191 }
192
193 const wchar_t* const booleans_w[] = { L"true", L"false" };
194
BOOST_AUTO_TEST_CASE(uses_traits_from_boolean_w)195 BOOST_AUTO_TEST_CASE(uses_traits_from_boolean_w)
196 {
197 std::wstring parsed;
198 prefixing_parser<wchar_t> p;
199 BOOST_REQUIRE(p.parse_boolean(L"true", parsed));
200 BOOST_CHECK_EQUAL(L"b:true", parsed);
201 }
202
number_parse_result_is_input_n(const char * param)203 void number_parse_result_is_input_n(const char* param) {
204 std::string parsed;
205 standard_parser<char> p;
206 BOOST_REQUIRE(p.parse_number(param, parsed));
207 BOOST_CHECK_EQUAL(param, parsed);
208 }
209
210 const char* const numbers_n[] = { "0", "-0", "1824", "-0.1", "123.142", "1e+0", "1E-0", "1.1e134" };
211
BOOST_AUTO_TEST_CASE(uses_traits_from_number_n)212 BOOST_AUTO_TEST_CASE(uses_traits_from_number_n)
213 {
214 std::string parsed;
215 prefixing_parser<char> p;
216 BOOST_REQUIRE(p.parse_number("12345", parsed));
217 BOOST_CHECK_EQUAL("n:12345", parsed);
218 }
219
number_parse_result_is_input_w(const wchar_t * param)220 void number_parse_result_is_input_w(const wchar_t* param) {
221 std::wstring parsed;
222 standard_parser<wchar_t> p;
223 BOOST_REQUIRE(p.parse_number(param, parsed));
224 BOOST_CHECK_EQUAL(param, parsed);
225 }
226
227 const wchar_t* const numbers_w[] = { L"0", L"-0", L"1824", L"-0.1", L"123.142", L"1e+0", L"1E-0", L"1.1e134" };
228
BOOST_AUTO_TEST_CASE(uses_traits_from_number_w)229 BOOST_AUTO_TEST_CASE(uses_traits_from_number_w)
230 {
231 std::wstring parsed;
232 prefixing_parser<wchar_t> p;
233 BOOST_REQUIRE(p.parse_number(L"12345", parsed));
234 BOOST_CHECK_EQUAL(L"n:12345", parsed);
235 }
236
237 struct string_input_n {
238 const char* encoded;
239 const char* expected;
240 };
241
string_parsed_correctly_n(string_input_n param)242 void string_parsed_correctly_n(string_input_n param) {
243 std::string parsed;
244 standard_parser<char> p;
245 BOOST_REQUIRE(p.parse_string(param.encoded, parsed));
246 BOOST_CHECK_EQUAL(param.expected, parsed);
247 }
248
249 const string_input_n strings_n[] = {
250 {"\"\"", ""},
251 {"\"abc\"", "abc"},
252 {"\"a\\nb\"", "a\nb"},
253 {"\"\\\"\"", "\""},
254 {"\"\\\\\"", "\\"},
255 {"\"\\/\"", "/"},
256 {"\"\\b\"", "\b"},
257 {"\"\\f\"", "\f"},
258 {"\"\\r\"", "\r"},
259 {"\"\\t\"", "\t"},
260 {"\"\\u0001\\u00f2\\u28Ec\"", "\x01" "\xC3\xB2" "\xE2\xA3\xAC"},
261 {"\"\\ud801\\udc37\"", "\xf0\x90\x90\xb7"} // U+10437
262 };
263
BOOST_AUTO_TEST_CASE(uses_string_callbacks)264 BOOST_AUTO_TEST_CASE(uses_string_callbacks)
265 {
266 std::string parsed;
267 prefixing_parser<char> p;
268 BOOST_REQUIRE(p.parse_string("\"a\"", parsed));
269 BOOST_CHECK_EQUAL("s:a", parsed);
270 }
271
272 struct string_input_w {
273 const wchar_t* encoded;
274 const wchar_t* expected;
275 };
276
string_parsed_correctly_w(string_input_w param)277 void string_parsed_correctly_w(string_input_w param) {
278 std::wstring parsed;
279 standard_parser<wchar_t> p;
280 BOOST_REQUIRE(p.parse_string(param.encoded, parsed));
281 BOOST_CHECK_EQUAL(param.expected, parsed);
282 }
283
284 const string_input_w strings_w[] = {
285 {L"\"\"", L""},
286 {L"\"abc\"", L"abc"},
287 {L"\"a\\nb\"", L"a\nb"},
288 {L"\"\\\"\"", L"\""},
289 {L"\"\\\\\"", L"\\"},
290 {L"\"\\/\"", L"/"},
291 {L"\"\\b\"", L"\b"},
292 {L"\"\\f\"", L"\f"},
293 {L"\"\\r\"", L"\r"},
294 {L"\"\\t\"", L"\t"},
295 {L"\"\\u0001\\u00f2\\u28Ec\"", L"\x0001" L"\x00F2" L"\x28EC"}
296 };
297
BOOST_AUTO_TEST_CASE(empty_array)298 BOOST_AUTO_TEST_CASE(empty_array) {
299 ptree tree;
300 standard_parser<char> p;
301 const char* input = " [ ]";
302 BOOST_REQUIRE(p.parse_array(input, tree));
303 BOOST_CHECK_EQUAL("", tree.data());
304 BOOST_CHECK_EQUAL(0u, tree.size());
305 }
306
BOOST_AUTO_TEST_CASE(array_gets_tagged)307 BOOST_AUTO_TEST_CASE(array_gets_tagged) {
308 wptree tree;
309 prefixing_parser<wchar_t> p;
310 const wchar_t* input = L" [ ]";
311 BOOST_REQUIRE(p.parse_array(input, tree));
312 BOOST_CHECK_EQUAL(L"a:", tree.data());
313 BOOST_CHECK_EQUAL(0u, tree.size());
314 }
315
BOOST_AUTO_TEST_CASE(array_with_values)316 BOOST_AUTO_TEST_CASE(array_with_values) {
317 wptree tree;
318 standard_parser<wchar_t> p;
319 const wchar_t* input = L"[\n"
320 L" 123, \"abc\" ,true ,\n"
321 L" null\n"
322 L" ]";
323 BOOST_REQUIRE(p.parse_array(input, tree));
324 BOOST_REQUIRE_EQUAL(4u, tree.size());
325 wptree::iterator it = tree.begin();
326 BOOST_CHECK_EQUAL(L"", it->first);
327 BOOST_CHECK_EQUAL(L"123", it->second.data());
328 ++it;
329 BOOST_CHECK_EQUAL(L"", it->first);
330 BOOST_CHECK_EQUAL(L"abc", it->second.data());
331 ++it;
332 BOOST_CHECK_EQUAL(L"", it->first);
333 BOOST_CHECK_EQUAL(L"true", it->second.data());
334 ++it;
335 BOOST_CHECK_EQUAL(L"", it->first);
336 BOOST_CHECK_EQUAL(L"null", it->second.data());
337 ++it;
338 BOOST_CHECK_EQUAL(tree.end(), it);
339 }
340
BOOST_AUTO_TEST_CASE(array_values_get_tagged)341 BOOST_AUTO_TEST_CASE(array_values_get_tagged) {
342 ptree tree;
343 prefixing_parser<char> p;
344 const char* input = "[\n"
345 " 123, \"abc\" ,true ,\n"
346 " null\n"
347 " ]";
348 BOOST_REQUIRE(p.parse_array(input, tree));
349 BOOST_REQUIRE_EQUAL(4u, tree.size());
350 BOOST_CHECK_EQUAL("a:", tree.data());
351 ptree::iterator it = tree.begin();
352 BOOST_CHECK_EQUAL("", it->first);
353 BOOST_CHECK_EQUAL("n:123", it->second.data());
354 ++it;
355 BOOST_CHECK_EQUAL("", it->first);
356 BOOST_CHECK_EQUAL("s:abc", it->second.data());
357 ++it;
358 BOOST_CHECK_EQUAL("", it->first);
359 BOOST_CHECK_EQUAL("b:true", it->second.data());
360 ++it;
361 BOOST_CHECK_EQUAL("", it->first);
362 BOOST_CHECK_EQUAL("_:null", it->second.data());
363 ++it;
364 BOOST_CHECK_EQUAL(tree.end(), it);
365 }
366
BOOST_AUTO_TEST_CASE(nested_array)367 BOOST_AUTO_TEST_CASE(nested_array) {
368 ptree tree;
369 standard_parser<char> p;
370 const char* input = "[[1,2],3,[4,5]]";
371 BOOST_REQUIRE(p.parse_array(input, tree));
372 BOOST_REQUIRE_EQUAL(3u, tree.size());
373 ptree::iterator it = tree.begin();
374 BOOST_CHECK_EQUAL("", it->first);
375 {
376 ptree& sub = it->second;
377 BOOST_CHECK_EQUAL("", sub.data());
378 BOOST_REQUIRE_EQUAL(2u, sub.size());
379 ptree::iterator iit = sub.begin();
380 BOOST_CHECK_EQUAL("", iit->first);
381 BOOST_CHECK_EQUAL("1", iit->second.data());
382 ++iit;
383 BOOST_CHECK_EQUAL("", iit->first);
384 BOOST_CHECK_EQUAL("2", iit->second.data());
385 ++iit;
386 BOOST_CHECK_EQUAL(sub.end(), iit);
387 }
388 ++it;
389 BOOST_CHECK_EQUAL("", it->first);
390 BOOST_CHECK_EQUAL("3", it->second.data());
391 ++it;
392 BOOST_CHECK_EQUAL("", it->first);
393 {
394 ptree& sub = it->second;
395 BOOST_CHECK_EQUAL("", sub.data());
396 BOOST_REQUIRE_EQUAL(2u, sub.size());
397 ptree::iterator iit = sub.begin();
398 BOOST_CHECK_EQUAL("", iit->first);
399 BOOST_CHECK_EQUAL("4", iit->second.data());
400 ++iit;
401 BOOST_CHECK_EQUAL("", iit->first);
402 BOOST_CHECK_EQUAL("5", iit->second.data());
403 ++iit;
404 BOOST_CHECK_EQUAL(sub.end(), iit);
405 }
406 ++it;
407 BOOST_CHECK_EQUAL(tree.end(), it);
408 }
409
BOOST_AUTO_TEST_CASE(empty_object)410 BOOST_AUTO_TEST_CASE(empty_object) {
411 ptree tree;
412 standard_parser<char> p;
413 const char* input = " { }";
414 BOOST_REQUIRE(p.parse_object(input, tree));
415 BOOST_CHECK_EQUAL("", tree.data());
416 BOOST_CHECK_EQUAL(0u, tree.size());
417 }
418
BOOST_AUTO_TEST_CASE(object_gets_tagged)419 BOOST_AUTO_TEST_CASE(object_gets_tagged) {
420 wptree tree;
421 prefixing_parser<wchar_t> p;
422 const wchar_t* input = L" { }";
423 BOOST_REQUIRE(p.parse_object(input, tree));
424 BOOST_CHECK_EQUAL(L"o:", tree.data());
425 BOOST_CHECK_EQUAL(0u, tree.size());
426 }
427
BOOST_AUTO_TEST_CASE(object_with_values)428 BOOST_AUTO_TEST_CASE(object_with_values) {
429 wptree tree;
430 standard_parser<wchar_t> p;
431 const wchar_t* input = L"{\n"
432 L" \"1\":123, \"2\"\n"
433 L" :\"abc\" ,\"3\": true ,\n"
434 L" \"4\" : null\n"
435 L" }";
436 BOOST_REQUIRE(p.parse_object(input, tree));
437 BOOST_REQUIRE_EQUAL(4u, tree.size());
438 wptree::iterator it = tree.begin();
439 BOOST_CHECK_EQUAL(L"1", it->first);
440 BOOST_CHECK_EQUAL(L"123", it->second.data());
441 ++it;
442 BOOST_CHECK_EQUAL(L"2", it->first);
443 BOOST_CHECK_EQUAL(L"abc", it->second.data());
444 ++it;
445 BOOST_CHECK_EQUAL(L"3", it->first);
446 BOOST_CHECK_EQUAL(L"true", it->second.data());
447 ++it;
448 BOOST_CHECK_EQUAL(L"4", it->first);
449 BOOST_CHECK_EQUAL(L"null", it->second.data());
450 ++it;
451 BOOST_CHECK_EQUAL(tree.end(), it);
452 }
453
BOOST_AUTO_TEST_CASE(object_values_get_tagged)454 BOOST_AUTO_TEST_CASE(object_values_get_tagged) {
455 ptree tree;
456 prefixing_parser<char> p;
457 const char* input = "{\n"
458 "\"1\": 123, \"2\": \"abc\" ,\"3\": true ,\n"
459 "\"4\": null\n"
460 "}";
461 BOOST_REQUIRE(p.parse_object(input, tree));
462 BOOST_REQUIRE_EQUAL(4u, tree.size());
463 BOOST_CHECK_EQUAL("o:", tree.data());
464 ptree::iterator it = tree.begin();
465 BOOST_CHECK_EQUAL("1", it->first);
466 BOOST_CHECK_EQUAL("n:123", it->second.data());
467 ++it;
468 BOOST_CHECK_EQUAL("2", it->first);
469 BOOST_CHECK_EQUAL("s:abc", it->second.data());
470 ++it;
471 BOOST_CHECK_EQUAL("3", it->first);
472 BOOST_CHECK_EQUAL("b:true", it->second.data());
473 ++it;
474 BOOST_CHECK_EQUAL("4", it->first);
475 BOOST_CHECK_EQUAL("_:null", it->second.data());
476 ++it;
477 BOOST_CHECK_EQUAL(tree.end(), it);
478 }
479
BOOST_AUTO_TEST_CASE(nested_object)480 BOOST_AUTO_TEST_CASE(nested_object) {
481 ptree tree;
482 standard_parser<char> p;
483 const char* input = "{\"a\":{\"b\":1,\"c\":2},\"d\":3,\"e\":{\"f\":4,\"g\":5}}";
484 BOOST_REQUIRE(p.parse_object(input, tree));
485 BOOST_REQUIRE_EQUAL(3u, tree.size());
486 ptree::iterator it = tree.begin();
487 BOOST_CHECK_EQUAL("a", it->first);
488 {
489 ptree& sub = it->second;
490 BOOST_CHECK_EQUAL("", sub.data());
491 BOOST_REQUIRE_EQUAL(2u, sub.size());
492 ptree::iterator iit = sub.begin();
493 BOOST_CHECK_EQUAL("b", iit->first);
494 BOOST_CHECK_EQUAL("1", iit->second.data());
495 ++iit;
496 BOOST_CHECK_EQUAL("c", iit->first);
497 BOOST_CHECK_EQUAL("2", iit->second.data());
498 ++iit;
499 BOOST_CHECK_EQUAL(sub.end(), iit);
500 }
501 ++it;
502 BOOST_CHECK_EQUAL("d", it->first);
503 BOOST_CHECK_EQUAL("3", it->second.data());
504 ++it;
505 BOOST_CHECK_EQUAL("e", it->first);
506 {
507 ptree& sub = it->second;
508 BOOST_CHECK_EQUAL("", sub.data());
509 BOOST_REQUIRE_EQUAL(2u, sub.size());
510 ptree::iterator iit = sub.begin();
511 BOOST_CHECK_EQUAL("f", iit->first);
512 BOOST_CHECK_EQUAL("4", iit->second.data());
513 ++iit;
514 BOOST_CHECK_EQUAL("g", iit->first);
515 BOOST_CHECK_EQUAL("5", iit->second.data());
516 ++iit;
517 BOOST_CHECK_EQUAL(sub.end(), iit);
518 }
519 ++it;
520 BOOST_CHECK_EQUAL(tree.end(), it);
521 }
522
BOOST_AUTO_TEST_CASE(array_in_object)523 BOOST_AUTO_TEST_CASE(array_in_object) {
524 ptree tree;
525 standard_parser<char> p;
526 const char* input = "{\"a\":[1,2],\"b\":3,\"c\":[4,5]}";
527 BOOST_REQUIRE(p.parse_object(input, tree));
528 BOOST_REQUIRE_EQUAL(3u, tree.size());
529 ptree::iterator it = tree.begin();
530 BOOST_CHECK_EQUAL("a", it->first);
531 {
532 ptree& sub = it->second;
533 BOOST_CHECK_EQUAL("", sub.data());
534 BOOST_REQUIRE_EQUAL(2u, sub.size());
535 ptree::iterator iit = sub.begin();
536 BOOST_CHECK_EQUAL("", iit->first);
537 BOOST_CHECK_EQUAL("1", iit->second.data());
538 ++iit;
539 BOOST_CHECK_EQUAL("", iit->first);
540 BOOST_CHECK_EQUAL("2", iit->second.data());
541 ++iit;
542 BOOST_CHECK_EQUAL(sub.end(), iit);
543 }
544 ++it;
545 BOOST_CHECK_EQUAL("b", it->first);
546 BOOST_CHECK_EQUAL("3", it->second.data());
547 ++it;
548 BOOST_CHECK_EQUAL("c", it->first);
549 {
550 ptree& sub = it->second;
551 BOOST_CHECK_EQUAL("", sub.data());
552 BOOST_REQUIRE_EQUAL(2u, sub.size());
553 ptree::iterator iit = sub.begin();
554 BOOST_CHECK_EQUAL("", iit->first);
555 BOOST_CHECK_EQUAL("4", iit->second.data());
556 ++iit;
557 BOOST_CHECK_EQUAL("", iit->first);
558 BOOST_CHECK_EQUAL("5", iit->second.data());
559 ++iit;
560 BOOST_CHECK_EQUAL(sub.end(), iit);
561 }
562 ++it;
563 BOOST_CHECK_EQUAL(tree.end(), it);
564 }
565
BOOST_AUTO_TEST_CASE(object_in_array)566 BOOST_AUTO_TEST_CASE(object_in_array) {
567 ptree tree;
568 standard_parser<char> p;
569 const char* input = "[{\"a\":1,\"b\":2},3,{\"c\":4,\"d\":5}]";
570 BOOST_REQUIRE(p.parse_array(input, tree));
571 BOOST_REQUIRE_EQUAL(3u, tree.size());
572 ptree::iterator it = tree.begin();
573 BOOST_CHECK_EQUAL("", it->first);
574 {
575 ptree& sub = it->second;
576 BOOST_CHECK_EQUAL("", sub.data());
577 BOOST_REQUIRE_EQUAL(2u, sub.size());
578 ptree::iterator iit = sub.begin();
579 BOOST_CHECK_EQUAL("a", iit->first);
580 BOOST_CHECK_EQUAL("1", iit->second.data());
581 ++iit;
582 BOOST_CHECK_EQUAL("b", iit->first);
583 BOOST_CHECK_EQUAL("2", iit->second.data());
584 ++iit;
585 BOOST_CHECK_EQUAL(sub.end(), iit);
586 }
587 ++it;
588 BOOST_CHECK_EQUAL("", it->first);
589 BOOST_CHECK_EQUAL("3", it->second.data());
590 ++it;
591 BOOST_CHECK_EQUAL("", it->first);
592 {
593 ptree& sub = it->second;
594 BOOST_CHECK_EQUAL("", sub.data());
595 BOOST_REQUIRE_EQUAL(2u, sub.size());
596 ptree::iterator iit = sub.begin();
597 BOOST_CHECK_EQUAL("c", iit->first);
598 BOOST_CHECK_EQUAL("4", iit->second.data());
599 ++iit;
600 BOOST_CHECK_EQUAL("d", iit->first);
601 BOOST_CHECK_EQUAL("5", iit->second.data());
602 ++iit;
603 BOOST_CHECK_EQUAL(sub.end(), iit);
604 }
605 ++it;
606 BOOST_CHECK_EQUAL(tree.end(), it);
607 }
608
BOOST_AUTO_TEST_CASE(parser_works_with_input_iterators)609 BOOST_AUTO_TEST_CASE(parser_works_with_input_iterators) {
610 const char* input = " {\n"
611 " \"1\":123, \"2\"\n"
612 " :\"abc\" ,\"3\": true ,\n"
613 " \"4\" : null, \"5\" : [ 1, 23\n"
614 " , 456 ]\n"
615 " }";
616
617 std::istringstream is(input);
618 typedef std::istreambuf_iterator<char> iterator;
619 json_parser::detail::standard_callbacks<ptree> callbacks;
620 json_parser::detail::utf8_utf8_encoding encoding;
621 json_parser::detail::parser<json_parser::detail::standard_callbacks<ptree>,
622 json_parser::detail::utf8_utf8_encoding,
623 iterator, iterator>
624 p(callbacks, encoding);
625
626 p.set_input("", boost::make_iterator_range(iterator(is), iterator()));
627 p.parse_value();
628
629 const ptree& tree = callbacks.output();
630 BOOST_REQUIRE_EQUAL(5u, tree.size());
631 ptree::const_iterator it = tree.begin();
632 BOOST_CHECK_EQUAL("1", it->first);
633 BOOST_CHECK_EQUAL("123", it->second.data());
634 ++it;
635 BOOST_CHECK_EQUAL("2", it->first);
636 BOOST_CHECK_EQUAL("abc", it->second.data());
637 ++it;
638 BOOST_CHECK_EQUAL("3", it->first);
639 BOOST_CHECK_EQUAL("true", it->second.data());
640 ++it;
641 BOOST_CHECK_EQUAL("4", it->first);
642 BOOST_CHECK_EQUAL("null", it->second.data());
643 ++it;
644 BOOST_CHECK_EQUAL("5", it->first);
645 {
646 const ptree& sub = it->second;
647 BOOST_CHECK_EQUAL("", sub.data());
648 BOOST_REQUIRE_EQUAL(3u, sub.size());
649 ptree::const_iterator iit = sub.begin();
650 BOOST_CHECK_EQUAL("", iit->first);
651 BOOST_CHECK_EQUAL("1", iit->second.data());
652 ++iit;
653 BOOST_CHECK_EQUAL("", iit->first);
654 BOOST_CHECK_EQUAL("23", iit->second.data());
655 ++iit;
656 BOOST_CHECK_EQUAL("", iit->first);
657 BOOST_CHECK_EQUAL("456", iit->second.data());
658 ++iit;
659 BOOST_CHECK_EQUAL(sub.end(), iit);
660 }
661 ++it;
662 BOOST_CHECK_EQUAL(tree.end(), it);
663 }
664
665 struct bad_parse_n {
666 const char* json;
667 const char* message_substring;
668 };
669
parse_error_thrown_with_message_n(bad_parse_n param)670 void parse_error_thrown_with_message_n(bad_parse_n param) {
671 try {
672 standard_parser<char> p;
673 ptree dummy;
674 p.parse_value(param.json, dummy);
675 BOOST_FAIL("expected exception");
676 } catch (json_parser::json_parser_error& e) {
677 std::string message = e.message();
678 BOOST_CHECK_MESSAGE(message.find(param.message_substring) !=
679 std::string::npos,
680 "bad error message on input '" << param.json
681 << "', need: '" << param.message_substring
682 << "' but found '" << message << "'");
683 }
684 }
685
686 const bad_parse_n errors_n[] = {
687 {"", "expected value"},
688 {"(", "expected value"},
689
690 {"n", "expected 'null'"},
691 {"nu", "expected 'null'"},
692 {"nul", "expected 'null'"},
693 {"n ", "expected 'null'"},
694 {"nu ", "expected 'null'"},
695 {"nul ", "expected 'null'"},
696 {"nx", "expected 'null'"},
697 {"nux", "expected 'null'"},
698 {"nulx", "expected 'null'"},
699
700 {"t", "expected 'true'"},
701 {"tr", "expected 'true'"},
702 {"tu", "expected 'true'"},
703 {"t ", "expected 'true'"},
704 {"tr ", "expected 'true'"},
705 {"tru ", "expected 'true'"},
706 {"tx", "expected 'true'"},
707 {"trx", "expected 'true'"},
708 {"trux", "expected 'true'"},
709
710 {"f", "expected 'false'"},
711 {"fa", "expected 'false'"},
712 {"fal", "expected 'false'"},
713 {"fals", "expected 'false'"},
714 {"f ", "expected 'false'"},
715 {"fa ", "expected 'false'"},
716 {"fal ", "expected 'false'"},
717 {"fals ", "expected 'false'"},
718 {"fx", "expected 'false'"},
719 {"fax", "expected 'false'"},
720 {"falx", "expected 'false'"},
721 {"falsx", "expected 'false'"},
722
723 {"-", "expected digits"},
724 {"01", "garbage after data"},
725 {"0.", "need at least one digit after '.'"},
726 {"0e", "need at least one digit in exponent"},
727 {"0e-", "need at least one digit in exponent"},
728
729 {"\"", "unterminated string"},
730 {"\"asd", "unterminated string"},
731 {"\"\n\"", "invalid code sequence"}, // control character
732 {"\"\xff\"", "invalid code sequence"}, // bad lead byte
733 {"\"\x80\"", "invalid code sequence"}, // stray trail byte
734 {"\"\xc0", "invalid code sequence"}, // eos after lead byte
735 {"\"\xc0\"", "invalid code sequence"}, // bad trail byte
736 {"\"\xc0m\"", "invalid code sequence"}, // also bad trail byte
737 {"\"\\", "invalid escape sequence"},
738 {"\"\\p\"", "invalid escape sequence"},
739 {"\"\\u", "invalid escape sequence"},
740 {"\"\\u\"", "invalid escape sequence"},
741 {"\"\\ug\"", "invalid escape sequence"},
742 {"\"\\u1\"", "invalid escape sequence"},
743 {"\"\\u1g\"", "invalid escape sequence"},
744 {"\"\\u11\"", "invalid escape sequence"},
745 {"\"\\u11g\"", "invalid escape sequence"},
746 {"\"\\u111\"", "invalid escape sequence"},
747 {"\"\\u111g\"", "invalid escape sequence"},
748 {"\"\\ude00\"", "stray low surrogate"},
749 {"\"\\ud900", "stray high surrogate"},
750 {"\"\\ud900foo\"", "stray high surrogate"},
751 {"\"\\ud900\\", "expected codepoint reference"},
752 {"\"\\ud900\\n\"", "expected codepoint reference"},
753 {"\"\\ud900\\u1000\"", "expected low surrogate"},
754
755 {"[", "expected value"},
756 {"[1", "expected ']' or ','"},
757 {"[1,", "expected value"},
758 {"[1,]", "expected value"},
759 {"[1}", "expected ']' or ','"},
760
761 {"{", "expected key string"},
762 {"{1:2}", "expected key string"},
763 {"{\"\"", "expected ':'"},
764 {"{\"\"}", "expected ':'"},
765 {"{\"\":", "expected value"},
766 {"{\"\":}", "expected value"},
767 {"{\"\":0", "expected '}' or ','"},
768 {"{\"\":0]", "expected '}' or ','"},
769 {"{\"\":0,", "expected key string"},
770 {"{\"\":0,}", "expected key string"},
771 };
772
773 struct bad_parse_w {
774 const wchar_t* json;
775 const char* message_substring;
776 };
777
parse_error_thrown_with_message_w(bad_parse_w param)778 void parse_error_thrown_with_message_w(bad_parse_w param) {
779 try {
780 standard_parser<wchar_t> p;
781 wptree dummy;
782 p.parse_value(param.json, dummy);
783 BOOST_FAIL("expected exception");
784 } catch (json_parser::json_parser_error& e) {
785 std::string message = e.message();
786 BOOST_CHECK_MESSAGE(message.find(param.message_substring) !=
787 std::string::npos,
788 "bad error message on input '" << param.json
789 << "', need: '" << param.message_substring
790 << "' but found '" << message << "'");
791 }
792 }
793
794 const bad_parse_w errors_w[] = {
795 {L"", "expected value"},
796 {L"(", "expected value"},
797
798 {L"n", "expected 'null'"},
799 {L"nu", "expected 'null'"},
800 {L"nul", "expected 'null'"},
801 {L"n ", "expected 'null'"},
802 {L"nu ", "expected 'null'"},
803 {L"nul ", "expected 'null'"},
804 {L"nx", "expected 'null'"},
805 {L"nux", "expected 'null'"},
806 {L"nulx", "expected 'null'"},
807
808 {L"t", "expected 'true'"},
809 {L"tr", "expected 'true'"},
810 {L"tu", "expected 'true'"},
811 {L"t ", "expected 'true'"},
812 {L"tr ", "expected 'true'"},
813 {L"tru ", "expected 'true'"},
814 {L"tx", "expected 'true'"},
815 {L"trx", "expected 'true'"},
816 {L"trux", "expected 'true'"},
817
818 {L"f", "expected 'false'"},
819 {L"fa", "expected 'false'"},
820 {L"fal", "expected 'false'"},
821 {L"fals", "expected 'false'"},
822 {L"f ", "expected 'false'"},
823 {L"fa ", "expected 'false'"},
824 {L"fal ", "expected 'false'"},
825 {L"fals ", "expected 'false'"},
826 {L"fx", "expected 'false'"},
827 {L"fax", "expected 'false'"},
828 {L"falx", "expected 'false'"},
829 {L"falsx", "expected 'false'"},
830
831 {L"-", "expected digits"},
832 {L"01", "garbage after data"},
833 {L"0.", "need at least one digit after '.'"},
834 {L"0e", "need at least one digit in exponent"},
835 {L"0e-", "need at least one digit in exponent"},
836
837 {L"\"", "unterminated string"},
838 {L"\"asd", "unterminated string"},
839 {L"\"\n\"", "invalid code sequence"}, // control character
840 // Encoding not known, so no UTF-16 encoding error tests.
841 {L"\"\\", "invalid escape sequence"},
842 {L"\"\\p\"", "invalid escape sequence"},
843 {L"\"\\u", "invalid escape sequence"},
844 {L"\"\\u\"", "invalid escape sequence"},
845 {L"\"\\ug\"", "invalid escape sequence"},
846 {L"\"\\u1\"", "invalid escape sequence"},
847 {L"\"\\u1g\"", "invalid escape sequence"},
848 {L"\"\\u11\"", "invalid escape sequence"},
849 {L"\"\\u11g\"", "invalid escape sequence"},
850 {L"\"\\u111\"", "invalid escape sequence"},
851 {L"\"\\u111g\"", "invalid escape sequence"},
852 {L"\"\\ude00\"", "stray low surrogate"},
853 {L"\"\\ud900", "stray high surrogate"},
854 {L"\"\\ud900foo\"", "stray high surrogate"},
855 {L"\"\\ud900\\", "expected codepoint reference"},
856 {L"\"\\ud900\\n\"", "expected codepoint reference"},
857 {L"\"\\ud900\\u1000\"", "expected low surrogate"},
858
859 {L"[", "expected value"},
860 {L"[1", "expected ']' or ','"},
861 {L"[1,", "expected value"},
862 {L"[1,]", "expected value"},
863 {L"[1}", "expected ']' or ','"},
864
865 {L"{", "expected key string"},
866 {L"{1:2}", "expected key string"},
867 {L"{\"\"", "expected ':'"},
868 {L"{\"\"}", "expected ':'"},
869 {L"{\"\":", "expected value"},
870 {L"{\"\":}", "expected value"},
871 {L"{\"\":0", "expected '}' or ','"},
872 {L"{\"\":0]", "expected '}' or ','"},
873 {L"{\"\":0,", "expected key string"},
874 {L"{\"\":0,}", "expected key string"},
875 };
876
877 template <typename T, std::size_t N>
arraysize(T (&)[N])878 std::size_t arraysize(T(&)[N]) { return N; }
879
880 #define ARRAY_TEST_CASE(fn, a) \
881 BOOST_PARAM_TEST_CASE(fn, (a), (a) + arraysize((a)))
882
883 using namespace boost::unit_test;
884
init_unit_test_suite(int,char * [])885 test_suite* init_unit_test_suite(int, char*[])
886 {
887 master_test_suite_t& ts = boost::unit_test::framework::master_test_suite();
888 ts.add(ARRAY_TEST_CASE(boolean_parse_result_is_input_n, booleans_n));
889 ts.add(ARRAY_TEST_CASE(boolean_parse_result_is_input_w, booleans_w));
890 ts.add(ARRAY_TEST_CASE(number_parse_result_is_input_n, numbers_n));
891 ts.add(ARRAY_TEST_CASE(number_parse_result_is_input_w, numbers_w));
892 ts.add(ARRAY_TEST_CASE(string_parsed_correctly_n, strings_n));
893 ts.add(ARRAY_TEST_CASE(string_parsed_correctly_w, strings_w));
894 ts.add(ARRAY_TEST_CASE(parse_error_thrown_with_message_n, errors_n));
895 ts.add(ARRAY_TEST_CASE(parse_error_thrown_with_message_w, errors_w));
896
897 return 0;
898 }
899