LCOV - code coverage report
Current view: top level - json - test_json.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.9 % 184 158
Test Date: 2026-04-14 15:39:31 Functions: 100.0 % 8 8

            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 */
        

Generated by: LCOV version 2.0-1