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