1 /*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *****************************************************************************
31 *
32 * Tests for bcl(3).
33 *
34 */
35
36 #include <stdlib.h>
37 #include <stdbool.h>
38 #include <string.h>
39
40 #include <bcl.h>
41
42 /**
43 * Takes an error code and aborts if it actually is an error.
44 * @param e The error code.
45 */
46 static void
err(BclError e)47 err(BclError e)
48 {
49 if (e != BCL_ERROR_NONE) abort();
50 }
51
52 int
main(void)53 main(void)
54 {
55 BclError e;
56 BclContext ctxt;
57 size_t scale;
58 BclNumber n, n2, n3, n4, n5, n6, n7;
59 char* res;
60 BclBigDig b = 0;
61
62 e = bcl_start();
63 err(e);
64
65 // We do this twice to test the reference counting code.
66 e = bcl_init();
67 err(e);
68 e = bcl_init();
69 err(e);
70
71 // If bcl is set to abort on fatal error, that is a bug because it should
72 // default to off.
73 if (bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
74
75 bcl_setAbortOnFatalError(true);
76
77 // Now it *should* be set.
78 if (!bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
79
80 // We do this twice to test the context stack.
81 ctxt = bcl_ctxt_create();
82 bcl_pushContext(ctxt);
83 ctxt = bcl_ctxt_create();
84 bcl_pushContext(ctxt);
85
86 // Ensure that the scale is properly set.
87 scale = 10;
88 bcl_ctxt_setScale(ctxt, scale);
89 scale = bcl_ctxt_scale(ctxt);
90 if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
91
92 scale = 16;
93 bcl_ctxt_setIbase(ctxt, scale);
94 scale = bcl_ctxt_ibase(ctxt);
95 if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
96
97 // Now the obase.
98 bcl_ctxt_setObase(ctxt, scale);
99 scale = bcl_ctxt_obase(ctxt);
100 if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
101
102 // Set the back for the tests
103 bcl_ctxt_setIbase(ctxt, 10);
104 scale = bcl_ctxt_ibase(ctxt);
105 if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
106 bcl_ctxt_setObase(ctxt, 10);
107 scale = bcl_ctxt_obase(ctxt);
108 if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
109
110 // Ensure that creating, duping, and copying works.
111 n = bcl_num_create();
112 n2 = bcl_dup(n);
113 bcl_copy(n, n2);
114
115 // Ensure that parsing works.
116 n3 = bcl_parse("2938");
117 err(bcl_err(n3));
118 n4 = bcl_parse("-28390.9108273");
119 err(bcl_err(n4));
120
121 // We also want to be sure that negatives work. This is a special case
122 // because bc and dc generate a negative instruction; they don't actually
123 // parse numbers as negative.
124 if (!bcl_num_neg(n4)) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
125
126 // Add them and check the result.
127 n5 = bcl_add_keep(n3, n4);
128 err(bcl_err(n5));
129 res = bcl_string(n5);
130 if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
131 if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
132
133 // We want to ensure all memory gets freed because we run this under
134 // Valgrind.
135 free(res);
136
137 // Add them and check the result.
138 n3 = bcl_add(n3, n4);
139 err(bcl_err(n3));
140 res = bcl_string_keep(n3);
141 if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
142 if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
143
144 // We want to ensure all memory gets freed because we run this under
145 // Valgrind.
146 free(res);
147
148 // Ensure that divmod, a special case, works.
149 n4 = bcl_parse("8937458902.2890347");
150 err(bcl_err(n4));
151 e = bcl_divmod_keep(n4, n3, &n5, &n6);
152 err(e);
153
154 res = bcl_string(n5);
155 if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
156 free(res);
157
158 res = bcl_string(n6);
159 if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
160 free(res);
161
162 // Ensure that divmod, a special case, works.
163 n4 = bcl_parse("8937458902.2890347");
164 err(bcl_err(n4));
165 e = bcl_divmod(bcl_dup(n4), n3, &n5, &n6);
166 err(e);
167
168 res = bcl_string(n5);
169 if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
170 free(res);
171
172 res = bcl_string(n6);
173 if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
174 free(res);
175
176 // Ensure that sqrt works. This is also a special case. The reason is
177 // because it is a one-argument function. Since all binary operators go
178 // through the same code (basically), we can test add and be done. However,
179 // sqrt does not, so we want to specifically test it.
180 n4 = bcl_sqrt(n4);
181 err(bcl_err(n4));
182
183 res = bcl_string(bcl_dup(n4));
184
185 if (strcmp(res, "94538.1346457028")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
186
187 free(res);
188
189 // We want to check that numbers are properly extended...
190 e = bcl_num_setScale(n4, 20);
191 err(e);
192
193 res = bcl_string(bcl_dup(n4));
194
195 if (strcmp(res, "94538.13464570280000000000"))
196 err(BCL_ERROR_FATAL_UNKNOWN_ERR);
197
198 free(res);
199
200 // ...and truncated.
201 e = bcl_num_setScale(n4, 0);
202 err(e);
203
204 res = bcl_string(bcl_dup(n4));
205
206 if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
207
208 free(res);
209
210 // Check conversion to hardware integers...
211 e = bcl_bigdig(n4, &b);
212 err(e);
213
214 if (b != 94538) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
215
216 // ...and back.
217 n4 = bcl_bigdig2num(b);
218 err(bcl_err(n4));
219
220 res = bcl_string(bcl_dup(n4));
221
222 if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
223
224 free(res);
225
226 // Check rand.
227 n4 = bcl_frand(10);
228 err(bcl_err(n4));
229
230 // Check that no asserts fire in shifting.
231 n4 = bcl_lshift(n4, bcl_bigdig2num(10));
232 err(bcl_err(n4));
233
234 // Repeat.
235 n3 = bcl_irand(n4);
236 err(bcl_err(n3));
237
238 // Repeat.
239 n2 = bcl_ifrand_keep(n3, 10);
240 err(bcl_err(n2));
241
242 // Repeat.
243 n2 = bcl_ifrand(bcl_dup(n3), 10);
244 err(bcl_err(n2));
245
246 // Still checking asserts.
247 e = bcl_rand_seedWithNum_keep(n3);
248 err(e);
249
250 // Still checking asserts.
251 e = bcl_rand_seedWithNum(n3);
252 err(e);
253
254 // Still checking asserts.
255 n4 = bcl_rand_seed2num();
256 err(bcl_err(n4));
257
258 // Finally, check modexp, yet another special case.
259 n5 = bcl_parse("10");
260 err(bcl_err(n5));
261
262 n6 = bcl_modexp_keep(n5, n5, n5);
263 err(bcl_err(n6));
264
265 n7 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5));
266 err(bcl_err(n7));
267
268 // Clean up.
269 bcl_num_free(n);
270
271 // Test leading zeroes.
272 if (bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
273
274 n = bcl_parse("0.01");
275 err(bcl_err(n));
276
277 n2 = bcl_parse("-0.01");
278 err(bcl_err(n2));
279
280 n3 = bcl_parse("1.01");
281 err(bcl_err(n3));
282
283 n4 = bcl_parse("-1.01");
284 err(bcl_err(n4));
285
286 res = bcl_string_keep(n);
287 if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
288
289 free(res);
290
291 res = bcl_string(bcl_dup(n));
292 if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
293
294 free(res);
295
296 res = bcl_string(bcl_dup(n2));
297 if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
298
299 free(res);
300
301 res = bcl_string(bcl_dup(n3));
302 if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
303
304 free(res);
305
306 res = bcl_string(bcl_dup(n4));
307 if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
308
309 free(res);
310
311 bcl_setLeadingZeroes(true);
312
313 if (!bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
314
315 res = bcl_string(bcl_dup(n));
316 if (strcmp(res, "0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
317
318 free(res);
319
320 res = bcl_string(bcl_dup(n2));
321 if (strcmp(res, "-0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
322
323 free(res);
324
325 res = bcl_string(bcl_dup(n3));
326 if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
327
328 free(res);
329
330 res = bcl_string(bcl_dup(n4));
331 if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
332
333 free(res);
334
335 bcl_setLeadingZeroes(false);
336
337 if (bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
338
339 res = bcl_string(n);
340 if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
341
342 free(res);
343
344 res = bcl_string(n2);
345 if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
346
347 free(res);
348
349 res = bcl_string(n3);
350 if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
351
352 free(res);
353
354 res = bcl_string(n4);
355 if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
356
357 free(res);
358
359 bcl_ctxt_freeNums(ctxt);
360
361 bcl_gc();
362
363 // We need to pop both contexts and free them.
364 bcl_popContext();
365
366 bcl_ctxt_free(ctxt);
367
368 ctxt = bcl_context();
369
370 bcl_popContext();
371
372 bcl_ctxt_free(ctxt);
373
374 // Decrement the reference counter to ensure all is freed.
375 bcl_free();
376
377 bcl_free();
378
379 bcl_end();
380
381 return 0;
382 }
383