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