LCOV - code coverage report
Current view: top level - util - test_amount.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 120 120
Test Date: 2026-04-14 15:39:31 Functions: 100.0 % 1 1

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2015, 2021 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 util/test_amount.c
      19              :  * @brief Tests for amount logic
      20              :  * @author Christian Grothoff <christian@grothoff.org>
      21              :  */
      22              : #include "taler/taler_util.h"
      23              : 
      24              : 
      25              : int
      26            1 : main (int argc,
      27              :       const char *const argv[])
      28              : {
      29              :   struct TALER_Amount a1;
      30              :   struct TALER_Amount a2;
      31              :   struct TALER_Amount a3;
      32              :   struct TALER_Amount r;
      33              :   char *c;
      34              : 
      35              :   (void) argc;
      36              :   (void) argv;
      37            1 :   GNUNET_log_setup ("test-amout",
      38              :                     "WARNING",
      39              :                     NULL);
      40              :   /* test invalid conversions */
      41            1 :   GNUNET_log_skip (6, GNUNET_NO);
      42              :   /* non-numeric */
      43            1 :   GNUNET_assert (GNUNET_SYSERR ==
      44              :                  TALER_string_to_amount ("EUR:4a",
      45              :                                          &a1));
      46              :   /* non-numeric */
      47            1 :   GNUNET_assert (GNUNET_SYSERR ==
      48              :                  TALER_string_to_amount ("EUR:4.4a",
      49              :                                          &a1));
      50              :   /* non-numeric */
      51            1 :   GNUNET_assert (GNUNET_SYSERR ==
      52              :                  TALER_string_to_amount ("EUR:4.a4",
      53              :                                          &a1));
      54              :   /* no currency */
      55            1 :   GNUNET_assert (GNUNET_SYSERR ==
      56              :                  TALER_string_to_amount (":4.a4",
      57              :                                          &a1));
      58              :   /* precision too high */
      59            1 :   GNUNET_assert (GNUNET_SYSERR ==
      60              :                  TALER_string_to_amount ("EUR:4.123456789",
      61              :                                          &a1));
      62              :   /* value too big */
      63            1 :   GNUNET_assert (GNUNET_SYSERR ==
      64              :                  TALER_string_to_amount (
      65              :                    "EUR:1234567890123456789012345678901234567890123456789012345678901234567890",
      66              :                    &a1));
      67            1 :   GNUNET_log_skip (0, GNUNET_YES);
      68              : 
      69              :   /* test conversion without fraction */
      70            1 :   GNUNET_assert (GNUNET_OK ==
      71              :                  TALER_string_to_amount ("EUR:4",
      72              :                                          &a1));
      73            1 :   GNUNET_assert (0 == strcasecmp ("EUR",
      74              :                                   a1.currency));
      75            1 :   GNUNET_assert (4 == a1.value);
      76            1 :   GNUNET_assert (0 == a1.fraction);
      77              : 
      78              :   /* test conversion with leading zero in fraction */
      79            1 :   GNUNET_assert (GNUNET_OK ==
      80              :                  TALER_string_to_amount ("EUR:0.02",
      81              :                                          &a2));
      82            1 :   GNUNET_assert (0 == strcasecmp ("EUR",
      83              :                                   a2.currency));
      84            1 :   GNUNET_assert (0 == a2.value);
      85            1 :   GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 2 == a2.fraction);
      86            1 :   c = TALER_amount_to_string (&a2);
      87            1 :   GNUNET_assert (0 == strcasecmp ("EUR:0.02",
      88              :                                   c));
      89            1 :   GNUNET_free (c);
      90              : 
      91              :   /* test conversion with leading space and with fraction */
      92            1 :   GNUNET_assert (GNUNET_OK ==
      93              :                  TALER_string_to_amount (" EUR:4.12",
      94              :                                          &a2));
      95            1 :   GNUNET_assert (0 == strcasecmp ("EUR",
      96              :                                   a2.currency));
      97            1 :   GNUNET_assert (4 == a2.value);
      98            1 :   GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 12 == a2.fraction);
      99              : 
     100              :   /* test use of local currency */
     101            1 :   GNUNET_assert (GNUNET_OK ==
     102              :                  TALER_string_to_amount (" LOCAL:4444.1000",
     103              :                                          &a3));
     104            1 :   GNUNET_assert (0 == strcasecmp ("LOCAL",
     105              :                                   a3.currency));
     106            1 :   GNUNET_assert (4444 == a3.value);
     107            1 :   GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 10 == a3.fraction);
     108              : 
     109              :   /* test CMP with equal and unequal currencies */
     110            1 :   GNUNET_assert (GNUNET_NO ==
     111              :                  TALER_amount_cmp_currency (&a1,
     112              :                                             &a3));
     113            1 :   GNUNET_assert (GNUNET_YES ==
     114              :                  TALER_amount_cmp_currency (&a1,
     115              :                                             &a2));
     116              : 
     117              :   /* test subtraction failure (currency mismatch) */
     118            1 :   GNUNET_assert (TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE ==
     119              :                  TALER_amount_subtract (&a3,
     120              :                                         &a3,
     121              :                                         &a2));
     122            1 :   GNUNET_assert (GNUNET_SYSERR ==
     123              :                  TALER_amount_normalize (&a3));
     124              : 
     125              :   /* test subtraction failure (negative result) */
     126            1 :   GNUNET_assert (TALER_AAR_INVALID_NEGATIVE_RESULT ==
     127              :                  TALER_amount_subtract (&a3,
     128              :                                         &a1,
     129              :                                         &a2));
     130            1 :   GNUNET_assert (GNUNET_SYSERR ==
     131              :                  TALER_amount_normalize (&a3));
     132              : 
     133              :   /* test subtraction success cases */
     134            1 :   GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
     135              :                  TALER_amount_subtract (&a3,
     136              :                                         &a2,
     137              :                                         &a1));
     138            1 :   GNUNET_assert (TALER_AAR_RESULT_ZERO ==
     139              :                  TALER_amount_subtract (&a3,
     140              :                                         &a1,
     141              :                                         &a1));
     142            1 :   GNUNET_assert (0 == a3.value);
     143            1 :   GNUNET_assert (0 == a3.fraction);
     144            1 :   GNUNET_assert (GNUNET_NO ==
     145              :                  TALER_amount_normalize (&a3));
     146              : 
     147              :   /* test addition success */
     148            1 :   GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
     149              :                  TALER_amount_add (&a3,
     150              :                                    &a3,
     151              :                                    &a2));
     152            1 :   GNUNET_assert (GNUNET_NO ==
     153              :                  TALER_amount_normalize (&a3));
     154              : 
     155              :   /* test normalization */
     156            1 :   a3.fraction = 2 * TALER_AMOUNT_FRAC_BASE;
     157            1 :   a3.value = 4;
     158            1 :   GNUNET_assert (GNUNET_YES ==
     159              :                  TALER_amount_normalize (&a3));
     160              : 
     161              :   /* test conversion to string */
     162            1 :   c = TALER_amount_to_string (&a3);
     163            1 :   GNUNET_assert (0 == strcmp ("EUR:6",
     164              :                               c));
     165            1 :   GNUNET_free (c);
     166              : 
     167              :   /* test normalization with fraction overflow */
     168            1 :   a3.fraction = 2 * TALER_AMOUNT_FRAC_BASE + 1;
     169            1 :   a3.value = 4;
     170            1 :   GNUNET_assert (GNUNET_YES ==
     171              :                  TALER_amount_normalize (&a3));
     172            1 :   c = TALER_amount_to_string (&a3);
     173            1 :   GNUNET_assert (0 == strcmp ("EUR:6.00000001",
     174              :                               c));
     175            1 :   GNUNET_free (c);
     176              : 
     177              :   /* test normalization with overflow */
     178            1 :   a3.fraction = 2 * TALER_AMOUNT_FRAC_BASE + 1;
     179            1 :   a3.value = UINT64_MAX - 1;
     180            1 :   GNUNET_assert (GNUNET_SYSERR ==
     181              :                  TALER_amount_normalize (&a3));
     182            1 :   c = TALER_amount_to_string (&a3);
     183            1 :   GNUNET_assert (NULL == c);
     184              : 
     185              :   /* test addition with overflow */
     186            1 :   a1.fraction = TALER_AMOUNT_FRAC_BASE - 1;
     187            1 :   a1.value = TALER_AMOUNT_MAX_VALUE - 5;
     188            1 :   a2.fraction = 2;
     189            1 :   a2.value = 5;
     190            1 :   GNUNET_assert (TALER_AAR_INVALID_RESULT_OVERFLOW ==
     191              :                  TALER_amount_add (&a3,
     192              :                                    &a1,
     193              :                                    &a2));
     194              : 
     195              :   /* test addition with underflow on fraction */
     196            1 :   a1.fraction = 1;
     197            1 :   a1.value = TALER_AMOUNT_MAX_VALUE;
     198            1 :   a2.fraction = 2;
     199            1 :   a2.value = 0;
     200            1 :   GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
     201              :                  TALER_amount_subtract (&a3,
     202              :                                         &a1,
     203              :                                         &a2));
     204            1 :   GNUNET_assert (TALER_AMOUNT_MAX_VALUE - 1 ==
     205              :                  a3.value);
     206            1 :   GNUNET_assert (TALER_AMOUNT_FRAC_BASE - 1 ==
     207              :                  a3.fraction);
     208              : 
     209              :   /* test division */
     210            1 :   GNUNET_assert (GNUNET_OK ==
     211              :                  TALER_string_to_amount ("EUR:3.33",
     212              :                                          &a1));
     213            1 :   TALER_amount_divide (&a2,
     214              :                        &a1,
     215              :                        1);
     216            1 :   GNUNET_assert (0 == strcasecmp ("EUR",
     217              :                                   a2.currency));
     218            1 :   GNUNET_assert (3 == a2.value);
     219            1 :   GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 33 == a2.fraction);
     220              : 
     221            1 :   TALER_amount_divide (&a2,
     222              :                        &a1,
     223              :                        3);
     224            1 :   GNUNET_assert (0 == strcasecmp ("EUR",
     225              :                                   a2.currency));
     226            1 :   GNUNET_assert (1 == a2.value);
     227            1 :   GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 11 == a2.fraction);
     228              : 
     229            1 :   TALER_amount_divide (&a2,
     230              :                        &a1,
     231              :                        2);
     232            1 :   GNUNET_assert (0 == strcasecmp ("EUR",
     233              :                                   a2.currency));
     234            1 :   GNUNET_assert (1 == a2.value);
     235            1 :   GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 1000 * 665 == a2.fraction);
     236            1 :   TALER_amount_divide (&a2,
     237              :                        &a1,
     238              :                        TALER_AMOUNT_FRAC_BASE * 2);
     239            1 :   GNUNET_assert (0 == strcasecmp ("EUR",
     240              :                                   a2.currency));
     241            1 :   GNUNET_assert (0 == a2.value);
     242            1 :   GNUNET_assert (1 == a2.fraction);
     243              : 
     244              :   /* test rounding #1 */
     245            1 :   GNUNET_assert (GNUNET_OK ==
     246              :                  TALER_string_to_amount ("EUR:0.01",
     247              :                                          &r));
     248            1 :   GNUNET_assert (GNUNET_OK ==
     249              :                  TALER_string_to_amount ("EUR:4.001",
     250              :                                          &a1));
     251            1 :   GNUNET_assert (GNUNET_OK ==
     252              :                  TALER_string_to_amount ("EUR:4",
     253              :                                          &a2));
     254            1 :   GNUNET_assert (GNUNET_OK ==
     255              :                  TALER_amount_round_down (&a1,
     256              :                                           &r));
     257            1 :   GNUNET_assert (GNUNET_NO ==
     258              :                  TALER_amount_round_down (&a1,
     259              :                                           &r));
     260            1 :   GNUNET_assert (0 == TALER_amount_cmp (&a1,
     261              :                                         &a2));
     262              : 
     263              :   /* test rounding #2 */
     264            1 :   GNUNET_assert (GNUNET_OK ==
     265              :                  TALER_string_to_amount ("EUR:0.001",
     266              :                                          &r));
     267              : 
     268            1 :   GNUNET_assert (GNUNET_OK ==
     269              :                  TALER_string_to_amount ("EUR:4.001",
     270              :                                          &a1));
     271            1 :   GNUNET_assert (GNUNET_OK ==
     272              :                  TALER_string_to_amount ("EUR:4.001",
     273              :                                          &a2));
     274            1 :   GNUNET_assert (GNUNET_NO ==
     275              :                  TALER_amount_round_down (&a1,
     276              :                                           &r));
     277            1 :   GNUNET_assert (0 == TALER_amount_cmp (&a1,
     278              :                                         &a2));
     279              : 
     280              :   /* test rounding #3 */
     281            1 :   GNUNET_assert (GNUNET_OK ==
     282              :                  TALER_string_to_amount ("BTC:5",
     283              :                                          &r));
     284            1 :   GNUNET_assert (GNUNET_OK ==
     285              :                  TALER_string_to_amount ("BTC:12.3",
     286              :                                          &a1));
     287            1 :   GNUNET_assert (GNUNET_OK ==
     288              :                  TALER_string_to_amount ("BTC:10",
     289              :                                          &a2));
     290            1 :   GNUNET_assert (GNUNET_OK ==
     291              :                  TALER_amount_round_down (&a1,
     292              :                                           &r));
     293            1 :   GNUNET_assert (0 == TALER_amount_cmp (&a1,
     294              :                                         &a2));
     295              : 
     296              :   /* test multiplication */
     297            1 :   GNUNET_assert (GNUNET_OK ==
     298              :                  TALER_string_to_amount ("BTC:0",
     299              :                                          &a1));
     300            1 :   GNUNET_assert (TALER_AAR_RESULT_ZERO ==
     301              :                  TALER_amount_multiply (&a2,
     302              :                                         &a1,
     303              :                                         42));
     304            1 :   GNUNET_assert (0 == TALER_amount_cmp (&a1,
     305              :                                         &a2));
     306            1 :   GNUNET_assert (GNUNET_OK ==
     307              :                  TALER_string_to_amount ("BTC:5.001",
     308              :                                          &a1));
     309            1 :   GNUNET_assert (GNUNET_OK ==
     310              :                  TALER_string_to_amount ("BTC:5001",
     311              :                                          &r));
     312            1 :   GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
     313              :                  TALER_amount_multiply (&a2,
     314              :                                         &a1,
     315              :                                         1000));
     316            1 :   GNUNET_assert (0 == TALER_amount_cmp (&r,
     317              :                                         &a2));
     318            1 :   GNUNET_assert (1000 ==
     319              :                  TALER_amount_divide2 (&a2,
     320              :                                        &a1));
     321            1 :   GNUNET_assert (GNUNET_OK ==
     322              :                  TALER_string_to_amount ("BTC:5006.00099999",
     323              :                                          &r));
     324            1 :   GNUNET_assert (1000 ==
     325              :                  TALER_amount_divide2 (&r,
     326              :                                        &a1));
     327            1 :   GNUNET_assert (GNUNET_OK ==
     328              :                  TALER_string_to_amount ("BTC:5000.99999999",
     329              :                                          &r));
     330            1 :   GNUNET_assert (999 ==
     331              :                  TALER_amount_divide2 (&r,
     332              :                                        &a1));
     333            1 :   GNUNET_assert (GNUNET_OK ==
     334              :                  TALER_string_to_amount ("BTC:0",
     335              :                                          &a1));
     336            1 :   GNUNET_assert (INT_MAX ==
     337              :                  TALER_amount_divide2 (&a2,
     338              :                                        &a1));
     339            1 :   GNUNET_assert (0 ==
     340              :                  TALER_amount_divide2 (&a1,
     341              :                                        &a2));
     342            1 :   return 0;
     343              : }
     344              : 
     345              : 
     346              : /* end of test_amount.c */
        

Generated by: LCOV version 2.0-1