/* * ***************************************************************************** * * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2023 Gavin D. Howard and contributors. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * ***************************************************************************** * * Tests for bcl(3). * */ #include #include #include #include /** * Takes an error code and aborts if it actually is an error. * @param e The error code. */ static void err(BclError e) { if (e != BCL_ERROR_NONE) abort(); } int main(void) { BclError e; BclContext ctxt; size_t scale; BclNumber n, n2, n3, n4, n5, n6, n7; char* res; BclBigDig b = 0; e = bcl_start(); err(e); // We do this twice to test the reference counting code. e = bcl_init(); err(e); e = bcl_init(); err(e); // If bcl is set to abort on fatal error, that is a bug because it should // default to off. if (bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR); bcl_setAbortOnFatalError(true); // Now it *should* be set. if (!bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // We do this twice to test the context stack. ctxt = bcl_ctxt_create(); bcl_pushContext(ctxt); ctxt = bcl_ctxt_create(); bcl_pushContext(ctxt); // Ensure that the scale is properly set. scale = 10; bcl_ctxt_setScale(ctxt, scale); scale = bcl_ctxt_scale(ctxt); if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR); scale = 16; bcl_ctxt_setIbase(ctxt, scale); scale = bcl_ctxt_ibase(ctxt); if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // Now the obase. bcl_ctxt_setObase(ctxt, scale); scale = bcl_ctxt_obase(ctxt); if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // Set the back for the tests bcl_ctxt_setIbase(ctxt, 10); scale = bcl_ctxt_ibase(ctxt); if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR); bcl_ctxt_setObase(ctxt, 10); scale = bcl_ctxt_obase(ctxt); if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // Ensure that creating, duping, and copying works. n = bcl_num_create(); n2 = bcl_dup(n); bcl_copy(n, n2); // Ensure that parsing works. n3 = bcl_parse("2938"); err(bcl_err(n3)); n4 = bcl_parse("-28390.9108273"); err(bcl_err(n4)); // We also want to be sure that negatives work. This is a special case // because bc and dc generate a negative instruction; they don't actually // parse numbers as negative. if (!bcl_num_neg(n4)) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // Add them and check the result. n5 = bcl_add_keep(n3, n4); err(bcl_err(n5)); res = bcl_string(n5); if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR); if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // We want to ensure all memory gets freed because we run this under // Valgrind. free(res); // Add them and check the result. n3 = bcl_add(n3, n4); err(bcl_err(n3)); res = bcl_string_keep(n3); if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR); if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // We want to ensure all memory gets freed because we run this under // Valgrind. free(res); // Ensure that divmod, a special case, works. n4 = bcl_parse("8937458902.2890347"); err(bcl_err(n4)); e = bcl_divmod_keep(n4, n3, &n5, &n6); err(e); res = bcl_string(n5); if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(n6); if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); // Ensure that divmod, a special case, works. n4 = bcl_parse("8937458902.2890347"); err(bcl_err(n4)); e = bcl_divmod(bcl_dup(n4), n3, &n5, &n6); err(e); res = bcl_string(n5); if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(n6); if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); // Ensure that sqrt works. This is also a special case. The reason is // because it is a one-argument function. Since all binary operators go // through the same code (basically), we can test add and be done. However, // sqrt does not, so we want to specifically test it. n4 = bcl_sqrt(n4); err(bcl_err(n4)); res = bcl_string(bcl_dup(n4)); if (strcmp(res, "94538.1346457028")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); // We want to check that numbers are properly extended... e = bcl_num_setScale(n4, 20); err(e); res = bcl_string(bcl_dup(n4)); if (strcmp(res, "94538.13464570280000000000")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); // ...and truncated. e = bcl_num_setScale(n4, 0); err(e); res = bcl_string(bcl_dup(n4)); if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); // Check conversion to hardware integers... e = bcl_bigdig(n4, &b); err(e); if (b != 94538) err(BCL_ERROR_FATAL_UNKNOWN_ERR); // ...and back. n4 = bcl_bigdig2num(b); err(bcl_err(n4)); res = bcl_string(bcl_dup(n4)); if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); // Check rand. n4 = bcl_frand(10); err(bcl_err(n4)); // Check that no asserts fire in shifting. n4 = bcl_lshift(n4, bcl_bigdig2num(10)); err(bcl_err(n4)); // Repeat. n3 = bcl_irand(n4); err(bcl_err(n3)); // Repeat. n2 = bcl_ifrand_keep(n3, 10); err(bcl_err(n2)); // Repeat. n2 = bcl_ifrand(bcl_dup(n3), 10); err(bcl_err(n2)); // Still checking asserts. e = bcl_rand_seedWithNum_keep(n3); err(e); // Still checking asserts. e = bcl_rand_seedWithNum(n3); err(e); // Still checking asserts. n4 = bcl_rand_seed2num(); err(bcl_err(n4)); // Finally, check modexp, yet another special case. n5 = bcl_parse("10"); err(bcl_err(n5)); n6 = bcl_modexp_keep(n5, n5, n5); err(bcl_err(n6)); n7 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5)); err(bcl_err(n7)); // Clean up. bcl_num_free(n); // Test leading zeroes. if (bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR); n = bcl_parse("0.01"); err(bcl_err(n)); n2 = bcl_parse("-0.01"); err(bcl_err(n2)); n3 = bcl_parse("1.01"); err(bcl_err(n3)); n4 = bcl_parse("-1.01"); err(bcl_err(n4)); res = bcl_string_keep(n); if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(bcl_dup(n)); if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(bcl_dup(n2)); if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(bcl_dup(n3)); if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(bcl_dup(n4)); if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); bcl_setLeadingZeroes(true); if (!bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR); res = bcl_string(bcl_dup(n)); if (strcmp(res, "0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(bcl_dup(n2)); if (strcmp(res, "-0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(bcl_dup(n3)); if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(bcl_dup(n4)); if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); bcl_setLeadingZeroes(false); if (bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR); res = bcl_string(n); if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(n2); if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(n3); if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); res = bcl_string(n4); if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR); free(res); bcl_ctxt_freeNums(ctxt); bcl_gc(); // We need to pop both contexts and free them. bcl_popContext(); bcl_ctxt_free(ctxt); ctxt = bcl_context(); bcl_popContext(); bcl_ctxt_free(ctxt); // Decrement the reference counter to ensure all is freed. bcl_free(); bcl_free(); bcl_end(); return 0; }