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