• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2002-2006 Marcin Kalicinski
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // For more information, see www.boost.org
9 // ----------------------------------------------------------------------------
10 
11 #include "test_utils.hpp"
12 #include <boost/property_tree/json_parser.hpp>
13 
14 ///////////////////////////////////////////////////////////////////////////////
15 // Test data
16 
17 const char *ok_data_1 =
18     "{}";
19 
20 const char *ok_data_2 =
21     "  \t {\n"
22     "  \t \"name 0\" : \"value\", \t \n"
23     "  \t \"name 1\" : \"\", \n"
24     "  \t \"name 2\" : true, \n"
25     "  \t \"name 3\" : false, \n"
26     "  \t \"name 4\" : null, \n"
27     "  \t \"name 5\" : 0, \n"
28     "  \t \"name 6\" : -5, \n"
29     "  \t \"name 7\" : 1.1, \n"
30     "  \t \"name 8\" : -956.45e+4, \n"
31     "  \t \"name 8\" : 5956.45E-11, \n"
32     "  \t \"name 9\" : [1,2,3,4], \n"
33     "  \t \"name 10\" : {\"a\":\"b\"} \n"
34     "  \t } \n";
35 
36 const char *ok_data_3 =
37     "{\"a\":{\"b\":\"c\"}}";
38 
39 const char *ok_data_4 =
40     "{\"a\":[{\"b\":\"c\"},{\"d\":\"e\"},1,2,3,4],\"f\":null}";
41 
42 const char *ok_data_6 =
43     "{\"menu\": {\n"
44     "    \"header\": \"SVG Viewer\",\n"
45     "    \"items\": [\n"
46     "        {\"id\": \"Open\"},\n"
47     "        {\"id\": \"OpenNew\", \"label\": \"Open New\"},\n"
48     "        null,\n"
49     "        {\"id\": \"ZoomIn\", \"label\": \"Zoom In\"},\n"
50     "        {\"id\": \"ZoomOut\", \"label\": \"Zoom Out\"},\n"
51     "        {\"id\": \"OriginalView\", \"label\": \"Original View\"},\n"
52     "        null,\n"
53     "        {\"id\": \"Quality\"},\n"
54     "        {\"id\": \"Pause\"},\n"
55     "        {\"id\": \"Mute\"},\n"
56     "        null,\n"
57     "        {\"id\": \"Find\", \"label\": \"Find...\"},\n"
58     "        {\"id\": \"FindAgain\", \"label\": \"Find Again\"},\n"
59     "        {\"id\": \"Copy\"},\n"
60     "        {\"id\": \"CopyAgain\", \"label\": \"Copy Again\"},\n"
61     "        {\"id\": \"CopySVG\", \"label\": \"Copy SVG\"},\n"
62     "        {\"id\": \"ViewSVG\", \"label\": \"View SVG\"},\n"
63     "        {\"id\": \"ViewSource\", \"label\": \"View Source\"},\n"
64     "        {\"id\": \"SaveAs\", \"label\": \"Save As\"},\n"
65     "        null,\n"
66     "        {\"id\": \"Help\"},\n"
67     "        {\"id\": \"About\", \"label\": \"About Adobe CVG Viewer...\"}\n"
68     "    ]\n"
69     "}}\n";
70 
71 const char *ok_data_7 =
72     "{\"web-app\": {\n"
73     "  \"servlet\": [    \n"
74     "    {\n"
75     "      \"servlet-name\": \"cofaxCDS\",\n"
76     "      \"servlet-class\": \"org.cofax.cds.CDSServlet\",\n"
77     "      \"init-param\": {\n"
78     "        \"configGlossary:installationAt\": \"Philadelphia, PA\",\n"
79     "        \"configGlossary:adminEmail\": \"ksm@pobox.com\",\n"
80     "        \"configGlossary:poweredBy\": \"Cofax\",\n"
81     "        \"configGlossary:poweredByIcon\": \"/images/cofax.gif\",\n"
82     "        \"configGlossary:staticPath\": \"/content/static\",\n"
83     "        \"templateProcessorClass\": \"org.cofax.WysiwygTemplate\",\n"
84     "        \"templateLoaderClass\": \"org.cofax.FilesTemplateLoader\",\n"
85     "        \"templatePath\": \"templates\",\n"
86     "        \"templateOverridePath\": \"\",\n"
87     "        \"defaultListTemplate\": \"listTemplate.htm\",\n"
88     "        \"defaultFileTemplate\": \"articleTemplate.htm\",\n"
89     "        \"useJSP\": false,\n"
90     "        \"jspListTemplate\": \"listTemplate.jsp\",\n"
91     "        \"jspFileTemplate\": \"articleTemplate.jsp\",\n"
92     "        \"cachePackageTagsTrack\": 200,\n"
93     "        \"cachePackageTagsStore\": 200,\n"
94     "        \"cachePackageTagsRefresh\": 60,\n"
95     "        \"cacheTemplatesTrack\": 100,\n"
96     "        \"cacheTemplatesStore\": 50,\n"
97     "        \"cacheTemplatesRefresh\": 15,\n"
98     "        \"cachePagesTrack\": 200,\n"
99     "        \"cachePagesStore\": 100,\n"
100     "        \"cachePagesRefresh\": 10,\n"
101     "        \"cachePagesDirtyRead\": 10,\n"
102     "        \"searchEngineListTemplate\": \"forSearchEnginesList.htm\",\n"
103     "        \"searchEngineFileTemplate\": \"forSearchEngines.htm\",\n"
104     "        \"searchEngineRobotsDb\": \"WEB-INF/robots.db\",\n"
105     "        \"useDataStore\": true,\n"
106     "        \"dataStoreClass\": \"org.cofax.SqlDataStore\",\n"
107     "        \"redirectionClass\": \"org.cofax.SqlRedirection\",\n"
108     "        \"dataStoreName\": \"cofax\",\n"
109     "        \"dataStoreDriver\": \"com.microsoft.jdbc.sqlserver.SQLServerDriver\",\n"
110     "        \"dataStoreUrl\": \"jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon\",\n"
111     "        \"dataStoreUser\": \"sa\",\n"
112     "        \"dataStorePassword\": \"dataStoreTestQuery\",\n"
113     "        \"dataStoreTestQuery\": \"SET NOCOUNT ON;select test='test';\",\n"
114     "        \"dataStoreLogFile\": \"/usr/local/tomcat/logs/datastore.log\",\n"
115     "        \"dataStoreInitConns\": 10,\n"
116     "        \"dataStoreMaxConns\": 100,\n"
117     "        \"dataStoreConnUsageLimit\": 100,\n"
118     "        \"dataStoreLogLevel\": \"debug\",\n"
119     "        \"maxUrlLength\": 500}},\n"
120     "    {\n"
121     "      \"servlet-name\": \"cofaxEmail\",\n"
122     "\n      \"servlet-class\": \"org.cofax.cds.EmailServlet\",\n"
123     "      \"init-param\": {\n"
124     "      \"mailHost\": \"mail1\",\n"
125     "      \"mailHostOverride\": \"mail2\"}},\n"
126     "    {\n"
127     "      \"servlet-name\": \"cofaxAdmin\",\n"
128     "      \"servlet-class\": \"org.cofax.cds.AdminServlet\"},\n"
129     " \n"
130     "    {\n"
131     "      \"servlet-name\": \"fileServlet\",\n"
132     "      \"servlet-class\": \"org.cofax.cds.FileServlet\"},\n"
133     "    {\n"
134     "      \"servlet-name\": \"cofaxTools\",\n"
135     "      \"servlet-class\": \"org.cofax.cms.CofaxToolsServlet\",\n"
136     "      \"init-param\": {\n"
137     "        \"templatePath\": \"toolstemplates/\",\n"
138     "        \"log\": 1,\n"
139     "        \"logLocation\": \"/usr/local/tomcat/logs/CofaxTools.log\",\n"
140     "        \"logMaxSize\": \"\",\n"
141     "        \"dataLog\": 1,\n"
142     "        \"dataLogLocation\": \"/usr/local/tomcat/logs/dataLog.log\",\n"
143     "        \"dataLogMaxSize\": \"\",\n"
144     "        \"removePageCache\": \"/content/admin/remove?cache=pages&id=\",\n"
145     "        \"removeTemplateCache\": \"/content/admin/remove?cache=templates&id=\",\n"
146     "        \"fileTransferFolder\": \"/usr/local/tomcat/webapps/content/fileTransferFolder\",\n"
147     "        \"lookInContext\": 1,\n"
148     "        \"adminGroupID\": 4,\n"
149     "        \"betaServer\": true}}],\n"
150     "  \"servlet-mapping\": {\n"
151     "    \"cofaxCDS\": \"/\",\n"
152     "    \"cofaxEmail\": \"/cofaxutil/aemail/*\",\n"
153     "    \"cofaxAdmin\": \"/admin/*\",\n"
154     "    \"fileServlet\": \"/static/*\",\n"
155     "    \"cofaxTools\": \"/tools/*\"},\n"
156     " \n"
157     "  \"taglib\": {\n"
158     "    \"taglib-uri\": \"cofax.tld\",\n"
159     "    \"taglib-location\": \"/WEB-INF/tlds/cofax.tld\"}}}\n";
160 
161 const char *ok_data_8 =
162     "{\"widget\": {\n"
163     "    \"debug\": \"on\",\n"
164     "    \"window\": {\n"
165     "        \"title\": \"Sample Konfabulator Widget\",        \"name\": \"main_window\",        \"width\": 500,        \"height\": 500\n"
166     "    },    \"image\": { \n"
167     "        \"src\": \"Images/Sun.png\",\n"
168     "        \"name\": \"sun1\",        \"hOffset\": 250,        \"vOffset\": 250,        \"alignment\": \"center\"\n"
169     "    },    \"text\": {\n"
170     "        \"data\": \"Click Here\",\n"
171     "        \"size\": 36,\n"
172     "        \"style\": \"bold\",        \"name\": \"text1\",        \"hOffset\": 250,        \"vOffset\": 100,        \"alignment\": \"center\",\n"
173     "        \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n"
174     "    }\n"
175     "}} \n";
176 
177 const char *ok_data_9 =
178     "{\"menu\": {\n"
179     "  \"id\": \"file\",\n"
180     "  \"value\": \"File:\",\n"
181     "  \"popup\": {\n"
182     "    \"menuitem\": [\n"
183     "      {\"value\": \"New\", \"onclick\": \"CreateNewDoc()\"},\n"
184     "      {\"value\": \"Open\", \"onclick\": \"OpenDoc()\"},\n"
185     "\n      {\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}\n"
186     "    ]\n"
187     "  }\n"
188     "}}\n";
189 
190 const char *ok_data_10 =
191     "{\n"
192     "   \"glossary\": {\n"
193     "       \"title\": \"example glossary\",\n"
194     "       \"GlossDiv\": {\n"
195     "           \"title\": \"S\",\n"
196     "           \"GlossList\": [{\n"
197     "                \"ID\": \"SGML\",\n"
198     "                \"SortAs\": \"SGML\",\n"
199     "                \"GlossTerm\": \"Standard Generalized Markup Language\",\n"
200     "                \"Acronym\": \"SGML\",\n"
201     "                \"Abbrev\": \"ISO 8879:1986\",\n"
202     "                \"GlossDef\": \n"
203     "\"A meta-markup language, used to create markup languages such as DocBook.\",\n"
204     "                \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"]\n"
205     "            }]\n"
206     "        }\n"
207     "    }\n"
208     "}\n";
209 
210 const char *ok_data_11 =
211     "{\n"
212     "    \"data\" : [\n"
213     "        {\n"
214     "            \"First Name\" : \"Bob\",\n"
215     "            \"Last Name\" : \"Smith\",\n"
216     "            \"Email\" : \"bsmith@someurl.com\",\n"
217     "            \"Phone\" : \"(555) 555-1212\"\n"
218     "        },\n"
219     "        {\n"
220     "            \"First Name\" : \"Jan\",\n"
221     "            \"Last Name\" : \"Smith\",\n"
222     "            \"Email\" : \"jsmith@someurl.com\",\n"
223     "            \"Phone\" : \"(555) 555-3434\"\n"
224     "        },\n"
225     "        {\n"
226     "            \"First Name\" : \"Sue\",\n"
227     "            \"Last Name\" : \"Smith\",\n"
228     "            \"Email\" : \"ssmith@someurl.com\",\n"
229     "            \"Phone\" : \"(555) 555-5656\"\n"
230     "        }\n"
231     "    ]\n"
232     "}\n";
233 
234 const char *ok_data_12 =
235     "{\"  \\\" \\\\ \\b \\f \\n \\r \\t  \" : \"\"}";
236 
237 const char *error_data_1 =
238     "";   // No root object
239 
240 const char *error_data_2 =
241     "{\n\"a\":1\n";      // Unclosed object brace
242 
243 const char *error_data_3 =
244     "{\n\"a\":\n[1,2,3,4\n}";      // Unclosed array brace
245 
246 const char *error_data_4 =
247     "{\n\"a\"\n}";      // No object
248 
249 const char *bug_data_pr4387 =
250     "[1, 2, 3]"; // Root array
251 
252 const char *bug_data_pr7180_1 =
253     "{\n"
254     "    \"a\": [\n"
255     "        \"1\",\n"
256     "        \"2\"\n"
257     "    ]\n"
258     "}\n";
259 const char *bug_data_pr7180_2 =
260     "{\"a\":[\"1\",\"2\"]}\n";
261 
262 struct ReadFunc
263 {
264     template<class Ptree>
operator ()ReadFunc265     void operator()(const std::string &filename, Ptree &pt) const
266     {
267         boost::property_tree::read_json(filename, pt);
268     }
269     template <class Ptree>
operator ()ReadFunc270     void operator()(
271         std::basic_istream<typename Ptree::key_type::value_type>& is,
272         Ptree& pt) const
273     {
274         boost::property_tree::read_json(is, pt);
275     }
276 };
277 
278 struct WriteFunc
279 {
WriteFuncWriteFunc280     WriteFunc(bool pretty = false) : pretty(pretty) {}
281 
282     template<class Ptree>
operator ()WriteFunc283     void operator()(const std::string &filename, const Ptree &pt) const
284     {
285         boost::property_tree::write_json(filename, pt, std::locale(), pretty);
286     }
287 
288     template<class Ptree>
operator ()WriteFunc289     void operator()(
290         std::basic_ostream<typename Ptree::key_type::value_type>& os,
291         Ptree& pt) const
292     {
293         boost::property_tree::write_json(os, pt, pretty);
294     }
295 
296     bool pretty;
297 };
298 
299 template<class Ptree>
test_json_parser()300 void test_json_parser()
301 {
302 
303     using namespace boost::property_tree;
304 
305     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
306     (
307         ReadFunc(), WriteFunc(false), ok_data_1, NULL,
308         "testok1.json", NULL, "testok1out.json", 1, 0, 0
309     );
310 
311     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
312     (
313         ReadFunc(), WriteFunc(false), ok_data_2, NULL,
314         "testok2.json", NULL, "testok2out.json", 18, 50, 74
315     );
316 
317     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
318     (
319         ReadFunc(), WriteFunc(false), ok_data_3, NULL,
320         "testok3.json", NULL, "testok3out.json", 3, 1, 2
321     );
322 
323     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
324     (
325         ReadFunc(), WriteFunc(false), ok_data_4, NULL,
326         "testok4.json", NULL, "testok4out.json", 11, 10, 4
327     );
328 
329     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
330     (
331         ReadFunc(), WriteFunc(false), ok_data_6, NULL,
332         "testok6.json", NULL, "testok6out.json", 56, 265, 111
333     );
334 
335     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
336     (
337         ReadFunc(), WriteFunc(false), ok_data_7, NULL,
338         "testok7.json", NULL, "testok7out.json", 87, 1046, 1216
339     );
340 
341     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
342     (
343         ReadFunc(), WriteFunc(false), ok_data_8, NULL,
344         "testok8.json", NULL, "testok8out.json", 23, 149, 125
345     );
346 
347     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
348     (
349         ReadFunc(), WriteFunc(false), ok_data_9, NULL,
350         "testok9.json", NULL, "testok9out.json", 15, 54, 60
351     );
352 
353     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
354     (
355         ReadFunc(), WriteFunc(false), ok_data_10, NULL,
356         "testok10.json", NULL, "testok10out.json", 17, 162, 85
357     );
358 
359     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
360     (
361         ReadFunc(), WriteFunc(false), ok_data_11, NULL,
362         "testok11.json", NULL, "testok11out.json", 17, 120, 91
363     );
364 
365     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
366     (
367         ReadFunc(), WriteFunc(false), ok_data_12, NULL,
368         "testok12.json", NULL, "testok12out.json", 2, 0, 17
369     );
370 
371     generic_parser_test_error<ptree, ReadFunc, WriteFunc, json_parser_error>
372     (
373         ReadFunc(), WriteFunc(false), error_data_1, NULL,
374         "testerr1.json", NULL, "testerr1out.json", 1
375     );
376 
377     generic_parser_test_error<ptree, ReadFunc, WriteFunc, json_parser_error>
378     (
379         ReadFunc(), WriteFunc(false), error_data_2, NULL,
380         "testerr2.json", NULL, "testerr2out.json", 3
381     );
382 
383     generic_parser_test_error<ptree, ReadFunc, WriteFunc, json_parser_error>
384     (
385         ReadFunc(), WriteFunc(false), error_data_3, NULL,
386         "testerr3.json", NULL, "testerr3out.json", 4
387     );
388 
389     generic_parser_test_error<ptree, ReadFunc, WriteFunc, json_parser_error>
390     (
391         ReadFunc(), WriteFunc(false), error_data_4, NULL,
392         "testerr4.json", NULL, "testerr4out.json", 3
393     );
394 
395     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
396     (
397         ReadFunc(), WriteFunc(false), bug_data_pr4387, NULL,
398         "testpr4387.json", NULL, "testpr4387out.json", 4, 3, 0
399     );
400 
401     check_exact_roundtrip<Ptree>(ReadFunc(), WriteFunc(true),
402                                  bug_data_pr7180_1);
403     check_exact_roundtrip<Ptree>(ReadFunc(), WriteFunc(false),
404                                  bug_data_pr7180_2);
405 
406 }
407 
test_escaping_utf8()408 void test_escaping_utf8()
409 {
410     // This is cyrillic text encoded as UTF-8
411     std::string str = "\xD0\x9C\xD0\xB0\xD0\xBC\xD0\xB0 "
412       "\xD0\xBC\xD1\x8B\xD0\xBB\xD0\xB0 \xD1\x80\xD0\xB0\xD0\xBC\xD1\x83";
413     // Should NOT escape UTF-8
414     BOOST_CHECK(boost::property_tree::json_parser::create_escapes(str) == str);
415 }
416 
test_escaping_wide()417 void test_escaping_wide()
418 {
419     // Should NOT escape characters within ASCII range.
420     std::wstring str1 = L"I am wstring with ASCII";
421     BOOST_CHECK(boost::property_tree::json_parser::create_escapes(str1) == str1);
422     // Should escape characters outside ASCII range - this is NOT utf-8
423     // This is cyrillic text
424     std::wstring str2 = L"\u041C\u0430\u043C\u0430 "
425         L"\u043C\u044B\u043B\u0430 \u0440\u0430\u043C\u0443";
426     BOOST_CHECK(boost::property_tree::json_parser::create_escapes(str2) ==
427         L"\\u041C\\u0430\\u043C\\u0430 "
428         L"\\u043C\\u044B\\u043B\\u0430 \\u0440\\u0430\\u043C\\u0443");
429 }
430 
test_main(int argc,char * argv[])431 int test_main(int argc, char *argv[])
432 {
433     using namespace boost::property_tree;
434     test_json_parser<ptree>();
435     test_json_parser<iptree>();
436     test_escaping_utf8();
437 #ifndef BOOST_NO_CWCHAR
438     test_json_parser<wptree>();
439     test_json_parser<wiptree>();
440     test_escaping_wide();
441 #endif
442     return 0;
443 }
444