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 */
err(BclError e)46 static void err(BclError e) {
47 if (e != BCL_ERROR_NONE) abort();
48 }
49
main(void)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 bcl_ctxt_freeNums(ctxt);
238
239 bcl_gc();
240
241 // We need to pop both contexts and free them.
242 bcl_popContext();
243
244 bcl_ctxt_free(ctxt);
245
246 ctxt = bcl_context();
247
248 bcl_popContext();
249
250 bcl_ctxt_free(ctxt);
251
252 // Decrement the reference counter to ensure all is freed.
253 bcl_free();
254
255 bcl_free();
256
257 return 0;
258 }
259