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

Generated by: LCOV version 2.0-1