exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_amount.c (12630B)


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