exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_json.c (18500B)


      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 /**
    110  * Verify JSON packing/parsing for price lists.
    111  *
    112  * @return 0 on success
    113  */
    114 static int
    115 test_amount_list (void)
    116 {
    117   struct TALER_AmountList al;
    118   struct TALER_AmountList parsed;
    119   struct GNUNET_JSON_Specification spec[] = {
    120     TALER_JSON_spec_amount_list ("costs",
    121                                  &parsed),
    122     GNUNET_JSON_spec_end ()
    123   };
    124   json_t *doc;
    125 
    126   GNUNET_assert (GNUNET_OK ==
    127                  TALER_string_to_amount_list ("EUR:1.2;CHF:3.4",
    128                                               &al));
    129   doc = GNUNET_JSON_PACK (
    130     TALER_JSON_pack_amount_list ("costs",
    131                                  &al));
    132   GNUNET_assert (NULL != doc);
    133   GNUNET_assert (GNUNET_OK ==
    134                  GNUNET_JSON_parse (doc,
    135                                     spec,
    136                                     NULL,
    137                                     NULL));
    138   GNUNET_assert (parsed.tal_len == al.tal_len);
    139   for (unsigned int i = 0; i<al.tal_len; i++)
    140     GNUNET_assert (0 ==
    141                    TALER_amount_cmp (&al.tal[i],
    142                                      &parsed.tal[i]));
    143   GNUNET_JSON_parse_free (spec);
    144   json_decref (doc);
    145   TALER_amount_list_free (&al);
    146 
    147   /* an empty list must survive as an empty array, and not
    148      become JSON null: "free" is a meaningful price */
    149   GNUNET_assert (GNUNET_OK ==
    150                  TALER_string_to_amount_list ("",
    151                                               &al));
    152   doc = GNUNET_JSON_PACK (
    153     TALER_JSON_pack_amount_list ("costs",
    154                                  &al));
    155   GNUNET_assert (NULL != doc);
    156   GNUNET_assert (json_is_array (json_object_get (doc,
    157                                                  "costs")));
    158   GNUNET_assert (GNUNET_OK ==
    159                  GNUNET_JSON_parse (doc,
    160                                     spec,
    161                                     NULL,
    162                                     NULL));
    163   GNUNET_assert (0 == parsed.tal_len);
    164   GNUNET_JSON_parse_free (spec);
    165   json_decref (doc);
    166   TALER_amount_list_free (&al);
    167 
    168   /* a repeated currency on the wire must be rejected, or a peer
    169      could advertise two prices and have us pick a different one
    170      than the user was shown */
    171   doc = json_pack ("{s:[s,s,s]}",
    172                    "costs",
    173                    "EUR:1",
    174                    "CHF:2",
    175                    "EUR:99");
    176   GNUNET_assert (NULL != doc);
    177   GNUNET_assert (GNUNET_OK !=
    178                  GNUNET_JSON_parse (doc,
    179                                     spec,
    180                                     NULL,
    181                                     NULL));
    182   json_decref (doc);
    183 
    184   /* as must a malformed entry */
    185   doc = json_pack ("{s:[s,s]}",
    186                    "costs",
    187                    "EUR:1",
    188                    "not-an-amount");
    189   GNUNET_assert (NULL != doc);
    190   GNUNET_assert (GNUNET_OK !=
    191                  GNUNET_JSON_parse (doc,
    192                                     spec,
    193                                     NULL,
    194                                     NULL));
    195   json_decref (doc);
    196   return 0;
    197 }
    198 
    199 
    200 struct TestPath_Closure
    201 {
    202   const char **object_ids;
    203 
    204   const json_t **parents;
    205 
    206   unsigned int results_length;
    207 
    208   int cmp_result;
    209 };
    210 
    211 
    212 static void
    213 path_cb (void *cls,
    214          const char *object_id,
    215          json_t *parent)
    216 {
    217   struct TestPath_Closure *cmp = cls;
    218   unsigned int i;
    219 
    220   if (NULL == cmp)
    221     return;
    222   i = cmp->results_length;
    223   if ((0 != strcmp (cmp->object_ids[i],
    224                     object_id)) ||
    225       (1 != json_equal (cmp->parents[i],
    226                         parent)))
    227     cmp->cmp_result = 1;
    228   cmp->results_length += 1;
    229 }
    230 
    231 
    232 static int
    233 test_contract (void)
    234 {
    235   struct TALER_PrivateContractHashP h1;
    236   struct TALER_PrivateContractHashP h2;
    237   json_t *c1;
    238   json_t *c2;
    239   json_t *c3;
    240   json_t *c4;
    241 
    242   c1 = json_pack ("{s:s, s:{s:s, s:{s:b}}}",
    243                   "k1", "v1",
    244                   "k2", "n1", "n2",
    245                   /***/ "$forgettable", "n1", true);
    246   GNUNET_assert (GNUNET_OK ==
    247                  TALER_JSON_contract_seed_forgettable (c1,
    248                                                        c1));
    249   GNUNET_assert (GNUNET_OK ==
    250                  TALER_JSON_contract_hash (c1,
    251                                            &h1));
    252   json_decref (c1);
    253 
    254   c1 = json_pack ("{s:s, s:{s:s, s:{s:s}}}",
    255                   "k1", "v1",
    256                   "k2", "n1", "n2",
    257                   /***/ "$forgettable", "n1", "salt");
    258   GNUNET_assert (NULL != c1);
    259   GNUNET_assert (GNUNET_OK ==
    260                  TALER_JSON_contract_mark_forgettable (c1,
    261                                                        "k1"));
    262   GNUNET_assert (GNUNET_OK ==
    263                  TALER_JSON_contract_mark_forgettable (c1,
    264                                                        "k2"));
    265   GNUNET_assert (GNUNET_OK ==
    266                  TALER_JSON_contract_hash (c1,
    267                                            &h1));
    268   GNUNET_assert (GNUNET_OK ==
    269                  TALER_JSON_contract_part_forget (c1,
    270                                                   "k1"));
    271   /* check salt was forgotten */
    272   GNUNET_assert (NULL ==
    273                  json_object_get (json_object_get (c1,
    274                                                    "$forgettable"),
    275                                   "k1"));
    276   GNUNET_assert (GNUNET_OK ==
    277                  TALER_JSON_contract_hash (c1,
    278                                            &h2));
    279   if (0 !=
    280       GNUNET_memcmp (&h1,
    281                      &h2))
    282   {
    283     GNUNET_break (0);
    284     json_decref (c1);
    285     return 1;
    286   }
    287   GNUNET_assert (GNUNET_OK ==
    288                  TALER_JSON_contract_part_forget (json_object_get (c1,
    289                                                                    "k2"),
    290                                                   "n1"));
    291   GNUNET_assert (GNUNET_OK ==
    292                  TALER_JSON_contract_hash (c1,
    293                                            &h2));
    294   if (0 !=
    295       GNUNET_memcmp (&h1,
    296                      &h2))
    297   {
    298     GNUNET_break (0);
    299     json_decref (c1);
    300     return 1;
    301   }
    302   GNUNET_assert (GNUNET_OK ==
    303                  TALER_JSON_contract_part_forget (c1,
    304                                                   "k2"));
    305   // json_dumpf (c1, stderr, JSON_INDENT (2));
    306   GNUNET_assert (GNUNET_OK ==
    307                  TALER_JSON_contract_hash (c1,
    308                                            &h2));
    309   json_decref (c1);
    310   if (0 !=
    311       GNUNET_memcmp (&h1,
    312                      &h2))
    313   {
    314     GNUNET_break (0);
    315     return 1;
    316   }
    317 
    318   c1 = json_pack ("{s:I, s:{s:s}, s:{s:b, s:{s:s}}, s:{s:s}}",
    319                   "k1", 1,
    320                   "$forgettable", "k1", "SALT",
    321                   "k2", "n1", true,
    322                   /***/ "$forgettable", "n1", "salt",
    323                   "k3", "n1", "string");
    324   GNUNET_assert (GNUNET_OK ==
    325                  TALER_JSON_contract_hash (c1,
    326                                            &h1));
    327   // json_dumpf (c1, stderr, JSON_INDENT (2));
    328   json_decref (c1);
    329   {
    330     char *s;
    331 
    332     s = GNUNET_STRINGS_data_to_string_alloc (&h1,
    333                                              sizeof (h1));
    334     if (0 !=
    335         strcmp (s,
    336                 "VDE8JPX0AEEE3EX1K8E11RYEWSZQKGGZCV6BWTE4ST1C8711P7H850Z7F2Q2HSSYETX87ERC2JNHWB7GTDWTDWMM716VKPSRBXD7SRR"))
    337     {
    338       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    339                   "Invalid reference hash: %s\n",
    340                   s);
    341       GNUNET_free (s);
    342       return 1;
    343     }
    344     GNUNET_free (s);
    345   }
    346 
    347 
    348   c2 = json_pack ("{s:s}",
    349                   "n1", "n2");
    350   GNUNET_assert (NULL != c2);
    351   GNUNET_assert (GNUNET_OK ==
    352                  TALER_JSON_contract_mark_forgettable (c2,
    353                                                        "n1"));
    354   c3 = json_pack ("{s:s, s:o}",
    355                   "k1", "v1",
    356                   "k2", c2);
    357   GNUNET_assert (NULL != c3);
    358   GNUNET_assert (GNUNET_OK ==
    359                  TALER_JSON_contract_mark_forgettable (c3,
    360                                                        "k1"));
    361   GNUNET_assert (GNUNET_OK ==
    362                  TALER_JSON_contract_hash (c3,
    363                                            &h1));
    364   GNUNET_assert (GNUNET_OK ==
    365                  TALER_JSON_contract_part_forget (c2,
    366                                                   "n1"));
    367   GNUNET_assert (GNUNET_OK ==
    368                  TALER_JSON_contract_hash (c3,
    369                                            &h2));
    370   json_decref (c3);
    371   c4 = json_pack ("{s:{s:s}, s:[{s:s}, {s:s}, {s:s}]}",
    372                   "abc1",
    373                   "xyz", "value",
    374                   "fruit",
    375                   "name", "banana",
    376                   "name", "apple",
    377                   "name", "orange");
    378   GNUNET_assert (NULL != c4);
    379   GNUNET_assert (GNUNET_SYSERR ==
    380                  TALER_JSON_expand_path (c4,
    381                                          "%.xyz",
    382                                          &path_cb,
    383                                          NULL));
    384   GNUNET_assert (GNUNET_OK ==
    385                  TALER_JSON_expand_path (c4,
    386                                          "$.nonexistent_id",
    387                                          &path_cb,
    388                                          NULL));
    389   GNUNET_assert (GNUNET_SYSERR ==
    390                  TALER_JSON_expand_path (c4,
    391                                          "$.fruit[n]",
    392                                          &path_cb,
    393                                          NULL));
    394 
    395   {
    396     const char *object_ids[] = { "xyz" };
    397     const json_t *parents[] = {
    398       json_object_get (c4,
    399                        "abc1")
    400     };
    401     struct TestPath_Closure tp = {
    402       .object_ids = object_ids,
    403       .parents = parents,
    404       .results_length = 0,
    405       .cmp_result = 0
    406     };
    407     GNUNET_assert (GNUNET_OK ==
    408                    TALER_JSON_expand_path (c4,
    409                                            "$.abc1.xyz",
    410                                            &path_cb,
    411                                            &tp));
    412     GNUNET_assert (1 == tp.results_length);
    413     GNUNET_assert (0 == tp.cmp_result);
    414   }
    415   {
    416     const char *object_ids[] = { "name" };
    417     const json_t *parents[] = {
    418       json_array_get (json_object_get (c4,
    419                                        "fruit"),
    420                       0)
    421     };
    422     struct TestPath_Closure tp = {
    423       .object_ids = object_ids,
    424       .parents = parents,
    425       .results_length = 0,
    426       .cmp_result = 0
    427     };
    428     GNUNET_assert (GNUNET_OK ==
    429                    TALER_JSON_expand_path (c4,
    430                                            "$.fruit[0].name",
    431                                            &path_cb,
    432                                            &tp));
    433     GNUNET_assert (1 == tp.results_length);
    434     GNUNET_assert (0 == tp.cmp_result);
    435   }
    436   {
    437     const char *object_ids[] = { "name", "name", "name" };
    438     const json_t *parents[] = {
    439       json_array_get (json_object_get (c4,
    440                                        "fruit"),
    441                       0),
    442       json_array_get (json_object_get (c4,
    443                                        "fruit"),
    444                       1),
    445       json_array_get (json_object_get (c4,
    446                                        "fruit"),
    447                       2)
    448     };
    449     struct TestPath_Closure tp = {
    450       .object_ids = object_ids,
    451       .parents = parents,
    452       .results_length = 0,
    453       .cmp_result = 0
    454     };
    455     GNUNET_assert (GNUNET_OK ==
    456                    TALER_JSON_expand_path (c4,
    457                                            "$.fruit[*].name",
    458                                            &path_cb,
    459                                            &tp));
    460     GNUNET_assert (3 == tp.results_length);
    461     GNUNET_assert (0 == tp.cmp_result);
    462   }
    463   json_decref (c4);
    464   if (0 !=
    465       GNUNET_memcmp (&h1,
    466                      &h2))
    467   {
    468     GNUNET_break (0);
    469     return 1;
    470   }
    471   return 0;
    472 }
    473 
    474 
    475 static int
    476 test_json_canon (void)
    477 {
    478   {
    479     json_t *c1;
    480     char *canon;
    481     c1 = json_pack ("{s:s}",
    482                     "k1", "Hello\nWorld");
    483 
    484     canon = TALER_JSON_canonicalize (c1);
    485     GNUNET_assert (NULL != canon);
    486 
    487     printf ("canon: '%s'\n", canon);
    488 
    489     GNUNET_assert (0 == strcmp (canon,
    490                                 "{\"k1\":\"Hello\\nWorld\"}"));
    491   }
    492   {
    493     json_t *c1;
    494     char *canon;
    495     c1 = json_pack ("{s:s}",
    496                     "k1", "Testing “unicode” characters");
    497 
    498     canon = TALER_JSON_canonicalize (c1);
    499     GNUNET_assert (NULL != canon);
    500 
    501     printf ("canon: '%s'\n", canon);
    502 
    503     GNUNET_assert (0 == strcmp (canon,
    504                                 "{\"k1\":\"Testing “unicode” characters\"}"));
    505   }
    506   {
    507     json_t *c1;
    508     char *canon;
    509     c1 = json_pack ("{s:s}",
    510                     "k1", "low range \x05 chars");
    511 
    512     canon = TALER_JSON_canonicalize (c1);
    513     GNUNET_assert (NULL != canon);
    514 
    515     printf ("canon: '%s'\n", canon);
    516 
    517     GNUNET_assert (0 == strcmp (canon,
    518                                 "{\"k1\":\"low range \\u0005 chars\"}"));
    519   }
    520 
    521 
    522   return 0;
    523 }
    524 
    525 
    526 static int
    527 test_rfc8785 (void)
    528 {
    529   struct TALER_PrivateContractHashP h1;
    530   json_t *c1;
    531 
    532   c1 = json_pack ("{s:s}",
    533                   "k1", "\x08\x0B\t\1\\\x0d");
    534   GNUNET_assert (GNUNET_OK ==
    535                  TALER_JSON_contract_hash (c1,
    536                                            &h1));
    537   {
    538     char *s;
    539 
    540     s = GNUNET_STRINGS_data_to_string_alloc (&h1,
    541                                              sizeof (h1));
    542     if (0 !=
    543         strcmp (s,
    544                 "531S33T8ZRGW6548G7T67PMDNGS4Z1D8A2GMB87G3PNKYTW6KGF7Q99XVCGXBKVA2HX6PR5ENJ1PQ5ZTYMMXQB6RM7S82VP7ZG2X5G8"))
    545     {
    546       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    547                   "Invalid reference hash: %s\n",
    548                   s);
    549       GNUNET_free (s);
    550       json_decref (c1);
    551       return 1;
    552     }
    553     GNUNET_free (s);
    554   }
    555   json_decref (c1);
    556   return 0;
    557 }
    558 
    559 
    560 static int
    561 test_array (void)
    562 {
    563   struct _data
    564   {
    565     char chars[2];
    566   };
    567   struct _data *data;
    568   size_t num_data;
    569   struct GNUNET_JSON_Specification spec[] = {
    570     TALER_JSON_spec_array_of_data ("nums",
    571                                    sizeof(*data),
    572                                    &num_data,
    573                                    (void **) &data),
    574     GNUNET_JSON_spec_end ()
    575   };
    576   json_t *d;
    577   const char *buf[] = {
    578     "01", "02", "03", "04",
    579     "Aa", "Bb", "Cc", "Dd"
    580   };
    581 
    582   d = json_pack ("{s:[s:s:s:s:s:s:s:s]}",
    583                  "nums",
    584                  "60RG","60S0","60SG","60T0",
    585                  "85GG","89H0","8DHG","8HJ0");
    586   GNUNET_assert (NULL != d);
    587   printf ("sizeof(*data)=%ld\n", sizeof(*data));
    588   printf ("array:>>%s<<\n", json_dumps (d, JSON_INDENT (2)));
    589   GNUNET_assert (GNUNET_OK ==
    590                  GNUNET_JSON_parse (d, spec,
    591                                     NULL, NULL));
    592   GNUNET_assert (sizeof(buf) / sizeof(*buf) == num_data);
    593   for (uint8_t i = 0; i<num_data; i++)
    594   {
    595     printf ("buf[%d]=%s vs data[%d]=%c%c\n",
    596             i, buf[i],
    597             i, data[i].chars[0], data[i].chars[1]);
    598     if (0 != memcmp (buf[i],&data[i], sizeof(*data)))
    599       return 2;
    600   }
    601   return 0;
    602 }
    603 
    604 
    605 int
    606 main (int argc,
    607       const char *const argv[])
    608 {
    609   (void) argc;
    610   (void) argv;
    611   GNUNET_log_setup ("test-json",
    612                     "WARNING",
    613                     NULL);
    614   if (0 != test_amount ())
    615     return 1;
    616   if (0 != test_amount_array ())
    617     return 1;
    618   if (0 != test_amount_list ())
    619     return 1;
    620   if (0 != test_contract ())
    621     return 2;
    622   if (0 != test_json_canon ())
    623     return 2;
    624   if (0 != test_rfc8785 ())
    625     return 2;
    626   if (0 != test_array ())
    627     return 2;
    628   return 0;
    629 }
    630 
    631 
    632 /* end of test_json.c */