Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2015, 2016, 2020 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 :
17 : /**
18 : * @file json/test_json.c
19 : * @brief Tests for Taler-specific crypto logic
20 : * @author Christian Grothoff <christian@grothoff.org>
21 : */
22 : #include "taler/platform.h"
23 : #include "taler/taler_util.h"
24 : #include "taler/taler_json_lib.h"
25 :
26 :
27 : /**
28 : * Test amount conversion from/to JSON.
29 : *
30 : * @return 0 on success
31 : */
32 : static int
33 1 : test_amount (void)
34 : {
35 : json_t *j;
36 : struct TALER_Amount a1;
37 : struct TALER_Amount a2;
38 : struct GNUNET_JSON_Specification spec[] = {
39 1 : TALER_JSON_spec_amount ("amount",
40 : "EUR",
41 : &a2),
42 1 : GNUNET_JSON_spec_end ()
43 : };
44 :
45 1 : GNUNET_assert (GNUNET_OK ==
46 : TALER_string_to_amount ("EUR:4.3",
47 : &a1));
48 1 : j = json_pack ("{s:o}", "amount", TALER_JSON_from_amount (&a1));
49 1 : GNUNET_assert (NULL != j);
50 1 : GNUNET_assert (GNUNET_OK ==
51 : GNUNET_JSON_parse (j, spec,
52 : NULL, NULL));
53 1 : GNUNET_assert (0 ==
54 : TALER_amount_cmp (&a1,
55 : &a2));
56 1 : json_decref (j);
57 1 : return 0;
58 : }
59 :
60 :
61 : /**
62 : * Verify JSON packing/parsing for amount arrays.
63 : *
64 : * @return 0 on success
65 : */
66 : static int
67 1 : test_amount_array (void)
68 : {
69 : struct TALER_Amount amounts[2];
70 1 : struct TALER_Amount *parsed = NULL;
71 1 : size_t parsed_len = 0;
72 : struct GNUNET_JSON_Specification spec[2];
73 : json_t *doc;
74 1 : const size_t num_amounts = sizeof (amounts) / sizeof (amounts[0]);
75 :
76 1 : GNUNET_assert (GNUNET_OK ==
77 : TALER_string_to_amount ("EUR:1.2",
78 : &amounts[0]));
79 1 : GNUNET_assert (GNUNET_OK ==
80 : TALER_string_to_amount ("EUR:3.4",
81 : &amounts[1]));
82 :
83 1 : spec[0] = TALER_JSON_spec_amount_any_array ("amounts",
84 : &parsed_len,
85 : &parsed);
86 1 : spec[1] = GNUNET_JSON_spec_end ();
87 :
88 1 : doc = GNUNET_JSON_PACK (
89 : TALER_JSON_pack_amount_array ("amounts",
90 : num_amounts,
91 : amounts));
92 1 : GNUNET_assert (NULL != doc);
93 1 : GNUNET_assert (GNUNET_OK ==
94 : GNUNET_JSON_parse (doc,
95 : spec,
96 : NULL,
97 : NULL));
98 1 : GNUNET_assert (parsed_len == num_amounts);
99 3 : for (size_t i = 0; i<num_amounts; i++)
100 2 : GNUNET_assert (0 ==
101 : TALER_amount_cmp (&amounts[i],
102 : &parsed[i]));
103 1 : GNUNET_JSON_parse_free (spec);
104 1 : json_decref (doc);
105 :
106 1 : return 0;
107 : }
108 :
109 :
110 : struct TestPath_Closure
111 : {
112 : const char **object_ids;
113 :
114 : const json_t **parents;
115 :
116 : unsigned int results_length;
117 :
118 : int cmp_result;
119 : };
120 :
121 :
122 : static void
123 5 : path_cb (void *cls,
124 : const char *object_id,
125 : json_t *parent)
126 : {
127 5 : struct TestPath_Closure *cmp = cls;
128 : unsigned int i;
129 :
130 5 : if (NULL == cmp)
131 0 : return;
132 5 : i = cmp->results_length;
133 5 : if ((0 != strcmp (cmp->object_ids[i],
134 5 : object_id)) ||
135 5 : (1 != json_equal (cmp->parents[i],
136 : parent)))
137 0 : cmp->cmp_result = 1;
138 5 : cmp->results_length += 1;
139 : }
140 :
141 :
142 : static int
143 1 : test_contract (void)
144 : {
145 : struct TALER_PrivateContractHashP h1;
146 : struct TALER_PrivateContractHashP h2;
147 : json_t *c1;
148 : json_t *c2;
149 : json_t *c3;
150 : json_t *c4;
151 :
152 1 : c1 = json_pack ("{s:s, s:{s:s, s:{s:b}}}",
153 : "k1", "v1",
154 : "k2", "n1", "n2",
155 : /***/ "$forgettable", "n1", true);
156 1 : GNUNET_assert (GNUNET_OK ==
157 : TALER_JSON_contract_seed_forgettable (c1,
158 : c1));
159 1 : GNUNET_assert (GNUNET_OK ==
160 : TALER_JSON_contract_hash (c1,
161 : &h1));
162 1 : json_decref (c1);
163 :
164 1 : c1 = json_pack ("{s:s, s:{s:s, s:{s:s}}}",
165 : "k1", "v1",
166 : "k2", "n1", "n2",
167 : /***/ "$forgettable", "n1", "salt");
168 1 : GNUNET_assert (NULL != c1);
169 1 : GNUNET_assert (GNUNET_OK ==
170 : TALER_JSON_contract_mark_forgettable (c1,
171 : "k1"));
172 1 : GNUNET_assert (GNUNET_OK ==
173 : TALER_JSON_contract_mark_forgettable (c1,
174 : "k2"));
175 1 : GNUNET_assert (GNUNET_OK ==
176 : TALER_JSON_contract_hash (c1,
177 : &h1));
178 1 : GNUNET_assert (GNUNET_OK ==
179 : TALER_JSON_contract_part_forget (c1,
180 : "k1"));
181 : /* check salt was forgotten */
182 1 : GNUNET_assert (NULL ==
183 : json_object_get (json_object_get (c1,
184 : "$forgettable"),
185 : "k1"));
186 1 : GNUNET_assert (GNUNET_OK ==
187 : TALER_JSON_contract_hash (c1,
188 : &h2));
189 1 : if (0 !=
190 1 : GNUNET_memcmp (&h1,
191 : &h2))
192 : {
193 0 : GNUNET_break (0);
194 0 : json_decref (c1);
195 0 : return 1;
196 : }
197 1 : GNUNET_assert (GNUNET_OK ==
198 : TALER_JSON_contract_part_forget (json_object_get (c1,
199 : "k2"),
200 : "n1"));
201 1 : GNUNET_assert (GNUNET_OK ==
202 : TALER_JSON_contract_hash (c1,
203 : &h2));
204 1 : if (0 !=
205 1 : GNUNET_memcmp (&h1,
206 : &h2))
207 : {
208 0 : GNUNET_break (0);
209 0 : json_decref (c1);
210 0 : return 1;
211 : }
212 1 : GNUNET_assert (GNUNET_OK ==
213 : TALER_JSON_contract_part_forget (c1,
214 : "k2"));
215 : // json_dumpf (c1, stderr, JSON_INDENT (2));
216 1 : GNUNET_assert (GNUNET_OK ==
217 : TALER_JSON_contract_hash (c1,
218 : &h2));
219 1 : json_decref (c1);
220 1 : if (0 !=
221 1 : GNUNET_memcmp (&h1,
222 : &h2))
223 : {
224 0 : GNUNET_break (0);
225 0 : return 1;
226 : }
227 :
228 1 : c1 = json_pack ("{s:I, s:{s:s}, s:{s:b, s:{s:s}}, s:{s:s}}",
229 : "k1", 1,
230 : "$forgettable", "k1", "SALT",
231 : "k2", "n1", true,
232 : /***/ "$forgettable", "n1", "salt",
233 : "k3", "n1", "string");
234 1 : GNUNET_assert (GNUNET_OK ==
235 : TALER_JSON_contract_hash (c1,
236 : &h1));
237 : // json_dumpf (c1, stderr, JSON_INDENT (2));
238 1 : json_decref (c1);
239 : {
240 : char *s;
241 :
242 1 : s = GNUNET_STRINGS_data_to_string_alloc (&h1,
243 : sizeof (h1));
244 1 : if (0 !=
245 1 : strcmp (s,
246 : "VDE8JPX0AEEE3EX1K8E11RYEWSZQKGGZCV6BWTE4ST1C8711P7H850Z7F2Q2HSSYETX87ERC2JNHWB7GTDWTDWMM716VKPSRBXD7SRR"))
247 : {
248 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249 : "Invalid reference hash: %s\n",
250 : s);
251 0 : GNUNET_free (s);
252 0 : return 1;
253 : }
254 1 : GNUNET_free (s);
255 : }
256 :
257 :
258 1 : c2 = json_pack ("{s:s}",
259 : "n1", "n2");
260 1 : GNUNET_assert (NULL != c2);
261 1 : GNUNET_assert (GNUNET_OK ==
262 : TALER_JSON_contract_mark_forgettable (c2,
263 : "n1"));
264 1 : c3 = json_pack ("{s:s, s:o}",
265 : "k1", "v1",
266 : "k2", c2);
267 1 : GNUNET_assert (NULL != c3);
268 1 : GNUNET_assert (GNUNET_OK ==
269 : TALER_JSON_contract_mark_forgettable (c3,
270 : "k1"));
271 1 : GNUNET_assert (GNUNET_OK ==
272 : TALER_JSON_contract_hash (c3,
273 : &h1));
274 1 : GNUNET_assert (GNUNET_OK ==
275 : TALER_JSON_contract_part_forget (c2,
276 : "n1"));
277 1 : GNUNET_assert (GNUNET_OK ==
278 : TALER_JSON_contract_hash (c3,
279 : &h2));
280 1 : json_decref (c3);
281 1 : c4 = json_pack ("{s:{s:s}, s:[{s:s}, {s:s}, {s:s}]}",
282 : "abc1",
283 : "xyz", "value",
284 : "fruit",
285 : "name", "banana",
286 : "name", "apple",
287 : "name", "orange");
288 1 : GNUNET_assert (NULL != c4);
289 1 : GNUNET_assert (GNUNET_SYSERR ==
290 : TALER_JSON_expand_path (c4,
291 : "%.xyz",
292 : &path_cb,
293 : NULL));
294 1 : GNUNET_assert (GNUNET_OK ==
295 : TALER_JSON_expand_path (c4,
296 : "$.nonexistent_id",
297 : &path_cb,
298 : NULL));
299 1 : GNUNET_assert (GNUNET_SYSERR ==
300 : TALER_JSON_expand_path (c4,
301 : "$.fruit[n]",
302 : &path_cb,
303 : NULL));
304 :
305 : {
306 1 : const char *object_ids[] = { "xyz" };
307 1 : const json_t *parents[] = {
308 1 : json_object_get (c4,
309 : "abc1")
310 : };
311 1 : struct TestPath_Closure tp = {
312 : .object_ids = object_ids,
313 : .parents = parents,
314 : .results_length = 0,
315 : .cmp_result = 0
316 : };
317 1 : GNUNET_assert (GNUNET_OK ==
318 : TALER_JSON_expand_path (c4,
319 : "$.abc1.xyz",
320 : &path_cb,
321 : &tp));
322 1 : GNUNET_assert (1 == tp.results_length);
323 1 : GNUNET_assert (0 == tp.cmp_result);
324 : }
325 : {
326 1 : const char *object_ids[] = { "name" };
327 1 : const json_t *parents[] = {
328 1 : json_array_get (json_object_get (c4,
329 : "fruit"),
330 : 0)
331 : };
332 1 : struct TestPath_Closure tp = {
333 : .object_ids = object_ids,
334 : .parents = parents,
335 : .results_length = 0,
336 : .cmp_result = 0
337 : };
338 1 : GNUNET_assert (GNUNET_OK ==
339 : TALER_JSON_expand_path (c4,
340 : "$.fruit[0].name",
341 : &path_cb,
342 : &tp));
343 1 : GNUNET_assert (1 == tp.results_length);
344 1 : GNUNET_assert (0 == tp.cmp_result);
345 : }
346 : {
347 1 : const char *object_ids[] = { "name", "name", "name" };
348 3 : const json_t *parents[] = {
349 1 : json_array_get (json_object_get (c4,
350 : "fruit"),
351 : 0),
352 1 : json_array_get (json_object_get (c4,
353 : "fruit"),
354 : 1),
355 1 : json_array_get (json_object_get (c4,
356 : "fruit"),
357 : 2)
358 : };
359 1 : struct TestPath_Closure tp = {
360 : .object_ids = object_ids,
361 : .parents = parents,
362 : .results_length = 0,
363 : .cmp_result = 0
364 : };
365 1 : GNUNET_assert (GNUNET_OK ==
366 : TALER_JSON_expand_path (c4,
367 : "$.fruit[*].name",
368 : &path_cb,
369 : &tp));
370 1 : GNUNET_assert (3 == tp.results_length);
371 1 : GNUNET_assert (0 == tp.cmp_result);
372 : }
373 1 : json_decref (c4);
374 1 : if (0 !=
375 1 : GNUNET_memcmp (&h1,
376 : &h2))
377 : {
378 0 : GNUNET_break (0);
379 0 : return 1;
380 : }
381 1 : return 0;
382 : }
383 :
384 :
385 : static int
386 1 : test_json_canon (void)
387 : {
388 : {
389 : json_t *c1;
390 : char *canon;
391 1 : c1 = json_pack ("{s:s}",
392 : "k1", "Hello\nWorld");
393 :
394 1 : canon = TALER_JSON_canonicalize (c1);
395 1 : GNUNET_assert (NULL != canon);
396 :
397 1 : printf ("canon: '%s'\n", canon);
398 :
399 1 : GNUNET_assert (0 == strcmp (canon,
400 : "{\"k1\":\"Hello\\nWorld\"}"));
401 : }
402 : {
403 : json_t *c1;
404 : char *canon;
405 1 : c1 = json_pack ("{s:s}",
406 : "k1", "Testing “unicode” characters");
407 :
408 1 : canon = TALER_JSON_canonicalize (c1);
409 1 : GNUNET_assert (NULL != canon);
410 :
411 1 : printf ("canon: '%s'\n", canon);
412 :
413 1 : GNUNET_assert (0 == strcmp (canon,
414 : "{\"k1\":\"Testing “unicode” characters\"}"));
415 : }
416 : {
417 : json_t *c1;
418 : char *canon;
419 1 : c1 = json_pack ("{s:s}",
420 : "k1", "low range \x05 chars");
421 :
422 1 : canon = TALER_JSON_canonicalize (c1);
423 1 : GNUNET_assert (NULL != canon);
424 :
425 1 : printf ("canon: '%s'\n", canon);
426 :
427 1 : GNUNET_assert (0 == strcmp (canon,
428 : "{\"k1\":\"low range \\u0005 chars\"}"));
429 : }
430 :
431 :
432 1 : return 0;
433 : }
434 :
435 :
436 : static int
437 1 : test_rfc8785 (void)
438 : {
439 : struct TALER_PrivateContractHashP h1;
440 : json_t *c1;
441 :
442 1 : c1 = json_pack ("{s:s}",
443 : "k1", "\x08\x0B\t\1\\\x0d");
444 1 : GNUNET_assert (GNUNET_OK ==
445 : TALER_JSON_contract_hash (c1,
446 : &h1));
447 : {
448 : char *s;
449 :
450 1 : s = GNUNET_STRINGS_data_to_string_alloc (&h1,
451 : sizeof (h1));
452 1 : if (0 !=
453 1 : strcmp (s,
454 : "531S33T8ZRGW6548G7T67PMDNGS4Z1D8A2GMB87G3PNKYTW6KGF7Q99XVCGXBKVA2HX6PR5ENJ1PQ5ZTYMMXQB6RM7S82VP7ZG2X5G8"))
455 : {
456 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
457 : "Invalid reference hash: %s\n",
458 : s);
459 0 : GNUNET_free (s);
460 0 : json_decref (c1);
461 0 : return 1;
462 : }
463 1 : GNUNET_free (s);
464 : }
465 1 : json_decref (c1);
466 1 : return 0;
467 : }
468 :
469 :
470 : static int
471 1 : test_array (void)
472 : {
473 : struct _data
474 : {
475 : char chars[2];
476 : };
477 : struct _data *data;
478 : size_t num_data;
479 : struct GNUNET_JSON_Specification spec[] = {
480 1 : TALER_JSON_spec_array_of_data ("nums",
481 : sizeof(*data),
482 : &num_data,
483 : (void **) &data),
484 1 : GNUNET_JSON_spec_end ()
485 : };
486 : json_t *d;
487 1 : const char *buf[] = {
488 : "01", "02", "03", "04",
489 : "Aa", "Bb", "Cc", "Dd"
490 : };
491 :
492 1 : d = json_pack ("{s:[s:s:s:s:s:s:s:s]}",
493 : "nums",
494 : "60RG","60S0","60SG","60T0",
495 : "85GG","89H0","8DHG","8HJ0");
496 1 : GNUNET_assert (NULL != d);
497 1 : printf ("sizeof(*data)=%ld\n", sizeof(*data));
498 1 : printf ("array:>>%s<<\n", json_dumps (d, JSON_INDENT (2)));
499 1 : GNUNET_assert (GNUNET_OK ==
500 : GNUNET_JSON_parse (d, spec,
501 : NULL, NULL));
502 1 : GNUNET_assert (sizeof(buf) / sizeof(*buf) == num_data);
503 9 : for (uint8_t i = 0; i<num_data; i++)
504 : {
505 8 : printf ("buf[%d]=%s vs data[%d]=%c%c\n",
506 : i, buf[i],
507 8 : i, data[i].chars[0], data[i].chars[1]);
508 8 : if (0 != memcmp (buf[i],&data[i], sizeof(*data)))
509 0 : return 2;
510 : }
511 1 : return 0;
512 : }
513 :
514 :
515 : int
516 1 : main (int argc,
517 : const char *const argv[])
518 : {
519 : (void) argc;
520 : (void) argv;
521 1 : GNUNET_log_setup ("test-json",
522 : "WARNING",
523 : NULL);
524 1 : if (0 != test_amount ())
525 0 : return 1;
526 1 : if (0 != test_amount_array ())
527 0 : return 1;
528 1 : if (0 != test_contract ())
529 0 : return 2;
530 1 : if (0 != test_json_canon ())
531 0 : return 2;
532 1 : if (0 != test_rfc8785 ())
533 0 : return 2;
534 1 : if (0 != test_array ())
535 0 : return 2;
536 1 : return 0;
537 : }
538 :
539 :
540 : /* end of test_json.c */
|