starting with tests for libtalerutil

This commit is contained in:
Christian Grothoff 2015-04-13 17:20:46 +02:00
parent 93bc450db3
commit 5827630699
9 changed files with 338 additions and 37 deletions

View File

@ -100,7 +100,7 @@ struct TALER_Amount
/** /**
* Parse denomination description, in the format "T : V : F". * Parse denomination description, in the format "T:V.F".
* *
* @param str denomination description * @param str denomination description
* @param denom denomination to write the result to * @param denom denomination to write the result to

View File

@ -489,5 +489,6 @@ TALER_refresh_link_encrypted_decode (const char *buf,
size_t buf_len); size_t buf_len);
/* FIXME: should also have _encode API... */
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014 Christian Grothoff (and other contributing authors) Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software

View File

@ -28,14 +28,40 @@ libtalerutil_la_LDFLAGS = \
-export-dynamic -no-undefined -export-dynamic -no-undefined
TESTS = \ TESTS = \
test-json-validations test_amount \
test_crypto \
test_json \
test_wireformats
check_PROGRAMS=\ check_PROGRAMS= \
test-json-validations test_amount \
test_crypto \
test_json \
test_wireformats
test_json_validations_SOURCES = \
test_json_validations.c test_amount_SOURCES = \
test_json_validations_LDADD = \ test_amount.c
test_amount_LDADD = \
-lgnunetutil \
libtalerutil.la
test_crypto_SOURCES = \
test_crypto.c
test_crypto_LDADD = \
-lgnunetutil \
libtalerutil.la
test_json_SOURCES = \
test_json.c
test_json_LDADD = \
-lgnunetutil \
-ljansson \
libtalerutil.la
test_wireformats_SOURCES = \
test_wireformats.c
test_wireformats_LDADD = \
-lgnunetutil \ -lgnunetutil \
-ljansson \ -ljansson \
libtalerutil.la libtalerutil.la

View File

@ -19,12 +19,7 @@
* @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Florian Dold * @author Florian Dold
* @author Benedikt Mueller * @author Benedikt Mueller
* * @author Christian Grothoff
* TODO:
* - the way this library currently deals with underflow/overflow
* is insufficient; just going for UINT32_MAX on overflow
* will not do; similar issues for incompatible currencies;
* we need some more explicit logic to say 'bogus value',
*/ */
#include "platform.h" #include "platform.h"
#include "taler_util.h" #include "taler_util.h"
@ -91,14 +86,14 @@ TALER_string_to_amount (const char *str,
{ {
return GNUNET_OK; return GNUNET_OK;
} }
if ( (str[i] < '0') || (str[i] > '9') ) if ( (value[i] < '0') || (value[i] > '9') )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Invalid character `%c'\n", "Invalid character `%c'\n",
str[i]); value[i]);
goto fail; goto fail;
} }
n = str[i] - '0'; n = value[i] - '0';
if (denom->value * 10 + n < denom->value) if (denom->value * 10 + n < denom->value)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@ -113,29 +108,29 @@ TALER_string_to_amount (const char *str,
i++; i++;
/* parse fraction */ /* parse fraction */
if ('\0' == str[i]) if ('\0' == value[i])
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Null after dot"); "Null after dot\n");
goto fail; goto fail;
} }
b = TALER_AMOUNT_FRAC_BASE / 10; b = TALER_AMOUNT_FRAC_BASE / 10;
while ('\0' != str[i]) while ('\0' != value[i])
{ {
if (0 == b) if (0 == b)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Fractional value too small (only %u digits supported)", "Fractional value too small (only %u digits supported)\n",
(unsigned int) TALER_AMOUNT_FRAC_LEN); (unsigned int) TALER_AMOUNT_FRAC_LEN);
goto fail; goto fail;
} }
if ( (str[i] < '0') || (str[i] > '9') ) if ( (value[i] < '0') || (value[i] > '9') )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Error after comma"); "Error after dot\n");
goto fail; goto fail;
} }
n = str[i] - '0'; n = value[i] - '0';
denom->fraction += n * b; denom->fraction += n * b;
b /= 10; b /= 10;
i++; i++;
@ -258,8 +253,8 @@ TALER_amount_cmp_currency (const struct TALER_Amount *a1,
if ( (GNUNET_NO == test_valid (a1)) || if ( (GNUNET_NO == test_valid (a1)) ||
(GNUNET_NO == test_valid (a2)) ) (GNUNET_NO == test_valid (a2)) )
return GNUNET_SYSERR; return GNUNET_SYSERR;
if (0 == strcmp (a1->currency, if (0 == strcasecmp (a1->currency,
a2->currency)) a2->currency))
return GNUNET_YES; return GNUNET_YES;
return GNUNET_NO; return GNUNET_NO;
} }
@ -286,8 +281,10 @@ TALER_amount_cmp (const struct TALER_Amount *a1,
TALER_amount_cmp_currency (a1, a2)); TALER_amount_cmp_currency (a1, a2));
n1 = *a1; n1 = *a1;
n2 = *a2; n2 = *a2;
TALER_amount_normalize (&n1); GNUNET_assert (GNUNET_SYSERR !=
TALER_amount_normalize (&n2); TALER_amount_normalize (&n1));
GNUNET_assert (GNUNET_SYSERR !=
TALER_amount_normalize (&n2));
if (n1.value == n2.value) if (n1.value == n2.value)
{ {
if (n1.fraction < n2.fraction) if (n1.fraction < n2.fraction)
@ -329,8 +326,12 @@ TALER_amount_subtract (struct TALER_Amount *diff,
} }
n1 = *a1; n1 = *a1;
n2 = *a2; n2 = *a2;
TALER_amount_normalize (&n1); if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) ||
TALER_amount_normalize (&n2); (GNUNET_SYSERR == TALER_amount_normalize (&n2)) )
{
invalidate (diff);
return GNUNET_SYSERR;
}
if (n1.fraction < n2.fraction) if (n1.fraction < n2.fraction)
{ {
@ -377,6 +378,7 @@ TALER_amount_add (struct TALER_Amount *sum,
{ {
struct TALER_Amount n1; struct TALER_Amount n1;
struct TALER_Amount n2; struct TALER_Amount n2;
struct TALER_Amount res;
if (GNUNET_YES != if (GNUNET_YES !=
TALER_amount_cmp_currency (a1, a2)) TALER_amount_cmp_currency (a1, a2))
@ -386,27 +388,32 @@ TALER_amount_add (struct TALER_Amount *sum,
} }
n1 = *a1; n1 = *a1;
n2 = *a2; n2 = *a2;
TALER_amount_normalize (&n1); if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) ||
TALER_amount_normalize (&n2); (GNUNET_SYSERR == TALER_amount_normalize (&n2)) )
{
invalidate (sum);
return GNUNET_SYSERR;
}
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (a1->currency, TALER_amount_get_zero (a1->currency,
sum)); &res));
sum->value = n1.value + n2.value; res.value = n1.value + n2.value;
if (sum->value < n1.value) if (res.value < n1.value)
{ {
/* integer overflow */ /* integer overflow */
invalidate (sum); invalidate (sum);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
sum->fraction = n1.fraction + n2.fraction; res.fraction = n1.fraction + n2.fraction;
if (GNUNET_SYSERR == if (GNUNET_SYSERR ==
TALER_amount_normalize (sum)) TALER_amount_normalize (&res))
{ {
/* integer overflow via carry from fraction */ /* integer overflow via carry from fraction */
invalidate (sum); invalidate (sum);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
*sum = res;
return GNUNET_OK; return GNUNET_OK;
} }
@ -438,6 +445,7 @@ TALER_amount_normalize (struct TALER_Amount *amount)
{ {
/* failed to normalize, adding up fractions caused /* failed to normalize, adding up fractions caused
main value to overflow! */ main value to overflow! */
invalidate (amount);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
return ret; return ret;

190
src/util/test_amount.c Normal file
View File

@ -0,0 +1,190 @@
/*
This file is part of TALER
(C) 2015 Christian Grothoff (and other contributing authors)
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, If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file util/test_amount.c
* @brief Tests for amount logic
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_amount_lib.h"
int
main(int argc,
const char *const argv[])
{
struct TALER_Amount a1;
struct TALER_Amount a2;
struct TALER_Amount a3;
char *c;
GNUNET_log_setup ("test-amout",
"WARNING",
NULL);
/* test invalid conversions */
GNUNET_log_skip (6, GNUNET_NO);
/* non-numeric */
GNUNET_assert (GNUNET_SYSERR ==
TALER_string_to_amount ("EUR:4a",
&a1));
/* non-numeric */
GNUNET_assert (GNUNET_SYSERR ==
TALER_string_to_amount ("EUR:4.4a",
&a1));
/* non-numeric */
GNUNET_assert (GNUNET_SYSERR ==
TALER_string_to_amount ("EUR:4.a4",
&a1));
/* no currency */
GNUNET_assert (GNUNET_SYSERR ==
TALER_string_to_amount (":4.a4",
&a1));
/* precision too high */
GNUNET_assert (GNUNET_SYSERR ==
TALER_string_to_amount ("EUR:4.1234567",
&a1));
/* value too big */
GNUNET_assert (GNUNET_SYSERR ==
TALER_string_to_amount ("EUR:1234567890123456789012345678901234567890123456789012345678901234567890",
&a1));
GNUNET_log_skip (0, GNUNET_YES);
/* test conversion without fraction */
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("EUR:4",
&a1));
GNUNET_assert (0 == strcasecmp ("EUR",
a1.currency));
GNUNET_assert (4 == a1.value);
GNUNET_assert (0 == a1.fraction);
/* test conversion with leading space and with fraction */
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (" eur:4.12",
&a2));
GNUNET_assert (0 == strcasecmp ("eur",
a2.currency));
GNUNET_assert (4 == a2.value);
GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 12 == a2.fraction);
/* test use of local currency */
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (" *LOCAL:4444.1000",
&a3));
GNUNET_assert (0 == strcasecmp ("*LOCAL",
a3.currency));
GNUNET_assert (4444 == a3.value);
GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 10 == a3.fraction);
/* test CMP with equal and unequal currencies */
GNUNET_assert (GNUNET_NO ==
TALER_amount_cmp_currency (&a1,
&a3));
GNUNET_assert (GNUNET_YES ==
TALER_amount_cmp_currency (&a1,
&a2));
/* test subtraction failure (currency missmatch) */
GNUNET_assert (GNUNET_SYSERR ==
TALER_amount_subtract (&a3,
&a3,
&a2));
GNUNET_assert (GNUNET_SYSERR ==
TALER_amount_normalize (&a3));
/* test subtraction failure (negative result) */
GNUNET_assert (GNUNET_SYSERR ==
TALER_amount_subtract (&a3,
&a1,
&a2));
GNUNET_assert (GNUNET_SYSERR ==
TALER_amount_normalize (&a3));
/* test subtraction success cases */
GNUNET_assert (GNUNET_YES ==
TALER_amount_subtract (&a3,
&a2,
&a1));
GNUNET_assert (GNUNET_NO ==
TALER_amount_subtract (&a3,
&a1,
&a1));
GNUNET_assert (0 == a3.value);
GNUNET_assert (0 == a3.fraction);
GNUNET_assert (GNUNET_NO ==
TALER_amount_normalize (&a3));
/* test addition success */
GNUNET_assert (GNUNET_OK ==
TALER_amount_add (&a3,
&a3,
&a2));
GNUNET_assert (GNUNET_NO ==
TALER_amount_normalize (&a3));
/* test normalization */
a3.fraction = 2 * TALER_AMOUNT_FRAC_BASE;
a3.value = 4;
GNUNET_assert (GNUNET_YES ==
TALER_amount_normalize (&a3));
/* test conversion to string */
c = TALER_amount_to_string (&a3);
GNUNET_assert (0 == strcmp ("EUR:6",
c));
GNUNET_free (c);
/* test normalization with fraction overflow */
a3.fraction = 2 * TALER_AMOUNT_FRAC_BASE + 1;
a3.value = 4;
GNUNET_assert (GNUNET_YES ==
TALER_amount_normalize (&a3));
c = TALER_amount_to_string (&a3);
GNUNET_assert (0 == strcmp ("EUR:6.000001",
c));
GNUNET_free (c);
/* test normalization with overflow */
a3.fraction = 2 * TALER_AMOUNT_FRAC_BASE + 1;
a3.value = UINT64_MAX - 1;
GNUNET_assert (GNUNET_SYSERR ==
TALER_amount_normalize (&a3));
c = TALER_amount_to_string (&a3);
GNUNET_assert (NULL == c);
/* test addition with overflow */
a1.fraction = TALER_AMOUNT_FRAC_BASE - 1;
a1.value = UINT64_MAX - 5;
a2.fraction = 2;
a2.value = 5;
GNUNET_assert (GNUNET_SYSERR ==
TALER_amount_add (&a3, &a1, &a2));
/* test addition with underflow on fraction */
a1.fraction = 1;
a1.value = UINT64_MAX;
a2.fraction = 2;
a2.value = 0;
GNUNET_assert (GNUNET_OK ==
TALER_amount_subtract (&a3, &a1, &a2));
GNUNET_assert (UINT64_MAX - 1 == a3.value);
GNUNET_assert (TALER_AMOUNT_FRAC_BASE - 1 == a3.fraction);
return 0;
}
/* end of test_amount.c */

38
src/util/test_crypto.c Normal file
View File

@ -0,0 +1,38 @@
/*
This file is part of TALER
(C) 2015 Christian Grothoff (and other contributing authors)
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, If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file util/test_crypto.c
* @brief Tests for Taler-specific crypto logic
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_crypto_lib.h"
int
main(int argc,
const char *const argv[])
{
GNUNET_log_setup ("test-crypto",
"WARNING",
NULL);
/* FIXME: implement test... */
return 0;
}
/* end of test_crypto.c */

38
src/util/test_json.c Normal file
View File

@ -0,0 +1,38 @@
/*
This file is part of TALER
(C) 2015 Christian Grothoff (and other contributing authors)
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, If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file util/test_json.c
* @brief Tests for Taler-specific crypto logic
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_json_lib.h"
int
main(int argc,
const char *const argv[])
{
GNUNET_log_setup ("test-json",
"WARNING",
NULL);
/* FIXME: implement test... */
return 0;
}
/* end of test_json.c */