/* * Copyright (c) 2008-2024 Stefan Krah. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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 AUTHOR 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 AUTHOR 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. */ #if defined(__GNUC__) || defined(__COMPCERT__) #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include "mpdecimal.h" #include "test.h" #include "vctest.h" #define MAXLINE 400000 #define MAXTOKEN 32 #ifndef _MSC_VER #include #define ASSERT(p) if (!(p)) {abort();} #else #define ASSERT(p) if (!(p)) {mpd_err_fatal("assertion failed");} #endif static int extended = 1; static int global_failure = 0; static int file_failure = 0; static mpd_ssize_t strtossize(const char *s, char **end, int base) { int64_t retval; errno = 0; retval = _mpd_strtossize(s, end, base); if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) { errno = ERANGE; } if (errno == ERANGE) { return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX; } return (mpd_ssize_t)retval; } static void mpd_init_rand(mpd_t *x) { long r = random() % 100; uint8_t sign = random()%2; if (r >= 80) { mpd_minalloc(x); } else if (r >= 60) { mpd_minalloc(x); mpd_set_flags(x, sign); } else if (r >= 40) { mpd_setspecial(x, sign, MPD_NAN); } else if (r >= 20) { mpd_setspecial(x, sign, MPD_SNAN); } else { mpd_setspecial(x, sign, MPD_INF); } } /* These ranges are needed for the official test suite * and are generally not problematic at all. */ #if defined(MPD_CONFIG_64) #define MPD_READ_MAX_PREC 1070000000000000000LL #elif defined(MPD_CONFIG_32) #define MPD_READ_MAX_PREC 1070000000 #else #error "config not defined" #endif static void mpd_readcontext(mpd_context_t *ctx) { if (extended) { ctx->prec=MPD_READ_MAX_PREC; ctx->emax=MPD_READ_MAX_PREC; ctx->emin=-MPD_READ_MAX_PREC; } else { ctx->prec=MPD_MAX_PREC; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; } ctx->round=MPD_ROUND_HALF_UP; ctx->traps=MPD_Traps; ctx->status=0; ctx->newtrap=0; ctx->clamp=0; ctx->allcr=1; } static void mpd_testcontext(mpd_context_t *ctx) { if (extended) { #if defined(MPD_CONFIG_64) ctx->prec=MPD_MAX_PREC; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; #elif defined(MPD_CONFIG_32) /* These ranges are needed for the official test suite. */ ctx->prec=999999999; ctx->emax=999999999; ctx->emin=-999999999; #else #error "config not defined" #endif } else { ctx->prec=MPD_MAX_PREC; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; } ctx->round=MPD_ROUND_HALF_UP; ctx->traps=MPD_Traps; ctx->status=0; ctx->newtrap=0; ctx->clamp=0; ctx->allcr=1; } static void mpd_assert_context_ok(const mpd_context_t *ctx) { ASSERT(0 < ctx->prec && ctx->prec <= MPD_READ_MAX_PREC); ASSERT(0 <= ctx->emax && ctx->emax <= MPD_READ_MAX_PREC); ASSERT(-MPD_READ_MAX_PREC <= ctx->emin && ctx->emin <= 0); ASSERT(0 <= ctx->round && ctx->round < MPD_ROUND_GUARD); ASSERT(ctx->traps <= MPD_Max_status); ASSERT(ctx->status <= MPD_Max_status); ASSERT(ctx->clamp == 0 || ctx->clamp == 1); ASSERT(ctx->allcr == 0 || ctx->allcr == 1); } /* Known differences that are within the spec. */ struct result_diff { const char *id; const char *calc; const char *expected; }; struct status_diff { const char *id; uint32_t calc; uint32_t expected; }; static struct result_diff ulp_cases[] = { /* Cases where the result is allowed to differ by less than one ULP. * Only needed if ctx->allcr is 0. */ { "expx013", "1.001000", "1.001001" }, { "expx020", "1.000000", "1.000001" }, { "expx109", "0.999999910000004049999878", "0.999999910000004049999879" }, { "expx1036", "1.005088", "1.005087" }, { "expx350", "1.0000000", "1.0000001" }, { "expx351", "1.0000000", "1.0000001" }, { "expx352", "1.0000000", "1.0000001" }, {NULL, NULL, NULL} }; static struct status_diff status_cases[] = { /* With a reduced working precision in mpd_qpow() the status matches. */ { "pwsx803", MPD_Inexact|MPD_Rounded|MPD_Subnormal|MPD_Underflow, MPD_Inexact|MPD_Rounded }, {NULL, 0, 0} }; static const char *skipit[] = { /* NULL reference, decimal16, decimal32, or decimal128 */ "absx900", "addx9990", "addx9991", "clam090", "clam091", "clam092", "clam093", "clam094", "clam095", "clam096", "clam097", "clam098", "clam099", "clam189", "clam190", "clam191", "clam192", "clam193", "clam194", "clam195", "clam196", "clam197", "clam198", "clam199", "comx990", "comx991", "cotx9990", "cotx9991", "ctmx9990", "ctmx9991", "ddabs900", "ddadd9990", "ddadd9991", "ddcom9990", "ddcom9991", "ddcot9990", "ddcot9991", "ddctm9990", "ddctm9991", "dddiv9998", "dddiv9999", "dddvi900", "dddvi901", "ddfma2990", "ddfma2991", "ddfma39990", "ddfma39991", "ddlogb900", "ddmax900", "ddmax901", "ddmxg900", "ddmxg901", "ddmin900", "ddmin901", "ddmng900", "ddmng901", "ddmul9990", "ddmul9991", "ddnextm900", "ddnextm900", "ddnextp900", "ddnextp900", "ddnextt900", "ddnextt901", "ddqua998", "ddqua999", "ddred900", "ddrem1000", "ddrem1001", "ddrmn1000", "ddrmn1001", "ddsub9990", "ddsub9991", "ddintx074", "ddintx094", "divx9998", "divx9999", "dvix900", "dvix901", "dqabs900", "dqadd9990", "dqadd9991", "dqcom990", "dqcom991", "dqcot9990", "dqcot9991", "dqctm9990", "dqctm9991", "dqdiv9998", "dqdiv9999", "dqdvi900", "dqdvi901", "dqfma2990", "dqfma2991", "dqadd39990", "dqadd39991", "dqlogb900", "dqmax900", "dqmax901", "dqmxg900", "dqmxg901", "dqmin900", "dqmin901", "dqmng900", "dqmng901", "dqmul9990", "dqmul9991", "dqnextm900", "dqnextp900", "dqnextt900", "dqnextt901", "dqqua998", "dqqua999", "dqred900", "dqrem1000", "dqrem1001", "dqrmn1000", "dqrmn1001", "dqsub9990", "dqsub9991", "dqintx074", "dqintx094", "expx900", "fmax2990", "fmax2991", "fmax39990", "fmax39991", "lnx900", "logx900", "logbx900", "maxx900", "maxx901", "mxgx900", "mxgx901", "mnm900", "mnm901", "mng900", "mng901", "minx900", "mulx990", "mulx991", "nextm900", "nextp900", "nextt900", "nextt901", "plu900", "powx900", "powx901", "pwsx900", "quax1022", "quax1023", "quax1024", "quax1025", "quax1026", "quax1027", "quax1028", "quax1029", "quax0a2", "quax0a3", "quax998", "quax999", "redx900", "remx1000", "remx1001", "rmnx900", "rmnx901", "sqtx9900", "subx9990", "subx9991", /* operand range violations, invalid context */ "expx901", "expx902", "expx903", "expx905", "lnx901", "lnx902", "lnx903", "lnx905", "logx901", "logx902", "logx903", "logx905", "powx1183", "powx1184", "powx4001", "powx4002", "powx4003", "powx4005", "powx4008", "powx4010", "powx4012", "powx4014", "scbx164", "scbx165", "scbx166", #if defined(MPD_CONFIG_32) && MPD_MINALLOC_MAX <= 4 /* Under the allocation failure tests, the result is numerically correct (1 == 1.00000) but without zero padding. This is by design, since in case of MPD_Malloc_error mpd_qsqrt() retries the operation with a lower context precision and allows all exact results. The MPD_MINALLOC_MAX < 64 feature is is officially unsupported but works (if the little-endian mpd_ln10_data arrays are adjusted). */ "sqtx9045", #endif /* skipped for decNumber, too */ "powx4302", "powx4303", "powx4303", "powx4342", "powx4343", "pwsx805", /* disagreement for three arg power */ "pwmx325", "pwmx326", NULL }; static inline int startswith(const char *token, const char *s) { return token != NULL && strncasecmp(token, s, strlen(s)) == 0; } static inline int eqtoken(const char *token, const char *s) { return token != NULL && strcasecmp(token, s) == 0; } static int check_skip(char *id) { int i; for (i = 0; skipit[i] != NULL; i++) { if (eqtoken(id, skipit[i])) { #if defined(RT_VERBOSITY) && RT_VERBOSITY == 2 fprintf(stderr, "SKIP: %s\n", id); #endif return 1; } } return 0; } static char * nexttoken(char *cp) { static char *start = NULL; static char *end = NULL; if (cp == NULL) { assert(end != NULL); cp = end; } for (; *cp != '\0'; cp++) { if (isspace((unsigned char)*cp)) { /* empty */ } else if (*cp == '"') { start = end = cp+1; for (; *end != '\0'; end++) { if (*end == '"' && *(end+1) == '"') end += 1; else if (*end == '"') break; } if (*end == '\0') return NULL; *end++ = '\0'; return start; } else if (*cp == '\'') { start = end = cp+1; for (; *end != '\0'; end++) { if (*end == '\'' && *(end+1) == '\'') end += 1; else if (*end == '\'') break; } if (*end == '\0') return NULL; *end++ = '\0'; return start; } else { start = end = cp; for (; *end != '\0'; end++) if (isspace((unsigned char)*end)) break; if (*end == '\0') return NULL; *end++ = '\0'; return start; } } return NULL; } /* split a line into tokens */ static int split(char *token[], char line[]) { char *cp; size_t len; int n = 0; cp = nexttoken(line); while (n < MAXTOKEN && cp != NULL) { len = strlen(cp); if ((token[n] = malloc(len+1)) == NULL) { mpd_err_fatal("out of memory"); } strcpy(token[n], cp); cp = nexttoken(NULL); n++; } token[n] = NULL; return n; } static void freetoken(char **token) { while (*token != NULL) { free(*token++); } } /* returns all expected conditions in a status flag */ static uint32_t scan_conditions(char **token) { char *condition = *token; uint32_t status = 0; while (condition != NULL) { if (startswith(condition, "--")) break; else if (eqtoken(condition, "Clamped")) status |= MPD_Clamped; else if (eqtoken(condition, "Conversion_syntax")) status |= MPD_Conversion_syntax; else if (eqtoken(condition, "Division_by_zero")) status |= MPD_Division_by_zero; else if (eqtoken(condition, "Division_impossible")) status |= MPD_Division_impossible; else if (eqtoken(condition, "Division_undefined")) status |= MPD_Division_undefined; else if (eqtoken(condition, "Fpu_error")) status |= MPD_Fpu_error; else if (eqtoken(condition, "Inexact")) status |= MPD_Inexact; else if (eqtoken(condition, "Invalid_context")) status |= MPD_Invalid_context; else if (eqtoken(condition, "Invalid_operation")) status |= MPD_Invalid_operation; else if (eqtoken(condition, "Malloc_error")) status |= MPD_Malloc_error; else if (eqtoken(condition, "Not_implemented")) status |= MPD_Not_implemented; else if (eqtoken(condition, "Overflow")) status |= MPD_Overflow; else if (eqtoken(condition, "Rounded")) status |= MPD_Rounded; else if (eqtoken(condition, "Subnormal")) status |= MPD_Subnormal; else if (eqtoken(condition, "Underflow")) status |= MPD_Underflow; else mpd_err_fatal("unknown status: %s", condition); condition = *(++token); } return status; } static void compare_expected(const char *calc, const char *expected, uint32_t expected_status, char *id, mpd_context_t *ctx) { char ctxstatus[MPD_MAX_FLAG_STRING]; char expstatus[MPD_MAX_FLAG_STRING]; #ifndef RT_VERBOSITY /* Do not print known pseudo-failures. */ int i; /* known ULP diffs */ if (ctx->allcr == 0) { for (i = 0; ulp_cases[i].id != NULL; i++) { if (eqtoken(id, ulp_cases[i].id) && strcmp(expected, ulp_cases[i].expected) == 0 && strcmp(calc, ulp_cases[i].calc) == 0) { return; } } } /* known status diffs */ for (i = 0; status_cases[i].id != NULL; i++) { if (eqtoken(id, status_cases[i].id) && expected_status == status_cases[i].expected && ctx->status == status_cases[i].calc) { return; } } #endif if (strcmp(calc, expected) != 0) { if (file_failure == 0) { fputs("\n\n", stderr); } fprintf(stderr, "FAIL: %s calc: %s expected: %s\n", id, calc, expected); global_failure = file_failure = 1; } if (ctx->status != expected_status) { if (file_failure == 0) { fputs("\n\n", stderr); } mpd_snprint_flags(ctxstatus, MPD_MAX_FLAG_STRING, ctx->status); mpd_snprint_flags(expstatus, MPD_MAX_FLAG_STRING, expected_status); fprintf(stderr, "FAIL: %s: status: calc: %s expected: %s\n", id, ctxstatus, expstatus); global_failure = file_failure = 1; } } static int equalmem(const mpd_t *a, const mpd_t *b) { mpd_ssize_t i; if (a->flags != b->flags) return 0; if (a->exp != b->exp) return 0; if (a->len != b->len) return 0; if (a->digits != b->digits) return 0; for (i = 0; i < a->len; i++) if (a->data[i] != b->data[i]) return 0; return 1; } static void check_equalmem(const mpd_t *a, const mpd_t *b, const char *id) { if (!equalmem(a, b)) { fprintf(stderr, "FAIL: const arg changed: %s\n", id); } } static unsigned long get_testno(char *token) { char *number; number = strpbrk(token, "0123456789"); ASSERT(number != NULL); return strtoul(number, NULL, 10); } /* scan a single operand and the expected result */ static int scan_1op_result(mpd_t *op1, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } mpd_set_string(op1, token[2], ctx); /* discard "->" */ if (token[3] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } /* expected result */ if (token[4] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } *result = token[4]; return 5; } /* scan a single operand and two results */ static int scan_1op_2results(mpd_t *op1, char **result1, char **result2, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } mpd_set_string(op1, token[2], ctx); /* discard "->" */ if (token[3] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } /* expected result1 */ if (token[4] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } *result1 = token[4]; /* expected result2 */ if (token[5] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } *result2 = token[5]; return 6; } /* scan decimal operand, string operand and the expected result */ static int scan_1op_str_result(mpd_t *op1, char **op2, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } *op2 = token[3]; /* discard "->" */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } *result = token[5]; return 6; } /* scan two operands and the expected result */ static int scan_2ops_result(mpd_t *op1, mpd_t *op2, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op2, token[3], ctx); /* discard "->" */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } *result = token[5]; return 6; } /* scan two operands and two results */ static int scan_2ops_2results(mpd_t *op1, mpd_t *op2, char **result1, char **result2, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op2, token[3], ctx); /* discard "->" */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result1 */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } *result1 = token[5]; /* expected result2 */ if (token[6] == NULL) { mpd_err_fatal("%s", token[0]); } *result2 = token[6]; return 7; } /* scan three operands and the expected result */ static int scan_3ops_result(mpd_t *op1, mpd_t *op2, mpd_t *op3, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op2, token[3], ctx); /* operand 2 */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op3, token[4], ctx); /* discard "->" */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result */ if (token[6] == NULL) { mpd_err_fatal("%s", token[0]); } *result = token[6]; return 7; } static mpd_t *op, *op1, *op2, *op3; static mpd_t *tmp, *tmp1, *tmp2, *tmp3; static mpd_t *result, *result1, *result2; /* Test triple conversion */ static void _TripleTest(const mpd_t *a, mpd_context_t *ctx, const char *testno) { mpd_uint128_triple_t triple; uint32_t status = 0; int ret = 0; #ifdef MPD_CONFIG_32 /* * 32-bit: as_triple() expects well-formed decimals. Skip test cases * that use the extended exponent, which is safe in the tests but not * in production. */ if (a->exp < MPD_MIN_ETINY || a->exp > MPD_MAX_EMAX) { return; } #endif triple = mpd_as_uint128_triple(a); switch (triple.tag) { case MPD_TRIPLE_QNAN: case MPD_TRIPLE_SNAN: ASSERT(triple.exp == 0) break; case MPD_TRIPLE_INF: ASSERT(triple.hi == 0 && triple.lo == 0 && triple.exp == 0) break; case MPD_TRIPLE_NORMAL: break; case MPD_TRIPLE_ERROR: ASSERT(triple.sign == 0 && triple.hi == 0 && triple.lo == 0 && triple.exp == 0) break; } /* Allocation failures in from_triple() */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(result); mpd_set_alloc_fail(ctx); status = 0; ret = mpd_from_uint128_triple(result, &triple, &status); mpd_set_alloc(ctx); if (!(status&MPD_Malloc_error)) { break; } ASSERT(ret == -1) ASSERT(mpd_isnan(result)) } if (triple.tag != MPD_TRIPLE_ERROR) { ASSERT(ret == 0) ASSERT(status == 0) check_equalmem(result, a, testno); } else { ASSERT(ret == -1) ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isnan(result)) } } /* Test both versions of mpd_to_sci. Do not use this if alloc_fail is set, since MPD_Malloc_error will only be triggered for one of the functions. */ static char * _mpd_to_sci(const mpd_t *dec, int fmt) { char *r, *s; mpd_ssize_t size; r = mpd_to_sci(dec, fmt); size = mpd_to_sci_size(&s, dec, fmt); if (r == NULL) { ASSERT(size == -1) ASSERT(s == NULL) } else { ASSERT(strcmp(r, s) == 0) ASSERT(size == (mpd_ssize_t)strlen(s)) } mpd_free(s); return r; } /* * Test a function returning pointer to char, accepting: * op1, context * * This function is used for "toSci", "toEng" and "apply" * and does not use a maxctx for the conversion of the operand. */ static void _cp_MpdCtx(char **token, char *(*func)(const mpd_t *, int), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected, *expected_fail = NULL; uint32_t expstatus; int n; mpd_readcontext(&maxctx); mpd_context_t *workctx = ctx; workctx->status = 0; n = scan_1op_result(op, &expected, token, workctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* Allocation failures for mpd_set_string */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); workctx->status = 0; mpd_set_alloc_fail(workctx); (void)scan_1op_result(tmp, &expected_fail, token, workctx); mpd_set_alloc(workctx); if (!(workctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } ASSERT(strcmp(expected, expected_fail) == 0) ASSERT(mpd_cmp_total(tmp, op) == 0) /* make a copy of the operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); calc = func(tmp, 1); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); mpd_set_alloc_fail(workctx); calc = func(tmp, 1); mpd_set_alloc(workctx); if (calc != NULL) { break; } } compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); } /* Test mpd_to_sci_size() and mpd_to_eng_size(). */ static void sci_eng_size(char **token, mpd_ssize_t (*func)(char **, const mpd_t *, int), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected, *expected_fail = NULL; uint32_t expstatus; mpd_ssize_t size; int n; mpd_readcontext(&maxctx); mpd_context_t *workctx = ctx; workctx->status = 0; n = scan_1op_result(op, &expected, token, workctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* Allocation failures for mpd_set_string */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); workctx->status = 0; mpd_set_alloc_fail(workctx); (void)scan_1op_result(tmp, &expected_fail, token, workctx); mpd_set_alloc(workctx); if (!(workctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } ASSERT(strcmp(expected, expected_fail) == 0) ASSERT(mpd_cmp_total(tmp, op) == 0) /* make a copy of the operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); size = func(&calc, tmp, 1); ASSERT(size == (mpd_ssize_t)strlen(calc)) /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); mpd_set_alloc_fail(workctx); size = func(&calc, tmp, 1); mpd_set_alloc(workctx); if (calc != NULL) { ASSERT(size == (mpd_ssize_t)strlen(calc)) break; } } compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); } /* Quick and dirty: parse hex escape sequences */ static char * parse_escapes(const char *s) { char hex[5]; char *res, *cp; unsigned int u; int n; cp = res = malloc(strlen(s)+1); if (res == NULL) { return NULL; } hex[0] = '0'; hex[1] = '\0'; while (*s) { if (*s == '\\' && *(s+1) == 'x') { for (n = 1; n < 4; n++) { if (!s[n]) { free(res); return NULL; } hex[n] = s[n]; } hex[n] = '\0'; sscanf(hex, "%x%n", &u, &n); *cp++ = (char)u; s += n; } else { *cp++ = *s++; } } *cp = '\0'; return res; } /* * Test a function returning pointer to char, accepting: * op1, fmt, context * * This function is used for "mpd_format". */ static void _cp_MpdFmtCtx(char **token, char *(*func)(const mpd_t *, const char *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *fmt; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_str_result(op1, &fmt, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); fmt = parse_escapes(fmt); expected = parse_escapes(expected); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op1, ctx); ctx->status = 0; calc = func(tmp, fmt, ctx); /* compare the calculated result to the expected result */ if (calc == NULL) { compare_expected("NULL", expected, expstatus, token[0], ctx); } else { compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } check_equalmem(tmp, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op1, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); calc = func(tmp, fmt, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(calc == NULL) } if (calc == NULL) { compare_expected("NULL", expected, expstatus, token[0], ctx); } else { compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } check_equalmem(tmp, op1, token[0]); free(fmt); free(expected); } /* * Test a function returning pointer to const char, accepting: * op1, context */ static void _ccp_MpdCtx(char **token, const char *(*func)(const mpd_t *, const mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; const char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc = func(tmp, ctx); compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); calc = func(tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(calc == NULL) } compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } /* Test a unary function */ static void _Res_Op_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* result and tmp are distinct decimals */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result equals operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* Test a unary function, quantize the operand before applying the actual function */ static void _Res_Op_CtxWithQuantize(char *token[], void (*func)(mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op, op1, &expected, token, &maxctx); mpd_quantize(op, op, op1, &maxctx); _TripleTest(op, ctx, token[0]); _TripleTest(op1, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* result and tmp are distinct decimals */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result equals operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } static void resolve_status_hack(uint32_t *expstatus, const uint32_t status) { /* hack #1 to resolve disagreement with results generated by decimal.py */ if ((*expstatus & MPD_Invalid_operation) && (status & MPD_Division_impossible)) { *expstatus = MPD_Division_impossible; } /* hack #2 to resolve disagreement with results generated by decimal.py */ if ((*expstatus & MPD_Invalid_operation) && (status & MPD_Division_undefined)) { *expstatus = MPD_Division_undefined; } } /* Test a binary function */ static void _Res_Binop_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* three distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); } /* Test a binary function where op1 == op2. */ static void _Res_EqualBinop_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands, distinct result */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp, tmp, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* all parameters equal */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; func(tmp, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* Test a binary function with a binary result */ static void _Binres_Binop_Ctx(char *token[], void (*func)(mpd_t *, mpd_t*, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected1, *expected2; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_2results(op1, op2, &expected1, &expected2, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* four distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result1); mpd_init_rand(result2); ctx->status = 0; mpd_set_alloc_count(ctx); func(result1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); resolve_status_hack(&expstatus, ctx->status); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result1); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(result2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result1 == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result2); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail <= INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) ASSERT(mpd_isnan(result2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result2 == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result1); ctx->status = 0; mpd_set_alloc_count(ctx); func(result1, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result1); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result1 == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result2); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) ASSERT(mpd_isnan(result2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result2 == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result1); ctx->status = 0; mpd_set_alloc_count(ctx); func(result1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result1); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result1 == tmp1, result2 == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* result1 == tmp2, result2 == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); } /* Test a binary function with a binary result; equal operands */ static void _Binres_EqualBinop_Ctx(char *token[], void (*func)(mpd_t *, mpd_t*, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected1, *expected2; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_2results(op, &expected1, &expected2, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct results */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result1); mpd_init_rand(result2); ctx->status = 0; func(result1, result2, tmp, tmp, ctx); resolve_status_hack(&expstatus, ctx->status); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result1); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, result2, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(result2)) } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result1 == tmp */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result2); ctx->status = 0; func(tmp, result2, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, result2, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) ASSERT(mpd_isnan(result2)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* result2 == tmp */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result1); ctx->status = 0; func(result1, tmp, tmp, tmp, ctx); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result1); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); } /* Test a ternary function */ static void _Res_Ternop_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_3ops_result(op1, op2, op3, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); _TripleTest(op3, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* four distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp3, op3, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp3, op3, token[0]); /* result == tmp3 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp3, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp3, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp3, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp3)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp3, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); } /* Test a ternary function, first and second operand equal */ static void _Res_EqEqOp_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp1, tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp2, tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); } /* Test a ternary function, first and third operand equal */ static void _Res_EqOpEq_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, tmp2, tmp1, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, tmp1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp1, tmp1, tmp2, tmp1, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, tmp1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp2, tmp1, tmp2, tmp1, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, tmp1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); } /* Test a ternary function, second and third operand equal */ static void _Res_OpEqEq_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, tmp2, tmp2, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp2, tmp1, tmp2, tmp2, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp1, tmp1, tmp2, tmp2, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); } /* Test a ternary function, first, second and third operand equal */ static void _Res_EqEqEq_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp, tmp, tmp, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result == tmp */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; func(tmp, tmp, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* * Test a binary function that returns an additional integer result. * Used for the comparison functions. */ static void _Int_Res_Binop_Ctx(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* three distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp1, tmp2, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp2, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); } /* * Test a binary function that returns an additional integer result. * Equal operands. * Used for the comparison functions. */ static void _Int_Res_EqualBinop_Ctx(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp, tmp, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* all parameters equal */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } } /* * Test a binary function that returns an additional integer result. * Function does not take a context argument. * Used for the comparison functions. */ static void _Int_Res_Binop(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* three distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp1, tmp2); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp1, tmp2); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp1, tmp2); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp1, tmp2); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp2, tmp1, tmp2); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp2, tmp1, tmp2); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); } /* * Test a binary function that returns an additional integer result. * Function does not take a context argument. * Equal operands. * Used for the comparison functions. */ static void _Int_Res_EqualBinop(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp, tmp); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp, tmp); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* all parameters equal */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp, tmp); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp, tmp); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } } /* * Test a binary function that returns only an integer result. * Used for the cmp functions. */ enum {SKIP_NONE, SKIP_NAN, SKIP_NONINT}; static void _Int_Binop_Ctx(int skip, char *token[], int (*func)(const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* two distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp2, ctx); snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(int_result== INT_MAX) } snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); } /* * Test a binary function that returns only an integer result. * Equal operands. * Used for the cmp functions. */ static void _Int_EqualBinop_Ctx(int skip, char *token[], int (*func)(const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp, ctx); snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(int_result== INT_MAX) } snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); } /* * Test a binary function that returns an int. * The function does not take a context argument. */ static void _Int_Binop(char *token[], int (*func)(const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* two distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp2); snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp2); mpd_set_alloc(ctx); if (int_result != INT_MAX) { break; } } snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); } /* * Test a binary function that returns an int. * Equal operands. * The function does not take a context argument. */ static void _Int_EqualBinop(char *token[], int (*func)(const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp); snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp); mpd_set_alloc(ctx); if (int_result != INT_MAX) { break; } } snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } static mpd_ssize_t scan_ssize(char *token[]) { errno = 0; if (token[1] == NULL) { errno = 1; return MPD_SSIZE_MAX; } return strtossize(token[1], NULL, 10); } static void _mpd_shiftl(mpd_t *res, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx) { ASSERT(!mpd_isspecial(a)); mpd_shiftl(res, a, n, ctx); } static void _mpd_shiftr(mpd_t *res, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx) { ASSERT(!mpd_isspecial(a)); (void)mpd_shiftr(res, a, n, ctx); } /* * Test a function with an mpd_t and an mpd_ssize_t operand. * Used for the shift functions. */ static void _Res_Op_Lsize_Ctx(int skip, char *token[], void (*func)(mpd_t *, const mpd_t *, mpd_ssize_t, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; mpd_ssize_t ssize; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* only integers are allowed for ssize */ if (skip && (mpd_isspecial(op2) || op2->exp != 0)) { /* fprintf(stderr, "SKIP: %s\n", token[0]); */ return; } ssize = mpd_get_ssize(op2, &maxctx); if (maxctx.status&MPD_Invalid_operation) { return; } /* two distinct decimals */ mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, ssize, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, ssize, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); ctx->status = 0; func(tmp1, tmp1, ssize, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, ssize, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* test mpd_qln10() */ static void _test_mpd_qln10(int skip, char *token[], mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; mpd_ssize_t ssize; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op1, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* only integers are allowed for ssize */ if (skip && (mpd_isspecial(op1) || op1->exp != 0)) { /* fprintf(stderr, "SKIP: %s\n", token[0]); */ return; } ssize = mpd_get_ssize(op1, &maxctx); if (maxctx.status&MPD_Invalid_operation) { return; } mpd_init_rand(result); ctx->status = 0; mpd_qln10(result, ssize, &ctx->status); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_qln10(result, ssize, &ctx->status); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } static void _Baseconv(char *token[], mpd_context_t *ctx) { mpd_context_t maxctx; uint32_t base; uint16_t *data16; uint32_t *data32; size_t len16, len32; size_t expected_len16, expected_len32; char *expected; uint32_t expstatus; char *calc; int n = 0; int i, iter = 0; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op1, &expected, token, &maxctx); ASSERT(mpd_isinteger(op1)) _TripleTest(op1, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* * base := (1<<15) * data16 := NULL * Allocation and deallocation on error by mpd_export_u16(). */ base = (1<<15); data16 = NULL; expected_len16 = mpd_export_u16(&data16, 0, base, op1, ctx); if (expected_len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<15) * data16 := NULL * Test allocation failures. */ base = (1<<15); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; mpd_set_alloc_fail(ctx); data16 = NULL; expected_len16 = mpd_export_u16(&data16, 0, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* If data16 == NULL, it is deallocated on failure. */ ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<15) * len(data16) := 1 * Simulate result from sizeinbase() that is too small. */ base = (1<<15); data16 = mpd_alloc(1, sizeof *data16); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); if (expected_len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<15) * len(data16) == 1 * Test allocation failures. */ base = (1<<15); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data16 = mpd_alloc(1, sizeof *data16); mpd_set_alloc_fail(ctx); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* Caller must free the memory that was passed in. */ mpd_free(data16); ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<16) * len(data16) := mpd_sizeinbase() */ base = (1U<<16); len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := 9999 * len(data16) := mpd_sizeinbase() */ base = 9999; len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); expected_len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (expected_len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := [2..16] * len(data16) := mpd_sizeinbase() */ iter = 16; for (i = 2; i <= iter; i++) { base = (uint32_t)i; len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); } /* * base := random(UINT_16_MAX) * len(data16) := mpd_sizeinbase() */ iter = 5; for (i = 0; i < iter; i++) { base = random() % UINT16_MAX; if (base < 2) base = 2; len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data16 = mpd_alloc(1, sizeof *data16); mpd_set_alloc_fail(ctx); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* Caller must free the memory that was passed in. */ mpd_free(data16); ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data16 = mpd_alloc(1, sizeof *data16); mpd_set_alloc_fail(ctx); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* Caller must free the memory that was passed in. */ mpd_free(data16); ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); } /* ================================================================ */ /* uint32_t bases */ /* ================================================================ */ /* * base := (1<<30) * data32 := NULL */ base = (1<<30); data32 = NULL; expected_len32 = mpd_export_u32(&data32, 0, base, op1, ctx); if (expected_len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := (1<<30) * data32 := NULL * Test allocation failures. */ base = (1<<30); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; mpd_set_alloc_fail(ctx); data32 = NULL; expected_len32 = mpd_export_u32(&data32, 0, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := (1<<30) * len(data32) := 1 */ base = (1<<30); data32 = mpd_alloc(1, sizeof *data32); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); if (expected_len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := (1<<30) * len(data32) := 1 * Test allocation failures. */ base = (1<<30); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := 10**9 * len(data32) := mpd_sizeinbase() */ base = 1000000000; len32 = mpd_sizeinbase(op1, base); data32 = mpd_alloc((mpd_size_t)len32, sizeof *data32); expected_len32 = mpd_export_u32(&data32, len32, base, op1, ctx); if (len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := 10**9 * len(data32) := mpd_sizeinbase() * Test allocation failures. */ base = 1000000000; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; mpd_set_alloc_fail(ctx); data32 = NULL; expected_len32 = mpd_export_u32(&data32, 0, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := 10**9 * len(data32) := 1 * Test allocation failures. */ base = 1000000000; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); for (i = 2; i <= 16; i++) { base = (uint32_t)i; len32 = mpd_sizeinbase(op1, base); data32 = mpd_alloc((mpd_size_t)len32, sizeof *data32); expected_len32 = mpd_export_u32(&data32, len32, base, op1, ctx); if (len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); } for (i = 0; i < 5; i++) { base = random() % UINT32_MAX; if (base < 2) base = 2; len32 = mpd_sizeinbase(op1, base); data32 = mpd_alloc((mpd_size_t)len32, sizeof *data32); expected_len32 = mpd_export_u32(&data32, len32, base, op1, ctx); if (len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); } } /* * Test a function returning a uint64_t, accepting: * op, context * * This function is used for: * - mpd_get_uint (64 bit) * - mpd_abs_uint (64 bit) * - mpd_get_u64 */ #ifndef MPD_LEGACY_COMPILER static void _u64_MpdCtx(char **token, uint64_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; uint64_t calc_uint; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_uint = func(tmp, ctx); snprintf(calc, 23, "%" PRIu64, calc_uint); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } #endif /* * Test a function returning a uint64_t, accepting: * op, context * * This function is used for: * - mpd_get_uint (64 bit) * - mpd_abs_uint (64 bit) * - mpd_get_u64 */ static void _u32_MpdCtx(char **token, uint32_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; uint32_t calc_uint; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_uint = func(tmp, ctx); snprintf(calc, 23, "%" PRIu32, calc_uint); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } /* * Test a function returning an mpd_ssize_t, accepting: * op, fmt, context * * This function is used for: * - mpd_get_ssize * - mpd_get_i64 * - mpd_get_i32 */ #ifndef MPD_LEGACY_COMPILER static void _i64_MpdCtx(char **token, int64_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int64_t calc_ssize; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_ssize = func(tmp, ctx); snprintf(calc, 23, "%" PRIi64, calc_ssize); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } #endif /* * Test a function returning an mpd_ssize_t, accepting: * op, fmt, context * * This function is used for: * - mpd_get_ssize * - mpd_get_i64 * - mpd_get_i32 */ static void _i32_MpdCtx(char **token, int32_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int32_t calc_ssize; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_ssize = func(tmp, ctx); snprintf(calc, 23, "%" PRIi32, calc_ssize); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } static void triple_cov(void) { mpd_uint128_triple_t triple = { MPD_TRIPLE_QNAN, 2, 0, 0, 0 }; uint32_t status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.sign = 0; triple.exp = 1; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_INF; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 2; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = INT64_MAX; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = INT64_MIN; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = MPD_SSIZE_MAX; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = MPD_SSIZE_MIN; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = (enum mpd_triple_class)10; triple.sign = 0; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) } /* process a file */ static void doit(const char *filename) { FILE *file; mpd_context_t ctx; char *line; char *tmpline; char *token[MAXTOKEN+1]; uint32_t testno; mpd_ssize_t l; mpd_testcontext(&ctx); ctx.traps = MPD_Malloc_error; file_failure = 0; if (strcmp(filename, "-") == 0) { file = stdin; } else { if ((file = fopen(filename, "r")) == NULL) { mpd_err_fatal("could not open %s", filename); } if (!startswith(filename, "official") && !startswith(filename, "additional")) { printf("%s ...", filename); fflush(stdout); } } if ((line = mpd_alloc(MAXLINE+1, sizeof *line)) == NULL) { mpd_err_fatal("out of memory"); } if ((tmpline = mpd_alloc(MAXLINE+1, sizeof *line)) == NULL) { mpd_err_fatal("out of memory"); } while (fgets(line, MAXLINE+1, file) != NULL) { /* split a line into tokens */ strcpy(tmpline, line); for (int i =0; i < MAXTOKEN+1; i++) { token[i] = NULL; } if (split(token, tmpline) == 0) { goto cleanup; } /* comments */ if (startswith(token[0], "--")) { goto cleanup; } /* end comments */ /* skip bool* tests in extra.decTest */ if (startswith(token[0], "bool")) { goto cleanup; } /* end skips */ /* directives */ if (startswith(token[0], "ExtendedRange")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "1") == 0) { extended = 1; } else if (strcmp(token[1], "0") == 0) { extended = 0; } else { mpd_err_fatal("%s: %s", filename, line); } goto cleanup; } if (startswith(token[0], "Precision")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "MAX_PREC") == 0) { l = MPD_MAX_PREC; } else { l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } } ctx.prec = l; goto cleanup; } if (startswith(token[0], "Rounding")) { ASSERT(token[1] != NULL); if (eqtoken(token[1], "Ceiling")) ctx.round = MPD_ROUND_CEILING; else if (eqtoken(token[1], "Up")) ctx.round = MPD_ROUND_UP; else if (eqtoken(token[1], "Half_up")) ctx.round = MPD_ROUND_HALF_UP; else if (eqtoken(token[1], "Half_even")) ctx.round = MPD_ROUND_HALF_EVEN; else if (eqtoken(token[1], "Half_down")) ctx.round = MPD_ROUND_HALF_DOWN; else if (eqtoken(token[1], "Down")) ctx.round = MPD_ROUND_DOWN; else if (eqtoken(token[1], "Floor")) ctx.round = MPD_ROUND_FLOOR; else if (eqtoken(token[1], "05up")) ctx.round = MPD_ROUND_05UP; else mpd_err_fatal("%s: %s", filename, line); goto cleanup; } if (startswith(token[0], "MaxExponent")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "MAX_EMAX") == 0) { l = MPD_MAX_EMAX; } else { l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } } ctx.emax = l; goto cleanup; } if (startswith(token[0], "MinExponent")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "MIN_EMIN") == 0) { l = MPD_MIN_EMIN; } else { l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } } ctx.emin = l; goto cleanup; } if (startswith(token[0], "Dectest")) { ASSERT(token[1] != NULL); if (token[1] == NULL) { mpd_err_fatal("%s: %s", filename, line); } doit(token[1]); goto cleanup; } /* end directives */ /* optional directives */ if (startswith(token[0], "Version")) { goto cleanup; } if (startswith(token[0], "Extended")) { goto cleanup; } if (startswith(token[0], "Clamp")) { ASSERT(token[1] != NULL); l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } if (!mpd_qsetclamp(&ctx, (int)l)) { mpd_err_fatal("%s: %s", filename, line); } goto cleanup; } if (startswith(token[0], "Locale")) { ASSERT(token[1] != NULL); if (token[1] == NULL) { mpd_err_fatal("%s: %s", filename, line); } if (extended) { printf("locale: %s\n", token[1]); fflush(stdout); } if (setlocale(LC_NUMERIC, token[1]) == NULL) { mpd_err_fatal("%s: %s", filename, line); } goto cleanup; } mpd_assert_context_ok(&ctx); /* end optional directives */ /* * Actual tests start here: * - token[0] is the id * - token[1] is the operation type * - testno can be used for setting a watchpoint in the debugger */ testno = (uint32_t)get_testno(token[0]); (void)testno; /* The id is in the skip list */ if (check_skip(token[0])) { goto cleanup; } #ifdef MPD_CONFIG_64 /* Skip 32-bit specific coverage tests. */ if (startswith(token[0], "cov32")) { goto cleanup; } #else /* Skip 64-bit specific coverage tests. */ if (startswith(token[0], "cov64")) { goto cleanup; } #endif /* Translate operation type for powmod */ if (startswith(token[0], "pwmx")) { free(token[1]); token[1] = malloc(sizeof("powmod")); strcpy(token[1], "powmod"); } /* end skips */ /* Unary functions with char * result */ if (eqtoken(token[1], "tosci") || eqtoken(token[1], "apply")) { _cp_MpdCtx(token, mpd_to_sci, &ctx); sci_eng_size(token, mpd_to_sci_size, &ctx); } else if (eqtoken(token[1], "toeng")) { _cp_MpdCtx(token, mpd_to_eng, &ctx); sci_eng_size(token, mpd_to_eng_size, &ctx); } else if (eqtoken(token[1], "format")) { _cp_MpdFmtCtx(token, mpd_format, &ctx); } /* Unary function with const char * result */ else if (eqtoken(token[1], "class")) { _ccp_MpdCtx(token, mpd_class, &ctx); } /* Unary functions with mpd_t * result */ else if (eqtoken(token[1], "abs")) { _Res_Op_Ctx(token, mpd_abs, &ctx); } else if (eqtoken(token[1], "copy")) { _Res_Op_Ctx(token, mpd_copy, &ctx); } else if (eqtoken(token[1], "copyabs")) { _Res_Op_Ctx(token, mpd_copy_abs, &ctx); } else if (eqtoken(token[1], "copynegate")) { _Res_Op_Ctx(token, mpd_copy_negate, &ctx); } else if (eqtoken(token[1], "exp")) { if (extended) { if (testno != 126) { ctx.allcr = 0; /* exp: err < 1ulp, but not correctly rounded */ _Res_Op_Ctx(token, mpd_exp, &ctx); ctx.allcr = 1; } } _Res_Op_Ctx(token, mpd_exp, &ctx); } else if (eqtoken(token[1], "invert")) { _Res_Op_Ctx(token, mpd_invert, &ctx); } else if (eqtoken(token[1], "invroot")) { _Res_Op_Ctx(token, mpd_invroot, &ctx); } else if (eqtoken(token[1], "ln")) { if (extended) { ctx.allcr = 0; _Res_Op_Ctx(token, mpd_ln, &ctx); ctx.allcr = 1; } _Res_Op_Ctx(token, mpd_ln, &ctx); } else if (eqtoken(token[1], "log10")) { if (extended) { ctx.allcr = 0; _Res_Op_Ctx(token, mpd_log10, &ctx); ctx.allcr = 1; } _Res_Op_Ctx(token, mpd_log10, &ctx); } else if (eqtoken(token[1], "logb")) { _Res_Op_Ctx(token, mpd_logb, &ctx); } else if (eqtoken(token[1], "minus")) { _Res_Op_Ctx(token, mpd_minus, &ctx); } else if (eqtoken(token[1], "nextminus")) { _Res_Op_Ctx(token, mpd_next_minus, &ctx); } else if (eqtoken(token[1], "nextplus")) { _Res_Op_Ctx(token, mpd_next_plus, &ctx); } else if (eqtoken(token[1], "plus")) { _Res_Op_Ctx(token, mpd_plus, &ctx); } else if (eqtoken(token[1], "reduce")) { _Res_Op_Ctx(token, mpd_reduce, &ctx); } else if (eqtoken(token[1], "squareroot")) { #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(16000000); #endif _Res_Op_Ctx(token, mpd_sqrt, &ctx); #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token[1], "quantize_squareroot")) { #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(16000000); #endif _Res_Op_CtxWithQuantize(token, mpd_sqrt, &ctx); #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token[1], "tointegral")) { _Res_Op_Ctx(token, mpd_round_to_int, &ctx); } else if (eqtoken(token[1], "tointegralx")) { _Res_Op_Ctx(token, mpd_round_to_intx, &ctx); } else if (eqtoken(token[1], "floor")) { _Res_Op_Ctx(token, mpd_floor, &ctx); } else if (eqtoken(token[1], "ceil")) { _Res_Op_Ctx(token, mpd_ceil, &ctx); } else if (eqtoken(token[1], "trunc")) { _Res_Op_Ctx(token, mpd_trunc, &ctx); } /* Binary function returning an int */ else if (eqtoken(token[1], "samequantum")) { _Int_Binop(token, mpd_same_quantum, &ctx); } /* Binary function returning an int, equal operands */ else if (eqtoken(token[1], "samequantum_eq")) { _Int_EqualBinop(token, mpd_same_quantum, &ctx); } /* Binary functions with mpd_t * result */ else if (eqtoken(token[1], "add")) { _Res_Binop_Ctx(token, mpd_add, &ctx); } else if (eqtoken(token[1], "and")) { _Res_Binop_Ctx(token, mpd_and, &ctx); } else if (eqtoken(token[1], "copysign")) { _Res_Binop_Ctx(token, mpd_copy_sign, &ctx); } else if (eqtoken(token[1], "divide")) { #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(16000000); #endif _Res_Binop_Ctx(token, mpd_div, &ctx); #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token[1], "divideint")) { _Res_Binop_Ctx(token, mpd_divint, &ctx); } else if (eqtoken(token[1], "max")) { _Res_Binop_Ctx(token, mpd_max, &ctx); } else if (eqtoken(token[1], "maxmag") || eqtoken(token[1], "max_mag")) { _Res_Binop_Ctx(token, mpd_max_mag, &ctx); } else if (eqtoken(token[1], "min")) { _Res_Binop_Ctx(token, mpd_min, &ctx); } else if (eqtoken(token[1], "minmag") || eqtoken(token[1], "min_mag")) { _Res_Binop_Ctx(token, mpd_min_mag, &ctx); } else if (eqtoken(token[1], "multiply")) { _Res_Binop_Ctx(token, mpd_mul, &ctx); } else if (eqtoken(token[1], "nexttoward")) { _Res_Binop_Ctx(token, mpd_next_toward, &ctx); } else if (eqtoken(token[1], "or")) { _Res_Binop_Ctx(token, mpd_or, &ctx); } else if (eqtoken(token[1], "power")) { if (extended) { ctx.allcr = 0; _Res_Binop_Ctx(token, mpd_pow, &ctx); ctx.allcr = 1; } _Res_Binop_Ctx(token, mpd_pow, &ctx); } else if (eqtoken(token[1], "quantize")) { _Res_Binop_Ctx(token, mpd_quantize, &ctx); } else if (eqtoken(token[1], "resc")) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, mpd_rescale, &ctx); } else if (eqtoken(token[1], "remainder")) { _Res_Binop_Ctx(token, mpd_rem, &ctx); } else if (eqtoken(token[1], "remaindernear")) { _Res_Binop_Ctx(token, mpd_rem_near, &ctx); } else if (eqtoken(token[1], "rotate")) { _Res_Binop_Ctx(token, mpd_rotate, &ctx); } else if (eqtoken(token[1], "scaleb")) { _Res_Binop_Ctx(token, mpd_scaleb, &ctx); } else if (eqtoken(token[1], "shift")) { _Res_Binop_Ctx(token, mpd_shift, &ctx); if (extended) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, mpd_shiftn, &ctx); } } else if (eqtoken(token[1], "subtract")) { _Res_Binop_Ctx(token, mpd_sub, &ctx); } else if (eqtoken(token[1], "xor")) { _Res_Binop_Ctx(token, mpd_xor, &ctx); } /* Binary functions with mpd_t result, equal operands */ else if (eqtoken(token[1], "add_eq")) { _Res_EqualBinop_Ctx(token, mpd_add, &ctx); } else if (eqtoken(token[1], "and_eq")) { _Res_EqualBinop_Ctx(token, mpd_and, &ctx); } else if (eqtoken(token[1], "copysign_eq")) { _Res_EqualBinop_Ctx(token, mpd_copy_sign, &ctx); } else if (eqtoken(token[1], "divide_eq")) { _Res_EqualBinop_Ctx(token, mpd_div, &ctx); } else if (eqtoken(token[1], "divideint_eq")) { _Res_EqualBinop_Ctx(token, mpd_divint, &ctx); } else if (eqtoken(token[1], "max_eq")) { _Res_EqualBinop_Ctx(token, mpd_max, &ctx); } else if (eqtoken(token[1], "maxmag_eq")) { _Res_EqualBinop_Ctx(token, mpd_max_mag, &ctx); } else if (eqtoken(token[1], "min_eq")) { _Res_EqualBinop_Ctx(token, mpd_min, &ctx); } else if (eqtoken(token[1], "minmag_eq")) { _Res_EqualBinop_Ctx(token, mpd_min_mag, &ctx); } else if (eqtoken(token[1], "multiply_eq")) { _Res_EqualBinop_Ctx(token, mpd_mul, &ctx); } else if (eqtoken(token[1], "nexttoward_eq")) { _Res_EqualBinop_Ctx(token, mpd_next_toward, &ctx); } else if (eqtoken(token[1], "or_eq")) { _Res_EqualBinop_Ctx(token, mpd_or, &ctx); } else if (eqtoken(token[1], "power_eq")) { if (extended) { ctx.allcr = 0; _Res_EqualBinop_Ctx(token, mpd_pow, &ctx); ctx.allcr = 1; } _Res_EqualBinop_Ctx(token, mpd_pow, &ctx); } else if (eqtoken(token[1], "quantize_eq")) { _Res_EqualBinop_Ctx(token, mpd_quantize, &ctx); } else if (eqtoken(token[1], "remainder_eq")) { _Res_EqualBinop_Ctx(token, mpd_rem, &ctx); } else if (eqtoken(token[1], "remaindernear_eq")) { _Res_EqualBinop_Ctx(token, mpd_rem_near, &ctx); } else if (eqtoken(token[1], "rotate_eq")) { _Res_EqualBinop_Ctx(token, mpd_rotate, &ctx); } else if (eqtoken(token[1], "scaleb_eq")) { _Res_EqualBinop_Ctx(token, mpd_scaleb, &ctx); } else if (eqtoken(token[1], "shift_eq")) { _Res_EqualBinop_Ctx(token, mpd_shift, &ctx); } else if (eqtoken(token[1], "subtract_eq")) { _Res_EqualBinop_Ctx(token, mpd_sub, &ctx); } else if (eqtoken(token[1], "xor_eq")) { _Res_EqualBinop_Ctx(token, mpd_xor, &ctx); } /* Binary function with binary result */ else if (eqtoken(token[1], "divmod")) { _Binres_Binop_Ctx(token, mpd_divmod, &ctx); } /* Binary function with binary result, equal operands */ else if (eqtoken(token[1], "divmod_eq")) { _Binres_EqualBinop_Ctx(token, mpd_divmod, &ctx); } /* Ternary functions with mpd_t result */ else if (eqtoken(token[1], "fma")) { _Res_Ternop_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod")) { _Res_Ternop_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, eq_eq_op */ else if (eqtoken(token[1], "fma_eq_eq_op")) { _Res_EqEqOp_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_eq_eq_op")) { _Res_EqEqOp_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, eq_op_eq */ else if (eqtoken(token[1], "fma_eq_op_eq")) { _Res_EqOpEq_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_eq_op_eq")) { _Res_EqOpEq_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, op_eq_eq */ else if (eqtoken(token[1], "fma_op_eq_eq")) { _Res_OpEqEq_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_op_eq_eq")) { _Res_OpEqEq_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, eq_eq_eq */ else if (eqtoken(token[1], "fma_eq_eq_eq")) { _Res_EqEqEq_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_eq_eq_eq")) { _Res_EqEqEq_Ctx(token, mpd_powmod, &ctx); } /* Special cases for the comparison functions */ else if (eqtoken(token[1], "compare")) { _Int_Res_Binop_Ctx(token, mpd_compare, &ctx); _Int_Binop_Ctx(SKIP_NAN, token, mpd_cmp, &ctx); } else if (eqtoken(token[1], "comparesig")) { _Int_Res_Binop_Ctx(token, mpd_compare_signal, &ctx); } else if (eqtoken(token[1], "comparetotal")) { _Int_Res_Binop(token, mpd_compare_total, &ctx); _Int_Binop(token, mpd_cmp_total, &ctx); } else if (eqtoken(token[1], "comparetotmag")) { _Int_Res_Binop(token, mpd_compare_total_mag, &ctx); _Int_Binop(token, mpd_cmp_total_mag, &ctx); } /* Special cases for the comparison functions, equal operands */ else if (eqtoken(token[1], "compare_eq")) { _Int_Res_EqualBinop_Ctx(token, mpd_compare, &ctx); _Int_EqualBinop_Ctx(SKIP_NAN, token, mpd_cmp, &ctx); } else if (eqtoken(token[1], "comparesig_eq")) { _Int_Res_EqualBinop_Ctx(token, mpd_compare_signal, &ctx); } else if (eqtoken(token[1], "comparetotal_eq")) { _Int_Res_EqualBinop(token, mpd_compare_total, &ctx); _Int_EqualBinop(token, mpd_cmp_total, &ctx); } else if (eqtoken(token[1], "comparetotmag_eq")) { _Int_Res_EqualBinop(token, mpd_compare_total_mag, &ctx); _Int_EqualBinop(token, mpd_cmp_total_mag, &ctx); } /* Special cases for the shift functions */ else if (eqtoken(token[1], "shiftleft")) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, _mpd_shiftl, &ctx); } else if (eqtoken(token[1], "shiftright")) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, _mpd_shiftr, &ctx); } /* Special case for mpd_qln10() */ else if (eqtoken(token[1], "ln10")) { _test_mpd_qln10(SKIP_NONINT, token, &ctx); } /* Special case for the base conversion functions */ else if (eqtoken(token[1], "baseconv")) { _Baseconv(token, &ctx); } /* Special cases for the get_int functions */ #ifdef MPD_CONFIG_64 else if (eqtoken(token[1], "get_uint64")) { _u64_MpdCtx(token, mpd_get_uint, &ctx); } else if (eqtoken(token[1], "get_uint64_abs")) { _u64_MpdCtx(token, mpd_abs_uint, &ctx); } else if (eqtoken(token[1], "get_ssize64")) { _i64_MpdCtx(token, mpd_get_ssize, &ctx); } #else else if (eqtoken(token[1], "get_uint32")) { _u32_MpdCtx(token, mpd_get_uint, &ctx); } else if (eqtoken(token[1], "get_uint32_abs")) { _u32_MpdCtx(token, mpd_abs_uint, &ctx); } else if (eqtoken(token[1], "get_ssize32")) { _i32_MpdCtx(token, mpd_get_ssize, &ctx); } #endif #ifndef MPD_LEGACY_COMPILER else if (eqtoken(token[1], "get_u64")) { _u64_MpdCtx(token, mpd_get_u64, &ctx); } else if (eqtoken(token[1], "get_i64")) { _i64_MpdCtx(token, mpd_get_i64, &ctx); } #endif else if (eqtoken(token[1], "get_u32")) { _u32_MpdCtx(token, mpd_get_u32, &ctx); } else if (eqtoken(token[1], "get_i32")) { _i32_MpdCtx(token, mpd_get_i32, &ctx); } else if (startswith(token[1], "get_")) { /* empty */ } else if (eqtoken(token[1], "rescale")) { /* empty */ } /* unknown operation */ else { mpd_err_fatal("%s: unknown operation: %s", filename, line); } /* end tests */ cleanup: freetoken(token); } mpd_free(line); mpd_free(tmpline); if (file != stdin) { fclose(file); } if (!startswith(filename, "official") && !startswith(filename, "additional") && !file_failure) { printf(" PASS\n"); } else { printf("\n"); } fflush(stdout); } static void traphandler(mpd_context_t *ctx) { if (ctx->newtrap & MPD_Malloc_error) { fprintf(stderr, "\n\n\ runtest: out of memory:\n\ - bignum tests require 200MB heap and 300KB stack.\n\ - normal tests require 10MB heap and 50KB stack.\n\n"); } else { fprintf(stderr, "\n\nruntest: unexpected error: relevant traps: %u\n\n", ctx->newtrap); } exit(1); } static void usage(void) { fputs("runtest: usage: runtest testfile [--custom] [--alloc]\n", stderr); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { const char *filename = NULL; bool custom_alloc = false; bool check_alloc = false; for (int i = 1; i < argc; i++) { if (!filename && (strcmp(argv[i], "-") == 0 || !startswith(argv[i], "--"))) { filename = argv[i]; } else if (!custom_alloc && strcmp(argv[i], "--custom") == 0) { custom_alloc = true; } else if (!check_alloc && strcmp(argv[i], "--alloc") == 0) { check_alloc = true; } else { usage(); } } if (filename == NULL) { usage(); } /* Test version */ if (strcmp(mpd_version(), "4.0.0") != (0)) { fputs("runtest: error: mpd_version() != 4.0.0\n", stderr); exit(EXIT_FAILURE); } if (strcmp(MPD_VERSION, "4.0.0") != (0)) { fputs("runtest: error: MPD_VERSION != 4.0.0\n", stderr); exit(EXIT_FAILURE); } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) #endif if (MPD_MAJOR_VERSION != (4)) { fputs("runtest: error: MPD_MAJOR_VERSION != 4\n", stderr); exit(EXIT_FAILURE); } if (MPD_MINOR_VERSION != (0)) { fputs("runtest: error: MPD_MINOR_VERSION != 0\n", stderr); exit(EXIT_FAILURE); } if (MPD_MICRO_VERSION != (0)) { fputs("runtest: error: MPD_MICRO_VERSION != 0\n", stderr); exit(EXIT_FAILURE); } if (MPD_VERSION_HEX != (0x04000000)) { fputs("runtest: error: MPD_VERSION_HEX != 0x04000000\n", stderr); exit(EXIT_FAILURE); } #ifdef _MSC_VER #pragma warning(pop) #endif extended = strcmp(filename, "-") != 0; /* Initialize random number generator */ srandom((unsigned int)time(NULL)); /* Initialize custom allocation functions */ mpd_init_alloc(custom_alloc, check_alloc); /* Initialize MPD_MINALLOC (optional, default is 2) */ MPD_MINALLOC = 2; /* Initialize trap handler */ mpd_traphandler = traphandler; op = mpd_qnew(); op1 = mpd_qnew(); op2 = mpd_qnew(); op3 = mpd_qnew(); tmp = mpd_qnew(); tmp1 = mpd_qnew(); tmp2 = mpd_qnew(); tmp3 = mpd_qnew(); result = mpd_qnew(); result1 = mpd_qnew(); result2 = mpd_qnew(); triple_cov(); doit(filename); mpd_del(op); mpd_del(op1); mpd_del(op2); mpd_del(op3); mpd_del(tmp); mpd_del(tmp1); mpd_del(tmp2); mpd_del(tmp3); mpd_del(result); mpd_del(result1); mpd_del(result2); return global_failure; }