Dali 3D User Interface Engine
utc-Dali-JsonParser.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #include <iostream>
19 #include <stdlib.h>
23 
24 using namespace Dali;
25 using namespace Dali::Toolkit;
26 
28 {
30 }
31 
33 {
35 }
36 
37 namespace
38 {
39 
40 std::string ReplaceQuotes(const std::string &in_s)
41 {
42  std::string s(in_s);
43  // wrong as no embedded quote but had regex link problems
44  std::replace(s.begin(), s.end(), '\'', '"');
45  return s;
46 }
47 
48 void CompareTrees(const TreeNode& a, const TreeNode& b)
49 {
50  DALI_TEST_CHECK( a.GetType() == b.GetType() );
51 
52  DALI_TEST_CHECK( a.Size() == b.Size() );
53 
54  if( a.GetName() )
55  {
56  DALI_TEST_CHECK( std::string( a.GetName() ) == std::string( b.GetName() ) );
57  }
58 
60 
61  switch( a.GetType() )
62  {
63  case TreeNode::OBJECT:
64  case TreeNode::ARRAY:
65  {
66  for( TreeNode::ConstIterator aiter = a.CBegin(), biter = b.CBegin();
67  aiter != a.CEnd() && biter != b.CEnd(); ++aiter, ++biter )
68  {
69  CompareTrees( (*aiter).second, (*biter).second );
70  }
71  break;
72  }
73  case TreeNode::STRING:
74  {
75  DALI_TEST_CHECK( std::string( a.GetString() ) == std::string( b.GetString() ) );
76  break;
77  }
78  case TreeNode::FLOAT:
79  {
80  DALI_TEST_CHECK( a.GetFloat() == b.GetFloat() );
81  break;
82  }
83  case TreeNode::INTEGER:
84  {
86  break;
87  }
88  case TreeNode::BOOLEAN:
89  {
91  break;
92  }
93  default:
94  {
95  break;
96  }
97  }
98 }
99 
100 
101 }
102 
103 
105 {
106  ToolkitTestApplication application;
107 
108  tet_infoline("JSON basic test");
109 
110  std::string s1( ReplaceQuotes(
111 "{ \
112  'string':'value2', \
113  'integer':2, \
114  'float':2.0, \
115  'boolean':true, \
116  'nil':null, \
117  'array':[1,2,3], \
118  'object':{'key':'value'} \
119 }"));
120 
121  JsonParser parser = JsonParser::New();
122 
123  parser.Parse( s1 );
124 
125  if(parser.ParseError())
126  {
127  std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
128  std::cout << " at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
129  }
130 
131  DALI_TEST_CHECK(!parser.ParseError());
132 
133  const TreeNode* root = parser.GetRoot();
134 
135  DALI_TEST_CHECK(root);
136 
137  DALI_TEST_CHECK(root->Size());
138 
139  TreeNode::ConstIterator iter = root->CBegin();
140  DALI_TEST_CHECK(iter != root->CEnd());
141 
142  const TreeNode* node = NULL;
143 
144  node = &((*iter).second);
145  DALI_TEST_CHECK(node);
146  DALI_TEST_CHECK(node->GetType() == TreeNode::STRING);
147  DALI_TEST_CHECK(std::string((*iter).first) == std::string("string"));
148  DALI_TEST_CHECK(std::string(node->GetString()) == std::string("value2"));
149 
150  ++iter;
151  DALI_TEST_CHECK(iter != root->CEnd());
152  node = &((*iter).second);
153  DALI_TEST_CHECK(node);
154  DALI_TEST_CHECK(node->GetType() == TreeNode::INTEGER);
155  DALI_TEST_CHECK(std::string((*iter).first) == std::string("integer"));
156  DALI_TEST_CHECK(node->GetInteger() == 2);
157 
158  ++iter;
159  DALI_TEST_CHECK(iter != root->CEnd());
160  node = &((*iter).second);
161  DALI_TEST_CHECK(node);
162  DALI_TEST_CHECK(node->GetType() == TreeNode::FLOAT);
163  DALI_TEST_CHECK(std::string((*iter).first) == std::string("float"));
164  DALI_TEST_CHECK(node->GetFloat() == 2.0);
165 
166  ++iter;
167  DALI_TEST_CHECK(iter != root->CEnd());
168  node = &((*iter).second);
169  DALI_TEST_CHECK(node);
170  DALI_TEST_CHECK(node->GetType() == TreeNode::BOOLEAN);
171  DALI_TEST_CHECK(std::string((*iter).first) == std::string("boolean"));
172  DALI_TEST_CHECK(node->GetBoolean());
173 
174  ++iter;
175  DALI_TEST_CHECK(iter != root->CEnd());
176  node = &((*iter).second);
177  DALI_TEST_CHECK(node);
178  DALI_TEST_CHECK(node->GetType() == TreeNode::IS_NULL);
179  DALI_TEST_CHECK(std::string((*iter).first) == std::string("nil"));
180 
181  ++iter;
182  DALI_TEST_CHECK(iter != root->CEnd());
183  node = &((*iter).second);
184  DALI_TEST_CHECK(node);
185  DALI_TEST_CHECK(node->GetType() == TreeNode::ARRAY);
186  DALI_TEST_CHECK(node->Size() == 3);
187  TreeNode::ConstIterator iterArray = node->CBegin();
188 
189  DALI_TEST_CHECK(iterArray != node->CEnd());
190  DALI_TEST_CHECK( ((*iterArray).second).GetType() == TreeNode::INTEGER);
191  DALI_TEST_CHECK( (*iterArray).first == NULL );
192  DALI_TEST_CHECK( ((*iterArray).second).GetInteger() == 1);
193 
194  ++iterArray;
195  DALI_TEST_CHECK(iterArray != node->CEnd());
196  DALI_TEST_CHECK( ((*iterArray).second).GetType() == TreeNode::INTEGER);
197  DALI_TEST_CHECK( (*iterArray).first == NULL );
198  DALI_TEST_CHECK( ((*iterArray).second).GetInteger() == 2);
199 
200  ++iterArray;
201  DALI_TEST_CHECK(iterArray != node->CEnd());
202  DALI_TEST_CHECK( ((*iterArray).second).GetType() == TreeNode::INTEGER);
203  DALI_TEST_CHECK( (*iterArray).first == NULL );
204  DALI_TEST_CHECK( ((*iterArray).second).GetInteger() == 3);
205 
206  ++iter;
207  DALI_TEST_CHECK(iter != root->CEnd());
208  node = &((*iter).second);
209  DALI_TEST_CHECK(node);
210  DALI_TEST_CHECK(node->GetType() == TreeNode::OBJECT);
211  DALI_TEST_CHECK(node->Size() == 1);
212 
213  TreeNode::ConstIterator iterObject = node->CBegin();
214  DALI_TEST_CHECK(iterObject != node->CEnd());
215  DALI_TEST_CHECK( ((*iterObject).second).GetType() == TreeNode::STRING);
216  DALI_TEST_CHECK( std::string((*iterObject).first) == std::string("key" ));
217  DALI_TEST_CHECK( std::string(((*iterObject).second).GetString()) == std::string("value"));
218 
220  END_TEST;
221 }
222 
224 {
225  ToolkitTestApplication application;
226 
227  tet_infoline("JSON Comments");
228 
229  std::string s1( ReplaceQuotes(" \
230 // some comments with empty line above \n\
231 { \
232  // inline comments \n\
233  'key':'value', // endline comments \n\
234  // more inline comments \n\
235  'key2':'value2' \
236 } \
237 "));
238 
239  JsonParser parser = JsonParser::New();
240 
241  parser.Parse( s1 );
242 
243  if(parser.ParseError())
244  {
245  std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
246  std::cout << " at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
247  }
248 
249  DALI_TEST_CHECK(!parser.ParseError());
250 
251  const TreeNode* root = parser.GetRoot();
252 
253  DALI_TEST_CHECK(root);
254 
255  DALI_TEST_CHECK(root->Size());
256 
257  const TreeNode& node = (*root->CBegin()).second;
258 
259  DALI_TEST_CHECK(node.GetType() == TreeNode::STRING);
260 
261  DALI_TEST_CHECK(node.GetString() == std::string("value"));
262 
263  DALI_TEST_CHECK((*root->CBegin()).first == std::string("key"));
264 
266  END_TEST;
267 }
268 
269 
271 {
272  ToolkitTestApplication application;
273 
274  tet_infoline("JSON Empty line comment");
275 
276  std::string s1( ReplaceQuotes(
277 "/*\n" \
278 "c comment\n" \
279 "*/"\
280 "// next empty line comment\n"\
281 "//\n"\
282 "{\n"\
283 " 'key':'value'\n"\
284 "}\n"\
285 ));
286 
287  JsonParser parser = JsonParser::New();
288 
289  parser.Parse( s1 );
290 
291  if(parser.ParseError())
292  {
293  std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
294  std::cout << " at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
295  }
296 
297  DALI_TEST_CHECK(!parser.ParseError());
298 
299  const TreeNode* root = parser.GetRoot();
300 
301  DALI_TEST_CHECK(root);
302 
303  DALI_TEST_CHECK(root->Size());
304 
305  const TreeNode& node = (*root->CBegin()).second;
306 
307  DALI_TEST_CHECK(node.GetType() == TreeNode::STRING);
308 
309  DALI_TEST_CHECK(node.GetString() == std::string("value"));
310 
311  DALI_TEST_CHECK((*root->CBegin()).first == std::string("key"));
312 
314  END_TEST;
315 }
316 
318 {
319  ToolkitTestApplication application;
320 
321  tet_infoline("JSON Merge");
322 
323  std::string s1( ReplaceQuotes(" \
324 { \
325  'animations': \
326  { \
327  'bump': \
328  { \
329  'properties': \
330  [ \
331  { \
332  'actor':'bump-image', \
333  'property':'uLightPosition', \
334  'value':[0.8, 0.0, -1.5], \
335  'alphaFunction': 'BOUNCE', \
336  'timePeriod': { 'duration': 2.5 } \
337  } \
338  ] \
339  } \
340  } \
341 } \
342 "));
343 
344  std::string s2( ReplaceQuotes(" \
345 { \
346  'animations': \
347  { \
348  'bump': \
349  { \
350  'duration': 5.0, \
351  'loop': true, \
352  'endAction':'DISCARD' \
353  } \
354  } \
355 } \
356 "));
357 
358  JsonParser parser = JsonParser::New();
359 
360  parser.Parse( s1 );
361 
362  if(parser.ParseError())
363  {
364  std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
365  std::cout << " at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
366  }
367  DALI_TEST_CHECK(!parser.ParseError());
368 
369  parser.Parse( s2 );
370 
371  if(parser.ParseError())
372  {
373  std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
374  std::cout << " at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
375  }
376 
377  DALI_TEST_CHECK(!parser.ParseError());
378 
379  const TreeNode* root = parser.GetRoot();
380  DALI_TEST_CHECK(root);
381 
382  const TreeNode *node = root->Find("bump");
383  DALI_TEST_CHECK(node);
384 
385  DALI_TEST_CHECK(static_cast<int>(node->Size()) == 4);
386 
387  DALI_TEST_CHECK( node->GetChild("duration") );
388  DALI_TEST_CHECK( node->GetChild("loop") );
389  DALI_TEST_CHECK( node->GetChild("properties") );
390 
391 
393  END_TEST;
394 }
395 
397 {
398  ToolkitTestApplication application;
399 
400  tet_infoline("JSON Pack & Write");
401 
402  std::string s1( ReplaceQuotes(" \
403 { \
404  'animations': \
405  { \
406  'bump': \
407  { \
408  'properties': \
409  [ \
410  { \
411  'actor':'bump-image', \
412  'property':'uLightPosition', \
413  'value':[0.8, 0.0, -1.5], \
414  'alphaFunction': 'BOUNCE', \
415  'timePeriod': { 'duration': 2.5 } \
416  } \
417  ] \
418  } \
419  } \
420 } \
421 "));
422 
423  JsonParser parser = JsonParser::New();
424 
425  parser.Parse( s1 );
426 
427  if(parser.ParseError())
428  {
429  std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
430  std::cout << " at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
431  }
432  DALI_TEST_CHECK(!parser.ParseError());
433 
434  std::stringstream a;
435  parser.Write(a, 2);
436 
437  parser.Pack();
438 
439  std::stringstream b;
440  parser.Write(b, 2);
441 
442  DALI_TEST_CHECK( a.str() == b.str() );
443 
445  END_TEST;
446 }
447 
448 namespace
449 {
450 
451 static const int NUMBER_OK_TESTS = 36;
452 const char *TEST_OK[NUMBER_OK_TESTS] = {
453  "{ 'hex': '\u0123\u4567\u89AB\uCDEF\uabcd\uef4A' }",
454  "{ 'special': '`[email protected]#$%^&*()_+-={:[,]}|;.</>?' }",
455  "{ 'slash': '/ & \' }",
456  "{'object with 1 member':['array with 1 element']}",
457  "[{}, [], -42, true, false, null]",
458  "{ 'integer': 1234567890 }",
459  "{ 'integer': 1234567890 }",
460  "{ 'real': -9876.543210 }",
461  "{ 'e': 0.123456789e-12 }",
462  "{ 'E': 1.234567890E+34 }",
463  "{ '': 23456789012E66 }",
464  "{ 'zero': 0 }",
465  "{ 'one': 1 }",
466  "{ 'space': ' ' }",
467  "{ 'backslash': '\' }",
468  "{ 'controls': '\\b\\f\\n\\r\\t' }",
469  "{ 'alpha': 'abcdefghijklmnopqrstuvwyz' }",
470  "{ 'ALPHA': 'ABCDEFGHIJKLMNOPQRSTUVWYZ' }",
471  "{ 'digit': '0123456789' }",
472  "{ '0123456789': 'digit' }",
473  "{ 'true': true }",
474  "{ 'false': false }",
475  "{ 'null': null }",
476  "{ 'array':[ ] }",
477  "{ 'object':{ } }",
478  "{ 'address': '1 Communication Centre. South Street' }",
479  "{ 'url': 'http://www.JSON.org/' }",
480  "{ 'comment': '// /* <!-- --' }",
481  "{ '# -- --> */': ' ' }",
482  "{ ' s p a c e d ' :[1,2 , 3,4 , 5 , 6 ,7 ]}",
483  "{ 'compact':[1,2,3,4,5,6,7]}",
484  "{ 'quotes': '&#34; \\u0022 %22 0x22 034 &#x22;' }",
485  "{ '\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`[email protected]#$%^&*()_+-=[]{}|;:': 'A key can be any string'}",
486  "[ 0.5 ,98.6, 99.44,1066,1e1,0.1e1,1e-1,1e00,2e+00,2e-00, 'rosebud']",
487  "{'JSON Test Pattern pass3': { 'The outermost value': 'must be an object or array.', 'In this test': 'It is an object.' } }",
488  "[[[[[[[[[[[[[[[[[[['Not too deep']]]]]]]]]]]]]]]]]]]",
489 };
490 }
491 
492 
494 {
495  ToolkitTestApplication application;
496 
497  tet_infoline("JSON Parse Success");
498 
499  JsonParser parser = JsonParser::New();
500 
501  for(int i = 0; i < NUMBER_OK_TESTS; ++i)
502  {
503  parser = JsonParser::New();
504 
505  parser.Parse( ReplaceQuotes(TEST_OK[i]) );
506 
507  if(parser.ParseError())
508  {
509  tet_printf("Valid JSON parse test %d Failed", i);
510  tet_printf("%s", ReplaceQuotes(TEST_OK[i]).c_str());
511 
512  tet_printf("JSON Error %d:%d: %s (%d)", parser.GetErrorLineNumber(), parser.GetErrorColumn(), parser.GetErrorDescription().c_str(), parser.GetErrorPosition());
513  }
514 
515  DALI_TEST_CHECK(!parser.ParseError());
516  }
517 
519  END_TEST;
520 }
521 
522 namespace
523 {
524 
525 static const int NUMBER_FAIL_TESTS = 34;
526 const char *TEST_FAIL[] = {
527  "[' tab\t character \t in\t string ']",
528  "['Extra close']]",
529  "['Colon instead of comma': false]",
530  "{'Numbers cannot have leading zeroes': 013}",
531  "['Bad value', truth]",
532  "['Illegal backslash escape: \017']",
533  "['Bad value', truth]['Illegal backslash escape: \017']",
534  "{'Comma instead if closing brace': true,",
535  "{'Double colon':: null}",
536  "{'Extra comma': true,}",
537  "['Unclosed array'",
538  "{'Illegal invocation': alert()}",
539  "{'Missing colon' null}",
540  "[0e]",
541  "{unquoted_key: 'keys must be quoted'}",
542  "'A JSON payload should be an object or array, not a string.'",
543  "[\naked]",
544  "{'Illegal expression': 1 + 2}",
545  "{'Extra value after close': true} 'misplaced quoted value'",
546  "[0e+]",
547  "[+23456789012E66]",
548  "['extra comma',]",
549  "['Comma after the close'],",
550  "['double extra comma',,]",
551  "['Illegal backslash escape: \x15']",
552  "['line\nbreak']",
553  "{'Comma instead of colon', null}",
554  "['mismatch'}",
555  "['line\nbreak']",
556  "[0e+-1]",
557  "{'Numbers cannot be hex': 0x14}",
558  "[ , '<-- missing value']",
559  "[{'no comma':1} {'b:2}]",
560  "{'extra comma':1,}",
561 };
562 }
563 
565 {
566  ToolkitTestApplication application;
567 
568  tet_infoline("JSON Fail");
569 
570  JsonParser parser = JsonParser::New();
571 
572  for(int i = 0; i < NUMBER_FAIL_TESTS; ++i)
573  {
574  parser = JsonParser::New();
575 
576  parser.Parse( ReplaceQuotes(TEST_FAIL[i]) );
577 
578  if(!parser.ParseError())
579  {
580  tet_printf("Invalid JSON parse test %d Failed", i);
581  tet_printf("%s", ReplaceQuotes(TEST_FAIL[i]).c_str());
582  tet_printf("JSON Error %d:%d %s (%s)", parser.GetErrorLineNumber(), parser.GetErrorColumn(),
583  parser.GetErrorDescription().c_str(), parser.GetErrorPosition());
584  }
585 
586  DALI_TEST_CHECK(parser.ParseError());
587  }
588 
589 
590  parser = JsonParser::New();
591 
592  parser.Parse( "['single quote']" );
593 
594  if(!parser.ParseError())
595  {
596  tet_printf("['single quote']");
597  }
598 
599  DALI_TEST_CHECK(parser.ParseError());
600 
602  END_TEST;
603 }
604 
606 {
607  ToolkitTestApplication application;
608 
609  tet_infoline("JSON error reporting");
610 
611  std::string s1( ReplaceQuotes("\
612 { \n\
613  'float':,], \n\
614 } \n\
615 "));
616 
617  JsonParser parser = JsonParser::New();
618 
619  parser.Parse( s1 );
620 
621  DALI_TEST_CHECK(parser.ParseError());
622 
623  DALI_TEST_CHECK(1 == parser.GetErrorLineNumber());
624  DALI_TEST_CHECK(53 == parser.GetErrorPosition());
625  DALI_TEST_CHECK(11 == parser.GetErrorColumn());
626 
628  END_TEST;
629 }
630 
632 {
633  ToolkitTestApplication application;
634 
635  tet_infoline("JSON Pack()");
636 
637  std::string s1( ReplaceQuotes("\
638 { \
639  'string':'value2', \
640  'integer':2, \
641  'float':2.3, \
642  'boolean':true, \
643  'nil':null, \
644  'array':[1,2,3], \
645  'object':{'key':'value'} \
646 } \
647 "));
648 
649  JsonParser parser = JsonParser::New();
650 
651  parser.Parse( s1 );
652 
653  std::stringstream ss1;
654  parser.Write(ss1, 2);
655 
656  parser.Pack(); // Pack() moves strings
657 
658  std::stringstream ss2;
659  parser.Write(ss2, 2);
660 
661  DALI_TEST_CHECK(ss1.str() == ss2.str());
662 
664  END_TEST;
665 }
666 
668 {
669  ToolkitTestApplication application;
670 
671  tet_infoline("JSON empty data");
672 
673  std::string s1( "" );
674 
675  JsonParser parser = JsonParser::New();
676 
677  parser.Parse( s1 );
678 
679  DALI_TEST_CHECK(parser.ParseError());
680 
682  END_TEST;
683 }
684 
686 {
687  ToolkitTestApplication application;
688  tet_infoline("JSON tree copy");
689 
690  std::string s1( ReplaceQuotes(" \
691 { \
692  'animations': \
693  { \
694  'bump': \
695  { \
696  'properties': \
697  [ \
698  { \
699  'actor':'bump-image', \
700  'property':'uLightPosition', \
701  'value':[0.8, 0.0, -1.5], \
702  'alphaFunction': 'BOUNCE', \
703  'timePeriod': { 'duration': 2.5 } \
704  } \
705  ] \
706  } \
707  } \
708 } \
709 "));
710 
711  JsonParser parser = JsonParser::New();
712 
713  parser.Parse( s1 );
714 
715  JsonParser parser2 = JsonParser::New(*parser.GetRoot());
716 
717  DALI_TEST_CHECK(parser.GetRoot());
718  DALI_TEST_CHECK(parser2.GetRoot());
719 
720  CompareTrees( *parser.GetRoot(), *parser2.GetRoot() );
721 
723  END_TEST;
724 }
725 
726 
728 {
729  ToolkitTestApplication application;
730  tet_infoline("JSON tree merge");
731 
732  std::string s1( ReplaceQuotes(" \
733 { \
734  'styles': \
735  { \
736  'button': \
737  { \
738  'backgroundColor':[0.8, 0.0, 1.0, 1.0], \
739  'foregroundColor':[1, 1, 1, 1] \
740  } \
741  } \
742 } \
743 "));
744 
745  JsonParser parser = JsonParser::New();
746  JsonParser testParser = JsonParser::New();
747 
748  testParser.Parse( s1 );
749 
750  parser.Parse( s1 );
751  parser.Parse( s1 ); // Merge the tree into itself. The value array should not grow.
752 
753  DALI_TEST_CHECK(parser.GetRoot());
754 
755  CompareTrees( *parser.GetRoot(), *testParser.GetRoot() );
756 
757  END_TEST;
758 }
Dali Docs Home
Read more about Dali