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