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