xref: /freebsd/contrib/bc/tests/bcl.c (revision 5bb3134a8c21cb87b30e135ef168483f0333dabb)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2021 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 	if (e != BCL_ERROR_NONE) abort();
48 }
49 
50 int main(void) {
51 
52 	BclError e;
53 	BclContext ctxt;
54 	size_t scale;
55 	BclNumber n, n2, n3, n4, n5, n6;
56 	char* res;
57 	BclBigDig b = 0;
58 
59 	// We do this twice to test the reference counting code.
60 	e = bcl_init();
61 	err(e);
62 	e = bcl_init();
63 	err(e);
64 
65 	// If bcl is set to abort on fatal error, that is a bug because it should
66 	// default to off.
67 	if (bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
68 
69 	bcl_setAbortOnFatalError(true);
70 
71 	// Now it *should* be set.
72 	if (!bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
73 
74 	// We do this twice to test the context stack.
75 	ctxt = bcl_ctxt_create();
76 	bcl_pushContext(ctxt);
77 	ctxt = bcl_ctxt_create();
78 	bcl_pushContext(ctxt);
79 
80 	// Ensure that the scale is properly set.
81 	scale = 10;
82 	bcl_ctxt_setScale(ctxt, scale);
83 	scale = bcl_ctxt_scale(ctxt);
84 	if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
85 
86 	scale = 16;
87 	bcl_ctxt_setIbase(ctxt, scale);
88 	scale = bcl_ctxt_ibase(ctxt);
89 	if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
90 
91 	// Now the obase.
92 	bcl_ctxt_setObase(ctxt, scale);
93 	scale = bcl_ctxt_obase(ctxt);
94 	if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
95 
96 	// Set the back for the tests
97 	bcl_ctxt_setIbase(ctxt, 10);
98 	scale = bcl_ctxt_ibase(ctxt);
99 	if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
100 	bcl_ctxt_setObase(ctxt, 10);
101 	scale = bcl_ctxt_obase(ctxt);
102 	if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
103 
104 	// Ensure that creating, duping, and copying works.
105 	n = bcl_num_create();
106 	n2 = bcl_dup(n);
107 	bcl_copy(n, n2);
108 
109 	// Ensure that parsing works.
110 	n3 = bcl_parse("2938");
111 	err(bcl_err(n3));
112 	n4 = bcl_parse("-28390.9108273");
113 	err(bcl_err(n4));
114 
115 	// We also want to be sure that negatives work. This is a special case
116 	// because bc and dc generate a negative instruction; they don't actually
117 	// parse numbers as negative.
118 	if (!bcl_num_neg(n4)) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
119 
120 	// Add them and check the result.
121 	n3 = bcl_add(n3, n4);
122 	err(bcl_err(n3));
123 	res = bcl_string(bcl_dup(n3));
124 	if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
125 
126 	// We want to ensure all memory gets freed because we run this under
127 	// Valgrind.
128 	free(res);
129 
130 	// Ensure that divmod, a special case, works.
131 	n4 = bcl_parse("8937458902.2890347");
132 	err(bcl_err(n4));
133 	e = bcl_divmod(bcl_dup(n4), n3, &n5, &n6);
134 	err(e);
135 
136 	res = bcl_string(n5);
137 
138 	if (strcmp(res, "-351137.0060159482"))
139 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
140 
141 	free(res);
142 
143 	res = bcl_string(n6);
144 
145 	if (strcmp(res, ".00000152374405414"))
146 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
147 
148 	free(res);
149 
150 	// Ensure that sqrt works. This is also a special case. The reason is
151 	// because it is a one-argument function. Since all binary operators go
152 	// through the same code (basically), we can test add and be done. However,
153 	// sqrt does not, so we want to specifically test it.
154 	n4 = bcl_sqrt(n4);
155 	err(bcl_err(n4));
156 
157 	res = bcl_string(bcl_dup(n4));
158 
159 	if (strcmp(res, "94538.1346457028"))
160 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
161 
162 	free(res);
163 
164 	// We want to check that numbers are properly extended...
165 	e = bcl_num_setScale(n4, 20);
166 	err(e);
167 
168 	res = bcl_string(bcl_dup(n4));
169 
170 	if (strcmp(res, "94538.13464570280000000000"))
171 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
172 
173 	free(res);
174 
175 	// ...and truncated.
176 	e = bcl_num_setScale(n4, 0);
177 	err(e);
178 
179 	res = bcl_string(bcl_dup(n4));
180 
181 	if (strcmp(res, "94538"))
182 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
183 
184 	free(res);
185 
186 	// Check conversion to hardware integers...
187 	e = bcl_bigdig(n4, &b);
188 	err(e);
189 
190 	if (b != 94538) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
191 
192 	// ...and back.
193 	n4 = bcl_bigdig2num(b);
194 	err(bcl_err(n4));
195 
196 	res = bcl_string(bcl_dup(n4));
197 
198 	if (strcmp(res, "94538"))
199 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
200 
201 	free(res);
202 
203 	// Check rand.
204 	n4 = bcl_frand(10);
205 	err(bcl_err(n4));
206 
207 	// Check that no asserts fire in shifting.
208 	n4 = bcl_lshift(n4, bcl_bigdig2num(10));
209 	err(bcl_err(n4));
210 
211 	// Repeat.
212 	n3 = bcl_irand(n4);
213 	err(bcl_err(n3));
214 
215 	// Repeat.
216 	n2 = bcl_ifrand(bcl_dup(n3), 10);
217 	err(bcl_err(n2));
218 
219 	// Still checking asserts.
220 	e = bcl_rand_seedWithNum(n3);
221 	err(e);
222 
223 	// Still checking asserts.
224 	n4 = bcl_rand_seed2num();
225 	err(bcl_err(n4));
226 
227 	// Finally, check modexp, yet another special case.
228 	n5 = bcl_parse("10");
229 	err(bcl_err(n5));
230 
231 	n6 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5));
232 	err(bcl_err(n6));
233 
234 	// Clean up.
235 	bcl_num_free(n);
236 
237 	// Test leading zeroes.
238 	if (bcl_leadingZeroes())
239 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
240 
241 	n = bcl_parse("0.01");
242 	err(bcl_err(n));
243 
244 	n2 = bcl_parse("-0.01");
245 	err(bcl_err(n2));
246 
247 	n3 = bcl_parse("1.01");
248 	err(bcl_err(n3));
249 
250 	n4 = bcl_parse("-1.01");
251 	err(bcl_err(n4));
252 
253 	res = bcl_string(bcl_dup(n));
254 	if (strcmp(res, ".01"))
255 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
256 
257 	free(res);
258 
259 	res = bcl_string(bcl_dup(n2));
260 	if (strcmp(res, "-.01"))
261 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
262 
263 	free(res);
264 
265 	res = bcl_string(bcl_dup(n3));
266 	if (strcmp(res, "1.01"))
267 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
268 
269 	free(res);
270 
271 	res = bcl_string(bcl_dup(n4));
272 	if (strcmp(res, "-1.01"))
273 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
274 
275 	free(res);
276 
277 	bcl_setLeadingZeroes(true);
278 
279 	if (!bcl_leadingZeroes())
280 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
281 
282 	res = bcl_string(bcl_dup(n));
283 	if (strcmp(res, "0.01"))
284 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
285 
286 	free(res);
287 
288 	res = bcl_string(bcl_dup(n2));
289 	if (strcmp(res, "-0.01"))
290 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
291 
292 	free(res);
293 
294 	res = bcl_string(bcl_dup(n3));
295 	if (strcmp(res, "1.01"))
296 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
297 
298 	free(res);
299 
300 	res = bcl_string(bcl_dup(n4));
301 	if (strcmp(res, "-1.01"))
302 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
303 
304 	free(res);
305 
306 	bcl_setLeadingZeroes(false);
307 
308 	if (bcl_leadingZeroes())
309 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
310 
311 	res = bcl_string(n);
312 	if (strcmp(res, ".01"))
313 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
314 
315 	free(res);
316 
317 	res = bcl_string(n2);
318 	if (strcmp(res, "-.01"))
319 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
320 
321 	free(res);
322 
323 	res = bcl_string(n3);
324 	if (strcmp(res, "1.01"))
325 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
326 
327 	free(res);
328 
329 	res = bcl_string(n4);
330 	if (strcmp(res, "-1.01"))
331 		err(BCL_ERROR_FATAL_UNKNOWN_ERR);
332 
333 	free(res);
334 
335 	bcl_ctxt_freeNums(ctxt);
336 
337 	bcl_gc();
338 
339 	// We need to pop both contexts and free them.
340 	bcl_popContext();
341 
342 	bcl_ctxt_free(ctxt);
343 
344 	ctxt = bcl_context();
345 
346 	bcl_popContext();
347 
348 	bcl_ctxt_free(ctxt);
349 
350 	// Decrement the reference counter to ensure all is freed.
351 	bcl_free();
352 
353 	bcl_free();
354 
355 	return 0;
356 }
357