/*
This file is part of TALER
Copyright (C) 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
*/
/**
* @file lib/test_stefan.c
* @brief test calculations on the STEFAN curve
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_json_lib.h"
#include
#include "exchange_api_handle.h"
/**
* Check if @a a and @a b are numerically close.
*
* @param a an amount
* @param b an amount
* @return true if both values are quite close
*/
static bool
amount_close (const struct TALER_Amount *a,
const struct TALER_Amount *b)
{
struct TALER_Amount delta;
switch (TALER_amount_cmp (a,
b))
{
case -1: /* a < b */
GNUNET_assert (0 <
TALER_amount_subtract (&delta,
b,
a));
break;
case 0:
/* perfect */
return true;
case 1: /* a > b */
GNUNET_assert (0 <
TALER_amount_subtract (&delta,
a,
b));
break;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Rounding error is %s\n",
TALER_amount2s (&delta));
if (delta.value > 0)
{
GNUNET_break (0);
return false;
}
if (delta.fraction > 5000)
{
GNUNET_break (0);
return false;
}
return true; /* let's consider this a rounding error */
}
int
main (int argc,
char **argv)
{
struct TALER_EXCHANGE_DenomPublicKey dk;
struct TALER_EXCHANGE_Keys keys = {
.denom_keys = &dk,
.num_denom_keys = 1
};
struct TALER_Amount brut;
struct TALER_Amount net;
(void) argc;
(void) argv;
GNUNET_log_setup ("test-stefan",
"INFO",
NULL);
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("MAGIC:0.00001",
&dk.value));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("MAGIC:1",
&keys.stefan_abs));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("MAGIC:0.13",
&keys.stefan_log));
keys.stefan_lin = 1.15;
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("MAGIC:4",
&brut));
GNUNET_log_skip (1,
GNUNET_NO);
GNUNET_assert (GNUNET_SYSERR ==
TALER_EXCHANGE_keys_stefan_b2n (&keys,
&brut,
&net));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("MAGIC:4",
&net));
GNUNET_log_skip (1,
GNUNET_NO);
GNUNET_assert (GNUNET_SYSERR ==
TALER_EXCHANGE_keys_stefan_n2b (&keys,
&net,
&brut));
keys.stefan_lin = 1.0;
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("MAGIC:4",
&brut));
GNUNET_log_skip (1,
GNUNET_NO);
GNUNET_assert (GNUNET_SYSERR ==
TALER_EXCHANGE_keys_stefan_b2n (&keys,
&brut,
&net));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("MAGIC:4",
&net));
GNUNET_log_skip (1,
GNUNET_NO);
GNUNET_assert (GNUNET_SYSERR ==
TALER_EXCHANGE_keys_stefan_n2b (&keys,
&net,
&brut));
GNUNET_assert (0 == GNUNET_get_log_skip ());
keys.stefan_lin = 0.1;
/* try various values for lin and log STEFAN values */
for (unsigned int li = 1; li < 13; li += 1)
{
keys.stefan_lin = 1.0 * li / 100.0;
for (unsigned int lx = 1; lx < 100; lx += 1)
{
keys.stefan_log.fraction = lx * TALER_AMOUNT_FRAC_BASE / 100;
/* Check brutto-to-netto is stable */
for (unsigned int i = 0; i<10; i++)
{
struct TALER_Amount rval;
brut.value = i;
brut.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
GNUNET_assert (GNUNET_SYSERR !=
TALER_EXCHANGE_keys_stefan_b2n (&keys,
&brut,
&net));
GNUNET_assert (GNUNET_SYSERR !=
TALER_EXCHANGE_keys_stefan_n2b (&keys,
&net,
&rval));
if (TALER_amount_is_zero (&net))
GNUNET_assert (TALER_amount_is_zero (&rval));
else
{
GNUNET_assert (amount_close (&brut,
&rval));
TALER_EXCHANGE_keys_stefan_round (&keys,
&rval);
GNUNET_assert (amount_close (&brut,
&rval));
}
}
/* Check netto-to-brutto is stable */
for (unsigned int i = 0; i<10; i++)
{
struct TALER_Amount rval;
net.value = i;
net.fraction = i * TALER_AMOUNT_FRAC_BASE / 10;
GNUNET_assert (GNUNET_SYSERR !=
TALER_EXCHANGE_keys_stefan_n2b (&keys,
&net,
&brut));
GNUNET_assert (GNUNET_SYSERR !=
TALER_EXCHANGE_keys_stefan_b2n (&keys,
&brut,
&rval));
GNUNET_assert (amount_close (&net,
&rval));
TALER_EXCHANGE_keys_stefan_round (&keys,
&rval);
GNUNET_assert (amount_close (&net,
&rval));
}
}
}
return 0;
}