• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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