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