LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_patch_product.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.7 % 165 148
Test Date: 2026-09-04 23:42:01 Functions: 100.0 % 10 10

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2020 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify
       6              :   it under the terms of the GNU General Public License as
       7              :   published by the Free Software Foundation; either version 3, or
       8              :   (at your option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful, but
      11              :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :   GNU General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU General Public
      16              :   License along with TALER; see the file COPYING.  If not, see
      17              :   <http://www.gnu.org/licenses/>
      18              : */
      19              : /**
      20              :  * @file src/testing/testing_api_cmd_patch_product.c
      21              :  * @brief command to test PATCH /product
      22              :  * @author Christian Grothoff
      23              :  */
      24              : #include "platform.h"
      25              : struct PatchProductState;
      26              : #define TALER_MERCHANT_PATCH_PRIVATE_PRODUCT_RESULT_CLOSURE struct PatchProductState
      27              : #include <taler/taler_exchange_service.h>
      28              : #include <taler/taler_testing_lib.h>
      29              : #include "taler/taler_merchant_service.h"
      30              : #include "taler/taler_merchant_testing_lib.h"
      31              : #include <taler/merchant/patch-private-products-PRODUCT_ID.h>
      32              : 
      33              : 
      34              : /**
      35              :  * State of a "PATCH /product" CMD.
      36              :  */
      37              : struct PatchProductState
      38              : {
      39              : 
      40              :   /**
      41              :    * Handle for a "GET product" request.
      42              :    */
      43              :   struct TALER_MERCHANT_PatchPrivateProductHandle *iph;
      44              : 
      45              :   /**
      46              :    * The interpreter state.
      47              :    */
      48              :   struct TALER_TESTING_Interpreter *is;
      49              : 
      50              :   /**
      51              :    * Base URL of the merchant serving the request.
      52              :    */
      53              :   const char *merchant_url;
      54              : 
      55              :   /**
      56              :    * ID of the product to run GET for.
      57              :    */
      58              :   const char *product_id;
      59              : 
      60              :   /**
      61              :    * description of the product
      62              :    */
      63              :   const char *description;
      64              : 
      65              :   /**
      66              :    * Map from IETF BCP 47 language tags to localized descriptions
      67              :    */
      68              :   json_t *description_i18n;
      69              : 
      70              :   /**
      71              :    * unit in which the product is measured (liters, kilograms, packages, etc.)
      72              :    */
      73              :   const char *unit;
      74              : 
      75              :   /**
      76              :    * the price for one @a unit of the product
      77              :    */
      78              :   struct TALER_Amount price;
      79              : 
      80              :   /**
      81              :    * Array of unit prices (may point to @e price for single-entry usage).
      82              :    */
      83              :   struct TALER_Amount *unit_prices;
      84              : 
      85              :   /**
      86              :    * Number of entries in @e unit_prices.
      87              :    */
      88              :   size_t unit_prices_len;
      89              : 
      90              :   /**
      91              :    * True if @e unit_prices must be freed.
      92              :    */
      93              :   bool owns_unit_prices;
      94              : 
      95              :   /**
      96              :    * True if we should send an explicit unit_price array.
      97              :    */
      98              :   bool use_unit_price_array;
      99              : 
     100              :   /**
     101              :    * base64-encoded product image
     102              :    */
     103              :   char *image;
     104              : 
     105              :   /**
     106              :    * list of taxes paid by the merchant
     107              :    */
     108              :   json_t *taxes;
     109              : 
     110              :   /**
     111              :    * in @e units, -1 to indicate "infinite" (i.e. electronic books)
     112              :    */
     113              :   int64_t total_stock;
     114              : 
     115              :   /**
     116              :    * Fractional stock component when fractional quantities are enabled.
     117              :    */
     118              :   uint32_t total_stock_frac;
     119              : 
     120              :   /**
     121              :    * Fractional precision level associated with fractional quantities.
     122              :    */
     123              :   uint32_t unit_precision_level;
     124              : 
     125              :   /**
     126              :    * whether fractional quantities are allowed for this product.
     127              :    */
     128              :   bool unit_allow_fraction;
     129              : 
     130              :   /**
     131              :    * Cached string representation of the stock level.
     132              :    */
     133              :   char unit_total_stock[64];
     134              : 
     135              :   /**
     136              :    * set to true if we should use the extended fractional API.
     137              :    */
     138              :   bool use_fractional;
     139              : 
     140              :   /**
     141              :    * in @e units.
     142              :    */
     143              :   int64_t total_lost;
     144              : 
     145              :   /**
     146              :    * where the product is in stock
     147              :    */
     148              :   json_t *address;
     149              : 
     150              :   /**
     151              :    * when the next restocking is expected to happen, 0 for unknown,
     152              :    */
     153              :   struct GNUNET_TIME_Timestamp next_restock;
     154              : 
     155              :   /**
     156              :    * Categories array length.
     157              :    */
     158              :   unsigned int num_cats;
     159              : 
     160              :   /**
     161              :    * Categories array.
     162              :    */
     163              :   uint64_t *cats;
     164              : 
     165              :   /**
     166              :    * Expected HTTP response code.
     167              :    */
     168              :   unsigned int http_status;
     169              : 
     170              : };
     171              : 
     172              : static void
     173           30 : patch_product_update_unit_total_stock (struct PatchProductState *pps)
     174              : {
     175              :   uint64_t stock;
     176              :   uint32_t frac;
     177              : 
     178           30 :   if (-1 == pps->total_stock)
     179              :   {
     180            0 :     stock = (uint64_t) INT64_MAX;
     181            0 :     frac = (uint32_t) INT32_MAX;
     182              :   }
     183              :   else
     184              :   {
     185           30 :     stock = (uint64_t) pps->total_stock;
     186           30 :     frac = pps->unit_allow_fraction ? pps->total_stock_frac : 0;
     187              :   }
     188           30 :   TALER_MERCHANT_format_stock_string (stock,
     189              :                                       frac,
     190           30 :                                       pps->unit_total_stock,
     191              :                                       sizeof (pps->unit_total_stock));
     192           30 : }
     193              : 
     194              : 
     195              : static uint32_t
     196           24 : default_precision_from_unit (const char *unit)
     197              : {
     198              :   struct PrecisionRule
     199              :   {
     200              :     const char *unit;
     201              :     uint32_t precision;
     202              :   };
     203              :   static const struct PrecisionRule rules[] = {
     204              :     { "WeightUnitMg", 0 },
     205              :     { "SizeUnitMm", 0 },
     206              :     { "WeightUnitG", 1 },
     207              :     { "SizeUnitCm", 1 },
     208              :     { "SurfaceUnitMm2", 1 },
     209              :     { "VolumeUnitMm3", 1 },
     210              :     { "WeightUnitOunce", 2 },
     211              :     { "SizeUnitInch", 2 },
     212              :     { "SurfaceUnitCm2", 2 },
     213              :     { "VolumeUnitOunce", 2 },
     214              :     { "VolumeUnitInch3", 2 },
     215              :     { "TimeUnitHour", 2 },
     216              :     { "TimeUnitMonth", 2 },
     217              :     { "WeightUnitTon", 3 },
     218              :     { "WeightUnitKg", 3 },
     219              :     { "WeightUnitPound", 3 },
     220              :     { "SizeUnitM", 3 },
     221              :     { "SizeUnitDm", 3 },
     222              :     { "SizeUnitFoot", 3 },
     223              :     { "SurfaceUnitDm2", 3 },
     224              :     { "SurfaceUnitFoot2", 3 },
     225              :     { "VolumeUnitCm3", 3 },
     226              :     { "VolumeUnitLitre", 3 },
     227              :     { "VolumeUnitGallon", 3 },
     228              :     { "TimeUnitSecond", 3 },
     229              :     { "TimeUnitMinute", 3 },
     230              :     { "TimeUnitDay", 3 },
     231              :     { "TimeUnitWeek", 3 },
     232              :     { "SurfaceUnitM2", 4 },
     233              :     { "SurfaceUnitInch2", 4 },
     234              :     { "TimeUnitYear", 4 },
     235              :     { "VolumeUnitDm3", 5 },
     236              :     { "VolumeUnitFoot3", 5 },
     237              :     { "VolumeUnitM3", 6 }
     238              :   };
     239              : 
     240           24 :   const size_t rules_len = sizeof (rules) / sizeof (rules[0]);
     241           24 :   if (NULL == unit)
     242            0 :     return 0;
     243              : 
     244          840 :   for (size_t i = 0; i<rules_len; i++)
     245          816 :     if (0 == strcmp (unit,
     246          816 :                      rules[i].unit))
     247            0 :       return rules[i].precision;
     248           24 :   return 0;
     249              : }
     250              : 
     251              : 
     252              : /**
     253              :  * Callback for a PATCH /products/$ID operation.
     254              :  *
     255              :  * @param cls closure for this function
     256              :  * @param result response being processed
     257              :  */
     258              : static void
     259           24 : patch_product_cb (struct PatchProductState *pis,
     260              :                   const struct TALER_MERCHANT_PatchPrivateProductResponse *
     261              :                   result)
     262              : {
     263           24 :   const struct TALER_MERCHANT_HttpResponse *hr = &result->hr;
     264              : 
     265           24 :   pis->iph = NULL;
     266           24 :   if (pis->http_status != hr->http_status)
     267              :   {
     268            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     269              :                 "Unexpected response code %u (%d) to command %s\n",
     270              :                 hr->http_status,
     271              :                 (int) hr->ec,
     272              :                 TALER_TESTING_interpreter_get_current_label (pis->is));
     273            0 :     TALER_TESTING_interpreter_fail (pis->is);
     274            0 :     return;
     275              :   }
     276           24 :   switch (hr->http_status)
     277              :   {
     278           16 :   case MHD_HTTP_NO_CONTENT:
     279           16 :     break;
     280            4 :   case MHD_HTTP_BAD_REQUEST:
     281            4 :     break;
     282            0 :   case MHD_HTTP_UNAUTHORIZED:
     283            0 :     break;
     284            0 :   case MHD_HTTP_FORBIDDEN:
     285            0 :     break;
     286            4 :   case MHD_HTTP_NOT_FOUND:
     287            4 :     break;
     288            0 :   case MHD_HTTP_CONFLICT:
     289            0 :     break;
     290            0 :   default:
     291            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     292              :                 "Unhandled HTTP status %u for PATCH /products/ID.\n",
     293              :                 hr->http_status);
     294              :   }
     295           24 :   TALER_TESTING_interpreter_next (pis->is);
     296              : }
     297              : 
     298              : 
     299              : /**
     300              :  * Run the "PATCH /products/$ID" CMD.
     301              :  *
     302              :  *
     303              :  * @param cls closure.
     304              :  * @param cmd command being run now.
     305              :  * @param is interpreter state.
     306              :  */
     307              : static void
     308           24 : patch_product_run (void *cls,
     309              :                    const struct TALER_TESTING_Command *cmd,
     310              :                    struct TALER_TESTING_Interpreter *is)
     311              : {
     312           24 :   struct PatchProductState *pis = cls;
     313              : 
     314           24 :   pis->is = is;
     315           24 :   pis->iph = TALER_MERCHANT_patch_private_product_create (
     316              :     TALER_TESTING_interpreter_get_context (is),
     317              :     pis->merchant_url,
     318              :     pis->product_id,
     319              :     pis->description,
     320              :     pis->unit,
     321           24 :     pis->unit_prices_len,
     322           24 :     pis->unit_prices);
     323           24 :   GNUNET_assert (
     324              :     GNUNET_OK ==
     325              :     TALER_MERCHANT_patch_private_product_set_options (
     326              :       pis->iph,
     327              :       TALER_MERCHANT_patch_private_product_option_description_i18n (pis->description_i18n),
     328              :       TALER_MERCHANT_patch_private_product_option_image (pis->image),
     329              :       TALER_MERCHANT_patch_private_product_option_taxes (pis->taxes),
     330              :       TALER_MERCHANT_patch_private_product_option_total_stock_val (pis->total_stock),
     331              :       TALER_MERCHANT_patch_private_product_option_total_lost (pis->total_lost),
     332              :       TALER_MERCHANT_patch_private_product_option_address (pis->address),
     333              :       TALER_MERCHANT_patch_private_product_option_next_restock (pis->next_restock),
     334              :       TALER_MERCHANT_patch_private_product_option_categories (pis->num_cats,
     335              :                                                               pis->cats)));
     336           24 :   GNUNET_assert (NULL != pis->iph);
     337           24 :   if (pis->use_fractional)
     338              :   {
     339            8 :     GNUNET_assert (
     340              :       GNUNET_OK ==
     341              :       TALER_MERCHANT_patch_private_product_set_options (
     342              :         pis->iph,
     343              :         TALER_MERCHANT_patch_private_product_option_total_stock_frac (
     344              :           pis->total_stock_frac),
     345              :         TALER_MERCHANT_patch_private_product_option_unit_allow_fraction (
     346              :           pis->unit_allow_fraction),
     347              :         TALER_MERCHANT_patch_private_product_option_unit_precision_level (
     348              :           pis->unit_precision_level)));
     349              :   }
     350              :   {
     351              :     enum TALER_ErrorCode ec;
     352              : 
     353           24 :     ec = TALER_MERCHANT_patch_private_product_start (
     354              :       pis->iph,
     355              :       &patch_product_cb,
     356              :       pis);
     357           24 :     GNUNET_assert (TALER_EC_NONE == ec);
     358              :   }
     359           24 : }
     360              : 
     361              : 
     362              : /**
     363              :  * Offers information from the PATCH /products CMD state to other
     364              :  * commands.
     365              :  *
     366              :  * @param cls closure
     367              :  * @param[out] ret result (could be anything)
     368              :  * @param trait name of the trait
     369              :  * @param index index number of the object to extract.
     370              :  * @return #GNUNET_OK on success
     371              :  */
     372              : static enum GNUNET_GenericReturnValue
     373           72 : patch_product_traits (void *cls,
     374              :                       const void **ret,
     375              :                       const char *trait,
     376              :                       unsigned int index)
     377              : {
     378           72 :   struct PatchProductState *pps = cls;
     379              :   struct TALER_TESTING_Trait traits[] = {
     380           72 :     TALER_TESTING_make_trait_product_description (pps->description),
     381           72 :     TALER_TESTING_make_trait_i18n_description (pps->description_i18n),
     382           72 :     TALER_TESTING_make_trait_product_unit (pps->unit),
     383           72 :     TALER_TESTING_make_trait_amount (&pps->price),
     384           72 :     TALER_TESTING_make_trait_product_image (pps->image),
     385           72 :     TALER_TESTING_make_trait_taxes (pps->taxes),
     386           72 :     TALER_TESTING_make_trait_product_stock (&pps->total_stock),
     387           72 :     TALER_TESTING_make_trait_product_unit_total_stock (
     388           72 :       pps->unit_total_stock),
     389           72 :     TALER_TESTING_make_trait_product_unit_precision_level (
     390           72 :       &pps->unit_precision_level),
     391           72 :     TALER_TESTING_make_trait_product_unit_allow_fraction (
     392           72 :       &pps->unit_allow_fraction),
     393           72 :     TALER_TESTING_make_trait_address (pps->address),
     394           72 :     TALER_TESTING_make_trait_timestamp (0,
     395           72 :                                         &pps->next_restock),
     396           72 :     TALER_TESTING_make_trait_product_id (pps->product_id),
     397           72 :     TALER_TESTING_trait_end (),
     398              :   };
     399              : 
     400           72 :   return TALER_TESTING_get_trait (traits,
     401              :                                   ret,
     402              :                                   trait,
     403              :                                   index);
     404              : }
     405              : 
     406              : 
     407              : /**
     408              :  * Free the state of a "GET product" CMD, and possibly
     409              :  * cancel a pending operation thereof.
     410              :  *
     411              :  * @param cls closure.
     412              :  * @param cmd command being run.
     413              :  */
     414              : static void
     415           24 : patch_product_cleanup (void *cls,
     416              :                        const struct TALER_TESTING_Command *cmd)
     417              : {
     418           24 :   struct PatchProductState *pis = cls;
     419              : 
     420           24 :   if (NULL != pis->iph)
     421              :   {
     422            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     423              :                 "PATCH /products/$ID operation did not complete\n");
     424            0 :     TALER_MERCHANT_patch_private_product_cancel (pis->iph);
     425              :   }
     426           24 :   if (pis->owns_unit_prices)
     427            2 :     GNUNET_free (pis->unit_prices);
     428           24 :   GNUNET_free (pis->cats);
     429           24 :   json_decref (pis->description_i18n);
     430           24 :   GNUNET_free (pis->image);
     431           24 :   json_decref (pis->taxes);
     432           24 :   json_decref (pis->address);
     433           24 :   GNUNET_free (pis);
     434           24 : }
     435              : 
     436              : 
     437              : struct TALER_TESTING_Command
     438           22 : TALER_TESTING_cmd_merchant_patch_product (
     439              :   const char *label,
     440              :   const char *merchant_url,
     441              :   const char *product_id,
     442              :   const char *description,
     443              :   json_t *description_i18n,
     444              :   const char *unit,
     445              :   const char *price,
     446              :   const char *image,
     447              :   json_t *taxes,
     448              :   int64_t total_stock,
     449              :   uint64_t total_lost,
     450              :   json_t *address,
     451              :   struct GNUNET_TIME_Timestamp next_restock,
     452              :   unsigned int http_status)
     453              : {
     454              :   struct PatchProductState *pis;
     455              : 
     456           22 :   GNUNET_assert ( (NULL == taxes) ||
     457              :                   json_is_array (taxes));
     458           22 :   pis = GNUNET_new (struct PatchProductState);
     459           22 :   pis->merchant_url = merchant_url;
     460           22 :   pis->product_id = product_id;
     461           22 :   pis->http_status = http_status;
     462           22 :   pis->description = description;
     463           22 :   pis->description_i18n = description_i18n; /* ownership taken */
     464           22 :   pis->unit = unit;
     465           22 :   pis->unit_precision_level = default_precision_from_unit (unit);
     466           22 :   GNUNET_assert (GNUNET_OK ==
     467              :                  TALER_string_to_amount (price,
     468              :                                          &pis->price));
     469           22 :   pis->unit_prices = &pis->price;
     470           22 :   pis->unit_prices_len = 1;
     471           22 :   pis->owns_unit_prices = false;
     472           22 :   pis->use_unit_price_array = false;
     473           22 :   pis->image = GNUNET_strdup (image);
     474           22 :   pis->taxes = taxes; /* ownership taken */
     475           22 :   pis->total_stock = total_stock;
     476           22 :   pis->total_stock_frac = 0;
     477           22 :   pis->unit_allow_fraction = false;
     478           22 :   pis->use_fractional = false;
     479           22 :   pis->total_lost = total_lost;
     480           22 :   pis->address = address; /* ownership taken */
     481           22 :   pis->next_restock = next_restock;
     482           22 :   patch_product_update_unit_total_stock (pis);
     483              :   {
     484           22 :     struct TALER_TESTING_Command cmd = {
     485              :       .cls = pis,
     486              :       .label = label,
     487              :       .run = &patch_product_run,
     488              :       .cleanup = &patch_product_cleanup,
     489              :       .traits = &patch_product_traits
     490              :     };
     491              : 
     492           22 :     return cmd;
     493              :   }
     494              : }
     495              : 
     496              : 
     497              : struct TALER_TESTING_Command
     498            6 : TALER_TESTING_cmd_merchant_patch_product2 (
     499              :   const char *label,
     500              :   const char *merchant_url,
     501              :   const char *product_id,
     502              :   const char *description,
     503              :   json_t *description_i18n,
     504              :   const char *unit,
     505              :   const char *price,
     506              :   const char *image,
     507              :   json_t *taxes,
     508              :   int64_t total_stock,
     509              :   uint32_t total_stock_frac,
     510              :   bool unit_allow_fraction,
     511              :   uint64_t total_lost,
     512              :   json_t *address,
     513              :   struct GNUNET_TIME_Timestamp next_restock,
     514              :   unsigned int http_status)
     515              : {
     516              :   struct TALER_TESTING_Command cmd;
     517              : 
     518            6 :   cmd = TALER_TESTING_cmd_merchant_patch_product (label,
     519              :                                                   merchant_url,
     520              :                                                   product_id,
     521              :                                                   description,
     522              :                                                   description_i18n,
     523              :                                                   unit,
     524              :                                                   price,
     525              :                                                   image,
     526              :                                                   taxes,
     527              :                                                   total_stock,
     528              :                                                   total_lost,
     529              :                                                   address,
     530              :                                                   next_restock,
     531              :                                                   http_status);
     532              :   {
     533            6 :     struct PatchProductState *pps = cmd.cls;
     534              : 
     535            6 :     pps->total_stock_frac = total_stock_frac;
     536            6 :     pps->unit_allow_fraction = unit_allow_fraction;
     537            6 :     pps->use_fractional = true;
     538            6 :     patch_product_update_unit_total_stock (pps);
     539              :   }
     540            6 :   return cmd;
     541              : }
     542              : 
     543              : 
     544              : struct TALER_TESTING_Command
     545            2 : TALER_TESTING_cmd_merchant_patch_product_with_unit_prices (
     546              :   const char *label,
     547              :   const char *merchant_url,
     548              :   const char *product_id,
     549              :   const char *description,
     550              :   const char *unit,
     551              :   const char *const *unit_prices,
     552              :   size_t unit_prices_len,
     553              :   unsigned int http_status)
     554              : {
     555              :   struct PatchProductState *pis;
     556              : 
     557            2 :   GNUNET_assert (0 < unit_prices_len);
     558            2 :   GNUNET_assert (NULL != unit_prices);
     559            2 :   pis = GNUNET_new (struct PatchProductState);
     560            2 :   pis->merchant_url = merchant_url;
     561            2 :   pis->product_id = product_id;
     562            2 :   pis->http_status = http_status;
     563            2 :   pis->description = description;
     564            2 :   pis->description_i18n = json_pack ("{s:s}", "en", description);
     565            2 :   pis->unit = unit;
     566            2 :   pis->unit_precision_level = default_precision_from_unit (unit);
     567            2 :   pis->unit_prices = GNUNET_new_array (unit_prices_len,
     568              :                                        struct TALER_Amount);
     569            2 :   pis->unit_prices_len = unit_prices_len;
     570            2 :   pis->owns_unit_prices = true;
     571            2 :   pis->use_unit_price_array = true;
     572            6 :   for (size_t i = 0; i < unit_prices_len; i++)
     573            4 :     GNUNET_assert (GNUNET_OK ==
     574              :                    TALER_string_to_amount (unit_prices[i],
     575              :                                            &pis->unit_prices[i]));
     576            2 :   pis->price = pis->unit_prices[0];
     577            2 :   pis->image = GNUNET_strdup ("");
     578            2 :   pis->taxes = json_array ();
     579            2 :   pis->total_stock = 5;
     580            2 :   pis->total_stock_frac = 0;
     581            2 :   pis->unit_allow_fraction = true;
     582            2 :   pis->unit_precision_level = 1;
     583            2 :   pis->use_fractional = true;
     584            2 :   pis->total_lost = 0;
     585            2 :   pis->address = json_object ();
     586            2 :   pis->next_restock = GNUNET_TIME_UNIT_FOREVER_TS;
     587            2 :   patch_product_update_unit_total_stock (pis);
     588              :   {
     589            2 :     struct TALER_TESTING_Command cmd = {
     590              :       .cls = pis,
     591              :       .label = label,
     592              :       .run = &patch_product_run,
     593              :       .cleanup = &patch_product_cleanup,
     594              :       .traits = &patch_product_traits
     595              :     };
     596              : 
     597            2 :     return cmd;
     598              :   }
     599              : }
     600              : 
     601              : 
     602              : struct TALER_TESTING_Command
     603            8 : TALER_TESTING_cmd_merchant_patch_product_with_categories (
     604              :   const char *label,
     605              :   const char *merchant_url,
     606              :   const char *product_id,
     607              :   const char *description,
     608              :   const char *unit,
     609              :   const char *price,
     610              :   unsigned int num_cats,
     611              :   const uint64_t *cats,
     612              :   unsigned int http_status)
     613              : {
     614              :   struct TALER_TESTING_Command cmd;
     615              : 
     616            8 :   cmd = TALER_TESTING_cmd_merchant_patch_product (
     617              :     label,
     618              :     merchant_url,
     619              :     product_id,
     620              :     description,
     621              :     json_pack ("{s:s}", "en", description),
     622              :     unit,
     623              :     price,
     624              :     "",
     625              :     json_array (),
     626              :     4, /* total stock */
     627              :     0, /* total lost */
     628              :     json_pack ("{s:s}", "street", "my street"),
     629            8 :     GNUNET_TIME_UNIT_ZERO_TS,
     630              :     http_status);
     631              :   {
     632            8 :     struct PatchProductState *pps = cmd.cls;
     633              : 
     634            8 :     pps->num_cats = num_cats;
     635            8 :     if (0 < num_cats)
     636              :     {
     637            8 :       pps->cats = GNUNET_new_array (num_cats,
     638              :                                     uint64_t);
     639           18 :       for (unsigned int i = 0; i < num_cats; i++)
     640           10 :         pps->cats[i] = cats[i];
     641              :     }
     642              :   }
     643            8 :   return cmd;
     644              : }
     645              : 
     646              : 
     647              : /* end of testing_api_cmd_patch_product.c */
        

Generated by: LCOV version 2.0-1