xref: /freebsd/contrib/bc/tests/bcl.c (revision 95eb4b873b6a8b527c5bd78d7191975dfca38998)
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
47 err(BclError e)
48 {
49 	if (e != BCL_ERROR_NONE) abort();
50 }
51 
52 int
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