• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "ejdb2.h"
2 #include <ejdb2/iowow/iwxstr.h>
3 #include <ejdb2/iowow/iwutils.h>
4 
5 #include "jbl.h"
6 #include "jbl_internal.h"
7 
8 #include <CUnit/Basic.h>
9 
init_suite(void)10 int init_suite(void) {
11   int rc = ejdb_init();
12   return rc;
13 }
14 
clean_suite(void)15 int clean_suite(void) {
16   return 0;
17 }
18 
_jbl_test1_1(int num,iwrc expected,jbl_print_flags_t pf)19 void _jbl_test1_1(int num, iwrc expected, jbl_print_flags_t pf) {
20   iwrc rc;
21   char path[64];
22   char path_expected[64];
23   JBL_NODE node = 0;
24   IWPOOL *pool;
25   char *data;
26   char *edata = 0;
27   IWXSTR *res = iwxstr_new();
28   CU_ASSERT_PTR_NOT_NULL_FATAL(res);
29 
30   snprintf(path, sizeof(path), "data%c%03d.json", IW_PATH_CHR, num);
31   snprintf(path_expected, sizeof(path_expected), "data%c%03d.expected.json", IW_PATH_CHR, num);
32   data = iwu_file_read_as_buf(path);
33   CU_ASSERT_PTR_NOT_NULL_FATAL(data);
34 
35   pool = iwpool_create(1024);
36   CU_ASSERT_PTR_NOT_NULL_FATAL(pool);
37 
38   rc = jbn_from_json(data, &node, pool);
39   if (rc) {
40     iwlog_ecode_error3(rc);
41   }
42   CU_ASSERT_EQUAL_FATAL(rc, expected);
43   CU_ASSERT_PTR_NOT_NULL_FATAL(node);
44   if (expected) {
45     goto finish;
46   }
47 
48   rc = jbn_as_json(node, jbl_xstr_json_printer, res, pf);
49   CU_ASSERT_EQUAL_FATAL(rc, 0);
50 
51   edata = iwu_file_read_as_buf(path_expected);
52   CU_ASSERT_PTR_NOT_NULL_FATAL(edata);
53 
54   FILE *f1 = fopen("f1.txt", "w");
55   FILE *f2 = fopen("f2.txt", "w");
56   fprintf(f1, "\n%s", edata);
57   fprintf(f2, "\n%s", iwxstr_ptr(res));
58   fclose(f1);
59   fclose(f2);
60 
61   fprintf(stderr, "ED %s\n", edata);
62   fprintf(stderr, "ED %s\n", iwxstr_ptr(res));
63 
64   CU_ASSERT_EQUAL_FATAL(strcmp(edata, iwxstr_ptr(res)), 0);
65 
66 finish:
67   if (edata) {
68     free(edata);
69   }
70   free(data);
71   iwpool_destroy(pool);
72   iwxstr_destroy(res);
73 }
74 
jbl_test1_1()75 void jbl_test1_1() {
76   _jbl_test1_1(1, 0, JBL_PRINT_PRETTY);
77   _jbl_test1_1(2, 0, JBL_PRINT_PRETTY | JBL_PRINT_CODEPOINTS);
78   _jbl_test1_1(3, 0, JBL_PRINT_PRETTY);
79   _jbl_test1_1(4, 0, JBL_PRINT_PRETTY);
80   _jbl_test1_1(5, 0, JBL_PRINT_PRETTY);
81 }
82 
jbl_test1_2()83 void jbl_test1_2() {
84   const char *data = "{\"foo\": \"b\\\"ar\", \"num1\":1223,"
85                      "\"n\\\"um2\":10.1226222, "
86                      "\"list\":[3,2.1,1,\"one\", \"two\", "
87                      "{}, {\"z\":false, \"t\":true}]}";
88   JBL jbl;
89   iwrc rc = jbl_from_json(&jbl, data);
90   CU_ASSERT_EQUAL_FATAL(rc, 0);
91 
92   IWXSTR *xstr = iwxstr_new();
93   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
94 
95   rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, false);
96   CU_ASSERT_EQUAL_FATAL(rc, 0);
97 
98   int res = strcmp(iwxstr_ptr(xstr),
99                    "{\"foo\":\"b\\\"ar\",\"num1\":1223,\"n\\\"um2\":10.1226222,"
100                    "\"list\":[3,2.1,1,\"one\",\"two\",{},{\"z\":false,\"t\":true}]}");
101   CU_ASSERT_EQUAL(res, 0);
102   jbl_destroy(&jbl);
103 
104   //
105   rc = jbl_from_json(&jbl, "{ ");
106   CU_ASSERT_EQUAL_FATAL(rc, JBL_ERROR_PARSE_JSON);
107 
108   iwxstr_destroy(xstr);
109 }
110 
jbl_test1_3()111 void jbl_test1_3() {
112   JBL_PTR jp;
113   iwrc rc = jbl_ptr_alloc("/", &jp);
114   CU_ASSERT_EQUAL_FATAL(rc, 0);
115   CU_ASSERT_EQUAL(jp->cnt, 1);
116   CU_ASSERT_TRUE(*jp->n[0] == '\0')
117   free(jp);
118 
119   rc = jbl_ptr_alloc("/foo", &jp);
120   CU_ASSERT_EQUAL_FATAL(rc, 0);
121   CU_ASSERT_EQUAL(jp->cnt, 1);
122   CU_ASSERT_FALSE(strcmp(jp->n[0], "foo"));
123   free(jp);
124 
125   rc = jbl_ptr_alloc("/foo/bar", &jp);
126   CU_ASSERT_EQUAL_FATAL(rc, 0);
127   CU_ASSERT_EQUAL(jp->cnt, 2);
128   CU_ASSERT_FALSE(strcmp(jp->n[0], "foo"));
129   CU_ASSERT_FALSE(strcmp(jp->n[1], "bar"));
130   free(jp);
131 
132   rc = jbl_ptr_alloc("/foo/bar/0/baz", &jp);
133   CU_ASSERT_EQUAL_FATAL(rc, 0);
134   CU_ASSERT_EQUAL(jp->cnt, 4);
135   CU_ASSERT_FALSE(strcmp(jp->n[0], "foo"));
136   CU_ASSERT_FALSE(strcmp(jp->n[1], "bar"));
137   CU_ASSERT_FALSE(strcmp(jp->n[2], "0"));
138   CU_ASSERT_FALSE(strcmp(jp->n[3], "baz"));
139   free(jp);
140 
141   rc = jbl_ptr_alloc("/foo/b~0ar/0/b~1az", &jp);
142   CU_ASSERT_EQUAL_FATAL(rc, 0);
143   CU_ASSERT_EQUAL(jp->cnt, 4);
144   CU_ASSERT_FALSE(strcmp(jp->n[0], "foo"));
145   CU_ASSERT_FALSE(strcmp(jp->n[1], "b~ar"));
146   CU_ASSERT_FALSE(strcmp(jp->n[2], "0"));
147   CU_ASSERT_FALSE(strcmp(jp->n[3], "b/az"));
148   free(jp);
149 
150   rc = jbl_ptr_alloc("/foo/", &jp);
151   CU_ASSERT_EQUAL(rc, JBL_ERROR_JSON_POINTER);
152   free(jp);
153 
154   rc = jbl_ptr_alloc("//", &jp);
155   CU_ASSERT_EQUAL(rc, JBL_ERROR_JSON_POINTER);
156   free(jp);
157 
158   rc = jbl_ptr_alloc("", &jp);
159   CU_ASSERT_EQUAL(rc, JBL_ERROR_JSON_POINTER);
160   free(jp);
161 
162   rc = jbl_ptr_alloc("~", &jp);
163   CU_ASSERT_EQUAL(rc, JBL_ERROR_JSON_POINTER);
164   free(jp);
165 }
166 
jbl_test1_4()167 void jbl_test1_4() {
168   //  { "foo": "bar",
169   //    "foo2": {
170   //      "foo3": {
171   //        "foo4": "bar4"
172   //      },
173   //      "foo5": "bar5"
174   //    },
175   //    "num1": 1,
176   //    "list1": ["one", "two", {"three": 3}]
177   //  }
178   char *data
179     = iwu_replace_char(
180         strdup("{'foo':'bar','foo2':{'foo3':{'foo4':'bar4'},'foo5':'bar5'},"
181                "'num1':1,'list1':['one','two',{'three':3}]}"),
182         '\'', '"');
183   JBL jbl, at, at2;
184   const char *sval;
185   int ival;
186   iwrc rc = jbl_from_json(&jbl, data);
187   CU_ASSERT_EQUAL_FATAL(rc, 0);
188 
189   rc = jbl_at(jbl, "/foo", &at);
190   CU_ASSERT_EQUAL_FATAL(rc, 0);
191   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
192 
193   sval = jbl_get_str(at);
194   CU_ASSERT_PTR_NOT_NULL_FATAL(sval);
195   CU_ASSERT_STRING_EQUAL(sval, "bar");
196   jbl_destroy(&at);
197 
198   rc = jbl_at(jbl, "/foo2/foo3", &at);
199   CU_ASSERT_EQUAL_FATAL(rc, 0);
200   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
201   CU_ASSERT_TRUE(at->bn.type == BINN_OBJECT);
202   rc = jbl_at(at, "/foo4", &at2);
203   CU_ASSERT_EQUAL_FATAL(rc, 0);
204   CU_ASSERT_PTR_NOT_NULL_FATAL(at2);
205   sval = jbl_get_str(at2);
206   CU_ASSERT_PTR_NOT_NULL_FATAL(sval);
207   CU_ASSERT_STRING_EQUAL(sval, "bar4");
208   jbl_destroy(&at2);
209   jbl_destroy(&at);
210 
211   at = (void*) 1;
212   rc = jbl_at(jbl, "/foo2/foo10", &at);
213   CU_ASSERT_EQUAL(rc, JBL_ERROR_PATH_NOTFOUND);
214   CU_ASSERT_PTR_NULL(at);
215   rc = 0;
216 
217   rc = jbl_at(jbl, "/foo2/*/foo4", &at);
218   CU_ASSERT_EQUAL_FATAL(rc, 0);
219   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
220   sval = jbl_get_str(at);
221   CU_ASSERT_PTR_NOT_NULL_FATAL(sval);
222   CU_ASSERT_STRING_EQUAL(sval, "bar4");
223   jbl_destroy(&at);
224 
225   rc = jbl_at(jbl, "/list1/1", &at);
226   CU_ASSERT_EQUAL_FATAL(rc, 0);
227   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
228   sval = jbl_get_str(at);
229   CU_ASSERT_STRING_EQUAL(sval, "two");
230   jbl_destroy(&at);
231 
232   rc = jbl_at(jbl, "/list1/2/three", &at);
233   CU_ASSERT_EQUAL_FATAL(rc, 0);
234   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
235   ival = jbl_get_i32(at);
236   CU_ASSERT_EQUAL(ival, 3);
237   jbl_destroy(&at);
238 
239   rc = jbl_at(jbl, "/list1/*/three", &at);
240   CU_ASSERT_EQUAL_FATAL(rc, 0);
241   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
242   ival = jbl_get_i32(at);
243   CU_ASSERT_EQUAL(ival, 3);
244   jbl_destroy(&at);
245 
246   rc = jbl_at(jbl, "/list1/*/*", &at);
247   CU_ASSERT_EQUAL_FATAL(rc, 0);
248   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
249   ival = jbl_get_i32(at);
250   CU_ASSERT_EQUAL(ival, 3);
251   jbl_destroy(&at);
252 
253   jbl_destroy(&jbl);
254   free(data);
255 }
256 
jbl_test1_5()257 void jbl_test1_5() {
258   IWXSTR *xstr = iwxstr_new();
259   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
260 
261   //  { "foo": "bar",
262   //    "foo2": {
263   //      "foo3": {
264   //        "foo4": "bar4"
265   //      },
266   //      "foo5": "bar5"
267   //    },
268   //    "num1": 1,
269   //    "list1": ["one", "two", {"three": 3}]
270   //  }
271   char *data
272     = iwu_replace_char(
273         strdup("{'foo':'bar','foo2':{'foo3':{'foo4':'bar4'},'foo5':'bar5'},"
274                "'num1':1,'list1':['one','two',{'three':3}]}"),
275         '\'', '"');
276   JBL jbl;
277   int res = 0;
278 
279   // Remove ROOT
280   JBL_PATCH p1[] = { { .op = JBP_REMOVE, .path = "/" } };
281   iwrc rc = jbl_from_json(&jbl, data);
282   CU_ASSERT_EQUAL_FATAL(rc, 0);
283   rc = jbl_patch(jbl, p1, sizeof(p1) / sizeof(p1[0]));
284   CU_ASSERT_EQUAL_FATAL(rc, 0);
285   jbl_destroy(&jbl);
286 
287 
288   // Remove "/foo"
289   JBL_PATCH p2[] = { { .op = JBP_REMOVE, .path = "/foo" } };
290   rc = jbl_from_json(&jbl, data);
291   CU_ASSERT_EQUAL_FATAL(rc, 0);
292   rc = jbl_patch(jbl, p2, sizeof(p2) / sizeof(p2[0]));
293   CU_ASSERT_EQUAL_FATAL(rc, 0);
294   rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, false);
295   CU_ASSERT_EQUAL_FATAL(rc, 0);
296   res = strcmp(iwxstr_ptr(
297                  xstr),
298                "{\"foo2\":{\"foo3\":{\"foo4\":\"bar4\"},\"foo5\":\"bar5\"},\"num1\":1,\"list1\":[\"one\",\"two\",{\"three\":3}]}");
299   CU_ASSERT_EQUAL(res, 0);
300   jbl_destroy(&jbl);
301   iwxstr_clear(xstr);
302 
303   // Remove /foo2/foo3/foo4
304   // Remove /list1/1
305   JBL_PATCH p3[] = {
306     { .op = JBP_REMOVE, .path = "/foo2/foo3/foo4" },
307     { .op = JBP_REMOVE, .path = "/list1/1"        }
308   };
309   rc = jbl_from_json(&jbl, data);
310   CU_ASSERT_EQUAL_FATAL(rc, 0);
311   rc = jbl_patch(jbl, p3, sizeof(p3) / sizeof(p3[0]));
312   CU_ASSERT_EQUAL_FATAL(rc, 0);
313   rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, false);
314   CU_ASSERT_EQUAL_FATAL(rc, 0);
315   res = strcmp(iwxstr_ptr(xstr),
316                "{\"foo\":\"bar\",\"foo2\":{\"foo3\":{},\"foo5\":\"bar5\"},\"num1\":1,\"list1\":[\"one\",{\"three\":3}]}");
317   CU_ASSERT_EQUAL(res, 0);
318   jbl_destroy(&jbl);
319   iwxstr_clear(xstr);
320   iwxstr_destroy(xstr);
321   free(data);
322 }
323 
apply_patch(const char * data,const char * patch,const char * result,IWXSTR * xstr,iwrc * rcp)324 void apply_patch(const char *data, const char *patch, const char *result, IWXSTR *xstr, iwrc *rcp) {
325   CU_ASSERT_TRUE_FATAL(data && patch && xstr && rcp);
326   JBL jbl = 0;
327   char *data2 = iwu_replace_char(strdup(data), '\'', '"');
328   char *patch2 = iwu_replace_char(strdup(patch), '\'', '"');
329   char *result2 = result ? iwu_replace_char(strdup(result), '\'', '"') : 0;
330   CU_ASSERT_TRUE_FATAL(data2 && patch2);
331 
332   iwrc rc = jbl_from_json(&jbl, data2);
333   RCGO(rc, finish);
334 
335   rc = jbl_patch_from_json(jbl, patch2);
336   RCGO(rc, finish);
337 
338   rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, false);
339   RCGO(rc, finish);
340 
341   if (result2) {
342     CU_ASSERT_STRING_EQUAL(result2, iwxstr_ptr(xstr));
343   }
344 
345 finish:
346   if (data2) {
347     free(data2);
348   }
349   if (patch2) {
350     free(patch2);
351   }
352   if (result2) {
353     free(result2);
354   }
355   if (jbl) {
356     jbl_destroy(&jbl);
357   }
358   *rcp = rc;
359 }
360 
apply_merge_patch(const char * data,const char * patch,const char * result,IWXSTR * xstr,iwrc * rcp)361 void apply_merge_patch(const char *data, const char *patch, const char *result, IWXSTR *xstr, iwrc *rcp) {
362   CU_ASSERT_TRUE_FATAL(data && patch && xstr && rcp);
363   JBL jbl = 0;
364   char *data2 = iwu_replace_char(strdup(data), '\'', '"');
365   char *patch2 = iwu_replace_char(strdup(patch), '\'', '"');
366   char *result2 = result ? iwu_replace_char(strdup(result), '\'', '"') : 0;
367   CU_ASSERT_TRUE_FATAL(data2 && patch2);
368 
369   iwrc rc = jbl_from_json(&jbl, data2);
370   RCGO(rc, finish);
371 
372   rc = jbl_merge_patch(jbl, patch2);
373   RCGO(rc, finish);
374 
375   rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, false);
376   RCGO(rc, finish);
377 
378   if (result2) {
379     CU_ASSERT_STRING_EQUAL(result2, iwxstr_ptr(xstr));
380   }
381 
382 finish:
383   if (data2) {
384     free(data2);
385   }
386   if (patch2) {
387     free(patch2);
388   }
389   if (result2) {
390     free(result2);
391   }
392   if (jbl) {
393     jbl_destroy(&jbl);
394   }
395   *rcp = rc;
396 }
397 
398 // Run tests: https://github.com/json-patch/json-patch-tests/blob/master/spec_tests.json
jbl_test1_6()399 void jbl_test1_6() {
400   iwrc rc;
401   IWXSTR *xstr = iwxstr_new();
402   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
403 
404   apply_patch("{'foo':'bar','foo2':{'foo3':{'foo4':'bar4'},'foo5':'bar5'},'num1':1,'list1':['one','two',{'three':3}]}",
405               "[{'op':'remove', 'path':'/foo'}]",
406               "{'foo2':{'foo3':{'foo4':'bar4'},'foo5':'bar5'},'num1':1,'list1':['one','two',{'three':3}]}",
407               xstr, &rc);
408   CU_ASSERT_EQUAL_FATAL(rc, 0);
409   iwxstr_clear(xstr);
410 
411   // 4.1. add with missing object
412   apply_patch("{ 'q': { 'bar': 2 } }",
413               "[ {'op': 'add', 'path': '/a/b', 'value': 1} ]",
414               0, xstr, &rc);
415   CU_ASSERT_EQUAL(rc, JBL_ERROR_PATCH_TARGET_INVALID);
416   iwxstr_clear(xstr);
417 
418   // A.1.  Adding an Object Member
419   apply_patch("{'foo': 'bar'}",
420               "[ { 'op': 'add', 'path': '/baz', 'value': 'qux' } ]",
421               "{'foo':'bar','baz':'qux'}", xstr, &rc);
422   CU_ASSERT_EQUAL_FATAL(rc, 0);
423   iwxstr_clear(xstr);
424 
425   // A.2.  Adding an Array Element
426   apply_patch("{'foo': [ 'bar', 'baz' ]}",
427               "[{ 'op': 'add', 'path': '/foo/1', 'value': 'qux' }]",
428               "{'foo':['bar','qux','baz']}", xstr, &rc);
429   CU_ASSERT_EQUAL_FATAL(rc, 0);
430   iwxstr_clear(xstr);
431 
432   // A.3.  Removing an Object Member
433   apply_patch("{'baz': 'qux','foo': 'bar'}",
434               "[{ 'op': 'remove', 'path': '/baz' }]",
435               "{'foo':'bar'}", xstr, &rc);
436   CU_ASSERT_EQUAL_FATAL(rc, 0);
437   iwxstr_clear(xstr);
438 
439   // A.4.  Removing an Array Element
440   apply_patch("{'foo': [ 'bar', 'qux', 'baz' ]}",
441               "[{ 'op': 'remove', 'path': '/foo/1' }]",
442               "{'foo':['bar','baz']}", xstr, &rc);
443   CU_ASSERT_EQUAL_FATAL(rc, 0);
444   iwxstr_clear(xstr);
445 
446   // A.5.  Replacing a Value
447   apply_patch("{'baz': 'qux','foo': 'bar'}",
448               "[{ 'op': 'replace', 'path': '/baz', 'value': 'boo' }]",
449               "{'foo':'bar','baz':'boo'}", xstr, &rc);
450   CU_ASSERT_EQUAL_FATAL(rc, 0);
451   iwxstr_clear(xstr);
452 
453   // A.5.1 #232
454   apply_patch("{'a':{'c':'N','s':'F'}}",
455               "[{'op':'replace', 'path':'/a/s', 'value':'A'}]",
456               "{'a':{'c':'N','s':'A'}}", xstr, &rc);
457   CU_ASSERT_EQUAL_FATAL(rc, 0);
458   iwxstr_clear(xstr);
459 
460   // A.6.  Moving a Value
461   apply_patch("{'foo': {'bar': 'baz','waldo': 'fred'},'qux': {'corge': 'grault'}}",
462               "[{ 'op': 'move', 'from': '/foo/waldo', 'path': '/qux/thud' }]",
463               "{'foo':{'bar':'baz'},'qux':{'corge':'grault','thud':'fred'}}", xstr, &rc);
464   CU_ASSERT_EQUAL_FATAL(rc, 0);
465   iwxstr_clear(xstr);
466 
467   // A.7.  Moving an Array Element
468   apply_patch("{'foo': [ 'all', 'grass', 'cows', 'eat' ]}",
469               "[{ 'op': 'move', 'from': '/foo/1', 'path': '/foo/3' }]",
470               "{'foo':['all','cows','eat','grass']}", xstr, &rc);
471   CU_ASSERT_EQUAL_FATAL(rc, 0);
472   iwxstr_clear(xstr);
473 
474   // A.8.  Testing a Value: Success
475   apply_patch("{'baz': 'qux','foo': [ 'a', 2, 'c' ]}",
476               "["
477               "{ 'op': 'test', 'path': '/baz', 'value': 'qux' },"
478               "{ 'op': 'test', 'path': '/foo/1', 'value': 2 }"
479               "]",
480               "{'baz':'qux','foo':['a',2,'c']}", xstr, &rc);
481   CU_ASSERT_EQUAL_FATAL(rc, 0);
482   iwxstr_clear(xstr);
483 
484   // A.8.  Testing a Value Object
485   apply_patch(
486     "{'foo':'bar','foo2':{'zaz':25, 'foo3':{'foo4':'bar4'},'foo5':'bar5'},'num1':1,'list1':['one','two',{'three':3}]}",
487     "[{ 'op': 'test', 'path': '/foo2', 'value': {'foo5':'bar5', 'zaz':25, 'foo3':{'foo4':'bar4'}} }]",
488     0,
489     xstr,
490     &rc);
491   CU_ASSERT_EQUAL_FATAL(rc, 0);
492   iwxstr_clear(xstr);
493 
494   apply_patch(
495     "{'foo':'bar','foo2':{'zaz':25, 'foo3':{'foo4':'bar4'},'foo5':'bar5'},'num1':1,'list1':['one','two',{'three':3}]}",
496     "[{ 'op': 'test', 'path': '/foo2', 'value': {'foo5':'bar5', 'zaz':25, 'foo3':{'foo41':'bar4'}} }]",
497     0,
498     xstr,
499     &rc);
500   CU_ASSERT_EQUAL_FATAL(rc, JBL_ERROR_PATCH_TEST_FAILED);
501   iwxstr_clear(xstr);
502 
503   apply_patch(
504     "{'foo':'bar','foo2':{'zaz':25, 'foo3':{'foo4':'bar4'},'foo5':'bar5'},'num1':1,'list1':['one','two',{'three':3}]}",
505     "[{ 'op': 'test', 'path': '/', 'value': {'num1':1, 'foo2':{'foo3':{'foo4':'bar4'}, 'zaz':25, 'foo5':'bar5'},'list1':['one','two',{'three':3}],'foo':'bar'} }]",
506     0,
507     xstr,
508     &rc);
509   CU_ASSERT_EQUAL_FATAL(rc, 0);
510   iwxstr_clear(xstr);
511 
512   apply_patch(
513     "{'foo':'bar','foo2':{'zaz':25, 'foo3':{'foo4':'bar4'},'foo5':'bar5'},'num1':1,'list1':['one','two',{'three':3}]}",
514     "[{ 'op': 'test', 'path': '/list1', 'value':['one','two',{'three':3}] }]",
515     0,
516     xstr,
517     &rc);
518   CU_ASSERT_EQUAL_FATAL(rc, 0);
519   iwxstr_clear(xstr);
520 
521   apply_patch(
522     "{'foo':'bar','foo2':{'zaz':25, 'foo3':{'foo4':'bar4'},'foo5':'bar5'},'num1':1,'list1':['one','two',{'three':3}]}",
523     "[{ 'op': 'test', 'path': '/list1', 'value':['two','one',{'three':3}] }]",
524     0,
525     xstr,
526     &rc);
527   CU_ASSERT_EQUAL_FATAL(rc, JBL_ERROR_PATCH_TEST_FAILED);
528   iwxstr_clear(xstr);
529 
530   // A.9.  Testing a Value: Error
531   apply_patch("{ 'baz': 'qux'}",
532               "[{ 'op': 'test', 'path': '/baz', 'value': 'bar' }]",
533               0, xstr, &rc);
534   CU_ASSERT_EQUAL(rc, JBL_ERROR_PATCH_TEST_FAILED);
535   iwxstr_clear(xstr);
536 
537   // A.10.  Adding a nested Member Object
538   apply_patch("{'foo': 'bar'}",
539               "[{ 'op': 'add', 'path': '/child', 'value': { 'grandchild': { } } }]",
540               "{'foo':'bar','child':{'grandchild':{}}}", xstr, &rc);
541   CU_ASSERT_EQUAL_FATAL(rc, 0);
542   iwxstr_clear(xstr);
543 
544   // A.11.  Ignoring Unrecognized Elements
545   apply_patch("{'foo': 'bar'}",
546               "[{ 'op': 'add', 'path': '/baz', 'value': 'qux', 'xyz': 123 }]",
547               "{'foo':'bar','baz':'qux'}", xstr, &rc);
548   CU_ASSERT_EQUAL_FATAL(rc, 0);
549   iwxstr_clear(xstr);
550 
551   // A.12.  Adding to a Non-existent Target
552   apply_patch("{'foo': 'bar'}",
553               "[{ 'op': 'add', 'path': '/baz/bat', 'value': 'qux' }]",
554               0, xstr, &rc);
555   CU_ASSERT_EQUAL(rc, JBL_ERROR_PATCH_TARGET_INVALID);
556   iwxstr_clear(xstr);
557 
558   // A.14. ~ Escape Ordering
559   apply_patch("{'/': 9,'~1': 10}",
560               "[{'op': 'test', 'path': '/~01', 'value': 10}]",
561               "{'/':9,'~1':10}", xstr, &rc);
562   CU_ASSERT_EQUAL_FATAL(rc, 0);
563   iwxstr_clear(xstr);
564 
565   // A.15. Comparing Strings and Numbers
566   apply_patch("{'/': 9,'~1': 10}",
567               "[{'op': 'test', 'path': '/~01', 'value': '10'}]",
568               "{'/':9,'~1':10}", xstr, &rc);
569   CU_ASSERT_EQUAL(rc, JBL_ERROR_PATCH_TEST_FAILED);
570   iwxstr_clear(xstr);
571 
572   // A.16. Adding an Array Value
573   apply_patch("{'foo': ['bar']}",
574               "[{'op': 'add', 'path': '/foo/-', 'value': ['abc', 'def'] }]",
575               "{'foo':['bar',['abc','def']]}", xstr, &rc);
576   CU_ASSERT_EQUAL_FATAL(rc, 0);
577   iwxstr_clear(xstr);
578 
579   // Apply non standard `increment` patch
580   apply_patch("{'foo': 1}",
581               "[{'op': 'increment', 'path': '/foo', 'value': 2}]",
582               "{'foo':3}", xstr, &rc);
583   CU_ASSERT_EQUAL_FATAL(rc, 0);
584   iwxstr_clear(xstr);
585 
586   // Apply non standard `swap` patch
587   apply_patch("{'foo': ['bar'], 'baz': {'gaz': 11}}",
588               "[{'op': 'swap', 'from': '/foo/0', 'path': '/baz/gaz'}]",
589               "{'foo':[11],'baz':{'gaz':'bar'}}", xstr, &rc);
590   CU_ASSERT_EQUAL_FATAL(rc, 0);
591   iwxstr_clear(xstr);
592 
593   apply_patch("{'foo': ['bar'], 'baz': {'gaz': 11}}",
594               "[{'op': 'swap', 'from': '/foo/0', 'path': '/baz/zaz'}]",
595               "{'foo':[],'baz':{'gaz':11,'zaz':'bar'}}", xstr, &rc);
596 
597   CU_ASSERT_EQUAL_FATAL(rc, 0);
598   iwxstr_clear(xstr);
599 
600   apply_patch("{'foo': 1}",
601               "[{'op': 'increment', 'path': '/foo', 'value': true}]",
602               "{'foo':3}", xstr, &rc);
603   CU_ASSERT_EQUAL_FATAL(rc, JBL_ERROR_PATCH_INVALID_VALUE);
604   iwxstr_clear(xstr);
605 
606   // Apply non standard add_create patch
607   apply_patch("{'foo': {'bar': 1}}",
608               "[{'op': 'add_create', 'path': '/foo/zaz/gaz', 'value': 22}]",
609               "{'foo':{'bar':1,'zaz':{'gaz':22}}}", xstr, &rc);
610   CU_ASSERT_EQUAL_FATAL(rc, 0);
611   iwxstr_clear(xstr);
612 
613   apply_patch("{'foo': {'bar': 1}}",
614               "[{'op': 'add_create', 'path': '/foo/bar/gaz', 'value': 22}]",
615               "{}", xstr, &rc);
616   CU_ASSERT_EQUAL_FATAL(rc, JBL_ERROR_PATCH_TARGET_INVALID);
617   iwxstr_clear(xstr);
618 
619   apply_patch("{'foo': {'bar': 1}}",
620               "[{'op': 'add_create', 'path': '/zaz/gaz', 'value': [1,2,3]}]",
621               "{'foo':{'bar':1},'zaz':{'gaz':[1,2,3]}}", xstr, &rc);
622   CU_ASSERT_EQUAL_FATAL(rc, 0);
623   iwxstr_clear(xstr);
624 
625   iwxstr_destroy(xstr);
626 }
627 
jbl_test1_7()628 void jbl_test1_7() {
629   iwrc rc;
630   IWXSTR *xstr = iwxstr_new();
631   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
632 
633   // #233
634   apply_merge_patch("{'n':'nv'}",
635                     "{'a':{'c':'v','d':'k'}}",
636                     "{'n':'nv','a':{'c':'v','d':'k'}}", xstr, &rc);
637   CU_ASSERT_EQUAL_FATAL(rc, 0);
638   iwxstr_clear(xstr);
639 
640   apply_merge_patch("{'a':'b'}",
641                     "{'a':'c'}",
642                     "{'a':'c'}", xstr, &rc);
643   CU_ASSERT_EQUAL_FATAL(rc, 0);
644   iwxstr_clear(xstr);
645 
646 
647   apply_merge_patch("{'a':'b'}",
648                     "{'b':'c'}",
649                     "{'a':'b','b':'c'}", xstr, &rc);
650   CU_ASSERT_EQUAL_FATAL(rc, 0);
651   iwxstr_clear(xstr);
652 
653   apply_merge_patch("{'a':'b'}",
654                     "{'a':null}",
655                     "{}", xstr, &rc);
656   CU_ASSERT_EQUAL_FATAL(rc, 0);
657   iwxstr_clear(xstr);
658 
659   apply_merge_patch("{'a':'b','b':'c'}",
660                     "{'a':null}",
661                     "{'b':'c'}", xstr, &rc);
662   CU_ASSERT_EQUAL_FATAL(rc, 0);
663   iwxstr_clear(xstr);
664 
665   apply_merge_patch("{'a':['b']}",
666                     "{'a':'c'}",
667                     "{'a':'c'}", xstr, &rc);
668   CU_ASSERT_EQUAL_FATAL(rc, 0);
669   iwxstr_clear(xstr);
670 
671   apply_merge_patch("{'a':'c'}",
672                     "{'a':['b']}",
673                     "{'a':['b']}", xstr, &rc);
674   CU_ASSERT_EQUAL_FATAL(rc, 0);
675   iwxstr_clear(xstr);
676 
677   apply_merge_patch("{'a':{'b':'c'}}",
678                     "{'a':{'b':'d','c':null}}",
679                     "{'a':{'b':'d'}}", xstr, &rc);
680   CU_ASSERT_EQUAL_FATAL(rc, 0);
681   iwxstr_clear(xstr);
682 
683   apply_merge_patch("{'a':[{'b':'c'}]}",
684                     "{'a':[1]}",
685                     "{'a':[1]}", xstr, &rc);
686   CU_ASSERT_EQUAL_FATAL(rc, 0);
687   iwxstr_clear(xstr);
688 
689   apply_merge_patch("['a','b']",
690                     "['c','d']",
691                     "['c','d']", xstr, &rc);
692   CU_ASSERT_EQUAL_FATAL(rc, 0);
693   iwxstr_clear(xstr);
694 
695   apply_merge_patch("{'a':'b'}",
696                     "['c']",
697                     "['c']", xstr, &rc);
698   CU_ASSERT_EQUAL_FATAL(rc, 0);
699   iwxstr_clear(xstr);
700 
701   apply_merge_patch("{'e':null}",
702                     "{'a':1}",
703                     "{'e':null,'a':1}", xstr, &rc);
704   CU_ASSERT_EQUAL_FATAL(rc, 0);
705   iwxstr_clear(xstr);
706 
707   apply_merge_patch("[1,2]",
708                     "{'a':'b','c':null}",
709                     "{'a':'b'}", xstr, &rc);
710   CU_ASSERT_EQUAL_FATAL(rc, 0);
711   iwxstr_clear(xstr);
712 
713   apply_merge_patch("{}",
714                     "{'a':{'bb':{'ccc':null}}}",
715                     "{'a':{'bb':{}}}", xstr, &rc);
716   CU_ASSERT_EQUAL_FATAL(rc, 0);
717   iwxstr_clear(xstr);
718 
719 
720   iwxstr_destroy(xstr);
721 }
722 
jbl_test1_8()723 void jbl_test1_8() {
724   JBL jbl, nested, at;
725   iwrc rc = jbl_create_empty_object(&jbl);
726   CU_ASSERT_EQUAL_FATAL(rc, 0);
727 
728   rc = jbl_create_empty_object(&nested);
729   CU_ASSERT_EQUAL_FATAL(rc, 0);
730 
731   rc = jbl_set_int64(nested, "nnum", 2233);
732   CU_ASSERT_EQUAL_FATAL(rc, 0);
733 
734   rc = jbl_set_int64(jbl, "mynum", 13223);
735   CU_ASSERT_EQUAL_FATAL(rc, 0);
736 
737   rc = jbl_set_string(jbl, "foo", "bar");
738   CU_ASSERT_EQUAL_FATAL(rc, 0);
739 
740   rc = jbl_set_nested(jbl, "nested", nested);
741   CU_ASSERT_EQUAL_FATAL(rc, 0);
742 
743   rc = jbl_at(jbl, "/mynum", &at);
744   CU_ASSERT_EQUAL_FATAL(rc, 0);
745   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
746   CU_ASSERT_EQUAL(jbl_get_i64(at), 13223);
747   jbl_destroy(&at);
748 
749   rc = jbl_at(jbl, "/foo", &at);
750   CU_ASSERT_EQUAL_FATAL(rc, 0);
751   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
752   CU_ASSERT_STRING_EQUAL(jbl_get_str(at), "bar");
753   jbl_destroy(&at);
754 
755   rc = jbl_at(jbl, "/nested/nnum", &at);
756   CU_ASSERT_EQUAL_FATAL(rc, 0);
757   CU_ASSERT_PTR_NOT_NULL_FATAL(at);
758   CU_ASSERT_EQUAL(jbl_get_i64(at), 2233);
759   jbl_destroy(&at);
760 
761   jbl_destroy(&jbl);
762   jbl_destroy(&nested);
763 }
764 
jbl_test1_9(void)765 void jbl_test1_9(void) {
766   IWPOOL *pool = iwpool_create(512);
767   IWPOOL *cpool = iwpool_create(512);
768   CU_ASSERT_PTR_NOT_NULL_FATAL(pool);
769   CU_ASSERT_PTR_NOT_NULL_FATAL(cpool);
770   const char *data = "{\"foo\": \"b\\\"ar\", \"num1\":1223,"
771                      "\"n\\\"um2\":10.1226222, "
772                      "\"list\":[3,2.1,1,\"one\" \"two\", "
773                      "{}, {\"z\":false, \"arr\":[9,8], \"t\":true}]}";
774 
775   JBL_NODE n, cn;
776   iwrc rc = jbn_from_json(data, &n, pool);
777   CU_ASSERT_EQUAL_FATAL(rc, 0);
778 
779   rc = jbn_clone(n, &cn, cpool);
780   CU_ASSERT_EQUAL_FATAL(rc, 0);
781 
782   IWXSTR *xstr = iwxstr_new();
783   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
784 
785   iwpool_destroy(pool);
786 
787   rc = jbn_as_json(cn, jbl_xstr_json_printer, xstr, 0);
788   CU_ASSERT_EQUAL_FATAL(rc, 0);
789 
790   CU_ASSERT_STRING_EQUAL(iwxstr_ptr(
791                            xstr),
792                          "{\"foo\":\"b\\\"ar\",\"num1\":1223,\"n\\\"um2\":10.1226222,\"list\":[3,2.1,1,\"one\",\"two\",{},{\"z\":false,\"arr\":[9,8],\"t\":true}]}"
793                          );
794 
795   iwpool_destroy(cpool);
796   iwxstr_destroy(xstr);
797 }
798 
jbl_test1_10(void)799 void jbl_test1_10(void) {
800   IWPOOL *pool = iwpool_create(512);
801   IWPOOL *tpool = iwpool_create(512);
802   IWXSTR *xstr = iwxstr_new();
803 
804   const char *src_data = "{\"foo\": \"b\\\"ar\", \"num1\":1223,"
805                          "\"n\\\"um2\":10.1226222, "
806                          "\"list\":[3,2.1,1,\"one\" \"two\", "
807                          "{}, {\"z\":false, \"arr\":[9,8], \"t\":true}]}";
808   const char *tgt_data = "{\"test\":{\"nested1\":22}}";
809   JBL_NODE n1, n2;
810   iwrc rc = jbn_from_json(src_data, &n1, pool);
811   CU_ASSERT_EQUAL_FATAL(rc, 0);
812 
813   rc = jbn_from_json(tgt_data, &n2, tpool);
814   CU_ASSERT_EQUAL_FATAL(rc, 0);
815 
816   rc = jbn_copy_path(n1, "/list/6/arr", n2, "/test/nested1", false, false, tpool);
817   CU_ASSERT_EQUAL_FATAL(rc, 0);
818 
819   rc = jbn_copy_path(n1, "/list/6/t", n2, "/test/t2", false, false, tpool);
820   CU_ASSERT_EQUAL_FATAL(rc, 0);
821 
822   rc = jbn_copy_path(n1, "/foo", n2, "/bar", false, false, tpool);
823   CU_ASSERT_EQUAL_FATAL(rc, 0);
824 
825   iwpool_destroy(pool);
826 
827   rc = jbn_as_json(n2, jbl_xstr_json_printer, xstr, 0);
828   CU_ASSERT_EQUAL_FATAL(rc, 0);
829 
830   CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr),
831                          "{\"test\":{\"nested1\":[9,8],\"t2\":true},\"bar\":\"b\\\"ar\"}");
832 
833   iwpool_destroy(tpool);
834   iwxstr_destroy(xstr);
835 }
836 
jbl_test1_11(void)837 void jbl_test1_11(void) {
838   IWPOOL *pool = iwpool_create(512);
839   IWXSTR *xstr = iwxstr_new();
840 
841   const char *src_data = "{\"foo\": \"b\\\"ar\", \"num1\":1223,"
842                          "\"n\\\"um2\":10.1226222, "
843                          "\"list\":[3,2.1,1,\"one\" \"two\", "
844                          "{}, {\"z\":false, \"arr\":[9,8], \"t\":true}]}";
845   const char *tgt_data = "{\"test\":{\"nested1\":22}, \"list\":[0,99]}";
846 
847   JBL_NODE n1, n2;
848   iwrc rc = jbn_from_json(src_data, &n1, pool);
849   CU_ASSERT_EQUAL_FATAL(rc, 0);
850 
851   rc = jbn_from_json(tgt_data, &n2, pool);
852   CU_ASSERT_EQUAL_FATAL(rc, 0);
853 
854   const char *paths[] = { "/foo", "/list/1", 0 };
855   rc = jbn_copy_paths(n1, n2, paths, false, false, pool);
856   CU_ASSERT_EQUAL_FATAL(rc, 0);
857 
858   rc = jbn_as_json(n2, jbl_xstr_json_printer, xstr, 0);
859   CU_ASSERT_EQUAL_FATAL(rc, 0);
860 
861   CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr),
862                          "{\"test\":{\"nested1\":22},\"list\":[0,2.1],\"foo\":\"b\\\"ar\"}");
863 
864   iwpool_destroy(pool);
865   iwxstr_destroy(xstr);
866 }
867 
jbl_test1_12(void)868 void jbl_test1_12(void) {
869 }
870 
main()871 int main() {
872   CU_pSuite pSuite = NULL;
873   if (CUE_SUCCESS != CU_initialize_registry()) {
874     return CU_get_error();
875   }
876   pSuite = CU_add_suite("jbl_test1", init_suite, clean_suite);
877   if (NULL == pSuite) {
878     CU_cleanup_registry();
879     return CU_get_error();
880   }
881   if (  (NULL == CU_add_test(pSuite, "jbl_test1_1", jbl_test1_1))
882      || (NULL == CU_add_test(pSuite, "jbl_test1_2", jbl_test1_2))
883      || (NULL == CU_add_test(pSuite, "jbl_test1_3", jbl_test1_3))
884      || (NULL == CU_add_test(pSuite, "jbl_test1_4", jbl_test1_4))
885      || (NULL == CU_add_test(pSuite, "jbl_test1_5", jbl_test1_5))
886      || (NULL == CU_add_test(pSuite, "jbl_test1_6", jbl_test1_6))
887      || (NULL == CU_add_test(pSuite, "jbl_test1_7", jbl_test1_7))
888      || (NULL == CU_add_test(pSuite, "jbl_test1_8", jbl_test1_8))
889      || (NULL == CU_add_test(pSuite, "jbl_test1_9", jbl_test1_9))
890      || (NULL == CU_add_test(pSuite, "jbl_test1_10", jbl_test1_10))
891      || (NULL == CU_add_test(pSuite, "jbl_test1_11", jbl_test1_11))) {
892     CU_cleanup_registry();
893     return CU_get_error();
894   }
895   CU_basic_set_mode(CU_BRM_VERBOSE);
896   CU_basic_run_tests();
897   int ret = CU_get_error() || CU_get_number_of_failures();
898   CU_cleanup_registry();
899   return ret;
900 }
901