LCOV - code coverage report
Current view: top level - exchangedb - test_wire_out.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 121 121
Test Date: 2026-09-11 18:55:36 Functions: 100.0 % 10 10

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2026 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              :  * @file exchangedb/test_wire_out.c
      18              :  * @brief tests for the exchangedb functions whose primary table is
      19              :  *        `wire_out`
      20              :  * @author Christian Grothoff
      21              :  *
      22              :  * Covers #TALER_EXCHANGEDB_insert_wire_out(),
      23              :  * #TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id(),
      24              :  * #TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id_by_account(),
      25              :  * #TALER_EXCHANGEDB_iterate_exchange_debit_transfers() and
      26              :  * #TALER_EXCHANGEDB_iterate_aggregation_amounts_for_kyc_check().
      27              :  *
      28              :  * `wire_out` records the transfers the exchange actually made.  It
      29              :  * references `wire_targets` for the receiver, which TDB_account() creates;
      30              :  * the exchange's own account is stored as a plain string.
      31              :  */
      32              : #include "test_common.h"
      33              : #include "exchange-database/insert_wire_out.h"
      34              : #include "exchange-database/iterate_aggregation_amounts_for_kyc_check.h"
      35              : #include "exchange-database/iterate_exchange_debit_transfers.h"
      36              : #include "exchange-database/iterate_wire_outs_above_serial_id.h"
      37              : #include "exchange-database/iterate_wire_outs_above_serial_id_by_account.h"
      38              : 
      39              : 
      40              : /**
      41              :  * Account the checks pay out to.
      42              :  */
      43              : static struct TDB_Account account;
      44              : 
      45              : 
      46              : /**
      47              :  * A second account, to show the filters are per account.
      48              :  */
      49              : static struct TDB_Account other;
      50              : 
      51              : 
      52              : /**
      53              :  * Build a timestamp from a number of seconds since the epoch.
      54              :  *
      55              :  * @param secs seconds since the epoch
      56              :  * @return the timestamp
      57              :  */
      58              : static struct GNUNET_TIME_Timestamp
      59            3 : ts (uint64_t secs)
      60              : {
      61            3 :   struct GNUNET_TIME_Absolute abs = {
      62            3 :     .abs_value_us = secs * 1000LLU * 1000LLU
      63              :   };
      64              : 
      65            3 :   return GNUNET_TIME_absolute_to_timestamp (abs);
      66              : }
      67              : 
      68              : 
      69              : /**
      70              :  * Closure for #wire_out_cb().
      71              :  */
      72              : struct OutContext
      73              : {
      74              :   /**
      75              :    * How many rows did the callback see?
      76              :    */
      77              :   unsigned int total;
      78              : 
      79              :   /**
      80              :    * Stop after this many rows; 0 for no limit.
      81              :    */
      82              :   unsigned int stop_after;
      83              : 
      84              :   /**
      85              :    * Wire transfer we are looking for, NULL to match nothing.
      86              :    */
      87              :   const struct TALER_WireTransferIdentifierRawP *wtid;
      88              : 
      89              :   /**
      90              :    * How many times did we see it?
      91              :    */
      92              :   unsigned int matched;
      93              : 
      94              :   /**
      95              :    * Amount reported for it.
      96              :    */
      97              :   struct TALER_Amount amount;
      98              : 
      99              :   /**
     100              :    * Receiver account reported for it, owned by this struct.
     101              :    */
     102              :   char *payto;
     103              : };
     104              : 
     105              : 
     106              : /**
     107              :  * Callback for the `wire_out` iterators.
     108              :  *
     109              :  * @param cls a `struct OutContext *`
     110              :  * @param rowid row of the transfer
     111              :  * @param date when it was made
     112              :  * @param wtid its wire transfer identifier
     113              :  * @param payto_uri where the money went
     114              :  * @param amount how much was transferred
     115              :  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop
     116              :  */
     117              : static enum GNUNET_GenericReturnValue
     118            8 : wire_out_cb (void *cls,
     119              :              uint64_t rowid,
     120              :              struct GNUNET_TIME_Timestamp date,
     121              :              const struct TALER_WireTransferIdentifierRawP *wtid,
     122              :              const struct TALER_FullPayto payto_uri,
     123              :              const struct TALER_Amount *amount)
     124              : {
     125            8 :   struct OutContext *ctx = cls;
     126              : 
     127              :   (void) rowid;
     128              :   (void) date;
     129            8 :   ctx->total++;
     130            8 :   if ( (NULL != ctx->wtid) &&
     131            1 :        (0 == GNUNET_memcmp (wtid,
     132              :                             ctx->wtid)) )
     133              :   {
     134            1 :     ctx->matched++;
     135            1 :     ctx->amount = *amount;
     136            1 :     GNUNET_free (ctx->payto);
     137            1 :     ctx->payto = GNUNET_strdup (payto_uri.full_payto);
     138              :   }
     139            8 :   if ( (0 != ctx->stop_after) &&
     140            1 :        (ctx->total >= ctx->stop_after) )
     141            1 :     return GNUNET_SYSERR;
     142            7 :   return GNUNET_OK;
     143              : }
     144              : 
     145              : 
     146              : /**
     147              :  * Closure for #transfer_cb().
     148              :  */
     149              : struct TransferContext
     150              : {
     151              :   /**
     152              :    * How many transfers did the callback see?
     153              :    */
     154              :   unsigned int total;
     155              : 
     156              :   /**
     157              :    * Row of the first transfer seen.
     158              :    */
     159              :   uint64_t first_row;
     160              : 
     161              :   /**
     162              :    * Sum of the whole-unit parts of the amounts seen.
     163              :    */
     164              :   uint64_t value_sum;
     165              : };
     166              : 
     167              : 
     168              : /**
     169              :  * Callback for #TALER_EXCHANGEDB_iterate_exchange_debit_transfers().
     170              :  *
     171              :  * @param cls a `struct TransferContext *`
     172              :  * @param row_id row of the transfer
     173              :  * @param payto_uri where the money went
     174              :  * @param execution_time when it was made
     175              :  * @param amount how much was transferred
     176              :  */
     177              : static void
     178           10 : transfer_cb (void *cls,
     179              :              uint64_t row_id,
     180              :              const char *payto_uri,
     181              :              struct GNUNET_TIME_Absolute execution_time,
     182              :              const struct TALER_Amount *amount)
     183              : {
     184           10 :   struct TransferContext *ctx = cls;
     185              : 
     186              :   (void) payto_uri;
     187              :   (void) execution_time;
     188           10 :   if (0 == ctx->total++)
     189            4 :     ctx->first_row = row_id;
     190           10 :   ctx->value_sum += amount->value;
     191           10 : }
     192              : 
     193              : 
     194              : /**
     195              :  * Closure for #amount_cb().
     196              :  */
     197              : struct AmountContext
     198              : {
     199              :   /**
     200              :    * How many amounts did the callback see?
     201              :    */
     202              :   unsigned int total;
     203              : 
     204              :   /**
     205              :    * Sum of the whole-unit parts of the amounts seen.
     206              :    */
     207              :   uint64_t value_sum;
     208              : 
     209              :   /**
     210              :    * Return this from the callback.
     211              :    */
     212              :   enum GNUNET_GenericReturnValue ret;
     213              : };
     214              : 
     215              : 
     216              : /**
     217              :  * Callback for
     218              :  * #TALER_EXCHANGEDB_iterate_aggregation_amounts_for_kyc_check().
     219              :  *
     220              :  * @param cls a `struct AmountContext *`
     221              :  * @param amount the transferred amount
     222              :  * @param date when it was transferred
     223              :  * @return what @e ret of the closure says
     224              :  */
     225              : static enum GNUNET_GenericReturnValue
     226            4 : amount_cb (void *cls,
     227              :            const struct TALER_Amount *amount,
     228              :            struct GNUNET_TIME_Absolute date)
     229              : {
     230            4 :   struct AmountContext *ctx = cls;
     231              : 
     232              :   (void) date;
     233            4 :   ctx->total++;
     234            4 :   ctx->value_sum += amount->value;
     235            4 :   return ctx->ret;
     236              : }
     237              : 
     238              : 
     239              : /**
     240              :  * Record an executed wire transfer.
     241              :  *
     242              :  * @param pg the database context
     243              :  * @param acc account the money went to
     244              :  * @param seed seed for the wire transfer identifier
     245              :  * @param when when the transfer was made, in seconds since the epoch
     246              :  * @param amount how much was transferred, e.g. "10"
     247              :  * @param metadata extra wire subject metadata, NULL for none
     248              :  * @param[out] wtid set to the wire transfer identifier used
     249              :  * @return transaction status
     250              :  */
     251              : static enum GNUNET_DB_QueryStatus
     252            3 : add_wire_out (struct TALER_EXCHANGEDB_PostgresContext *pg,
     253              :               const struct TDB_Account *acc,
     254              :               uint32_t seed,
     255              :               uint64_t when,
     256              :               const char *amount,
     257              :               const char *metadata,
     258              :               struct TALER_WireTransferIdentifierRawP *wtid)
     259              : {
     260            3 :   struct TALER_FullPayto exchange_payto = {
     261              :     .full_payto = (char *) "payto://x-taler-bank/localhost/exchange"
     262              :   };
     263            3 :   struct TALER_Amount a = TDB_amount (amount);
     264              : 
     265            3 :   TDB_fill (wtid,
     266              :             sizeof (*wtid),
     267              :             seed);
     268            3 :   return TALER_EXCHANGEDB_insert_wire_out (pg,
     269              :                                            ts (when),
     270              :                                            wtid,
     271              :                                            &acc->h_full,
     272              :                                            "exchange-account-1",
     273              :                                            exchange_payto,
     274              :                                            &a,
     275              :                                            metadata);
     276              : }
     277              : 
     278              : 
     279              : /**
     280              :  * Nothing is reported while the table is empty.
     281              :  *
     282              :  * @param pg the database context
     283              :  * @return 0 on success
     284              :  */
     285              : static int
     286            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
     287              : {
     288            1 :   struct OutContext ctx = { 0 };
     289            1 :   struct TransferContext tctx = { 0 };
     290            1 :   struct AmountContext actx = { 0 };
     291            1 :   struct TALER_Amount zero = TDB_amount ("0");
     292              : 
     293            1 :   TDB_account (pg,
     294              :                10,
     295              :                &account);
     296            1 :   TDB_account (pg,
     297              :                11,
     298              :                &other);
     299            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     300              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id (pg,
     301              :                                                               0,
     302              :                                                               &wire_out_cb,
     303              :                                                               &ctx));
     304            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     305              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id_by_account (
     306              :             pg,
     307              :             "exchange-account-1",
     308              :             0,
     309              :             &wire_out_cb,
     310              :             &ctx));
     311            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     312              :           TALER_EXCHANGEDB_iterate_exchange_debit_transfers (pg,
     313              :                                                              &zero,
     314              :                                                              0,
     315              :                                                              10,
     316              :                                                              NULL,
     317              :                                                              &transfer_cb,
     318              :                                                              &tctx));
     319            1 :   actx.ret = GNUNET_OK;
     320            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     321              :           TALER_EXCHANGEDB_iterate_aggregation_amounts_for_kyc_check (
     322              :             pg,
     323              :             &account.h_normalized,
     324              :             GNUNET_TIME_UNIT_ZERO_ABS,
     325              :             &amount_cb,
     326              :             &actx));
     327            1 :   FAILIF (0 != ctx.total);
     328            1 :   FAILIF (0 != tctx.total);
     329            1 :   FAILIF (0 != actx.total);
     330            1 :   return 0;
     331              : }
     332              : 
     333              : 
     334              : /**
     335              :  * A recorded transfer comes back with what it was recorded with.
     336              :  *
     337              :  * @param pg the database context
     338              :  * @return 0 on success
     339              :  */
     340              : static int
     341            1 : check_insert (struct TALER_EXCHANGEDB_PostgresContext *pg)
     342              : {
     343              :   struct TALER_WireTransferIdentifierRawP wtid;
     344              :   struct OutContext ctx;
     345            1 :   struct TALER_Amount expect = TDB_amount ("10");
     346              : 
     347            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     348              :           add_wire_out (pg,
     349              :                         &account,
     350              :                         10,
     351              :                         1600000000,
     352              :                         "10",
     353              :                         NULL,
     354              :                         &wtid));
     355            1 :   FAILIF (1 != TDB_count (pg,
     356              :                           "FROM wire_out"));
     357            1 :   memset (&ctx,
     358              :           0,
     359              :           sizeof (ctx));
     360            1 :   ctx.wtid = &wtid;
     361            1 :   FAILIF (0 >=
     362              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id (pg,
     363              :                                                               0,
     364              :                                                               &wire_out_cb,
     365              :                                                               &ctx));
     366            1 :   FAILIF_C (1 != ctx.matched,
     367              :             GNUNET_free (ctx.payto));
     368            1 :   FAILIF_C (0 != TALER_amount_cmp (&ctx.amount,
     369              :                                    &expect),
     370              :             GNUNET_free (ctx.payto));
     371            1 :   FAILIF_C (0 != strcmp (ctx.payto,
     372              :                          account.payto.full_payto),
     373              :             GNUNET_free (ctx.payto));
     374            1 :   GNUNET_free (ctx.payto);
     375            1 :   return 0;
     376              : }
     377              : 
     378              : 
     379              : /**
     380              :  * The by-account iterator filters on the exchange's own bank account, and
     381              :  * the serial bound and the abort return behave as documented.
     382              :  *
     383              :  * @param pg the database context
     384              :  * @return 0 on success
     385              :  */
     386              : static int
     387            1 : check_iterate (struct TALER_EXCHANGEDB_PostgresContext *pg)
     388              : {
     389              :   struct TALER_WireTransferIdentifierRawP w2;
     390              :   struct TALER_WireTransferIdentifierRawP w3;
     391              :   struct OutContext ctx;
     392              : 
     393            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     394              :           add_wire_out (pg,
     395              :                         &account,
     396              :                         11,
     397              :                         1600003600,
     398              :                         "2",
     399              :                         "invoice-42",
     400              :                         &w2));
     401            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     402              :           add_wire_out (pg,
     403              :                         &other,
     404              :                         12,
     405              :                         1600007200,
     406              :                         "5",
     407              :                         NULL,
     408              :                         &w3));
     409            1 :   FAILIF (3 != TDB_count (pg,
     410              :                           "FROM wire_out"));
     411              : 
     412            1 :   memset (&ctx,
     413              :           0,
     414              :           sizeof (ctx));
     415            1 :   FAILIF (3 !=
     416              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id (pg,
     417              :                                                               0,
     418              :                                                               &wire_out_cb,
     419              :                                                               &ctx));
     420            1 :   GNUNET_free (ctx.payto);
     421            1 :   memset (&ctx,
     422              :           0,
     423              :           sizeof (ctx));
     424            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     425              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id (pg,
     426              :                                                               1000,
     427              :                                                               &wire_out_cb,
     428              :                                                               &ctx));
     429            1 :   FAILIF (0 != ctx.total);
     430              : 
     431              :   /* everything went out through the same exchange account */
     432            1 :   memset (&ctx,
     433              :           0,
     434              :           sizeof (ctx));
     435            1 :   FAILIF (3 !=
     436              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id_by_account (
     437              :             pg,
     438              :             "exchange-account-1",
     439              :             0,
     440              :             &wire_out_cb,
     441              :             &ctx));
     442            1 :   GNUNET_free (ctx.payto);
     443            1 :   memset (&ctx,
     444              :           0,
     445              :           sizeof (ctx));
     446            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     447              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id_by_account (
     448              :             pg,
     449              :             "exchange-account-2",
     450              :             0,
     451              :             &wire_out_cb,
     452              :             &ctx));
     453            1 :   FAILIF (0 != ctx.total);
     454              : 
     455              :   /* a callback that gives up stops the iteration */
     456            1 :   memset (&ctx,
     457              :           0,
     458              :           sizeof (ctx));
     459            1 :   ctx.stop_after = 1;
     460            1 :   FAILIF (3 !=
     461              :           TALER_EXCHANGEDB_iterate_wire_outs_above_serial_id (pg,
     462              :                                                               0,
     463              :                                                               &wire_out_cb,
     464              :                                                               &ctx));
     465            1 :   FAILIF (1 != ctx.total);
     466            1 :   GNUNET_free (ctx.payto);
     467            1 :   return 0;
     468              : }
     469              : 
     470              : 
     471              : /**
     472              :  * The AML views filter by amount and by receiving account.
     473              :  *
     474              :  * @param pg the database context
     475              :  * @return 0 on success
     476              :  */
     477              : static int
     478            1 : check_aml_views (struct TALER_EXCHANGEDB_PostgresContext *pg)
     479              : {
     480            1 :   struct TALER_Amount zero = TDB_amount ("0");
     481            1 :   struct TALER_Amount five = TDB_amount ("5");
     482              :   struct TransferContext ctx;
     483              :   struct AmountContext actx;
     484              :   uint64_t lowest;
     485              : 
     486            1 :   memset (&ctx,
     487              :           0,
     488              :           sizeof (ctx));
     489            1 :   FAILIF (3 !=
     490              :           TALER_EXCHANGEDB_iterate_exchange_debit_transfers (pg,
     491              :                                                              &zero,
     492              :                                                              0,
     493              :                                                              10,
     494              :                                                              NULL,
     495              :                                                              &transfer_cb,
     496              :                                                              &ctx));
     497            1 :   FAILIF (10 + 2 + 5 != ctx.value_sum);
     498            1 :   lowest = ctx.first_row;
     499              : 
     500            1 :   memset (&ctx,
     501              :           0,
     502              :           sizeof (ctx));
     503            1 :   FAILIF (2 !=
     504              :           TALER_EXCHANGEDB_iterate_exchange_debit_transfers (pg,
     505              :                                                              &five,
     506              :                                                              0,
     507              :                                                              10,
     508              :                                                              NULL,
     509              :                                                              &transfer_cb,
     510              :                                                              &ctx));
     511            1 :   FAILIF (10 + 5 != ctx.value_sum);
     512              : 
     513            1 :   memset (&ctx,
     514              :           0,
     515              :           sizeof (ctx));
     516            1 :   FAILIF (2 !=
     517              :           TALER_EXCHANGEDB_iterate_exchange_debit_transfers (pg,
     518              :                                                              &zero,
     519              :                                                              0,
     520              :                                                              10,
     521              :                                                              &account.
     522              :                                                              h_normalized,
     523              :                                                              &transfer_cb,
     524              :                                                              &ctx));
     525            1 :   FAILIF (10 + 2 != ctx.value_sum);
     526              : 
     527              :   /* the negative limit walks the table backwards */
     528            1 :   memset (&ctx,
     529              :           0,
     530              :           sizeof (ctx));
     531            1 :   FAILIF (3 !=
     532              :           TALER_EXCHANGEDB_iterate_exchange_debit_transfers (pg,
     533              :                                                              &zero,
     534              :                                                              1000,
     535              :                                                              -10,
     536              :                                                              NULL,
     537              :                                                              &transfer_cb,
     538              :                                                              &ctx));
     539            1 :   FAILIF (lowest == ctx.first_row);
     540              : 
     541              :   /* the KYC view groups by the credited account */
     542            1 :   memset (&actx,
     543              :           0,
     544              :           sizeof (actx));
     545            1 :   actx.ret = GNUNET_OK;
     546            1 :   FAILIF (2 !=
     547              :           TALER_EXCHANGEDB_iterate_aggregation_amounts_for_kyc_check (
     548              :             pg,
     549              :             &account.h_normalized,
     550              :             GNUNET_TIME_UNIT_ZERO_ABS,
     551              :             &amount_cb,
     552              :             &actx));
     553            1 :   FAILIF (10 + 2 != actx.value_sum);
     554              : 
     555            1 :   memset (&actx,
     556              :           0,
     557              :           sizeof (actx));
     558            1 :   actx.ret = GNUNET_OK;
     559            1 :   FAILIF (1 !=
     560              :           TALER_EXCHANGEDB_iterate_aggregation_amounts_for_kyc_check (
     561              :             pg,
     562              :             &other.h_normalized,
     563              :             GNUNET_TIME_UNIT_ZERO_ABS,
     564              :             &amount_cb,
     565              :             &actx));
     566            1 :   FAILIF (5 != actx.value_sum);
     567              : 
     568              :   /* a limit in the future hides everything */
     569            1 :   memset (&actx,
     570              :           0,
     571              :           sizeof (actx));
     572            1 :   actx.ret = GNUNET_OK;
     573            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     574              :           TALER_EXCHANGEDB_iterate_aggregation_amounts_for_kyc_check (
     575              :             pg,
     576              :             &account.h_normalized,
     577              :             GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS),
     578              :             &amount_cb,
     579              :             &actx));
     580            1 :   FAILIF (0 != actx.total);
     581              : 
     582              :   /* and an aborting callback is not an error */
     583            1 :   memset (&actx,
     584              :           0,
     585              :           sizeof (actx));
     586            1 :   actx.ret = GNUNET_NO;
     587            1 :   FAILIF (0 >
     588              :           TALER_EXCHANGEDB_iterate_aggregation_amounts_for_kyc_check (
     589              :             pg,
     590              :             &account.h_normalized,
     591              :             GNUNET_TIME_UNIT_ZERO_ABS,
     592              :             &amount_cb,
     593              :             &actx));
     594            1 :   FAILIF (1 != actx.total);
     595            1 :   return 0;
     596              : }
     597              : 
     598              : 
     599              : /**
     600              :  * The checks to run, in order.
     601              :  */
     602              : static const struct TDB_Test tests[] = {
     603              :   { "wire-out-empty",
     604              :     &check_empty },
     605              :   { "wire-out-insert",
     606              :     &check_insert },
     607              :   { "wire-out-iterate",
     608              :     &check_iterate },
     609              :   { "wire-out-aml-views",
     610              :     &check_aml_views },
     611              :   { NULL, NULL }
     612              : };
     613              : 
     614              : 
     615              : int
     616            1 : main (int argc,
     617              :       char *const *argv)
     618              : {
     619              :   int ret;
     620              : 
     621            1 :   ret = TDB_main (argc,
     622              :                   argv,
     623              :                   "test-wire-out",
     624              :                   "Tests for the exchangedb `wire_out' table",
     625              :                   tests);
     626            1 :   TDB_account_free (&account);
     627            1 :   TDB_account_free (&other);
     628            1 :   return ret;
     629              : }
     630              : 
     631              : 
     632              : /* end of test_wire_out.c */
        

Generated by: LCOV version 2.0-1