1 /*
2 * Copyright (c) 2020-2024 Stefan Krah. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27
28 #ifdef _AIX
29 #define __STDC_FORMAT_MACROS
30 #endif
31
32 #ifndef _MSC_VER
33 #include "config.h"
34 #ifdef HAVE_PTHREAD_H
35 #include <pthread.h>
36 #endif
37 #endif
38
39 #include <cctype>
40 #include <cerrno>
41 #include <cinttypes>
42 #include <clocale>
43 #include <cstdint>
44 #include <cstdio>
45 #include <cstdlib>
46 #include <cstring>
47 #include <ctime>
48
49 #include <algorithm>
50 #include <atomic>
51 #include <fstream>
52 #include <iostream>
53 #include <random>
54 #include <sstream>
55 #include <string>
56 #include <thread>
57 #include <utility>
58 #include <vector>
59
60 #include "mpdecimal.h"
61
62 #include "decimal.hh"
63 #include "test.hh"
64 #include "vctest.hh"
65
66
67 using decimal::ValueError;
68 using decimal::MallocError;
69 using decimal::RuntimeError;
70 using decimal::InvalidOperation;
71 using decimal::Decimal;
72 using decimal::Context;
73 using decimal::context_template;
74 using decimal::context;
75
76 using decimal::util::safe_downcast;
77
78 #if defined(MPD_CONFIG_32)
79 using test::set_alloc_limit;
80 #endif
81 using test::set_alloc;
82 using test::set_alloc_fail;
83
84
85 enum skip_cmp {SKIP_NONE, SKIP_NAN, SKIP_NONINT};
86
87 /*
88 * These extended ranges are required for the official test suite and are
89 * not problematic for its specific test cases. However, they should not
90 * be used in production code.
91 *
92 * The use of the directive "ExtendedRange" is not related to the "Extended"
93 * directive that is briefly referred to in the official tests.
94 */
95 #if defined(MPD_CONFIG_64)
96 #define MPD_READ_MAX_PREC 1070000000000000000LL
97 #elif defined(MPD_CONFIG_32)
98 #define MPD_READ_MAX_PREC 1070000000
99 #else
100 #error "config not defined"
101 #endif
102
103 static mpd_context_t
readcontext(const bool extended)104 readcontext(const bool extended)
105 {
106 mpd_context_t c;
107
108 if (extended) {
109 c.prec = MPD_READ_MAX_PREC;
110 c.emax = MPD_READ_MAX_PREC;
111 c.emin = -MPD_READ_MAX_PREC;
112 }
113 else {
114 c.prec = MPD_MAX_PREC;
115 c.emax = MPD_MAX_EMAX;
116 c.emin = MPD_MIN_EMIN;
117 }
118
119 c.traps = MPD_Malloc_error;
120 c.status = 0;
121 c.newtrap = 0;
122 c.round = MPD_ROUND_HALF_UP;
123 c.clamp = 0;
124 c.allcr = 1;
125
126 return c;
127 }
128
129 static mpd_context_t
testcontext(const bool extended)130 testcontext(const bool extended)
131 {
132 mpd_context_t c;
133
134 if (extended) {
135 #if defined(MPD_CONFIG_64)
136 c.prec = MPD_MAX_PREC;
137 c.emax = MPD_MAX_EMAX;
138 c.emin = MPD_MIN_EMIN;
139 #elif defined(MPD_CONFIG_32)
140 c.prec = 999999999;
141 c.emax = 999999999;
142 c.emin = -999999999;
143 #else
144 #error "config not defined"
145 #endif
146 }
147 else {
148 c.prec = MPD_MAX_PREC;
149 c.emax = MPD_MAX_EMAX;
150 c.emin = MPD_MIN_EMIN;
151 }
152
153 c.traps = MPD_Malloc_error;
154 c.status = 0;
155 c.newtrap = 0;
156 c.round = MPD_ROUND_HALF_UP;
157 c.clamp = 0;
158 c.allcr = 1;
159
160 return c;
161 }
162
163 static void
mpd_assert_context_ok(const Context & c,const std::vector<std::string> & token)164 mpd_assert_context_ok(const Context& c, const std::vector<std::string>& token)
165 {
166 const mpd_context_t *ctx = c.getconst();
167
168 DECIMAL_ASSERT(0 < ctx->prec && ctx->prec <= MPD_READ_MAX_PREC, token);
169 DECIMAL_ASSERT(0 <= ctx->emax && ctx->emax <= MPD_READ_MAX_PREC, token);
170 DECIMAL_ASSERT(-MPD_READ_MAX_PREC <= ctx->emin && ctx->emin <= 0, token);
171 DECIMAL_ASSERT(0 <= ctx->round && ctx->round < MPD_ROUND_GUARD, token);
172 DECIMAL_ASSERT(ctx->traps <= MPD_Max_status, token);
173 DECIMAL_ASSERT(ctx->status <= MPD_Max_status, token);
174 DECIMAL_ASSERT(ctx->clamp == 0 || ctx->clamp == 1, token);
175 DECIMAL_ASSERT(ctx->allcr == 0 || ctx->allcr == 1, token);
176 }
177
178
179 /* Known differences that are within the spec */
180 struct result_diff {
181 const char *id;
182 const char *calc;
183 const char *expected;
184 };
185
186 struct status_diff {
187 const char *id;
188 uint32_t calc;
189 uint32_t expected;
190 };
191
192 static const struct result_diff ulp_cases[] {
193 /* Cases where the result is allowed to differ by less than one ULP.
194 * Only needed if ctx->allcr is 0. */
195 { "expx013", "1.001000", "1.001001" },
196 { "expx020", "1.000000", "1.000001" },
197 { "expx109", "0.999999910000004049999878", "0.999999910000004049999879" },
198 { "expx1036", "1.005088", "1.005087" },
199 { "expx350", "1.0000000", "1.0000001" },
200 { "expx351", "1.0000000", "1.0000001" },
201 { "expx352", "1.0000000", "1.0000001" },
202 };
203
204 static const struct status_diff status_cases[] {
205 /* With a reduced working precision in mpd_qpow() the status matches. */
206 { "pwsx803", MPD_Inexact|MPD_Rounded|MPD_Subnormal|MPD_Underflow, MPD_Inexact|MPD_Rounded },
207 };
208
209 static const char *skipit[] {
210 /* NULL reference, decimal16, decimal32, or decimal128 */
211 "absx900",
212 "addx9990",
213 "addx9991",
214 "clam090",
215 "clam091",
216 "clam092",
217 "clam093",
218 "clam094",
219 "clam095",
220 "clam096",
221 "clam097",
222 "clam098",
223 "clam099",
224 "clam189",
225 "clam190",
226 "clam191",
227 "clam192",
228 "clam193",
229 "clam194",
230 "clam195",
231 "clam196",
232 "clam197",
233 "clam198",
234 "clam199",
235 "comx990",
236 "comx991",
237 "cotx9990",
238 "cotx9991",
239 "ctmx9990",
240 "ctmx9991",
241 "ddabs900",
242 "ddadd9990",
243 "ddadd9991",
244 "ddcom9990",
245 "ddcom9991",
246 "ddcot9990",
247 "ddcot9991",
248 "ddctm9990",
249 "ddctm9991",
250 "dddiv9998",
251 "dddiv9999",
252 "dddvi900",
253 "dddvi901",
254 "ddfma2990",
255 "ddfma2991",
256 "ddfma39990",
257 "ddfma39991",
258 "ddlogb900",
259 "ddmax900",
260 "ddmax901",
261 "ddmxg900",
262 "ddmxg901",
263 "ddmin900",
264 "ddmin901",
265 "ddmng900",
266 "ddmng901",
267 "ddmul9990",
268 "ddmul9991",
269 "ddnextm900",
270 "ddnextm900",
271 "ddnextp900",
272 "ddnextp900",
273 "ddnextt900",
274 "ddnextt901",
275 "ddqua998",
276 "ddqua999",
277 "ddred900",
278 "ddrem1000",
279 "ddrem1001",
280 "ddrmn1000",
281 "ddrmn1001",
282 "ddsub9990",
283 "ddsub9991",
284 "ddintx074",
285 "ddintx094",
286 "divx9998",
287 "divx9999",
288 "dvix900",
289 "dvix901",
290 "dqabs900",
291 "dqadd9990",
292 "dqadd9991",
293 "dqcom990",
294 "dqcom991",
295 "dqcot9990",
296 "dqcot9991",
297 "dqctm9990",
298 "dqctm9991",
299 "dqdiv9998",
300 "dqdiv9999",
301 "dqdvi900",
302 "dqdvi901",
303 "dqfma2990",
304 "dqfma2991",
305 "dqadd39990",
306 "dqadd39991",
307 "dqlogb900",
308 "dqmax900",
309 "dqmax901",
310 "dqmxg900",
311 "dqmxg901",
312 "dqmin900",
313 "dqmin901",
314 "dqmng900",
315 "dqmng901",
316 "dqmul9990",
317 "dqmul9991",
318 "dqnextm900",
319 "dqnextp900",
320 "dqnextt900",
321 "dqnextt901",
322 "dqqua998",
323 "dqqua999",
324 "dqred900",
325 "dqrem1000",
326 "dqrem1001",
327 "dqrmn1000",
328 "dqrmn1001",
329 "dqsub9990",
330 "dqsub9991",
331 "dqintx074",
332 "dqintx094",
333 "expx900",
334 "fmax2990",
335 "fmax2991",
336 "fmax39990",
337 "fmax39991",
338 "lnx900",
339 "logx900",
340 "logbx900",
341 "maxx900",
342 "maxx901",
343 "mxgx900",
344 "mxgx901",
345 "mnm900",
346 "mnm901",
347 "mng900",
348 "mng901",
349 "minx900",
350 "mulx990",
351 "mulx991",
352 "nextm900",
353 "nextp900",
354 "nextt900",
355 "nextt901",
356 "plu900",
357 "powx900",
358 "powx901",
359 "pwsx900",
360 "quax1022",
361 "quax1023",
362 "quax1024",
363 "quax1025",
364 "quax1026",
365 "quax1027",
366 "quax1028",
367 "quax1029",
368 "quax0a2",
369 "quax0a3",
370 "quax998",
371 "quax999",
372 "redx900",
373 "remx1000",
374 "remx1001",
375 "rmnx900",
376 "rmnx901",
377 "sqtx9900",
378 "subx9990",
379 "subx9991",
380 /* operand range violations, invalid context */
381 "expx901",
382 "expx902",
383 "expx903",
384 "expx905",
385 "lnx901",
386 "lnx902",
387 "lnx903",
388 "lnx905",
389 "logx901",
390 "logx902",
391 "logx903",
392 "logx905",
393 "powx1183",
394 "powx1184",
395 "powx4001",
396 "powx4002",
397 "powx4003",
398 "powx4005",
399 "powx4008",
400 "powx4010",
401 "powx4012",
402 "powx4014",
403 "scbx164",
404 "scbx165",
405 "scbx166",
406 #if defined(MPD_CONFIG_32) && MPD_MINALLOC_MAX <= 4
407 /* Under the allocation failure tests, the result is numerically correct
408 (1 == 1.00000) but without zero padding. This is by design, since in
409 case of MPD_Malloc_error mpd_qsqrt() retries the operation with a lower
410 context precision and allows all exact results.
411
412 The MPD_MINALLOC_MAX < 64 feature is is officially unsupported but works
413 (if the little-endian mpd_ln10_data arrays are adjusted).
414 */
415 "sqtx9045",
416 #endif
417 /* skipped for decNumber, too */
418 "powx4302",
419 "powx4303",
420 "powx4303",
421 "powx4342",
422 "powx4343",
423 "pwsx805",
424 /* disagreement for three arg power */
425 "pwmx325",
426 "pwmx326",
427 };
428
429 static mpd_ssize_t
strtossize(const char * s,char ** end,int base)430 strtossize(const char *s, char **end, int base)
431 {
432 int64_t retval;
433
434 errno = 0;
435 retval = _mpd_strtossize(s, end, base);
436 if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) {
437 errno = ERANGE;
438 }
439 if (errno == ERANGE) {
440 return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX;
441 }
442
443 return static_cast<mpd_ssize_t>(retval);
444 }
445
446 static uint64_t
rnd(void)447 rnd(void)
448 {
449 static thread_local std::mt19937_64 r(time(nullptr));
450
451 return r();
452 }
453
454 static void
mpd_init_rand(Decimal & x)455 mpd_init_rand(Decimal &x)
456 {
457 Context maxcontext{readcontext(false)};
458 uint64_t r = rnd() % 100;
459 uint8_t sign = rnd() % 2;
460
461 if (r >= 80) {
462 x = Decimal("-1111111111e20200", maxcontext);
463 }
464 else if (r >= 60) {
465 x = Decimal("-1111111111222222222233333333334444444444555555555566666666667777777777"
466 "888888888899999999990000000000e-1201", maxcontext);
467 }
468 else if (r >= 40) {
469 x = sign ? Decimal("-nan") : Decimal("nan");
470 }
471 else if (r >= 20) {
472 x = sign ? Decimal("-snan") : Decimal("snan");
473 }
474 else {
475 x = sign ? Decimal("-inf") : Decimal("inf");
476 }
477 }
478
479 static bool
skip_test(const std::string & id)480 skip_test(const std::string& id)
481 {
482 const auto& loc = std::find(std::begin(skipit), std::end(skipit), id);
483 if (loc != std::end(skipit)) {
484 return true;
485 }
486
487 return false;
488 }
489
490 static bool
startswith(const std::string & s,const char * prefix)491 startswith(const std::string& s, const char *prefix)
492 {
493 return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
494 }
495
496 static bool
endswith(const std::string & s,const char * suffix)497 endswith(const std::string& s, const char *suffix)
498 {
499 std::string rs(s);
500 std::string prefix(suffix);
501 std::reverse(rs.begin(), rs.end());
502 std::reverse(prefix.begin(), prefix.end());
503 return startswith(rs, prefix.c_str());
504 }
505
506 static bool
eqtoken(const std::string & tok,const char * s)507 eqtoken(const std::string& tok, const char *s)
508 {
509 return strcasecmp(tok.c_str(), s) == 0;
510 }
511
512 static bool
istokchar(unsigned char c)513 istokchar(unsigned char c)
514 {
515 return std::isalnum(c) || (std::ispunct(c) && c != '"' && c != '\'');
516 }
517
518 static int
nexttoken(std::string::const_iterator & start,std::string::const_iterator & end,std::string::const_iterator & next_start,const std::string::const_iterator & nul)519 nexttoken(std::string::const_iterator& start,
520 std::string::const_iterator& end,
521 std::string::const_iterator& next_start,
522 const std::string::const_iterator& nul)
523 {
524 end = next_start;
525
526 for (; end != nul; end++) {
527 if (isspace(static_cast<unsigned char>(*end))) {
528 /* empty */
529 }
530 else if (*end == '-' && (end+1) != nul && *(end+1) == '-') {
531 start = end = next_start = nul;
532 return 0;
533 }
534 else if (*end == '"') {
535 start = ++end;
536 for (; end != nul; end++) {
537 if (*end == '"') {
538 if ((end+1) != nul && *(end+1) == '"') {
539 end++; /* official test cases: "1""1" is parsed as a single string. */
540 }
541 else {
542 next_start = end+1;
543 return 0;
544 }
545 }
546 }
547 return -1;
548 }
549 else if (*end == '\'') {
550 start = ++end;
551 for (; end != nul; end++) {
552 if (*end == '\'') {
553 if ((end+1) != nul && *(end+1) == '\'') {
554 end++; /* official test cases: '1''1' is parsed as a single string. */
555 }
556 else {
557 next_start = end+1;
558 return 0;
559 }
560 }
561 }
562 return -1;
563 }
564 else {
565 start = end;
566 for (; end != nul; end++) {
567 if (std::isspace(static_cast<unsigned char>(*end))) {
568 break;
569 }
570 if (!istokchar(static_cast<unsigned char>(*end))) {
571 return -1;
572 }
573 }
574 next_start = end;
575 return 0;
576 }
577 }
578
579 start = next_start = end;
580 return 0;
581 }
582
583 /* split a line into tokens */
584 static std::vector<std::string>
split(const std::string & line)585 split(const std::string& line)
586 {
587 std::string::const_iterator start = line.begin();
588 std::string::const_iterator end = start;
589 std::string::const_iterator next_start = start;
590 const std::string::const_iterator nul = line.end();
591 std::vector<std::string> token;
592
593 while (true) {
594 const int r = nexttoken(start, end, next_start, nul);
595 if (r < 0) {
596 std::cerr << "parse_error: " << line << std::endl;
597 std::exit(EXIT_FAILURE);
598 }
599 if (end == start && end == next_start) {
600 break;
601 }
602 std::string tok{start, end};
603 token.push_back(tok);
604 }
605
606 return token;
607 }
608
609 /* returns all expected conditions in a status flag */
610 static uint32_t
scan_conditions(const std::vector<std::string> & token,const size_t n)611 scan_conditions(const std::vector<std::string>& token, const size_t n)
612 {
613 uint32_t status = 0;
614
615 for (size_t i = n; i < token.size(); i++) {
616 const std::string condition = token[i];
617
618 if (eqtoken(condition, "Clamped")) {
619 status |= MPD_Clamped;
620 }
621 else if (eqtoken(condition, "Conversion_syntax")) {
622 status |= MPD_Conversion_syntax;
623 }
624 else if (eqtoken(condition, "Division_by_zero")) {
625 status |= MPD_Division_by_zero;
626 }
627 else if (eqtoken(condition, "Division_impossible")) {
628 status |= MPD_Division_impossible;
629 }
630 else if (eqtoken(condition, "Division_undefined")) {
631 status |= MPD_Division_undefined;
632 }
633 else if (eqtoken(condition, "Fpu_error")) {
634 status |= MPD_Fpu_error;
635 }
636 else if (eqtoken(condition, "Inexact")) {
637 status |= MPD_Inexact;
638 }
639 else if (eqtoken(condition, "Invalid_context")) {
640 status |= MPD_Invalid_context;
641 }
642 else if (eqtoken(condition, "Invalid_operation")) {
643 status |= MPD_Invalid_operation;
644 }
645 else if (eqtoken(condition, "Malloc_error")) {
646 status |= MPD_Malloc_error;
647 }
648 else if (eqtoken(condition, "Not_implemented")) {
649 status |= MPD_Not_implemented;
650 }
651 else if (eqtoken(condition, "Overflow")) {
652 status |= MPD_Overflow;
653 }
654 else if (eqtoken(condition, "Rounded")) {
655 status |= MPD_Rounded;
656 }
657 else if (eqtoken(condition, "Subnormal")) {
658 status |= MPD_Subnormal;
659 }
660 else if (eqtoken(condition, "Underflow")) {
661 status |= MPD_Underflow;
662 }
663 else {
664 err_token(token, "scan_conditions: unknown status");
665 }
666 }
667
668 return status;
669 }
670
671 static void
compare_expected(const std::vector<std::string> & token,const std::string & calc,const std::string & expected,uint32_t expected_status,const Context & ctx)672 compare_expected(const std::vector<std::string>& token,
673 const std::string& calc,
674 const std::string& expected,
675 uint32_t expected_status,
676 const Context& ctx)
677 {
678 const std::string id = token.at(0);
679
680 /* known ULP diffs */
681 if (ctx.allcr() == 0) {
682 for (const auto& c : ulp_cases) {
683 if (id == c.id && expected == c.expected && calc == c.calc) {
684 return;
685 }
686 }
687 }
688
689 /* known status diffs */
690 for (const auto& c : status_cases) {
691 if (id == c.id && expected_status == c.expected && ctx.status() == c.calc) {
692 return;
693 }
694 }
695
696 if (calc != expected) {
697 err_token(token, "calc: ", calc, " expected: ", expected);
698 }
699
700 if (ctx.status() != expected_status) {
701 char ctxstatus[MPD_MAX_FLAG_STRING];
702 char expstatus[MPD_MAX_FLAG_STRING];
703
704 mpd_snprint_flags(ctxstatus, MPD_MAX_FLAG_STRING, ctx.status());
705 mpd_snprint_flags(expstatus, MPD_MAX_FLAG_STRING, expected_status);
706
707 err_token(token, "calc: [", ctxstatus, "] expected: [", expstatus, "]");
708 }
709 }
710
711 static bool
equalmem(const Decimal & x,const Decimal & y)712 equalmem(const Decimal& x, const Decimal& y)
713 {
714 const mpd_t *a = x.getconst();
715 const mpd_t *b = y.getconst();
716
717 if ((a->flags & ~MPD_DATAFLAGS) != (b->flags & ~MPD_DATAFLAGS) ||
718 a->exp != b->exp ||
719 a->len != b->len ||
720 a->digits != b->digits) {
721 return false;
722 }
723
724 for (mpd_ssize_t i = 0; i < a->len; i++) {
725 if (a->data[i] != b->data[i]) {
726 return false;
727 }
728 }
729
730 return true;
731 }
732
733 static void
check_equalmem(const std::vector<std::string> & token,const Decimal & a,const Decimal & b)734 check_equalmem(const std::vector<std::string>& token, const Decimal& a, const Decimal& b)
735 {
736 if (!equalmem(a, b)) {
737 err_token(token, "const arg changed");
738 }
739 }
740
741 static unsigned long
get_testno(const std::vector<std::string> & token)742 get_testno(const std::vector<std::string>& token)
743 {
744 const char *number = strpbrk(token.at(0).c_str(), "0123456789");
745 if (number == nullptr) {
746 err_token(token, "invalid test id: ", token.at(0));
747 }
748 return strtoul(number, nullptr, 10);
749 }
750
751 /* scan a single operand and the expected result */
752 static size_t
scan_op_expected(Decimal & op,std::string & expected,const std::vector<std::string> & token,Context & ctx)753 scan_op_expected(Decimal& op,
754 std::string& expected,
755 const std::vector<std::string>& token,
756 Context& ctx)
757 {
758 op = Decimal(token.at(2), ctx);
759 if (token.at(3) != "->") {
760 err_token(token, "expected '->' token");
761 }
762 expected = token.at(4);
763
764 return 5;
765 }
766
767 /* scan decimal operand, string operand and the expected result */
768 static size_t
scan_op_string_expected(Decimal & op1,std::string & op2,std::string & result,const std::vector<std::string> & token,Context & ctx)769 scan_op_string_expected(Decimal& op1,
770 std::string& op2,
771 std::string& result,
772 const std::vector<std::string>& token,
773 Context& ctx)
774 {
775 op1 = Decimal(token.at(2), ctx);
776 op2 = token.at(3);
777 if (token.at(4) != "->") {
778 err_token(token, "expected '->' token");
779 }
780 result = token.at(5);
781
782 return 6;
783 }
784
785 /* scan two operands and the expected result */
786 static size_t
scan_op_op_expected(Decimal & op1,Decimal & op2,std::string & result,const std::vector<std::string> & token,Context & ctx)787 scan_op_op_expected(Decimal& op1,
788 Decimal& op2,
789 std::string& result,
790 const std::vector<std::string>& token,
791 Context& ctx)
792 {
793 op1 = Decimal(token.at(2), ctx);
794 op2 = Decimal(token.at(3), ctx);
795 if (token.at(4) != "->") {
796 err_token(token, "expected '->' token");
797 }
798 result = token.at(5);
799
800 return 6;
801 }
802
803 /* scan one operands and two results */
804 static size_t
scan_op_expected_expected(Decimal & op1,std::string & result1,std::string & result2,const std::vector<std::string> & token,Context & ctx)805 scan_op_expected_expected(Decimal& op1,
806 std::string& result1,
807 std::string& result2,
808 const std::vector<std::string>& token,
809 Context& ctx)
810 {
811 op1 = Decimal(token.at(2), ctx);
812 if (token.at(3) != "->") {
813 err_token(token, "expected '->' token");
814 }
815 result1 = token.at(4);
816 result2 = token.at(5);
817
818 return 6;
819 }
820
821 /* scan two operands and two results */
822 static size_t
scan_op_op_expected_expected(Decimal & op1,Decimal & op2,std::string & result1,std::string & result2,const std::vector<std::string> & token,Context & ctx)823 scan_op_op_expected_expected(Decimal& op1,
824 Decimal& op2,
825 std::string& result1,
826 std::string& result2,
827 const std::vector<std::string>& token,
828 Context& ctx)
829 {
830 op1 = Decimal(token.at(2), ctx);
831 op2 = Decimal(token.at(3), ctx);
832 if (token.at(4) != "->") {
833 err_token(token, "expected '->' token");
834 }
835 result1 = token.at(5);
836 result2 = token.at(6);
837
838 return 7;
839 }
840
841 /* scan three operands and the expected result */
842 static size_t
scan_op_op_op_expected(Decimal & op1,Decimal & op2,Decimal & op3,std::string & result,const std::vector<std::string> & token,Context & ctx)843 scan_op_op_op_expected(Decimal& op1,
844 Decimal& op2,
845 Decimal& op3,
846 std::string& result,
847 const std::vector<std::string>& token,
848 Context& ctx)
849 {
850 op1 = Decimal(token.at(2), ctx);
851 op2 = Decimal(token.at(3), ctx);
852 op3 = Decimal(token.at(4), ctx);
853 if (token.at(5) != "->") {
854 err_token(token, "expected '->' token");
855 }
856 result = token.at(6);
857
858 return 7;
859 }
860
861 /* Triple tests */
862 static void
Triple(const std::vector<std::string> & token,const Decimal & dec,Context & ctx)863 Triple(const std::vector<std::string>& token, const Decimal &dec, Context &ctx)
864 {
865 #ifdef MPD_CONFIG_32
866 /*
867 * 32-bit: as_triple() expects well-formed decimals. Skip test cases
868 * that use the extended exponent, which is safe in the tests but not
869 * in production.
870 */
871 if (!dec.isspecial()) {
872 if (dec.exponent() < MPD_MIN_ETINY || dec.exponent() > MPD_MAX_EMAX) {
873 return;
874 }
875 }
876 #endif
877
878 mpd_uint128_triple_t triple = dec.as_uint128_triple();
879 switch (triple.tag) {
880 case MPD_TRIPLE_QNAN: case MPD_TRIPLE_SNAN:
881 DECIMAL_ASSERT(triple.exp == 0, token);
882 break;
883 case MPD_TRIPLE_INF:
884 DECIMAL_ASSERT(triple.hi == 0 && triple.lo == 0 && triple.exp == 0,
885 token);
886 break;
887 case MPD_TRIPLE_NORMAL:
888 break;
889 case MPD_TRIPLE_ERROR:
890 DECIMAL_ASSERT(triple.sign == 0 && triple.hi == 0 &&
891 triple.lo == 0 && triple.exp == 0,
892 token);
893 return;
894 }
895
896 /* Allocation failures in Decimal(triple) */
897 Decimal d = 10;
898 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
899
900 set_alloc_fail(ctx, n);
901 try {
902 d = Decimal(triple);
903 }
904 catch (MallocError&) {
905 set_alloc(ctx);
906 DECIMAL_ASSERT(d == 10, token);
907 continue;
908 }
909
910 set_alloc(ctx);
911 break;
912 }
913
914 check_equalmem(token, d, dec);
915 DECIMAL_ASSERT(d.cmp_total(dec) == 0, token);
916 }
917
918 /*
919 * This function is used for "toSci", "toEng" and "apply" and does not use
920 * a maxcontext for the conversion of the operand.
921 */
922 typedef std::string (Decimal::*String_DecimalContext)(bool) const;
923 static void
Str_DecCtx(String_DecimalContext func,const std::vector<std::string> & token,const bool extended)924 Str_DecCtx(String_DecimalContext func,
925 const std::vector<std::string>& token,
926 const bool extended)
927 {
928 Context maxcontext{readcontext(extended)};
929 Decimal op;
930 Decimal tmp;
931 std::string expected;
932 std::string expected_fail;
933 std::string calc;
934
935 Context& workctx = context;
936 workctx.status(0);
937 const size_t i = scan_op_expected(op, expected, token, workctx);
938 const uint32_t expstatus = scan_conditions(token, i);
939 if (expstatus != workctx.status()) {
940 err_token(token, "op: ", op, " expstatus: ", expstatus, " got: ", workctx.status());
941 }
942 Triple(token, op, workctx);
943
944 /* Allocation failures for Decimal() */
945 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
946 mpd_init_rand(tmp);
947 const Decimal save_tmp = tmp;
948
949 workctx.status(0);
950 set_alloc_fail(workctx, n);
951 try {
952 (void)scan_op_expected(tmp, expected_fail, token, workctx);
953 }
954 catch (MallocError&) {
955 set_alloc(workctx);
956 check_equalmem(token, tmp, save_tmp);
957 continue;
958 }
959
960 set_alloc(workctx);
961 break;
962 }
963 /* internal sanity checks */
964 DECIMAL_ASSERT(expected == expected_fail, token);
965 DECIMAL_ASSERT(tmp.cmp_total(op) == 0, token);
966
967 /* make a copy of the operand */
968 mpd_init_rand(tmp);
969 tmp = op;
970
971 workctx.status(0);
972 calc = (tmp.*func)(true);
973
974 /* compare the calculated result with the expected result */
975 compare_expected(token, calc, expected, 0, workctx);
976 check_equalmem(token, tmp, op);
977
978 /* Allocation failures */
979 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
980 mpd_init_rand(tmp);
981 tmp = op;
982
983 workctx.status(0);
984 set_alloc_fail(workctx, n);
985 try {
986 calc = (tmp.*func)(true);
987 }
988 catch (MallocError&) {
989 set_alloc(context);
990 check_equalmem(token, tmp, op);
991 continue;
992 }
993
994 set_alloc(workctx);
995 break;
996 }
997
998 compare_expected(token, calc, expected, 0, workctx);
999 check_equalmem(token, tmp, op);
1000 }
1001
1002 #ifdef __INTEL_COMPILER
1003 #pragma warning(disable : 186)
1004 #endif
1005 /* Quick and dirty: parse hex escape sequences */
1006 static std::string
parse_escapes_backslash(const char * s)1007 parse_escapes_backslash(const char *s)
1008 {
1009 char hex[5];
1010 char *result, *cp;
1011 unsigned int u;
1012 unsigned char b;
1013 int n;
1014
1015 std::shared_ptr<char> ptr(new char[strlen(s)+1], std::default_delete<char[]>());
1016 cp = result = ptr.get();
1017
1018 hex[0] = '0';
1019 hex[1] = '\0';
1020 while (*s) {
1021 if (*s == '\\' && *(s+1) == 'x') {
1022 for (n = 1; n < 4; n++) {
1023 if (!s[n]) {
1024 err_raise("parse hex escapes: invalid escape sequence");
1025 }
1026 hex[n] = s[n];
1027 }
1028 hex[n] = '\0';
1029 sscanf(hex, "%x%n", &u, &n);
1030 b = safe_downcast<unsigned char, unsigned int>(u);
1031 *cp++ = static_cast<char>(b);
1032 s += n;
1033 }
1034 else {
1035 *cp++ = *s++;
1036 }
1037 }
1038
1039 *cp = '\0';
1040 return std::string(result);
1041 }
1042
1043 static std::string
parse_escapes_hexstring(const char * s)1044 parse_escapes_hexstring(const char *s)
1045 {
1046 const std::string hex{s};
1047 const size_t len = hex.size();
1048 std::vector<char> bytes;
1049
1050 if (len % 2 != 0) {
1051 err_raise("parse hex escapes: invalid escape sequence");
1052 }
1053
1054 for (size_t i = 0; i < len; i += 2) {
1055 std::string twodigits = hex.substr(i, 2);
1056 const unsigned long ul = strtoul(twodigits.c_str(), nullptr, 16);
1057 const unsigned char b = safe_downcast<unsigned char, unsigned long>(ul);
1058 bytes.push_back(static_cast<char>(b));
1059 }
1060
1061 return std::string(bytes.data(), bytes.size());
1062 }
1063
1064 static std::string
parse_escapes(const char * s)1065 parse_escapes(const char *s)
1066 {
1067 if (startswith(s, "HEX")) {
1068 return parse_escapes_hexstring(s+3);
1069 }
1070 else {
1071 return parse_escapes_backslash(s);
1072 }
1073 }
1074
1075 /* This function is used for Decimal::format. */
1076 static void
Fmt(const std::vector<std::string> & token,const bool extended)1077 Fmt(const std::vector<std::string>& token, const bool extended)
1078 {
1079 Context maxcontext{readcontext(extended)};
1080 Decimal op, tmp;
1081 std::string fmt, expected;
1082 std::string calc;
1083
1084 const size_t i = scan_op_string_expected(op, fmt, expected, token, maxcontext);
1085 const uint32_t expstatus = scan_conditions(token, i);
1086 Triple(token, op, maxcontext);
1087
1088 fmt = parse_escapes(fmt.c_str());
1089 expected = parse_escapes(expected.c_str());
1090
1091 mpd_init_rand(tmp);
1092 tmp = op;
1093
1094 context.status(0);
1095 try {
1096 calc = tmp.format(fmt);
1097 }
1098 catch (ValueError&) {
1099 DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token);
1100 DECIMAL_ASSERT(context.status() == 0, token);
1101 check_equalmem(token, tmp, op);
1102 #ifdef __mips__
1103 return;
1104 #endif
1105 }
1106
1107 DECIMAL_ASSERT(expstatus == 0 || expstatus == MPD_Invalid_operation, token);
1108 if (expstatus == 0) {
1109 compare_expected(token, calc, expected, expstatus, context);
1110 check_equalmem(token, tmp, op);
1111 }
1112
1113 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
1114 mpd_init_rand(tmp);
1115 tmp = op;
1116
1117 context.status(0);
1118 set_alloc_fail(context, n);
1119 try {
1120 calc = tmp.format(fmt);
1121 }
1122 catch (MallocError&) {
1123 set_alloc(context);
1124 continue;
1125 }
1126 #ifndef __mips__ /* miscompilation */
1127 catch (ValueError&) {
1128 DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token);
1129 DECIMAL_ASSERT(context.status() == 0, token);
1130 }
1131 #endif
1132
1133 set_alloc(context);
1134 break;
1135 }
1136
1137 DECIMAL_ASSERT(expstatus == 0 || expstatus == MPD_Invalid_operation, token);
1138 if (expstatus == 0) {
1139 compare_expected(token, calc, expected, expstatus, context);
1140 check_equalmem(token, tmp, op);
1141 }
1142 }
1143
1144 /* test number class */
1145 static void
Class(const std::vector<std::string> & token,const bool extended)1146 Class(const std::vector<std::string>& token, const bool extended)
1147 {
1148 Context maxcontext{readcontext(extended)};
1149 Decimal op, tmp;
1150 std::string expected;
1151
1152 const size_t n = scan_op_expected(op, expected, token, maxcontext);
1153 const uint32_t expstatus = scan_conditions(token, n);
1154 Triple(token, op, maxcontext);
1155
1156 mpd_init_rand(tmp);
1157 tmp = op;
1158
1159 context.status(0);
1160 std::string calc = tmp.number_class(context);
1161 compare_expected(token, calc, expected, expstatus, context);
1162 check_equalmem(token, tmp, op);
1163 }
1164
1165 /* test a unary function */
1166 typedef Decimal (Decimal::*Decimal_Decimal)() const;
1167
1168 static void
Dec_Dec_RunSingle(Decimal & result,Decimal & tmp,const std::vector<std::string> & token,const Decimal_Decimal func,const Decimal & op,const std::string & expected,const uint32_t expstatus)1169 Dec_Dec_RunSingle(Decimal& result, Decimal& tmp,
1170 const std::vector<std::string>& token,
1171 const Decimal_Decimal func,
1172 const Decimal& op,
1173 const std::string& expected,
1174 const uint32_t expstatus)
1175 {
1176 uint64_t incr = 1;
1177 for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) {
1178 mpd_init_rand(result);
1179 mpd_init_rand(tmp);
1180 tmp = op;
1181
1182 const Decimal save_result = result;
1183 context.status(0);
1184 set_alloc_fail(context, n);
1185 try {
1186 result = (tmp.*func)();
1187 }
1188 catch (MallocError&) {
1189 set_alloc(context);
1190 check_equalmem(token, result, save_result);
1191 check_equalmem(token, tmp, op);
1192 if (n > 50) {
1193 incr = rnd() % 100 + 1;
1194 }
1195 continue;
1196 }
1197
1198 set_alloc(context);
1199 break;
1200 }
1201
1202 const std::string calc = result.to_sci();
1203 compare_expected(token, calc, expected, expstatus, context);
1204 if (&tmp != &result) {
1205 check_equalmem(token, tmp, op);
1206 }
1207 }
1208
1209 static void
Dec_Dec(Decimal_Decimal func,const std::vector<std::string> & token,const bool extended)1210 Dec_Dec(Decimal_Decimal func,
1211 const std::vector<std::string>& token,
1212 const bool extended)
1213 {
1214 Context maxcontext{readcontext(extended)};
1215 Decimal op, result, tmp;
1216 std::string expected;
1217
1218 const size_t n = scan_op_expected(op, expected, token, maxcontext);
1219 const uint32_t expstatus = scan_conditions(token, n);
1220 Triple(token, op, maxcontext);
1221
1222 Dec_Dec_RunSingle(result, tmp, token, func, op, expected, expstatus);
1223 Dec_Dec_RunSingle(tmp, tmp, token, func, op, expected, expstatus);
1224 }
1225
1226 /* test a unary function with an optional context argument */
1227 typedef Decimal (Decimal::*Decimal_DecimalContext)(Context&) const;
1228
1229 static void
Dec_DecCtx_RunSingle(Decimal & result,Decimal & tmp,const std::vector<std::string> & token,const Decimal_DecimalContext func,const Decimal & op,const std::string & expected,const uint32_t expstatus)1230 Dec_DecCtx_RunSingle(Decimal& result, Decimal& tmp,
1231 const std::vector<std::string>& token,
1232 const Decimal_DecimalContext func,
1233 const Decimal& op,
1234 const std::string& expected,
1235 const uint32_t expstatus)
1236 {
1237 uint64_t incr = 1;
1238 for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) {
1239 mpd_init_rand(result);
1240 mpd_init_rand(tmp);
1241 tmp = op;
1242
1243 const Decimal save_result = result;
1244 context.status(0);
1245 set_alloc_fail(context, n);
1246 try {
1247 result = (tmp.*func)(context);
1248 }
1249 catch (MallocError&) {
1250 set_alloc(context);
1251 check_equalmem(token, result, save_result);
1252 check_equalmem(token, tmp, op);
1253 if (n > 50) {
1254 incr = rnd() % 100 + 1;
1255 }
1256 continue;
1257 }
1258
1259 set_alloc(context);
1260 break;
1261 }
1262
1263 const std::string calc = result.to_sci();
1264 compare_expected(token, calc, expected, expstatus, context);
1265 if (&tmp != &result) {
1266 check_equalmem(token, tmp, op);
1267 }
1268 }
1269
1270 static void
Dec_DecCtx(Decimal_DecimalContext func,const std::vector<std::string> & token,const bool extended)1271 Dec_DecCtx(Decimal_DecimalContext func,
1272 const std::vector<std::string>& token,
1273 const bool extended)
1274 {
1275 Context maxcontext{readcontext(extended)};
1276 Decimal op, result, tmp;
1277 std::string expected;
1278
1279 const size_t n = scan_op_expected(op, expected, token, maxcontext);
1280 const uint32_t expstatus = scan_conditions(token, n);
1281 Triple(token, op, maxcontext);
1282
1283 Dec_DecCtx_RunSingle(result, tmp, token, func, op, expected, expstatus);
1284 Dec_DecCtx_RunSingle(tmp, tmp, token, func, op, expected, expstatus);
1285 }
1286
1287 /* Same as Dec_DecCtx, but quantize the operand before applying the actual function */
1288 static void
Dec_DecCtxWithQuantize(Decimal_DecimalContext func,const std::vector<std::string> & token,const bool extended)1289 Dec_DecCtxWithQuantize(Decimal_DecimalContext func,
1290 const std::vector<std::string>& token,
1291 const bool extended)
1292 {
1293 Context maxcontext{readcontext(extended)};
1294 Decimal op, scale, result, tmp;
1295 std::string expected;
1296
1297 const size_t n = scan_op_op_expected(op, scale, expected, token, maxcontext);
1298 const uint32_t expstatus = scan_conditions(token, n);
1299 Triple(token, op, maxcontext);
1300 Triple(token, scale, maxcontext);
1301
1302 op = op.quantize(scale, maxcontext);
1303
1304 Dec_DecCtx_RunSingle(result, tmp, token, func, op, expected, expstatus);
1305 Dec_DecCtx_RunSingle(tmp, tmp, token, func, op, expected, expstatus);
1306 }
1307
1308 /* Test a binary function */
1309 typedef Decimal (Decimal::*Decimal_DecimalDecimalContext)(const Decimal&, Context&) const;
1310
1311 static void
resolve_status_hack(uint32_t & expstatus,const uint32_t status)1312 resolve_status_hack(uint32_t& expstatus, const uint32_t status)
1313 {
1314 /* hack #1 to resolve disagreement with results generated by decimal.py */
1315 if ((expstatus & MPD_Invalid_operation) &&
1316 (status & MPD_Division_impossible)) {
1317 expstatus = MPD_Division_impossible;
1318 }
1319
1320 /* hack #2 to resolve disagreement with results generated by decimal.py */
1321 if ((expstatus & MPD_Invalid_operation) &&
1322 (status & MPD_Division_undefined)) {
1323 expstatus = MPD_Division_undefined;
1324 }
1325 }
1326
1327 static void
Dec_DecDecCtx_RunSingle(Decimal & result,Decimal & tmp1,Decimal & tmp2,const std::vector<std::string> & token,const Decimal_DecimalDecimalContext func,const Decimal & op1,const Decimal & op2,const std::string & expected,const uint32_t expstatus)1328 Dec_DecDecCtx_RunSingle(Decimal& result, Decimal& tmp1, Decimal& tmp2,
1329 const std::vector<std::string>& token,
1330 const Decimal_DecimalDecimalContext func,
1331 const Decimal& op1, const Decimal &op2,
1332 const std::string& expected,
1333 const uint32_t expstatus)
1334 {
1335 uint64_t incr = 1;
1336 for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) {
1337 mpd_init_rand(tmp1);
1338 mpd_init_rand(tmp2);
1339 tmp1 = op1;
1340 tmp2 = op2;
1341
1342 const Decimal save_result = result;
1343 context.status(0);
1344 set_alloc_fail(context, n);
1345 try {
1346 result = (tmp1.*func)(tmp2, context);
1347 }
1348 catch (MallocError&) {
1349 set_alloc(context);
1350 check_equalmem(token, result, save_result);
1351 check_equalmem(token, tmp1, op1);
1352 check_equalmem(token, tmp2, op2);
1353 if (n > 50) {
1354 incr = rnd() % 100 + 1;
1355 }
1356 continue;
1357 }
1358
1359 set_alloc(context);
1360 break;
1361 }
1362
1363 const std::string calc = result.to_sci();
1364 compare_expected(token, calc, expected, expstatus, context);
1365 if (&tmp1 != &result) {
1366 check_equalmem(token, tmp1, op1);
1367 }
1368 if (&tmp2 != &result) {
1369 check_equalmem(token, tmp2, op2);
1370 }
1371 }
1372
1373 static void
Dec_DecDecCtx(const Decimal_DecimalDecimalContext func,const std::vector<std::string> & token,const bool scan_equal,const bool extended)1374 Dec_DecDecCtx(const Decimal_DecimalDecimalContext func,
1375 const std::vector<std::string>& token,
1376 const bool scan_equal,
1377 const bool extended)
1378 {
1379 Context maxcontext{readcontext(extended)};
1380 Decimal result, tmp1, tmp2;
1381 Decimal op1, op2;
1382 std::string expected;
1383 uint32_t expstatus;
1384 size_t n;
1385
1386 if (scan_equal) {
1387 n = scan_op_expected(op1, expected, token, maxcontext);
1388 op2 = op1;
1389 }
1390 else {
1391 n = scan_op_op_expected(op1, op2, expected, token, maxcontext);
1392 }
1393 expstatus = scan_conditions(token, n);
1394 Triple(token, op1, maxcontext);
1395 Triple(token, op2, maxcontext);
1396
1397 context.status(0);
1398 result = (op1.*func)(op2, context);
1399
1400 Dec_DecDecCtx_RunSingle(result, tmp1, tmp2, token, func, op1, op2, expected, expstatus);
1401 Dec_DecDecCtx_RunSingle(tmp1, tmp1, tmp2, token, func, op1, op2, expected, expstatus);
1402 Dec_DecDecCtx_RunSingle(tmp2, tmp1, tmp2, token, func, op1, op2, expected, expstatus);
1403
1404 if (equalmem(op1, op2)) {
1405 Dec_DecDecCtx_RunSingle(result, tmp1, tmp1, token, func, op1, op2, expected, expstatus);
1406 Dec_DecDecCtx_RunSingle(tmp1, tmp1, tmp1, token, func, op1, op2, expected, expstatus);
1407 }
1408 }
1409
1410 /* Test a binary function with a binary result */
1411 typedef std::pair<Decimal, Decimal> (Decimal::*DecimalPair_DecimalDecimalContext)(const Decimal&, Context&) const;
1412
1413 static void
DecPair_DecDecCtx_RunSingle(std::pair<Decimal,Decimal> & result,Decimal & tmp1,Decimal & tmp2,const std::vector<std::string> & token,const DecimalPair_DecimalDecimalContext func,const Decimal & op1,const Decimal & op2,const std::string & expected1,const std::string & expected2,const uint32_t expstatus)1414 DecPair_DecDecCtx_RunSingle(std::pair<Decimal, Decimal>& result, Decimal& tmp1, Decimal& tmp2,
1415 const std::vector<std::string>& token,
1416 const DecimalPair_DecimalDecimalContext func,
1417 const Decimal& op1, const Decimal &op2,
1418 const std::string& expected1, const std::string& expected2,
1419 const uint32_t expstatus)
1420 {
1421 uint64_t incr = 1;
1422 for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) {
1423 mpd_init_rand(tmp1);
1424 mpd_init_rand(tmp2);
1425 tmp1 = op1;
1426 tmp2 = op2;
1427 const Decimal first = result.first;
1428 const Decimal second = result.second;
1429
1430 context.status(0);
1431 set_alloc_fail(context, n);
1432 try {
1433 result = (tmp1.*func)(tmp2, context);
1434 }
1435 catch (MallocError&) {
1436 set_alloc(context);
1437 check_equalmem(token, result.first, first);
1438 check_equalmem(token, result.second, second);
1439 check_equalmem(token, tmp1, op1);
1440 check_equalmem(token, tmp2, op2);
1441 if (n > 50) {
1442 incr = rnd() % 100 + 1;
1443 }
1444 continue;
1445 }
1446
1447 set_alloc(context);
1448 break;
1449 }
1450
1451 std::string calc = result.first.to_sci();
1452 compare_expected(token, calc, expected1, expstatus, context);
1453
1454 calc = result.second.to_sci();
1455 compare_expected(token, calc, expected2, expstatus, context);
1456
1457 if (&tmp1 != &result.first && &tmp1 != &result.second) {
1458 check_equalmem(token, tmp1, op1);
1459 }
1460 if (&tmp2 != &result.first && &tmp2 != &result.second) {
1461 check_equalmem(token, tmp2, op2);
1462 }
1463 }
1464
1465 static void
DecPair_DecDecCtx(const DecimalPair_DecimalDecimalContext func,const std::vector<std::string> & token,const bool scan_equal,const bool extended)1466 DecPair_DecDecCtx(const DecimalPair_DecimalDecimalContext func,
1467 const std::vector<std::string>& token,
1468 const bool scan_equal,
1469 const bool extended)
1470 {
1471 Context maxcontext{readcontext(extended)};
1472 std::pair<Decimal, Decimal> result;
1473 Decimal tmp1, tmp2;
1474 Decimal op1, op2;
1475 std::string expected1, expected2;
1476 uint32_t expstatus;
1477 size_t n;
1478
1479 if (scan_equal) {
1480 n = scan_op_expected_expected(op1, expected1, expected2,
1481 token, maxcontext);
1482 op2 = op1;
1483 }
1484 else {
1485 n = scan_op_op_expected_expected(op1, op2, expected1, expected2,
1486 token, maxcontext);
1487 }
1488 expstatus = scan_conditions(token, n);
1489 Triple(token, op1, maxcontext);
1490 Triple(token, op2, maxcontext);
1491
1492 context.status(0);
1493 result = (op1.*func)(op2, context);
1494 resolve_status_hack(expstatus, context.status());
1495
1496 DecPair_DecDecCtx_RunSingle(result, tmp1, tmp2, token, func, op1, op2, expected1, expected2, expstatus);
1497 DecPair_DecDecCtx_RunSingle(result, result.first, tmp2, token, func, op1, op2, expected1, expected2, expstatus);
1498 DecPair_DecDecCtx_RunSingle(result, tmp1, result.first, token, func, op1, op2, expected1, expected2, expstatus);
1499 DecPair_DecDecCtx_RunSingle(result, result.second, tmp2, token, func, op1, op2, expected1, expected2, expstatus);
1500 DecPair_DecDecCtx_RunSingle(result, tmp1, result.second, token, func, op1, op2, expected1, expected2, expstatus);
1501
1502 if (equalmem(op1, op2)) {
1503 DecPair_DecDecCtx_RunSingle(result, tmp1, tmp1, token, func, op1, op2, expected1, expected2, expstatus);
1504 DecPair_DecDecCtx_RunSingle(result, result.first, result.first, token, func, op1, op2, expected1, expected2, expstatus);
1505 DecPair_DecDecCtx_RunSingle(result, result.second, result.second, token, func, op1, op2, expected1, expected2, expstatus);
1506 }
1507 }
1508
1509 /* Test a ternary function */
1510 typedef Decimal (Decimal::*Decimal_DecimalDecimalDecimalContext)(const Decimal&, const Decimal&, Context&) const;
1511
1512 static void
Dec_DecDecDecCtx_RunSingle(Decimal & result,Decimal & tmp1,Decimal & tmp2,Decimal & tmp3,const std::vector<std::string> & token,const Decimal_DecimalDecimalDecimalContext func,const Decimal & op1,const Decimal & op2,const Decimal & op3,const std::string & expected,const uint32_t expstatus)1513 Dec_DecDecDecCtx_RunSingle(Decimal& result, Decimal& tmp1, Decimal& tmp2, Decimal& tmp3,
1514 const std::vector<std::string>& token,
1515 const Decimal_DecimalDecimalDecimalContext func,
1516 const Decimal& op1, const Decimal &op2, const Decimal &op3,
1517 const std::string& expected,
1518 const uint32_t expstatus)
1519 {
1520 uint64_t incr = 1;
1521 for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) {
1522 mpd_init_rand(tmp1);
1523 mpd_init_rand(tmp2);
1524 mpd_init_rand(tmp3);
1525 tmp1 = op1;
1526 tmp2 = op2;
1527 tmp3 = op3;
1528
1529 const Decimal save_result = result;
1530 context.status(0);
1531 set_alloc_fail(context, n);
1532 try {
1533 result = (tmp1.*func)(tmp2, tmp3, context);
1534 }
1535 catch (MallocError&) {
1536 set_alloc(context);
1537 check_equalmem(token, result, save_result);
1538 check_equalmem(token, tmp1, op1);
1539 check_equalmem(token, tmp2, op2);
1540 check_equalmem(token, tmp3, op3);
1541 if (n > 100) {
1542 incr = rnd() % 100 + 1;
1543 }
1544 continue;
1545 }
1546
1547 set_alloc(context);
1548 break;
1549 }
1550
1551 const std::string calc = result.to_sci();
1552 compare_expected(token, calc, expected, expstatus, context);
1553 if (&tmp1 != &result) {
1554 check_equalmem(token, tmp1, op1);
1555 }
1556 if (&tmp2 != &result) {
1557 check_equalmem(token, tmp2, op2);
1558 }
1559 if (&tmp3 != &result) {
1560 check_equalmem(token, tmp3, op3);
1561 }
1562 }
1563
1564 enum ternary_equal { OpOpOp, EqEqOp, EqOpEq, OpEqEq, EqEqEq };
1565 static void
Dec_DecDecDecCtx(const Decimal_DecimalDecimalDecimalContext func,enum ternary_equal scan_equal,const std::vector<std::string> & token,const bool extended)1566 Dec_DecDecDecCtx(const Decimal_DecimalDecimalDecimalContext func,
1567 enum ternary_equal scan_equal,
1568 const std::vector<std::string>& token,
1569 const bool extended)
1570 {
1571 Context maxcontext{readcontext(extended)};
1572 Decimal result, tmp1, tmp2, tmp3;
1573 Decimal op1, op2, op3;
1574 std::string expected;
1575 uint32_t expstatus;
1576 size_t n;
1577
1578 switch (scan_equal) {
1579 case OpOpOp:
1580 n = scan_op_op_op_expected(op1, op2, op3, expected, token, maxcontext);
1581 break;
1582 case EqEqOp:
1583 n = scan_op_op_expected(op1, op3, expected, token, maxcontext);
1584 op2 = op1;
1585 break;
1586 case EqOpEq:
1587 n = scan_op_op_expected(op1, op2, expected, token, maxcontext);
1588 op3 = op1;
1589 break;
1590 case OpEqEq:
1591 n = scan_op_op_expected(op1, op2, expected, token, maxcontext);
1592 op3 = op2;
1593 break;
1594 case EqEqEq:
1595 n = scan_op_expected(op1, expected, token, maxcontext);
1596 op3 = op2 = op1;
1597 break;
1598 default:
1599 err_raise("internal error: unexpected tag");
1600 break;
1601 }
1602 expstatus = scan_conditions(token, n);
1603 Triple(token, op1, maxcontext);
1604 Triple(token, op2, maxcontext);
1605 Triple(token, op3, maxcontext);
1606
1607 Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, tmp3, token, func, op1, op2, op3, expected, expstatus);
1608 Dec_DecDecDecCtx_RunSingle(result, result, tmp2, tmp3, token, func, op1, op2, op3, expected, expstatus);
1609 Dec_DecDecDecCtx_RunSingle(result, tmp1, result, tmp3, token, func, op1, op2, op3, expected, expstatus);
1610 Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, result, token, func, op1, op2, op3, expected, expstatus);
1611
1612 if (equalmem(op1, op2)) {
1613 Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp1, tmp3, token, func, op1, op2, op3, expected, expstatus);
1614 Dec_DecDecDecCtx_RunSingle(result, result, result, tmp3, token, func, op1, op2, op3, expected, expstatus);
1615 Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp1, result, token, func, op1, op2, op3, expected, expstatus);
1616 }
1617
1618 if (equalmem(op1, op3)) {
1619 Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, tmp1, token, func, op1, op2, op3, expected, expstatus);
1620 Dec_DecDecDecCtx_RunSingle(result, result, tmp2, result, token, func, op1, op2, op3, expected, expstatus);
1621 Dec_DecDecDecCtx_RunSingle(result, tmp1, result, tmp1, token, func, op1, op2, op3, expected, expstatus);
1622 }
1623
1624 if (equalmem(op2, op3)) {
1625 Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, tmp2, token, func, op1, op2, op3, expected, expstatus);
1626 Dec_DecDecDecCtx_RunSingle(result, result, tmp2, tmp2, token, func, op1, op2, op3, expected, expstatus);
1627 Dec_DecDecDecCtx_RunSingle(result, tmp1, result, result, token, func, op1, op2, op3, expected, expstatus);
1628 }
1629
1630 if (equalmem(op1, op2) && equalmem(op1, op3)) {
1631 Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp1, tmp1, token, func, op1, op2, op3, expected, expstatus);
1632 Dec_DecDecDecCtx_RunSingle(result, result, result, result, token, func, op1, op2, op3, expected, expstatus);
1633 }
1634 }
1635
1636 /* Test a binary function with no context argument */
1637 typedef Decimal (Decimal::*Decimal_DecimalDecimal)(const Decimal&) const;
1638
1639 static void
Dec_DecDec_RunSingle(Decimal & result,Decimal & tmp1,Decimal & tmp2,const std::vector<std::string> & token,const Decimal_DecimalDecimal func,const Decimal & op1,const Decimal & op2,const std::string & expected,const uint32_t expstatus)1640 Dec_DecDec_RunSingle(Decimal& result, Decimal& tmp1, Decimal& tmp2,
1641 const std::vector<std::string>& token,
1642 const Decimal_DecimalDecimal func,
1643 const Decimal& op1, const Decimal &op2,
1644 const std::string& expected,
1645 const uint32_t expstatus)
1646 {
1647 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
1648 mpd_init_rand(tmp1);
1649 mpd_init_rand(tmp2);
1650 tmp1 = op1;
1651 tmp2 = op2;
1652
1653 const Decimal save_result = result;
1654 context.status(0);
1655 set_alloc_fail(context, n);
1656 try {
1657 result = (tmp1.*func)(tmp2);
1658 }
1659 catch (MallocError&) {
1660 set_alloc(context);
1661 check_equalmem(token, result, save_result);
1662 check_equalmem(token, tmp1, op1);
1663 check_equalmem(token, tmp2, op2);
1664 continue;
1665 }
1666
1667 set_alloc(context);
1668 break;
1669 }
1670
1671 const std::string calc = result.to_sci();
1672 compare_expected(token, calc, expected, expstatus, context);
1673 if (&tmp1 != &result) {
1674 check_equalmem(token, tmp1, op1);
1675 }
1676 if (&tmp2 != &result) {
1677 check_equalmem(token, tmp2, op2);
1678 }
1679 }
1680
1681 static void
Dec_DecDec(const Decimal_DecimalDecimal func,const std::vector<std::string> & token,const bool scan_equal,const bool extended)1682 Dec_DecDec(const Decimal_DecimalDecimal func,
1683 const std::vector<std::string>& token,
1684 const bool scan_equal,
1685 const bool extended)
1686 {
1687 Context maxcontext{readcontext(extended)};
1688 Decimal result, tmp1, tmp2;
1689 Decimal op1, op2;
1690 std::string expected;
1691 uint32_t expstatus;
1692 size_t n;
1693
1694 if (scan_equal) {
1695 n = scan_op_expected(op1, expected, token, maxcontext);
1696 op2 = op1;
1697 }
1698 else {
1699 n = scan_op_op_expected(op1, op2, expected, token, maxcontext);
1700 }
1701 expstatus = scan_conditions(token, n);
1702 Triple(token, op1, maxcontext);
1703 Triple(token, op2, maxcontext);
1704
1705 Dec_DecDec_RunSingle(result, tmp1, tmp2, token, func, op1, op2, expected, expstatus);
1706 Dec_DecDec_RunSingle(tmp1, tmp1, tmp2, token, func, op1, op2, expected, expstatus);
1707 Dec_DecDec_RunSingle(tmp2, tmp1, tmp2, token, func, op1, op2, expected, expstatus);
1708
1709 if (equalmem(op1, op2)) {
1710 Dec_DecDec_RunSingle(result, tmp1, tmp1, token, func, op1, op2, expected, expstatus);
1711 Dec_DecDec_RunSingle(tmp1, tmp1, tmp1, token, func, op1, op2, expected, expstatus);
1712 }
1713 }
1714
1715 /* Test a binary function that returns an integer result */
1716 typedef int (Decimal::*Int_DecimalDecimal)(const Decimal&) const;
1717
1718 static void
Int_DecDec_RunSingle(Decimal & tmp1,Decimal & tmp2,const enum skip_cmp skip,const std::vector<std::string> & token,const Int_DecimalDecimal func,const Decimal & op1,const Decimal & op2,const std::string & expected,const uint32_t expstatus)1719 Int_DecDec_RunSingle(Decimal& tmp1, Decimal& tmp2,
1720 const enum skip_cmp skip,
1721 const std::vector<std::string>& token,
1722 const Int_DecimalDecimal func,
1723 const Decimal& op1, const Decimal &op2,
1724 const std::string& expected,
1725 const uint32_t expstatus)
1726 {
1727 int int_result = -101;
1728
1729 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
1730 mpd_init_rand(tmp1);
1731 mpd_init_rand(tmp2);
1732 tmp1 = op1;
1733 tmp2 = op2;
1734
1735 context.status(0);
1736 set_alloc_fail(context, n);
1737 try {
1738 int_result = (tmp1.*func)(tmp2);
1739 }
1740 catch (MallocError&) {
1741 set_alloc(context);
1742 check_equalmem(token, tmp1, op1);
1743 check_equalmem(token, tmp2, op2);
1744 continue;
1745 }
1746
1747 set_alloc(context);
1748 break;
1749 }
1750
1751 char buf[11];
1752 snprintf(buf, sizeof buf, "%d", int_result);
1753 if (skip == SKIP_NONE || int_result != INT_MAX) {
1754 compare_expected(token, buf, expected, expstatus, context);
1755 }
1756 check_equalmem(token, tmp1, op1);
1757 check_equalmem(token, tmp2, op2);
1758 }
1759
1760 static void
Int_DecDec(const Int_DecimalDecimal func,const std::vector<std::string> & token,const enum skip_cmp skip,const bool scan_equal,const bool extended)1761 Int_DecDec(const Int_DecimalDecimal func,
1762 const std::vector<std::string>& token,
1763 const enum skip_cmp skip,
1764 const bool scan_equal,
1765 const bool extended)
1766 {
1767 Context maxcontext{readcontext(extended)};
1768 Decimal tmp1, tmp2;
1769 Decimal op1, op2;
1770 std::string expected;
1771 uint32_t expstatus;
1772 size_t n;
1773
1774 if (scan_equal) {
1775 n = scan_op_expected(op1, expected, token, maxcontext);
1776 op2 = op1;
1777 }
1778 else {
1779 n = scan_op_op_expected(op1, op2, expected, token, maxcontext);
1780 }
1781 expstatus = scan_conditions(token, n);
1782 Triple(token, op1, maxcontext);
1783 Triple(token, op2, maxcontext);
1784
1785 Int_DecDec_RunSingle(tmp1, tmp2, skip, token, func, op1, op2, expected, expstatus);
1786 if (equalmem(op1, op2)) {
1787 Int_DecDec_RunSingle(tmp1, tmp1, skip, token, func, op1, op2, expected, expstatus);
1788 }
1789 }
1790
1791 /* Test a binary function that returns a bool result */
1792 typedef bool (Decimal::*Bool_DecimalDecimal)(const Decimal&) const;
1793
1794 static void
Bool_DecDec_RunSingle(Decimal & tmp1,Decimal & tmp2,const enum skip_cmp skip,const std::vector<std::string> & token,const Bool_DecimalDecimal func,const Decimal & op1,const Decimal & op2,const std::string & expected,const uint32_t expstatus)1795 Bool_DecDec_RunSingle(Decimal& tmp1, Decimal& tmp2,
1796 const enum skip_cmp skip,
1797 const std::vector<std::string>& token,
1798 const Bool_DecimalDecimal func,
1799 const Decimal& op1, const Decimal &op2,
1800 const std::string& expected,
1801 const uint32_t expstatus)
1802 {
1803 int int_result = -101;
1804
1805 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
1806 mpd_init_rand(tmp1);
1807 mpd_init_rand(tmp2);
1808 tmp1 = op1;
1809 tmp2 = op2;
1810
1811 context.status(0);
1812 set_alloc_fail(context, n);
1813 try {
1814 int_result = (tmp1.*func)(tmp2);
1815 }
1816 catch (MallocError&) {
1817 set_alloc(context);
1818 DECIMAL_ASSERT(int_result== INT_MAX, token);
1819 check_equalmem(token, tmp1, op1);
1820 check_equalmem(token, tmp2, op2);
1821 continue;
1822 }
1823
1824 set_alloc(context);
1825 break;
1826 }
1827
1828 char buf[11];
1829 snprintf(buf, 11, "%d", int_result);
1830 if (skip == SKIP_NONE || int_result != INT_MAX) {
1831 compare_expected(token, buf, expected, expstatus, context);
1832 }
1833 check_equalmem(token, tmp1, op1);
1834 check_equalmem(token, tmp2, op2);
1835 }
1836
1837 static void
Bool_DecDec(const Bool_DecimalDecimal func,const std::vector<std::string> & token,const enum skip_cmp skip,const bool scan_equal,const bool extended)1838 Bool_DecDec(const Bool_DecimalDecimal func,
1839 const std::vector<std::string>& token,
1840 const enum skip_cmp skip,
1841 const bool scan_equal,
1842 const bool extended)
1843 {
1844 Context maxcontext{readcontext(extended)};
1845 Decimal tmp1, tmp2;
1846 Decimal op1, op2;
1847 std::string expected;
1848 uint32_t expstatus;
1849 size_t n;
1850
1851 if (scan_equal) {
1852 n = scan_op_expected(op1, expected, token, maxcontext);
1853 op2 = op1;
1854 }
1855 else {
1856 n = scan_op_op_expected(op1, op2, expected, token, maxcontext);
1857 }
1858 expstatus = scan_conditions(token, n);
1859 Triple(token, op1, maxcontext);
1860 Triple(token, op2, maxcontext);
1861
1862 Bool_DecDec_RunSingle(tmp1, tmp2, skip, token, func, op1, op2, expected, expstatus);
1863 if (equalmem(op1, op2)) {
1864 Bool_DecDec_RunSingle(tmp1, tmp1, skip, token, func, op1, op2, expected, expstatus);
1865 }
1866 }
1867
1868 static mpd_ssize_t
scan_ssize(const std::string & tok)1869 scan_ssize(const std::string& tok)
1870 {
1871 errno = 0;
1872 mpd_ssize_t x = strtossize(tok.c_str(), nullptr, 10);
1873 if (errno != 0) {
1874 err_raise("invalid conversion to ssize_t");
1875 }
1876 return x;
1877 }
1878
1879 /* Test a function with a Decimal and an int64_t operand */
1880 typedef Decimal (Decimal::*Decimal_DecimalInt64Context)(int64_t, Context&) const;
1881
1882 static void
Dec_DecInt64_RunSingle(Decimal & result,Decimal & tmp,const std::vector<std::string> & token,const Decimal_DecimalInt64Context func,const Decimal & op,const int64_t i64,const std::string & expected,const uint32_t expstatus)1883 Dec_DecInt64_RunSingle(Decimal& result, Decimal& tmp,
1884 const std::vector<std::string>& token,
1885 const Decimal_DecimalInt64Context func,
1886 const Decimal& op,
1887 const int64_t i64,
1888 const std::string& expected,
1889 const uint32_t expstatus)
1890 {
1891 /* Allocation failures */
1892 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
1893 mpd_init_rand(tmp);
1894 tmp = op;
1895
1896 context.status(0);
1897 set_alloc_fail(context, n);
1898 try {
1899 result = (tmp.*func)(i64, context);
1900 }
1901 catch (MallocError&) {
1902 check_equalmem(token, tmp, op);
1903 set_alloc(context);
1904 continue;
1905 }
1906
1907 set_alloc(context);
1908 break;
1909 }
1910
1911 const std::string calc = result.to_sci();
1912 compare_expected(token, calc, expected, expstatus, context);
1913 if (&tmp != &result) {
1914 check_equalmem(token, tmp, op);
1915 }
1916 }
1917
1918 static void
Dec_DecInt64Ctx(const Decimal_DecimalInt64Context func,const std::vector<std::string> & token,const bool extended)1919 Dec_DecInt64Ctx(const Decimal_DecimalInt64Context func,
1920 const std::vector<std::string>& token,
1921 const bool extended)
1922 {
1923 Context maxcontext{readcontext(extended)};
1924 Decimal result, tmp;
1925 Decimal op1, op2;
1926 std::string expected;
1927
1928 const size_t n = scan_op_op_expected(op1, op2, expected, token, maxcontext);
1929 const uint32_t expstatus = scan_conditions(token, n);
1930 Triple(token, op1, maxcontext);
1931 Triple(token, op2, maxcontext);
1932
1933 if (op2.isspecial() || op2.exponent() != 0) {
1934 return;
1935 }
1936
1937 const int64_t i64 = mpd_get_ssize(op2.getconst(), maxcontext.get());
1938 if (maxcontext.status() & MPD_Invalid_operation) {
1939 return;
1940 }
1941
1942 Dec_DecInt64_RunSingle(result, tmp, token, func, op1, i64, expected, expstatus);
1943 Dec_DecInt64_RunSingle(tmp, tmp, token, func, op1, i64, expected, expstatus);
1944 }
1945
1946 /* Test decimal::ln10 */
1947 static void
ln10(const std::vector<std::string> & token,const bool extended)1948 ln10(const std::vector<std::string>& token, const bool extended)
1949 {
1950 Context maxcontext{readcontext(extended)};
1951 Decimal result;
1952 Decimal op;
1953 std::string expected;
1954
1955 const size_t n = scan_op_expected(op, expected, token, maxcontext);
1956 const uint32_t expstatus = scan_conditions(token, n);
1957 Triple(token, op, maxcontext);
1958
1959 if (op.isspecial() || op.exponent() != 0) {
1960 return;
1961 }
1962
1963 const int64_t i64 = mpd_get_ssize(op.getconst(), maxcontext.get());
1964 if (maxcontext.status() & MPD_Invalid_operation) {
1965 return;
1966 }
1967
1968 for (uint64_t i = 1; i < UINT64_MAX-1; i++) {
1969 const Decimal save_result = result;
1970
1971 context.status(0);
1972 set_alloc_fail(context, i);
1973 try {
1974 result = Decimal::ln10(i64, context);
1975 }
1976 catch (MallocError&) {
1977 set_alloc(context);
1978 check_equalmem(token, result, save_result);
1979 continue;
1980 }
1981
1982 set_alloc(context);
1983 break;
1984 }
1985
1986 const std::string calc = result.to_sci();
1987 compare_expected(token, calc, expected, expstatus, context);
1988 }
1989
1990 /* Test u64() */
1991 static void
u64_DecCtx(const std::vector<std::string> & token,const bool extended)1992 u64_DecCtx(const std::vector<std::string>& token, const bool extended)
1993 {
1994 Context maxcontext{readcontext(extended)};
1995 Decimal op;
1996 uint64_t u64;
1997 char calc[23];
1998 std::string expected;
1999
2000 const size_t n = scan_op_expected(op, expected, token, maxcontext);
2001 const uint32_t expstatus = scan_conditions(token, n);
2002 Triple(token, op, maxcontext);
2003
2004 context.status(0);
2005 try {
2006 u64 = op.u64();
2007 }
2008 catch (ValueError&) {
2009 DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token);
2010 return;
2011 }
2012
2013 snprintf(calc, 23, "%" PRIu64, u64);
2014 compare_expected(token, calc, expected, expstatus, context);
2015 }
2016
2017 /* Test u32() */
2018 static void
u32_DecCtx(const std::vector<std::string> & token,const bool extended)2019 u32_DecCtx(const std::vector<std::string>& token, const bool extended)
2020 {
2021 Context maxcontext{readcontext(extended)};
2022 Decimal op;
2023 std::string expected;
2024 uint32_t u32;
2025 char calc[23];
2026
2027 const size_t n = scan_op_expected(op, expected, token, maxcontext);
2028 const uint32_t expstatus = scan_conditions(token, n);
2029 Triple(token, op, maxcontext);
2030
2031 context.status(0);
2032 try {
2033 u32 = op.u32();
2034 }
2035 catch (ValueError&) {
2036 DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token);
2037 return;
2038 }
2039
2040 snprintf(calc, sizeof calc, "%" PRIu32, u32);
2041 compare_expected(token, calc, expected, 0, context);
2042 }
2043
2044 /* Test a function returning an int64_t */
2045 static void
i64_DecCtx(const std::vector<std::string> & token,const bool extended)2046 i64_DecCtx(const std::vector<std::string>& token, const bool extended)
2047 {
2048 Context maxcontext{readcontext(extended)};
2049 Decimal op;
2050 std::string expected;
2051 int64_t i64;
2052 char calc[23];
2053
2054 const size_t n = scan_op_expected(op, expected, token, maxcontext);
2055 const uint32_t expstatus = scan_conditions(token, n);
2056 Triple(token, op, maxcontext);
2057
2058 context.status(0);
2059 try {
2060 i64 = op.i64();
2061 }
2062 catch (ValueError&) {
2063 DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token);
2064 return;
2065 }
2066
2067 snprintf(calc, sizeof calc, "%" PRIi64, i64);
2068 compare_expected(token, calc, expected, 0, context);
2069 }
2070
2071 /* Test a function returning an int64_t */
2072 static void
i32_DecCtx(const std::vector<std::string> & token,const bool extended)2073 i32_DecCtx(const std::vector<std::string>& token, const bool extended)
2074 {
2075 Context maxcontext{readcontext(extended)};
2076 Decimal op;
2077 std::string expected;
2078 int32_t i32;
2079 char calc[23];
2080
2081 const size_t n = scan_op_expected(op, expected, token, maxcontext);
2082 const uint32_t expstatus = scan_conditions(token, n);
2083 Triple(token, op, maxcontext);
2084
2085 context.status(0);
2086 try {
2087 i32 = op.i32();
2088 }
2089 catch (ValueError&) {
2090 DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token);
2091 return;
2092 }
2093
2094 snprintf(calc, sizeof calc, "%" PRIi32, i32);
2095 compare_expected(token, calc, expected, 0, context);
2096 }
2097
2098 static void
test_copy_constructor(void)2099 test_copy_constructor(void)
2100 {
2101 const std::vector<std::string> token{"copy_constr"};
2102 Decimal a = Decimal(1).shiftl((decimal::MINALLOC*MPD_RDIGITS));
2103 Decimal b = Decimal(1).shiftl((2*decimal::MINALLOC*MPD_RDIGITS));
2104 Decimal c = 2025;
2105 Context ctx;
2106
2107 /* static ==> dynamic */
2108 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
2109
2110 set_alloc_fail(ctx, n);
2111 try {
2112 c = a;
2113 }
2114 catch (MallocError&) {
2115 set_alloc(ctx);
2116 DECIMAL_ASSERT(c == 2025, token);
2117 continue;
2118 }
2119
2120 set_alloc(ctx);
2121 break;
2122 }
2123
2124 DECIMAL_ASSERT(c == a, token);
2125
2126 /* static ==> larger dynamic */
2127 for (uint64_t n = 1; n < UINT64_MAX-1; n++) {
2128
2129 set_alloc_fail(ctx, n);
2130 try {
2131 c = b;
2132 }
2133 catch (MallocError&) {
2134 set_alloc(ctx);
2135 DECIMAL_ASSERT(c == a, token);
2136 continue;
2137 }
2138
2139 set_alloc(ctx);
2140 break;
2141 }
2142
2143 DECIMAL_ASSERT(c == b, token);
2144 }
2145
2146 /* process an input stream of test cases */
2147 static bool skip_bignum = false;
2148 static std::atomic<uint32_t> bignum_counter{0};
2149
2150 static void
do_stream(std::istream & in,bool extended=true)2151 do_stream(std::istream& in, bool extended=true)
2152 {
2153 std::string line;
2154
2155 context = Context(testcontext(extended));
2156
2157 while (std::getline(in, line)) {
2158 std::vector<std::string> token = split(line);
2159 if (token.size() == 0) {
2160 continue;
2161 }
2162
2163 if (skip_bignum) { /* small thread stack */
2164 bool cont = false;
2165 for (const std::string &s : token) {
2166 /* This is a simple heuristic, which works for the test cases
2167 in additional.topTest. */
2168 if (s.size() > 4096) {
2169 cont = true;
2170 bignum_counter++;
2171 break;
2172 }
2173 }
2174 if (cont) {
2175 continue;
2176 }
2177 }
2178
2179 if (startswith(token.at(0), "ExtendedRange")) {
2180 if (token.at(1) == "1") {
2181 extended = true;
2182 }
2183 else if (token.at(1) == "0") {
2184 extended = false;
2185 }
2186 else {
2187 err_token(token, "value must be 1 or 0");
2188 }
2189 continue;
2190 }
2191
2192 if (startswith(token.at(0), "Precision")) {
2193 if (token.at(1) == "MAX_PREC") {
2194 context.prec(MPD_MAX_PREC);
2195 }
2196 else {
2197 mpd_context_t ctx = *context.getconst();
2198 const mpd_ssize_t l = scan_ssize(token.at(1));
2199 ctx.prec = l;
2200 context = Context(ctx);
2201 }
2202 continue;
2203 }
2204
2205 if (startswith(token.at(0), "MinExponent")) {
2206 if (token.at(1) == "MIN_EMIN") {
2207 context.emin(MPD_MIN_EMIN);
2208 }
2209 else {
2210 mpd_context_t ctx = *context.getconst();
2211 const mpd_ssize_t l = scan_ssize(token.at(1));
2212 ctx.emin = l;
2213 context = Context(ctx);
2214 }
2215 continue;
2216 }
2217
2218 if (startswith(token.at(0), "MaxExponent")) {
2219 if (token.at(1) == "MAX_EMAX") {
2220 context.emax(MPD_MAX_EMAX);
2221 }
2222 else {
2223 mpd_context_t ctx = *context.getconst();
2224 const mpd_ssize_t l = scan_ssize(token.at(1));
2225 ctx.emax = l;
2226 context = Context(ctx);
2227 }
2228 continue;
2229 }
2230
2231 if (startswith(token.at(0), "Rounding")) {
2232 if (eqtoken(token.at(1), "Up")) {
2233 context.round(MPD_ROUND_UP);
2234 }
2235 else if (eqtoken(token.at(1), "Down")) {
2236 context.round(MPD_ROUND_DOWN);
2237 }
2238 else if (eqtoken(token.at(1), "Ceiling")) {
2239 context.round(MPD_ROUND_CEILING);
2240 }
2241 else if (eqtoken(token.at(1), "Floor")) {
2242 context.round(MPD_ROUND_FLOOR);
2243 }
2244 else if (eqtoken(token.at(1), "Half_up")) {
2245 context.round(MPD_ROUND_HALF_UP);
2246 }
2247 else if (eqtoken(token.at(1), "Half_down")) {
2248 context.round(MPD_ROUND_HALF_DOWN);
2249 }
2250 else if (eqtoken(token.at(1), "Half_even")) {
2251 context.round(MPD_ROUND_HALF_EVEN);
2252 }
2253 else if (eqtoken(token.at(1), "05up")) {
2254 context.round(MPD_ROUND_05UP);
2255 }
2256 else {
2257 err_token(token, "invalid rounding mode");
2258 }
2259
2260 continue;
2261 }
2262
2263 if (startswith(token.at(0), "Clamp")) {
2264 const int l = static_cast<int>(scan_ssize(token.at(1)));
2265 context.clamp(l);
2266 continue;
2267 }
2268
2269 if (startswith(token.at(0), "Locale")) {
2270 if (setlocale(LC_NUMERIC, token.at(1).c_str()) == nullptr) {
2271 err_token(token, "invalid or missing locale");
2272 }
2273 continue;
2274 }
2275
2276 if (startswith(token.at(0), "Version")) {
2277 continue; /* optional directive */
2278 }
2279
2280 if (startswith(token.at(0), "Extended")) {
2281 continue; /* optional directive */
2282 }
2283
2284 mpd_assert_context_ok(context, token);
2285
2286 /*
2287 * Actual tests start here:
2288 * - token.at(0) is the id
2289 * - token.at(1) is the operation type
2290 * - testno can be used for setting a watchpoint in the debugger
2291 */
2292 const unsigned long testno = get_testno(token);
2293 (void)testno;
2294
2295 if (skip_test(token.at(0))) {
2296 continue; /* id is in the skip list */
2297 }
2298
2299 #ifdef MPD_CONFIG_64
2300 if (startswith(token.at(0), "cov32")) {
2301 continue; /* skip 32-bit specific coverage tests */
2302 }
2303 #else
2304 if (startswith(token.at(0), "cov64")) {
2305 continue; /* skip 64-bit specific coverage tests */
2306 }
2307 #endif
2308
2309 if (startswith(token.at(0), "pwmx")) {
2310 token.at(1) = std::string("powmod");
2311 }
2312
2313 /* Unary functions with std::string result */
2314 if (eqtoken(token.at(1), "tosci") || eqtoken(token.at(1), "apply")) {
2315 Str_DecCtx(&Decimal::to_sci, token, extended);
2316 }
2317 else if (eqtoken(token.at(1), "toeng")) {
2318 Str_DecCtx(&Decimal::to_eng, token, extended);
2319 }
2320 else if (eqtoken(token.at(1), "format")) {
2321 Fmt(token, extended);
2322 }
2323
2324 /* Unary function with const char * result */
2325 else if (eqtoken(token.at(1), "class")) {
2326 Class(token, extended);
2327 }
2328
2329 /* Unary functions with Decimal result */
2330 else if (eqtoken(token.at(1), "abs")) {
2331 Dec_DecCtx(&Decimal::abs, token, extended);
2332 }
2333 else if (eqtoken(token.at(1), "copy")) {
2334 Dec_Dec(&Decimal::copy, token, extended);
2335 }
2336 else if (eqtoken(token.at(1), "copyabs")) {
2337 Dec_Dec(&Decimal::copy_abs, token, extended);
2338 }
2339 else if (eqtoken(token.at(1), "copynegate")) {
2340 Dec_Dec(&Decimal::copy_negate, token, extended);
2341 }
2342 else if (eqtoken(token.at(1), "exp")) {
2343 if (extended) {
2344 if (testno != 126) {
2345 /* Almost all test cases in the official tests are
2346 correctly rounded even when context.allcr is not
2347 set. */
2348 context.allcr(0);
2349 Dec_DecCtx(&Decimal::exp, token, extended);
2350 context.allcr(1);
2351 }
2352 }
2353 Dec_DecCtx(&Decimal::exp, token, extended);
2354 }
2355 else if (eqtoken(token.at(1), "invert")) {
2356 Dec_DecCtx(&Decimal::logical_invert, token, extended);
2357 }
2358 else if (eqtoken(token.at(1), "invroot")) {
2359 Dec_DecCtx(&Decimal::invroot, token, extended);
2360 }
2361 else if (eqtoken(token.at(1), "ln")) {
2362 if (extended) {
2363 /* All test cases in the official tests are correctly rounded
2364 even when context.allcr is not set. */
2365 context.allcr(0);
2366 Dec_DecCtx(&Decimal::ln, token, extended);
2367 context.allcr(1);
2368 }
2369 Dec_DecCtx(&Decimal::ln, token, extended);
2370 }
2371 else if (eqtoken(token.at(1), "log10")) {
2372 if (extended) {
2373 /* All test cases in the official tests are correctly rounded
2374 even when context.allcr is not set. */
2375 context.allcr(0);
2376 Dec_DecCtx(&Decimal::log10, token, extended);
2377 context.allcr(1);
2378 }
2379 Dec_DecCtx(&Decimal::log10, token, extended);
2380 }
2381 else if (eqtoken(token.at(1), "logb")) {
2382 Dec_DecCtx(&Decimal::logb, token, extended);
2383 }
2384 else if (eqtoken(token.at(1), "minus")) {
2385 Dec_DecCtx(&Decimal::minus, token, extended);
2386 }
2387 else if (eqtoken(token.at(1), "nextminus")) {
2388 Dec_DecCtx(&Decimal::next_minus, token, extended);
2389 }
2390 else if (eqtoken(token.at(1), "nextplus")) {
2391 Dec_DecCtx(&Decimal::next_plus, token, extended);
2392 }
2393 else if (eqtoken(token.at(1), "plus")) {
2394 Dec_DecCtx(&Decimal::plus, token, extended);
2395 }
2396 else if (eqtoken(token.at(1), "reduce")) {
2397 Dec_DecCtx(&Decimal::reduce, token, extended);
2398 }
2399 else if (eqtoken(token.at(1), "squareroot")) {
2400 #ifdef MPD_CONFIG_32
2401 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(16000000);
2402 #endif
2403 Dec_DecCtx(&Decimal::sqrt, token, extended);
2404 #ifdef MPD_CONFIG_32
2405 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(SIZE_MAX);
2406 #endif
2407 }
2408 else if (eqtoken(token.at(1), "quantize_squareroot")) {
2409 #ifdef MPD_CONFIG_32
2410 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(16000000);
2411 #endif
2412 Dec_DecCtxWithQuantize(&Decimal::sqrt, token, extended);
2413 #ifdef MPD_CONFIG_32
2414 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(SIZE_MAX);
2415 #endif
2416 }
2417 else if (eqtoken(token.at(1), "tointegral")) {
2418 Dec_DecCtx(&Decimal::to_integral, token, extended);
2419 }
2420 else if (eqtoken(token.at(1), "tointegralx")) {
2421 Dec_DecCtx(&Decimal::to_integral_exact, token, extended);
2422 }
2423 else if (eqtoken(token.at(1), "floor")) {
2424 Dec_DecCtx(&Decimal::floor, token, extended);
2425 }
2426 else if (eqtoken(token.at(1), "ceil")) {
2427 Dec_DecCtx(&Decimal::ceil, token, extended);
2428 }
2429 else if (eqtoken(token.at(1), "trunc")) {
2430 Dec_DecCtx(&Decimal::trunc, token, extended);
2431 }
2432
2433 /* Binary function returning an int */
2434 else if (eqtoken(token.at(1), "samequantum")) {
2435 Bool_DecDec(&Decimal::same_quantum, token, SKIP_NONE, false, extended);
2436 }
2437
2438 /* Binary function returning an int, equal operands */
2439 else if (eqtoken(token.at(1), "samequantum_eq")) {
2440 Bool_DecDec(&Decimal::same_quantum, token, SKIP_NONE, true, extended);
2441 }
2442
2443 /* Binary functions with Decimal result */
2444 else if (eqtoken(token.at(1), "add")) {
2445 Dec_DecDecCtx(&Decimal::add, token, false, extended);
2446 Dec_DecDec(&Decimal::operator+, token, false, extended);
2447 }
2448 else if (eqtoken(token.at(1), "and")) {
2449 Dec_DecDecCtx(&Decimal::logical_and, token, false, extended);
2450 }
2451 else if (eqtoken(token.at(1), "copysign")) {
2452 Dec_DecDec(&Decimal::copy_sign, token, false, extended);
2453 }
2454 else if (eqtoken(token.at(1), "divide")) {
2455 #ifdef MPD_CONFIG_32
2456 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(16000000);
2457 #endif
2458 Dec_DecDecCtx(&Decimal::div, token, false, extended);
2459 Dec_DecDec(&Decimal::operator/, token, false, extended);
2460 #ifdef MPD_CONFIG_32
2461 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(SIZE_MAX);
2462 #endif
2463 }
2464 else if (eqtoken(token.at(1), "divideint")) {
2465 Dec_DecDecCtx(&Decimal::divint, token, false, extended);
2466 }
2467 else if (eqtoken(token.at(1), "max")) {
2468 Dec_DecDecCtx(&Decimal::max, token, false, extended);
2469 }
2470 else if (eqtoken(token.at(1), "maxmag") || eqtoken(token.at(1), "max_mag")) {
2471 Dec_DecDecCtx(&Decimal::max_mag, token, false, extended);
2472 }
2473 else if (eqtoken(token.at(1), "min")) {
2474 Dec_DecDecCtx(&Decimal::min, token, false, extended);
2475 }
2476 else if (eqtoken(token.at(1), "minmag") || eqtoken(token.at(1), "min_mag")) {
2477 Dec_DecDecCtx(&Decimal::min_mag, token, false, extended);
2478 }
2479 else if (eqtoken(token.at(1), "multiply")) {
2480 Dec_DecDecCtx(&Decimal::mul, token, false, extended);
2481 Dec_DecDec(&Decimal::operator*, token, false, extended);
2482 }
2483 else if (eqtoken(token.at(1), "nexttoward")) {
2484 Dec_DecDecCtx(&Decimal::next_toward, token, false, extended);
2485 }
2486 else if (eqtoken(token.at(1), "or")) {
2487 Dec_DecDecCtx(&Decimal::logical_or, token, false, extended);
2488 }
2489 else if (eqtoken(token.at(1), "power")) {
2490 if (extended) {
2491 /* All test cases in the official tests are correctly rounded
2492 even when context.allcr is not set. */
2493 context.allcr(0);
2494 Dec_DecDecCtx(&Decimal::pow, token, false, extended);
2495 context.allcr(1);
2496 }
2497 Dec_DecDecCtx(&Decimal::pow, token, false, extended);
2498 }
2499 else if (eqtoken(token.at(1), "quantize")) {
2500 Dec_DecDecCtx(&Decimal::quantize, token, false, extended);
2501 }
2502 else if (eqtoken(token.at(1), "resc")) {
2503 Dec_DecInt64Ctx(&Decimal::rescale, token, extended);
2504 }
2505 else if (eqtoken(token.at(1), "remainder")) {
2506 Dec_DecDecCtx(&Decimal::rem, token, false, extended);
2507 Dec_DecDec(&Decimal::operator%, token, false, extended);
2508 }
2509 else if (eqtoken(token.at(1), "remaindernear")) {
2510 Dec_DecDecCtx(&Decimal::rem_near, token, false, extended);
2511 }
2512 else if (eqtoken(token.at(1), "rotate")) {
2513 Dec_DecDecCtx(&Decimal::rotate, token, false, extended);
2514 }
2515 else if (eqtoken(token.at(1), "scaleb")) {
2516 Dec_DecDecCtx(&Decimal::scaleb, token, false, extended);
2517 }
2518 else if (eqtoken(token.at(1), "shift")) {
2519 Dec_DecDecCtx(&Decimal::shift, token, false, extended);
2520 if (extended) {
2521 Dec_DecInt64Ctx(&Decimal::shiftn, token, extended);
2522 }
2523 }
2524 else if (eqtoken(token.at(1), "subtract")) {
2525 Dec_DecDecCtx(&Decimal::sub, token, false, extended);
2526 Dec_DecDec(&Decimal::operator-, token, false, extended);
2527 }
2528 else if (eqtoken(token.at(1), "xor")) {
2529 Dec_DecDecCtx(&Decimal::logical_xor, token, false, extended);
2530 }
2531
2532 /* Binary functions with Decimal result, equal operands */
2533 else if (eqtoken(token.at(1), "add_eq")) {
2534 Dec_DecDecCtx(&Decimal::add, token, true, extended);
2535 Dec_DecDec(&Decimal::operator+, token, true, extended);
2536 }
2537 else if (eqtoken(token.at(1), "and_eq")) {
2538 Dec_DecDecCtx(&Decimal::logical_and, token, true, extended);
2539 }
2540 else if (eqtoken(token.at(1), "copysign_eq")) {
2541 Dec_DecDec(&Decimal::copy_sign, token, true, extended);
2542 }
2543 else if (eqtoken(token.at(1), "divide_eq")) {
2544 Dec_DecDecCtx(&Decimal::div, token, true, extended);
2545 Dec_DecDec(&Decimal::operator/, token, true, extended);
2546 }
2547 else if (eqtoken(token.at(1), "divideint_eq")) {
2548 Dec_DecDecCtx(&Decimal::divint, token, true, extended);
2549 }
2550 else if (eqtoken(token.at(1), "max_eq")) {
2551 Dec_DecDecCtx(&Decimal::max, token, true, extended);
2552 }
2553 else if (eqtoken(token.at(1), "maxmag_eq")) {
2554 Dec_DecDecCtx(&Decimal::max_mag, token, true, extended);
2555 }
2556 else if (eqtoken(token.at(1), "min_eq")) {
2557 Dec_DecDecCtx(&Decimal::min, token, true, extended);
2558 }
2559 else if (eqtoken(token.at(1), "minmag_eq")) {
2560 Dec_DecDecCtx(&Decimal::min_mag, token, true, extended);
2561 }
2562 else if (eqtoken(token.at(1), "multiply_eq")) {
2563 Dec_DecDecCtx(&Decimal::mul, token, true, extended);
2564 Dec_DecDec(&Decimal::operator*, token, true, extended);
2565 }
2566 else if (eqtoken(token.at(1), "nexttoward_eq")) {
2567 Dec_DecDecCtx(&Decimal::next_toward, token, true, extended);
2568 }
2569 else if (eqtoken(token.at(1), "or_eq")) {
2570 Dec_DecDecCtx(&Decimal::logical_or, token, true, extended);
2571 }
2572 else if (eqtoken(token.at(1), "power_eq")) {
2573 if (extended) {
2574 /* see power */
2575 context.allcr(0);
2576 Dec_DecDecCtx(&Decimal::pow, token, true, extended);
2577 context.allcr(1);
2578 }
2579 Dec_DecDecCtx(&Decimal::pow, token, true, extended);
2580 }
2581 else if (eqtoken(token.at(1), "quantize_eq")) {
2582 Dec_DecDecCtx(&Decimal::quantize, token, true, extended);
2583 }
2584 else if (eqtoken(token.at(1), "remainder_eq")) {
2585 Dec_DecDecCtx(&Decimal::rem, token, true, extended);
2586 Dec_DecDec(&Decimal::operator%, token, true, extended);
2587 }
2588 else if (eqtoken(token.at(1), "remaindernear_eq")) {
2589 Dec_DecDecCtx(&Decimal::rem_near, token, true, extended);
2590 }
2591 else if (eqtoken(token.at(1), "rotate_eq")) {
2592 Dec_DecDecCtx(&Decimal::rotate, token, true, extended);
2593 }
2594 else if (eqtoken(token.at(1), "scaleb_eq")) {
2595 Dec_DecDecCtx(&Decimal::scaleb, token, true, extended);
2596 }
2597 else if (eqtoken(token.at(1), "shift_eq")) {
2598 Dec_DecDecCtx(&Decimal::shift, token, true, extended);
2599 }
2600 else if (eqtoken(token.at(1), "subtract_eq")) {
2601 Dec_DecDecCtx(&Decimal::sub, token, true, extended);
2602 Dec_DecDec(&Decimal::operator-, token, true, extended);
2603 }
2604 else if (eqtoken(token.at(1), "xor_eq")) {
2605 Dec_DecDecCtx(&Decimal::logical_xor, token, true, extended);
2606 }
2607
2608 /* Binary function with Decimal pair result */
2609 else if (eqtoken(token.at(1), "divmod")) {
2610 DecPair_DecDecCtx(&Decimal::divmod, token, false, extended);
2611 }
2612 /* Binary function with Decimal pair result, equal operands */
2613 else if (eqtoken(token.at(1), "divmod_eq")) {
2614 DecPair_DecDecCtx(&Decimal::divmod, token, true, extended);
2615 }
2616
2617 /* Ternary functions with Decimal result */
2618 else if (eqtoken(token.at(1), "fma")) {
2619 Dec_DecDecDecCtx(&Decimal::fma, OpOpOp, token, extended);
2620 }
2621 else if (eqtoken(token.at(1), "powmod")) {
2622 Dec_DecDecDecCtx(&Decimal::powmod, OpOpOp, token, extended);
2623 }
2624
2625 /* Ternary functions with Decimal result, eq_eq_op */
2626 else if (eqtoken(token.at(1), "fma_eq_eq_op")) {
2627 Dec_DecDecDecCtx(&Decimal::fma, EqEqOp, token, extended);
2628 }
2629 else if (eqtoken(token.at(1), "powmod_eq_eq_op")) {
2630 Dec_DecDecDecCtx(&Decimal::powmod, EqEqOp, token, extended);
2631 }
2632
2633 /* Ternary functions with Decimal result, eq_op_eq */
2634 else if (eqtoken(token.at(1), "fma_eq_op_eq")) {
2635 Dec_DecDecDecCtx(&Decimal::fma, EqOpEq, token, extended);
2636 }
2637 else if (eqtoken(token.at(1), "powmod_eq_op_eq")) {
2638 Dec_DecDecDecCtx(&Decimal::powmod, EqOpEq, token, extended);
2639 }
2640
2641 /* Ternary functions with Decimal result, op_eq_eq */
2642 else if (eqtoken(token.at(1), "fma_op_eq_eq")) {
2643 Dec_DecDecDecCtx(&Decimal::fma, OpEqEq, token, extended);
2644 }
2645 else if (eqtoken(token.at(1), "powmod_op_eq_eq")) {
2646 Dec_DecDecDecCtx(&Decimal::powmod, OpEqEq, token, extended);
2647 }
2648
2649 /* Ternary functions with Decimal result, eq_eq_eq */
2650 else if (eqtoken(token.at(1), "fma_eq_eq_eq")) {
2651 Dec_DecDecDecCtx(&Decimal::fma, EqEqEq, token, extended);
2652 }
2653 else if (eqtoken(token.at(1), "powmod_eq_eq_eq")) {
2654 Dec_DecDecDecCtx(&Decimal::powmod, EqEqEq, token, extended);
2655 }
2656
2657 /* Special cases for the comparison functions */
2658 else if (eqtoken(token.at(1), "compare")) {
2659 Dec_DecDecCtx(&Decimal::compare, token, false, extended);
2660 Int_DecDec(&Decimal::cmp, token, SKIP_NAN, false, extended);
2661 }
2662 else if (eqtoken(token.at(1), "comparesig")) {
2663 Dec_DecDecCtx(&Decimal::compare_signal, token, false, extended);
2664 }
2665
2666 else if (eqtoken(token.at(1), "comparetotal")) {
2667 Dec_DecDec(&Decimal::compare_total, token, false, extended);
2668 Int_DecDec(&Decimal::cmp_total, token, SKIP_NONE, false, extended);
2669 }
2670 else if (eqtoken(token.at(1), "comparetotmag")) {
2671 Dec_DecDec(&Decimal::compare_total_mag, token, false, extended);
2672 Int_DecDec(&Decimal::cmp_total_mag, token, SKIP_NONE, false, extended);
2673 }
2674
2675 /* Special cases for the comparison functions, equal operands */
2676 else if (eqtoken(token.at(1), "compare_eq")) {
2677 Dec_DecDecCtx(&Decimal::compare, token, true, extended);
2678 Int_DecDec(&Decimal::cmp, token, SKIP_NAN, true, extended);
2679 }
2680 else if (eqtoken(token.at(1), "comparesig_eq")) {
2681 Dec_DecDecCtx(&Decimal::compare_signal, token, true, extended);
2682 }
2683
2684 else if (eqtoken(token.at(1), "comparetotal_eq")) {
2685 Dec_DecDec(&Decimal::compare_total, token, true, extended);
2686 Int_DecDec(&Decimal::cmp_total, token, SKIP_NAN, true, extended);
2687 }
2688 else if (eqtoken(token.at(1), "comparetotmag_eq")) {
2689 Dec_DecDec(&Decimal::compare_total_mag, token, true, extended);
2690 Int_DecDec(&Decimal::cmp_total_mag, token, SKIP_NAN, true, extended);
2691 }
2692
2693 /* Special cases for the shift functions */
2694 else if (eqtoken(token.at(1), "shiftleft")) {
2695 Dec_DecInt64Ctx(&Decimal::shiftl, token, extended);
2696 }
2697 else if (eqtoken(token.at(1), "shiftright")) {
2698 Dec_DecInt64Ctx(&Decimal::shiftr, token, extended);
2699 }
2700
2701 /* Special case for Decimal::ln10() */
2702 else if (eqtoken(token.at(1), "ln10")) {
2703 ln10(token, extended);
2704 }
2705
2706 /* Special cases for the get_int functions */
2707 else if (eqtoken(token.at(1), "get_u64") || eqtoken(token.at(1), "get_uint64")) {
2708 u64_DecCtx(token, extended);
2709 }
2710 else if (eqtoken(token.at(1), "get_u32") || eqtoken(token.at(1), "get_uint32")) {
2711 u32_DecCtx(token, extended);
2712 }
2713 else if (eqtoken(token.at(1), "get_i64") || eqtoken(token.at(1), "get_int64")) {
2714 i64_DecCtx(token, extended);
2715 }
2716 else if (eqtoken(token.at(1), "get_i32") || eqtoken(token.at(1), "get_int32")) {
2717 i32_DecCtx(token, extended);
2718 }
2719
2720 else if (startswith(token.at(0), "bool")) {
2721 /* skip: not implemented: bool tests in extra.decTest */
2722 continue;
2723 }
2724
2725 else if (eqtoken(token.at(1), "get_uint64_abs") ||
2726 eqtoken(token.at(1), "get_ssize64") ||
2727 eqtoken(token.at(1), "get_uint32_abs") ||
2728 eqtoken(token.at(1), "get_ssize32")) {
2729 /* skip: not implemented */
2730 }
2731
2732 else if (eqtoken(token.at(1), "rescale")) {
2733 /*
2734 * skip: 'rescale' is obsolete in the standard and Decimal::rescale()
2735 * is not equivalent to the obsolete version.
2736 */
2737 }
2738 else if (eqtoken(token.at(1), "baseconv")) {
2739 /* skip: not implemented */
2740 }
2741 else {
2742 err_token(token, "unknown operation");
2743 }
2744 }
2745 }
2746
2747 static int
exit_status(const std::vector<std::string> & status)2748 exit_status(const std::vector<std::string>& status)
2749 {
2750 for (auto p : status) {
2751 if (p != "PASS") {
2752 return EXIT_FAILURE;
2753 }
2754 }
2755
2756 return EXIT_SUCCESS;
2757 }
2758
2759 static void
do_file(const std::string & filename,std::vector<std::string> & status,size_t i,bool threaded)2760 do_file(const std::string& filename, std::vector<std::string>& status, size_t i, bool threaded)
2761 {
2762 try {
2763 if (threaded) {
2764 /* Thread local context is initialized on first access. */
2765 if (context.prec() != 1) {
2766 err_raise("automatic context initialization from template failed");
2767 }
2768 }
2769
2770 std::ifstream in{filename};
2771 if (!in.is_open()) {
2772 err_raise("could not open ", filename);
2773 }
2774
2775 do_stream(in);
2776
2777 if (in.bad()) {
2778 err_raise("iterating over lines failed in ", filename);
2779 }
2780 } catch (test::Failure& e) {
2781 status[i] = e.what();
2782 }
2783 }
2784
2785 /* process a file list */
2786 static int
do_files(const std::vector<std::string> & files)2787 do_files(const std::vector<std::string>& files)
2788 {
2789 const size_t n = files.size();
2790 std::vector<std::string> status(n, "PASS");
2791
2792 for (size_t i = 0; i < n; i++) {
2793 std::cout << files[i] << " ... " << std::flush;
2794 do_file(files[i], status, i, false);
2795 std::cout << status[i] << "\n" << std::flush;
2796 }
2797
2798 std::cout << "\n" << std::flush;
2799
2800 return exit_status(status);
2801 }
2802
2803 /* process a file list, using std::thread */
2804 static int
do_files_thread(const std::vector<std::string> & files)2805 do_files_thread(const std::vector<std::string>& files)
2806 {
2807 const size_t n = files.size();
2808 std::vector<std::string> status(n, "PASS");
2809 std::vector<std::thread> t(n);
2810
2811 for (size_t i = 0; i < n; i++) {
2812 t[i] = std::thread(do_file, files[i], std::ref(status), i, true);
2813 }
2814
2815 for (size_t i = 0; i < n; i++) {
2816 t[i].join();
2817 }
2818
2819 for (size_t i = 0; i < n; i++) {
2820 std::cout << files[i] << " ... " << status[i] << "\n" << std::flush;
2821 }
2822
2823 std::cout << "\n" << std::flush;
2824
2825 if (skip_bignum) {
2826 std::cout << "NOTE: std::thread stack size < 512K: skipped "
2827 << bignum_counter << " bignum test case"
2828 << (bignum_counter == 1 ? "\n\n" : "s\n\n")
2829 << std::flush;
2830 }
2831
2832 return exit_status(status);
2833 }
2834
2835 #ifdef HAVE_PTHREAD_H
2836 /*
2837 * The pthread section is for systems like AIX, which have a std::thread stack
2838 * size that is too small for the bignum tests. std::thread does not allow to
2839 * set the stack size.
2840 */
2841 #define THREAD_STACK_SIZE 1048576
2842
2843 struct thread_info {
2844 size_t index;
2845 pthread_t tid;
2846 const std::string *filename;
2847 std::vector<std::string> *status;
2848 };
2849
2850 static bool
thread_stack_too_small_for_bignum()2851 thread_stack_too_small_for_bignum()
2852 {
2853 pthread_attr_t tattr;
2854 size_t size;
2855 int ret;
2856
2857 ret = pthread_attr_init(&tattr);
2858 if (ret != 0) {
2859 err_raise("thread attribute initialization failed");
2860 }
2861
2862 ret = pthread_attr_getstacksize(&tattr, &size);
2863 pthread_attr_destroy(&tattr);
2864
2865 if (ret != 0) {
2866 err_raise("getting thread stack size failed");
2867 }
2868
2869 return size < 524288;
2870 }
2871
2872 static void *
do_file_pthread(void * arg)2873 do_file_pthread(void *arg)
2874 {
2875 struct thread_info *tinfo = static_cast<struct thread_info *>(arg);
2876
2877 try {
2878 if (context.prec() != 1) {
2879 err_raise("automatic context initialization from template failed");
2880 }
2881
2882 std::ifstream in{*tinfo->filename};
2883 if (!in.is_open()) {
2884 err_raise("could not open ", *tinfo->filename);
2885 }
2886
2887 do_stream(in);
2888
2889 if (in.bad()) {
2890 err_raise("iterating over lines failed in ", *tinfo->filename);
2891 }
2892 } catch (test::Failure& e) {
2893 (*tinfo->status)[tinfo->index] = e.what();
2894 }
2895
2896 return nullptr;
2897 }
2898
2899 /* process a file list, using pthread */
2900 static int
do_files_pthread(const std::vector<std::string> & files)2901 do_files_pthread(const std::vector<std::string>& files)
2902 {
2903 const size_t n = files.size();
2904 std::vector<std::string> status(n, "PASS");
2905 std::vector<struct thread_info> tinfo(n);
2906 pthread_attr_t tattr;
2907 int ret;
2908
2909 ret = pthread_attr_init(&tattr);
2910 if (ret != 0) {
2911 err_raise("thread attribute initialization failed");
2912 }
2913
2914 ret = pthread_attr_setstacksize(&tattr, THREAD_STACK_SIZE);
2915 if (ret != 0) {
2916 pthread_attr_destroy(&tattr);
2917 err_raise("setting thread stack size failed");
2918 }
2919
2920 for (size_t i = 0; i < n; i++) {
2921 tinfo[i].index = i;
2922 tinfo[i].filename = &files[i];
2923 tinfo[i].status = &status;
2924
2925 ret = pthread_create(&tinfo[i].tid, &tattr, &do_file_pthread, &tinfo[i]);
2926 if (ret != 0) {
2927 pthread_attr_destroy(&tattr);
2928 err_raise("could not create thread");
2929 }
2930 }
2931
2932 for (size_t i = 0; i < n; i++) {
2933 ret = pthread_join(tinfo[i].tid, nullptr);
2934 if (ret != 0) {
2935 pthread_attr_destroy(&tattr);
2936 err_raise("error in thread execution");
2937 }
2938 }
2939
2940 for (size_t i = 0; i < n; i++) {
2941 std::cout << files[i] << " ... " << status[i] << "\n" << std::flush;
2942 }
2943
2944 std::cout << "\n" << std::flush;
2945
2946 pthread_attr_destroy(&tattr);
2947
2948 return exit_status(status);
2949 }
2950 #endif /* HAVE_PTHREAD_H */
2951
2952
2953 static const int32_t int32_cases[] = {
2954 INT32_MIN, INT32_MIN+1, INT32_MIN+2,
2955 INT32_MAX-2, INT32_MAX-1, INT32_MAX,
2956 -10, -5, -1, 0, 5, 10,
2957 -999999999, -99999999, -9999999, -999999, -99999, -9999, -999, -99, -9,
2958 -1000500001, -100050001, -10050001, -1005001, -105001, -10501, -1501, -151,
2959 -1000000001, -100000001, -10000001, -1000001, -100001, -10001, -1001, -101,
2960 -1000000000, -100000000, -10000000, -1000000, -100000, -10000, -1000, -100,
2961 999999999, 99999999, 9999999, 999999, 99999, 9999, 999, 99, 9,
2962 1000500001, 100050001, 10050001, 1005001, 105001, 10501, 1501, 151,
2963 1000000001, 100000001, 10000001, 1000001, 100001, 10001, 1001, 101,
2964 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100,
2965 -(1<<30),
2966 -(1<<29), -(1<<28), -(1<<27), -(1<<26), -(1<<25), -(1<<24), -(1<<23), -(1<<22), -(1<<21), -(1<<20),
2967 -(1<<19), -(1<<18), -(1<<17), -(1<<16), -(1<<15), -(1<<14), -(1<<13), -(1<<12), -(1<<11), -(1<<10),
2968 -(1<<9), -(1<<8), -(1<<7), -(1<<6), -(1<<5), -(1<<4), -(1<<3), -(1<<2), -(1<<1), -(1<<0),
2969 (1<<30),
2970 (1<<29), (1<<28), (1<<27), (1<<26), (1<<25), (1<<24), (1<<23), (1<<22), (1<<21), (1<<20),
2971 (1<<19), (1<<18), (1<<17), (1<<16), (1<<15), (1<<14), (1<<13), (1<<12), (1<<11), (1<<10),
2972 (1<<9), (1<<8), (1<<7), (1<<6), (1<<5), (1<<4), (1<<3), (1<<2), (1<<1), (1<<0)
2973 };
2974
2975 static const int64_t int64_cases[] = {
2976 INT64_MIN, INT64_MIN+1, INT64_MIN+2, -10, -5, -1, 0, 5, 10, INT64_MAX-2, INT64_MAX-1, INT64_MAX,
2977 -999999999999999999LL, -99999999999999999LL, -9999999999999999LL, -999999999999999LL, -99999999999999LL, -9999999999999LL,
2978 -999999999999LL, -99999999999LL, -9999999999LL, -999999999LL, -99999999LL, -9999999LL, -999999LL, -99999LL, -9999LL, -999LL, -99LL, -9LL,
2979 -1000000000000000000LL, -100000000000000000LL, -10000000000000000LL, -1000000000000000LL, -100000000000000LL, -10000000000000LL,
2980 -1000000000000LL, -100000000000LL, -10000000000LL, -1000000000LL, -100000000LL, -10000000LL, -1000000LL, -100000LL, -10000LL, -1000LL, -100LL, -10LL,
2981 -1000000005000000000LL, -100000005000000000LL, -10000005000000000LL, -1000005000000000LL, -100000005000000LL, -10000005000000LL,
2982 -1000005000000LL, -100005000000LL, -10000005000LL, -1000005000LL, -100005000LL, -10005000LL, -1005000LL, -100050LL, -10050LL, -1050LL, -150LL, -15LL,
2983 -1000000005000000001LL, -100000005000000001LL, -10000005000000001LL, -1000005000000001LL, -100000005000001LL, -10000005000001LL,
2984 -1000005000001LL, -100005000001LL, -10000005001LL, -1000005001LL, -100005001LL, -10005001LL, -1005001LL, -100051LL, -10051LL, -1051LL, -151LL, -15LL,
2985 999999999999999999LL, 99999999999999999LL, 9999999999999999LL, 999999999999999LL, 99999999999999LL, 9999999999999LL,
2986 999999999999LL, 99999999999LL, 9999999999LL, 999999999LL, 99999999LL, 9999999LL, 999999LL, 99999LL, 9999LL, 999LL, 99LL, 9LL,
2987 1000000000000000000LL, 100000000000000000LL, 10000000000000000LL, 1000000000000000LL, 100000000000000LL, 10000000000000LL,
2988 1000000000000LL, 100000000000LL, 10000000000LL, 1000000000LL, 100000000LL, 10000000LL, 1000000LL, 100000LL, 10000LL, 1000LL, 100LL, 10LL,
2989 1000000005000000000LL, 100000005000000000LL, 10000005000000000LL, 1000005000000000LL, 100000005000000LL, 10000005000000LL,
2990 1000005000000LL, 100005000000LL, 10000005000LL, 1000005000LL, 100005000LL, 10005000LL, 1005000LL, 100050LL, 10050LL, 1050LL, 150LL, 15LL,
2991 1000000005000000001LL, 100000005000000001LL, 10000005000000001LL, 1000005000000001LL, 100000005000001LL, 10000005000001LL,
2992 1000005000001LL, 100005000001LL, 10000005001LL, 1000005001LL, 100005001LL, 10005001LL, 1005001LL, 100051LL, 10051LL, 1051LL, 151LL, 15LL,
2993 -(1LL<<62), -(1LL<<61), -(1LL<<60),
2994 -(1LL<<59), -(1LL<<58), -(1LL<<57), -(1LL<<56), -(1LL<<55), -(1LL<<54), -(1LL<<53), -(1LL<<52), -(1LL<<51), -(1LL<<50),
2995 -(1LL<<39), -(1LL<<38), -(1LL<<37), -(1LL<<36), -(1LL<<35), -(1LL<<34), -(1LL<<33), -(1LL<<32), -(1LL<<31), -(1LL<<30),
2996 -(1LL<<29), -(1LL<<28), -(1LL<<27), -(1LL<<26), -(1LL<<25), -(1LL<<24), -(1LL<<23), -(1LL<<22), -(1LL<<21), -(1LL<<20),
2997 -(1LL<<19), -(1LL<<18), -(1LL<<17), -(1LL<<16), -(1LL<<15), -(1LL<<14), -(1LL<<13), -(1LL<<12), -(1LL<<11), -(1LL<<10),
2998 -(1LL<<9), -(1LL<<8), -(1LL<<7), -(1LL<<6), -(1LL<<5), -(1LL<<4), -(1LL<<3), -(1LL<<2), -(1LL<<1), -(1LL<<0),
2999 -(1LL<<62), -(1LL<<61), -(1LL<<60),
3000 (1LL<<59), (1LL<<58), (1LL<<57), (1LL<<56), (1LL<<55), (1LL<<54), (1LL<<53), (1LL<<52), (1LL<<51), (1LL<<50),
3001 (1LL<<39), (1LL<<38), (1LL<<37), (1LL<<36), (1LL<<35), (1LL<<34), (1LL<<33), (1LL<<32), (1LL<<31), (1LL<<30),
3002 (1LL<<29), (1LL<<28), (1LL<<27), (1LL<<26), (1LL<<25), (1LL<<24), (1LL<<23), (1LL<<22), (1LL<<21), (1LL<<20),
3003 (1LL<<19), (1LL<<18), (1LL<<17), (1LL<<16), (1LL<<15), (1LL<<14), (1LL<<13), (1LL<<12), (1LL<<11), (1LL<<10),
3004 (1LL<<9), (1LL<<8), (1LL<<7), (1LL<<6), (1LL<<5), (1LL<<4), (1LL<<3), (1LL<<2), (1LL<<1), (1LL<<0),
3005 };
3006
3007 static const char *init_cases[] = {
3008 "sNaN", "sNaN19",
3009 "sNaN1982612612300000002000000000050000000000000000101111111111111112111111111111111111111111111111111111111111111111"
3010 "111111111111111111111111111111111111111111111111111111111111111",
3011 "-sNaN", "-sNaN19",
3012 "-sNaN198261261230000000200000000005000000000000000010111111111111111211111111111111111111111111111111111111111111111"
3013 "1111111111111111111111111111111111111111111111111111111111111111",
3014 "NaN", "NaN19",
3015 "NaN19826126123000000020000000000500000000000000001011111111111111121111111111111111111111111111111111111111111111111"
3016 "11111111111111111111111111111111111111111111111111111111111111",
3017 "-NaN", "-NaN19",
3018 "-NaN1982612612300000002000000000050000000000000000101111111111111112111111111111111111111111111111111111111111111111"
3019 "111111111111111111111111111111111111111111111111111111111111111",
3020 "inf", "-inf",
3021 "-1", "-0", "0", "1",
3022 "1e10", "-1e10",
3023 "1.21019218731291112376416152e10",
3024 "-1.21019218731291112376416152e10",
3025 "0.0000000000000000000000000000000000000000000000000001e-999999",
3026 "-0.0000000000000000000000000000000000000000000000000001e-999999"
3027 };
3028
3029 static void
test_set_i32(void)3030 test_set_i32(void)
3031 {
3032 const Context savecontext = context;
3033 context.status(0);
3034 for (const char *s : init_cases) {
3035 for (const int32_t& x : int32_cases) {
3036 Decimal v{s};
3037
3038 v = x;
3039 assertEqual(context.status(), 0U);
3040 assertEqualStr(v, std::to_string(x));
3041 }
3042 }
3043 context = savecontext;
3044 }
3045
3046 static void
test_set_i64(void)3047 test_set_i64(void)
3048 {
3049 const Context savecontext = context;
3050 context.status(0);
3051 for (const char *s : init_cases) {
3052 for (const int64_t& x : int64_cases) {
3053 Decimal v{s};
3054
3055 v = x;
3056 assertEqual(context.status(), 0U);
3057 assertEqualStr(v, std::to_string(x));
3058 }
3059 }
3060 context = savecontext;
3061 }
3062
3063
3064 /* process a single test file */
3065 static void
usage(void)3066 usage(void)
3067 {
3068 std::cerr << "runtest: usage: runtest testfile [--custom] [--alloc] [--thread|--pthread]" << std::endl;
3069 exit(EXIT_FAILURE);
3070 }
3071
3072 static std::vector<std::string>
collect_files(const std::string & topfile)3073 collect_files(const std::string& topfile)
3074 {
3075 std::vector<std::string> files;
3076 std::string line;
3077
3078 std::ifstream in{topfile};
3079 if (!in.is_open()) {
3080 err_exit("could not open file");
3081 }
3082
3083 while (std::getline(in, line)) {
3084 std::vector<std::string> token = split(line);
3085 if (token.size() == 0) {
3086 continue;
3087 }
3088
3089 if (startswith(token.at(0), "Dectest")) {
3090 files.push_back(token.at(1));
3091 continue;
3092 }
3093 else {
3094 err_exit("parse error");
3095 }
3096 }
3097
3098 if (in.bad()) {
3099 err_exit("iterating over lines failed");
3100 }
3101
3102 return files;
3103 }
3104
3105
3106 int
main(int argc,char * argv[])3107 main(int argc, char *argv[])
3108 {
3109 std::vector<std::string> args(argv + (argc!=0), argv + argc);
3110 std::string filename = "";
3111 bool custom_alloc = false;
3112 bool check_alloc = false;
3113 bool thread = false;
3114 bool pthread = false;
3115
3116 for (auto arg : args) {
3117 if (filename == "" && (arg == "-" || !startswith(arg, "--"))) {
3118 filename = arg;
3119 }
3120 else if (!custom_alloc && arg == "--custom") {
3121 custom_alloc = true;
3122 }
3123 else if (!check_alloc && arg == "--alloc") {
3124 check_alloc = true;
3125 }
3126 else if (!thread && arg == "--thread") {
3127 thread = true;
3128 }
3129 else if (!pthread && arg == "--pthread") {
3130 pthread = true;
3131 }
3132 else {
3133 usage();
3134 }
3135 }
3136 if (filename == "") {
3137 usage();
3138 }
3139
3140 /* std::thread needs 300K stack size for the bignum tests. */
3141 #ifdef HAVE_PTHREAD_H
3142 if (thread && thread_stack_too_small_for_bignum()) {
3143 skip_bignum = true;
3144 }
3145 #endif
3146
3147 /* Initialize custom allocation functions */
3148 test::init_alloc(custom_alloc, check_alloc);
3149
3150 /* Initialize the context template */
3151 context_template = Context(1, 1, -1);
3152
3153 /* Initialize main thread context */
3154 context = context_template;
3155
3156 /* Initial tests */
3157 test_set_i32();
3158 test_set_i64();
3159 test_copy_constructor();
3160
3161
3162 /* Read test cases from stdin */
3163 if (filename == "-") {
3164 try {
3165 do_stream(std::cin, /*extended=*/false);
3166 }
3167 catch (test::Failure& e) {
3168 std::cerr << "<stdin> ... " << e.what() << "\n" << std::flush;
3169 return EXIT_FAILURE;
3170 }
3171 std::cout << "<stdin> ... PASS\n\n" << std::flush;
3172 return EXIT_SUCCESS;
3173 }
3174
3175 /* Collect test files */
3176 std::vector<std::string> files;
3177 if (endswith(filename, ".decTest")) {
3178 files.push_back(filename);
3179 }
3180 else if (endswith(filename, ".topTest")) {
3181 std::ifstream in{filename};
3182 if (!in.is_open()) {
3183 err_exit("could not open file");
3184 }
3185
3186 files = collect_files(filename);
3187
3188 if (in.bad()) {
3189 err_exit("iterating over lines failed");
3190 }
3191 }
3192 else {
3193 err_exit("unrecognized file extension: expect .decTest or .topTest");
3194 }
3195
3196 /* Run all tests */
3197 if (thread) {
3198 return do_files_thread(files);
3199 }
3200 else if (pthread) {
3201 #ifdef HAVE_PTHREAD_H
3202 return do_files_pthread(files);
3203 #else
3204 err_exit("pthread not found on this system: use --thread");
3205 #endif
3206 }
3207 else {
3208 return do_files(files);
3209 }
3210 }
3211