From 5827630699a725e24a59d94861b01bad310f6a02 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 13 Apr 2015 17:20:46 +0200 Subject: [PATCH] starting with tests for libtalerutil --- src/include/taler_amount_lib.h | 2 +- src/include/taler_crypto_lib.h | 1 + src/include/taler_json_lib.h | 2 +- src/util/Makefile.am | 38 +++- src/util/amount.c | 66 +++--- src/util/test_amount.c | 190 ++++++++++++++++++ src/util/test_crypto.c | 38 ++++ src/util/test_json.c | 38 ++++ ..._json_validations.c => test_wireformats.c} | 0 9 files changed, 338 insertions(+), 37 deletions(-) create mode 100644 src/util/test_amount.c create mode 100644 src/util/test_crypto.c create mode 100644 src/util/test_json.c rename src/util/{test_json_validations.c => test_wireformats.c} (100%) diff --git a/src/include/taler_amount_lib.h b/src/include/taler_amount_lib.h index 82952f0b2..54eeda844 100644 --- a/src/include/taler_amount_lib.h +++ b/src/include/taler_amount_lib.h @@ -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 denom denomination to write the result to diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index d7d12354a..3c8aee557 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -489,5 +489,6 @@ TALER_refresh_link_encrypted_decode (const char *buf, size_t buf_len); +/* FIXME: should also have _encode API... */ #endif diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index 9410d5088..7e0955688 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -1,6 +1,6 @@ /* 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 terms of the GNU General Public License as published by the Free Software diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 2a5cdefef..804ff85a2 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -28,14 +28,40 @@ libtalerutil_la_LDFLAGS = \ -export-dynamic -no-undefined TESTS = \ - test-json-validations + test_amount \ + test_crypto \ + test_json \ + test_wireformats -check_PROGRAMS=\ - test-json-validations +check_PROGRAMS= \ + test_amount \ + test_crypto \ + test_json \ + test_wireformats -test_json_validations_SOURCES = \ - test_json_validations.c -test_json_validations_LDADD = \ + +test_amount_SOURCES = \ + 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 \ -ljansson \ libtalerutil.la diff --git a/src/util/amount.c b/src/util/amount.c index fcf12692f..74ffcd36f 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -19,12 +19,7 @@ * @author Sree Harsha Totakura * @author Florian Dold * @author Benedikt Mueller - * - * 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', + * @author Christian Grothoff */ #include "platform.h" #include "taler_util.h" @@ -91,14 +86,14 @@ TALER_string_to_amount (const char *str, { return GNUNET_OK; } - if ( (str[i] < '0') || (str[i] > '9') ) + if ( (value[i] < '0') || (value[i] > '9') ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid character `%c'\n", - str[i]); + value[i]); goto fail; } - n = str[i] - '0'; + n = value[i] - '0'; if (denom->value * 10 + n < denom->value) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -113,29 +108,29 @@ TALER_string_to_amount (const char *str, i++; /* parse fraction */ - if ('\0' == str[i]) + if ('\0' == value[i]) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Null after dot"); + "Null after dot\n"); goto fail; } b = TALER_AMOUNT_FRAC_BASE / 10; - while ('\0' != str[i]) + while ('\0' != value[i]) { if (0 == b) { 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); goto fail; } - if ( (str[i] < '0') || (str[i] > '9') ) + if ( (value[i] < '0') || (value[i] > '9') ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Error after comma"); + "Error after dot\n"); goto fail; } - n = str[i] - '0'; + n = value[i] - '0'; denom->fraction += n * b; b /= 10; i++; @@ -258,8 +253,8 @@ TALER_amount_cmp_currency (const struct TALER_Amount *a1, if ( (GNUNET_NO == test_valid (a1)) || (GNUNET_NO == test_valid (a2)) ) return GNUNET_SYSERR; - if (0 == strcmp (a1->currency, - a2->currency)) + if (0 == strcasecmp (a1->currency, + a2->currency)) return GNUNET_YES; return GNUNET_NO; } @@ -286,8 +281,10 @@ TALER_amount_cmp (const struct TALER_Amount *a1, TALER_amount_cmp_currency (a1, a2)); n1 = *a1; n2 = *a2; - TALER_amount_normalize (&n1); - TALER_amount_normalize (&n2); + GNUNET_assert (GNUNET_SYSERR != + TALER_amount_normalize (&n1)); + GNUNET_assert (GNUNET_SYSERR != + TALER_amount_normalize (&n2)); if (n1.value == n2.value) { if (n1.fraction < n2.fraction) @@ -329,8 +326,12 @@ TALER_amount_subtract (struct TALER_Amount *diff, } n1 = *a1; n2 = *a2; - TALER_amount_normalize (&n1); - TALER_amount_normalize (&n2); + if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) || + (GNUNET_SYSERR == TALER_amount_normalize (&n2)) ) + { + invalidate (diff); + return GNUNET_SYSERR; + } if (n1.fraction < n2.fraction) { @@ -377,6 +378,7 @@ TALER_amount_add (struct TALER_Amount *sum, { struct TALER_Amount n1; struct TALER_Amount n2; + struct TALER_Amount res; if (GNUNET_YES != TALER_amount_cmp_currency (a1, a2)) @@ -386,27 +388,32 @@ TALER_amount_add (struct TALER_Amount *sum, } n1 = *a1; n2 = *a2; - TALER_amount_normalize (&n1); - TALER_amount_normalize (&n2); + if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) || + (GNUNET_SYSERR == TALER_amount_normalize (&n2)) ) + { + invalidate (sum); + return GNUNET_SYSERR; + } GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (a1->currency, - sum)); - sum->value = n1.value + n2.value; - if (sum->value < n1.value) + &res)); + res.value = n1.value + n2.value; + if (res.value < n1.value) { /* integer overflow */ invalidate (sum); return GNUNET_SYSERR; } - sum->fraction = n1.fraction + n2.fraction; + res.fraction = n1.fraction + n2.fraction; if (GNUNET_SYSERR == - TALER_amount_normalize (sum)) + TALER_amount_normalize (&res)) { /* integer overflow via carry from fraction */ invalidate (sum); return GNUNET_SYSERR; } + *sum = res; return GNUNET_OK; } @@ -438,6 +445,7 @@ TALER_amount_normalize (struct TALER_Amount *amount) { /* failed to normalize, adding up fractions caused main value to overflow! */ + invalidate (amount); return GNUNET_SYSERR; } return ret; diff --git a/src/util/test_amount.c b/src/util/test_amount.c new file mode 100644 index 000000000..4741bcf36 --- /dev/null +++ b/src/util/test_amount.c @@ -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 +*/ + +/** + * @file util/test_amount.c + * @brief Tests for amount logic + * @author Christian Grothoff + */ +#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 */ diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c new file mode 100644 index 000000000..a375bcfbb --- /dev/null +++ b/src/util/test_crypto.c @@ -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 +*/ + +/** + * @file util/test_crypto.c + * @brief Tests for Taler-specific crypto logic + * @author Christian Grothoff + */ +#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 */ diff --git a/src/util/test_json.c b/src/util/test_json.c new file mode 100644 index 000000000..9eb72fb8c --- /dev/null +++ b/src/util/test_json.c @@ -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 +*/ + +/** + * @file util/test_json.c + * @brief Tests for Taler-specific crypto logic + * @author Christian Grothoff + */ +#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 */ diff --git a/src/util/test_json_validations.c b/src/util/test_wireformats.c similarity index 100% rename from src/util/test_json_validations.c rename to src/util/test_wireformats.c