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 */