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