]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/tests/bcl.c
contrib/bc: merge version 5.1.0 from vendor branch
[FreeBSD/FreeBSD.git] / contrib / bc / tests / bcl.c
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 }