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 (12658B)


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