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