1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2023 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; 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 n3 = bcl_add(n3, n4); 128 err(bcl_err(n3)); 129 res = bcl_string(bcl_dup(n3)); 130 if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 131 132 // We want to ensure all memory gets freed because we run this under 133 // Valgrind. 134 free(res); 135 136 // Ensure that divmod, a special case, works. 137 n4 = bcl_parse("8937458902.2890347"); 138 err(bcl_err(n4)); 139 e = bcl_divmod(bcl_dup(n4), n3, &n5, &n6); 140 err(e); 141 142 res = bcl_string(n5); 143 144 if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 145 146 free(res); 147 148 res = bcl_string(n6); 149 150 if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 151 152 free(res); 153 154 // Ensure that sqrt works. This is also a special case. The reason is 155 // because it is a one-argument function. Since all binary operators go 156 // through the same code (basically), we can test add and be done. However, 157 // sqrt does not, so we want to specifically test it. 158 n4 = bcl_sqrt(n4); 159 err(bcl_err(n4)); 160 161 res = bcl_string(bcl_dup(n4)); 162 163 if (strcmp(res, "94538.1346457028")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 164 165 free(res); 166 167 // We want to check that numbers are properly extended... 168 e = bcl_num_setScale(n4, 20); 169 err(e); 170 171 res = bcl_string(bcl_dup(n4)); 172 173 if (strcmp(res, "94538.13464570280000000000")) 174 err(BCL_ERROR_FATAL_UNKNOWN_ERR); 175 176 free(res); 177 178 // ...and truncated. 179 e = bcl_num_setScale(n4, 0); 180 err(e); 181 182 res = bcl_string(bcl_dup(n4)); 183 184 if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 185 186 free(res); 187 188 // Check conversion to hardware integers... 189 e = bcl_bigdig(n4, &b); 190 err(e); 191 192 if (b != 94538) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 193 194 // ...and back. 195 n4 = bcl_bigdig2num(b); 196 err(bcl_err(n4)); 197 198 res = bcl_string(bcl_dup(n4)); 199 200 if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 201 202 free(res); 203 204 // Check rand. 205 n4 = bcl_frand(10); 206 err(bcl_err(n4)); 207 208 // Check that no asserts fire in shifting. 209 n4 = bcl_lshift(n4, bcl_bigdig2num(10)); 210 err(bcl_err(n4)); 211 212 // Repeat. 213 n3 = bcl_irand(n4); 214 err(bcl_err(n3)); 215 216 // Repeat. 217 n2 = bcl_ifrand(bcl_dup(n3), 10); 218 err(bcl_err(n2)); 219 220 // Still checking asserts. 221 e = bcl_rand_seedWithNum(n3); 222 err(e); 223 224 // Still checking asserts. 225 n4 = bcl_rand_seed2num(); 226 err(bcl_err(n4)); 227 228 // Finally, check modexp, yet another special case. 229 n5 = bcl_parse("10"); 230 err(bcl_err(n5)); 231 232 n6 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5)); 233 err(bcl_err(n6)); 234 235 // Clean up. 236 bcl_num_free(n); 237 238 // Test leading zeroes. 239 if (bcl_leadingZeroes()) 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")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 255 256 free(res); 257 258 res = bcl_string(bcl_dup(n2)); 259 if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 260 261 free(res); 262 263 res = bcl_string(bcl_dup(n3)); 264 if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 265 266 free(res); 267 268 res = bcl_string(bcl_dup(n4)); 269 if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 270 271 free(res); 272 273 bcl_setLeadingZeroes(true); 274 275 if (!bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 276 277 res = bcl_string(bcl_dup(n)); 278 if (strcmp(res, "0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 279 280 free(res); 281 282 res = bcl_string(bcl_dup(n2)); 283 if (strcmp(res, "-0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 284 285 free(res); 286 287 res = bcl_string(bcl_dup(n3)); 288 if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 289 290 free(res); 291 292 res = bcl_string(bcl_dup(n4)); 293 if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 294 295 free(res); 296 297 bcl_setLeadingZeroes(false); 298 299 if (bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 300 301 res = bcl_string(n); 302 if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 303 304 free(res); 305 306 res = bcl_string(n2); 307 if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 308 309 free(res); 310 311 res = bcl_string(n3); 312 if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 313 314 free(res); 315 316 res = bcl_string(n4); 317 if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); 318 319 free(res); 320 321 bcl_ctxt_freeNums(ctxt); 322 323 bcl_gc(); 324 325 // We need to pop both contexts and free them. 326 bcl_popContext(); 327 328 bcl_ctxt_free(ctxt); 329 330 ctxt = bcl_context(); 331 332 bcl_popContext(); 333 334 bcl_ctxt_free(ctxt); 335 336 // Decrement the reference counter to ensure all is freed. 337 bcl_free(); 338 339 bcl_free(); 340 341 bcl_end(); 342 343 return 0; 344 } 345