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