1 /* Copyright (c) 2011, 2020, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /*
24   NOTE: This is a more-or-less direct port of the main() program
25   in strings/decimal.c to a Google Test.
26  */
27 
28 #include "my_config.h"
29 
30 #include <gtest/gtest.h>
31 #include <math.h>
32 #include <string.h>
33 
34 #include "decimal.h"
35 #include "m_string.h"
36 #include "my_inttypes.h"
37 #include "my_macros.h"
38 #include "sql/my_decimal.h"
39 #include "unittest/gunit/benchmark.h"
40 
41 namespace decimal_unittest {
42 
43 #define DIG_PER_DEC1 9
44 #define DIG_BASE 1000000000
45 #define ROUND_UP(X) (((X) + DIG_PER_DEC1 - 1) / DIG_PER_DEC1)
46 typedef decimal_digit_t dec1;
47 
48 int full = 0;
49 decimal_t a, b, c;
50 decimal_digit_t buf1[50], buf2[50], buf3[50];
51 
dump_decimal(decimal_t * d)52 void dump_decimal(decimal_t *d) {
53   int i;
54   printf("/* intg=%d, frac=%d, sign=%d, buf[]={", d->intg, d->frac, d->sign);
55   for (i = 0; i < ROUND_UP(d->frac) + ROUND_UP(d->intg) - 1; i++)
56     printf("%09d, ", d->buf[i]);
57   printf("%09d} */ ", d->buf[i]);
58 }
59 
60 /*
61   The purpose of all these define wrappers is to get a "call stack"
62   whenever some EXPECT_XX generates a failure. A sample error message:
63 
64   # .../unittest/gunit/decimal-t.cc:134: FailureValue of: s
65   #   Actual: "0"
66   # Expected: orig
67   # Which is: "1000000000"
68   #  arguments were: '999999999', -9, HALF_UP
69   # Google Test trace:
70   # .../unittest/gunit/decimal-t.cc:387:
71   # .../unittest/gunit/decimal-t.cc:686:
72  */
73 
74 #define check_result_code(p1, p2) \
75   {                               \
76     SCOPED_TRACE("");             \
77     do_check_result_code(p1, p2); \
78   }
79 
80 #define print_decimal(p1, p2, p3, p4, p5) \
81   {                                       \
82     SCOPED_TRACE("");                     \
83     do_print_decimal(p1, p2, p3, p4, p5); \
84   }
85 
86 #define test_s2d(p1, p2, p3) \
87   {                          \
88     SCOPED_TRACE("");        \
89     do_test_s2d(p1, p2, p3); \
90   }
91 
92 #define test_d2f(p1, p2) \
93   {                      \
94     SCOPED_TRACE("");    \
95     do_test_d2f(p1, p2); \
96   }
97 
98 #define test_d2b2d(p1, p2, p3, p4, p5) \
99   {                                    \
100     SCOPED_TRACE("");                  \
101     do_test_d2b2d(p1, p2, p3, p4, p5); \
102   }
103 
104 #define test_f2d(p1, p2) \
105   {                      \
106     SCOPED_TRACE("");    \
107     do_test_f2d(p1, p2); \
108   }
109 
110 #define test_ull2d(p1, p2, p3) \
111   {                            \
112     SCOPED_TRACE("");          \
113     do_test_ull2d(p1, p2, p3); \
114   }
115 
116 #define test_ll2d(p1, p2, p3) \
117   {                           \
118     SCOPED_TRACE("");         \
119     do_test_ll2d(p1, p2, p3); \
120   }
121 
122 #define test_d2ull(p1, p2, p3) \
123   {                            \
124     SCOPED_TRACE("");          \
125     do_test_d2ull(p1, p2, p3); \
126   }
127 
128 #define test_d2ll(p1, p2, p3) \
129   {                           \
130     SCOPED_TRACE("");         \
131     do_test_d2ll(p1, p2, p3); \
132   }
133 
134 #define test_da(p1, p2, p3, p4) \
135   {                             \
136     SCOPED_TRACE("");           \
137     do_test_da(p1, p2, p3, p4); \
138   }
139 
140 #define test_ds(p1, p2, p3, p4) \
141   {                             \
142     SCOPED_TRACE("");           \
143     do_test_ds(p1, p2, p3, p4); \
144   }
145 
146 #define test_dc(p1, p2, p3) \
147   {                         \
148     SCOPED_TRACE("");       \
149     do_test_dc(p1, p2, p3); \
150   }
151 
152 #define test_dm(p1, p2, p3, p4) \
153   {                             \
154     SCOPED_TRACE("");           \
155     do_test_dm(p1, p2, p3, p4); \
156   }
157 
158 #define test_dv(p1, p2, p3, p4) \
159   {                             \
160     SCOPED_TRACE("");           \
161     do_test_dv(p1, p2, p3, p4); \
162   }
163 
164 #define test_md(p1, p2, p3, p4) \
165   {                             \
166     SCOPED_TRACE("");           \
167     do_test_md(p1, p2, p3, p4); \
168   }
169 
170 #define test_ro(p1, p2, p3, p4, p5) \
171   {                                 \
172     SCOPED_TRACE("");               \
173     do_test_ro(p1, p2, p3, p4, p5); \
174   }
175 
176 #define test_format(p1, p2, p3, p4, p5) \
177   {                                     \
178     SCOPED_TRACE("");                   \
179     do_test_format(p1, p2, p3, p4, p5); \
180   }
181 
182 #define test_mx(p1, p2, p3) \
183   {                         \
184     SCOPED_TRACE("");       \
185     do_test_mx(p1, p2, p3); \
186   }
187 
188 #define test_pr(p1, p2, p3, p4, p5) \
189   {                                 \
190     SCOPED_TRACE("");               \
191     do_test_pr(p1, p2, p3, p4, p5); \
192   }
193 
194 #define test_widen_fraction(p1, p2, p3) \
195   {                                     \
196     SCOPED_TRACE("");                   \
197     do_test_widen_fraction(p1, p2, p3); \
198   }
199 
200 #define test_sh(p1, p2, p3, p4) \
201   {                             \
202     SCOPED_TRACE("");           \
203     do_test_sh(p1, p2, p3, p4); \
204   }
205 
206 #define test_fr(p1, p2) \
207   {                     \
208     SCOPED_TRACE("");   \
209     do_test_fr(p1, p2); \
210   }
211 
do_check_result_code(int actual,int want)212 void do_check_result_code(int actual, int want) { EXPECT_EQ(want, actual); }
213 
do_print_decimal(decimal_t * d,const char * orig,int actual,int want,const char * msg)214 void do_print_decimal(decimal_t *d, const char *orig, int actual, int want,
215                       const char *msg) {
216   char s[100];
217   int slen = sizeof(s);
218 
219   if (full) dump_decimal(d);
220   decimal2string(d, s, &slen);
221   check_result_code(actual, want);
222   if (orig) {
223     EXPECT_STREQ(orig, s) << " arguments were: " << msg;
224   }
225 }
226 
test_d2s()227 void test_d2s() {
228   char s[100];
229   int slen, res;
230 
231   /***********************************/
232   printf("==== decimal2string ====\n");
233   a.buf[0] = 12345;
234   a.intg = 5;
235   a.frac = 0;
236   a.sign = false;
237   slen = sizeof(s);
238   res = decimal2string(&a, s, &slen);
239   dump_decimal(&a);
240   printf("  -->  res=%d str='%s' len=%d\n", res, s, slen);
241 
242   a.buf[1] = 987000000;
243   a.frac = 3;
244   slen = sizeof(s);
245   res = decimal2string(&a, s, &slen);
246   dump_decimal(&a);
247   printf("  -->  res=%d str='%s' len=%d\n", res, s, slen);
248 
249   a.sign = true;
250   slen = sizeof(s);
251   res = decimal2string(&a, s, &slen);
252   dump_decimal(&a);
253   printf("  -->  res=%d str='%s' len=%d\n", res, s, slen);
254 
255   slen = 8;
256   res = decimal2string(&a, s, &slen);
257   dump_decimal(&a);
258   printf("  -->  res=%d str='%s' len=%d\n", res, s, slen);
259 
260   slen = 5;
261   res = decimal2string(&a, s, &slen);
262   dump_decimal(&a);
263   printf("  -->  res=%d str='%s' len=%d\n", res, s, slen);
264 
265   a.buf[0] = 987000000;
266   a.frac = 3;
267   a.intg = 0;
268   slen = sizeof(s);
269   res = decimal2string(&a, s, &slen);
270   dump_decimal(&a);
271   printf("  -->  res=%d str='%s' len=%d\n", res, s, slen);
272 }
273 
do_test_s2d(const char * s,const char * orig,int ex)274 void do_test_s2d(const char *s, const char *orig, int ex) {
275   char s1[100];
276   int res;
277   sprintf(s1, "'%s'", s);
278   const char *end = strend(s);
279   res = string2decimal(s, &a, &end);
280   print_decimal(&a, orig, res, ex, s1);
281 }
282 
do_test_d2f(const char * s,int ex)283 void do_test_d2f(const char *s, int ex) {
284   char s1[100];
285   double x;
286   int res;
287 
288   sprintf(s1, "'%s'", s);
289   const char *end = strend(s);
290   string2decimal(s, &a, &end);
291   res = decimal2double(&a, &x);
292   if (full) dump_decimal(&a);
293   check_result_code(res, ex);
294 }
295 
do_test_d2b2d(const char * str,int p,int s,const char * orig,int ex)296 void do_test_d2b2d(const char *str, int p, int s, const char *orig, int ex) {
297   char s1[100];
298   char s2[100 * 2];
299   uchar buf[100];
300   int res, i, size = decimal_bin_size(p, s);
301 
302   sprintf(s1, "'%s'", str);
303   const char *end = strend(str);
304   string2decimal(str, &a, &end);
305   res = decimal2bin(&a, buf, p, s);
306   sprintf(s2, "%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size);
307   if (full) {
308     printf("0x");
309     for (i = 0; i < size; i++) printf("%02x", ((uchar *)buf)[i]);
310   }
311   res = bin2decimal(buf, &a, p, s);
312   print_decimal(&a, orig, res, ex, s2);
313 }
314 
do_test_f2d(double from,int ex)315 void do_test_f2d(double from, int ex) {
316   int res;
317   char s1[100];
318 
319   res = double2decimal(from, &a);
320   sprintf(s1, "%-40.*f => res=%d    ", DBL_DIG - 2, from, res);
321   print_decimal(&a, nullptr, res, ex, s1);
322 }
323 
do_test_ull2d(ulonglong from,const char * orig,int ex)324 void do_test_ull2d(ulonglong from, const char *orig, int ex) {
325   char s[100];
326   char s1[100 * 2];
327   int res;
328 
329   res = ulonglong2decimal(from, &a);
330   longlong10_to_str(from, s, 10);
331   sprintf(s1, "%-40s => res=%d    ", s, res);
332   print_decimal(&a, orig, res, ex, s1);
333 }
334 
do_test_ll2d(longlong from,const char * orig,int ex)335 void do_test_ll2d(longlong from, const char *orig, int ex) {
336   char s[100];
337   char s1[100 * 2];
338   int res;
339 
340   res = longlong2decimal(from, &a);
341   longlong10_to_str(from, s, -10);
342   sprintf(s1, "%-40s => res=%d    ", s, res);
343   print_decimal(&a, orig, res, ex, s1);
344 }
345 
do_test_d2ull(const char * s,const char * orig,int ex)346 void do_test_d2ull(const char *s, const char *orig, int ex) {
347   char s1[100];
348   char s2[100 * 2];
349   ulonglong x;
350   int res;
351 
352   const char *end = strend(s);
353   string2decimal(s, &a, &end);
354   res = decimal2ulonglong(&a, &x);
355   if (full) dump_decimal(&a);
356   longlong10_to_str(x, s1, 10);
357   sprintf(s2, "%-40s => res=%d    %s\n", s, res, s1);
358   check_result_code(res, ex);
359   if (orig) {
360     EXPECT_STREQ(orig, s1) << " arguments were: " << s2;
361   }
362 }
363 
do_test_d2ll(const char * s,const char * orig,int ex)364 void do_test_d2ll(const char *s, const char *orig, int ex) {
365   char s1[100];
366   char s2[100 * 2];
367   longlong x;
368   int res;
369 
370   const char *end = strend(s);
371   string2decimal(s, &a, &end);
372   res = decimal2longlong(&a, &x);
373   if (full) dump_decimal(&a);
374   longlong10_to_str(x, s1, -10);
375   sprintf(s2, "%-40s => res=%d    %s\n", s, res, s1);
376   check_result_code(res, ex);
377   if (orig) {
378     EXPECT_STREQ(orig, s1) << " arguments were: " << s2;
379   }
380 }
381 
do_test_da(const char * s1,const char * s2,const char * orig,int ex)382 void do_test_da(const char *s1, const char *s2, const char *orig, int ex) {
383   char s[100];
384   int res;
385   sprintf(s, "'%s' + '%s'", s1, s2);
386   const char *end = strend(s1);
387   string2decimal(s1, &a, &end);
388   end = strend(s2);
389   string2decimal(s2, &b, &end);
390   res = decimal_add(&a, &b, &c);
391   print_decimal(&c, orig, res, ex, s);
392 }
393 
do_test_ds(const char * s1,const char * s2,const char * orig,int ex)394 void do_test_ds(const char *s1, const char *s2, const char *orig, int ex) {
395   char s[100];
396   int res;
397   sprintf(s, "'%s' - '%s'", s1, s2);
398   const char *end = strend(s1);
399   string2decimal(s1, &a, &end);
400   end = strend(s2);
401   string2decimal(s2, &b, &end);
402   res = decimal_sub(&a, &b, &c);
403   print_decimal(&c, orig, res, ex, s);
404 }
405 
do_test_dc(const char * s1,const char * s2,int orig)406 void do_test_dc(const char *s1, const char *s2, int orig) {
407   char s[100];
408   int res;
409   sprintf(s, "'%s' <=> '%s'", s1, s2);
410   const char *end = strend(s1);
411   string2decimal(s1, &a, &end);
412   end = strend(s2);
413   string2decimal(s2, &b, &end);
414   res = decimal_cmp(&a, &b);
415   EXPECT_EQ(orig, res) << " arguments were: " << s;
416 }
417 
do_test_dm(const char * s1,const char * s2,const char * orig,int ex)418 void do_test_dm(const char *s1, const char *s2, const char *orig, int ex) {
419   char s[100];
420   int res;
421   sprintf(s, "'%s' * '%s'", s1, s2);
422   const char *end = strend(s1);
423   string2decimal(s1, &a, &end);
424   end = strend(s2);
425   string2decimal(s2, &b, &end);
426   res = decimal_mul(&a, &b, &c);
427   print_decimal(&c, orig, res, ex, s);
428 }
429 
do_test_dv(const char * s1,const char * s2,const char * orig,int ex)430 void do_test_dv(const char *s1, const char *s2, const char *orig, int ex) {
431   char s[100];
432   int res;
433   sprintf(s, "'%s' / '%s'", s1, s2);
434   const char *end = strend(s1);
435   string2decimal(s1, &a, &end);
436   end = strend(s2);
437   string2decimal(s2, &b, &end);
438   res = decimal_div(&a, &b, &c, 5);
439   check_result_code(res, ex);
440   if (res != E_DEC_DIV_ZERO) print_decimal(&c, orig, res, ex, s);
441 }
442 
do_test_md(const char * s1,const char * s2,const char * orig,int ex)443 void do_test_md(const char *s1, const char *s2, const char *orig, int ex) {
444   char s[100];
445   int res;
446   sprintf(s, "'%s' %% '%s'", s1, s2);
447   const char *end = strend(s1);
448   string2decimal(s1, &a, &end);
449   end = strend(s2);
450   string2decimal(s2, &b, &end);
451   res = decimal_mod(&a, &b, &c);
452   check_result_code(res, ex);
453   if (res != E_DEC_DIV_ZERO) print_decimal(&c, orig, res, ex, s);
454 }
455 
456 const char *round_mode[] = {"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING",
457                             "FLOOR"};
458 
do_test_ro(const char * s1,int n,decimal_round_mode mode,const char * orig,int ex)459 void do_test_ro(const char *s1, int n, decimal_round_mode mode,
460                 const char *orig, int ex) {
461   char s[100];
462   int res;
463   sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]);
464   const char *end = strend(s1);
465   string2decimal(s1, &a, &end);
466   res = decimal_round(&a, &b, n, mode);
467   print_decimal(&b, orig, res, ex, s);
468 }
469 
do_test_format(const char * s1,const char * s2,int n,const char * orig,int ex)470 void do_test_format(const char *s1, const char *s2, int n, const char *orig,
471                     int ex) {
472   char s[200];
473   decimal_t a, b, c, d;
474   decimal_digit_t buf1[9], buf2[9], buf3[9], buf4[9];
475   int res;
476   a.buf = buf1;
477   b.buf = buf2;
478   c.buf = buf3;
479   d.buf = buf4;
480   a.len = sizeof(buf1) / sizeof(dec1);
481   b.len = sizeof(buf2) / sizeof(dec1);
482   c.len = sizeof(buf3) / sizeof(dec1);
483   d.len = sizeof(buf4) / sizeof(dec1);
484 
485   sprintf(s, "'%s' %% '%s'", s1, s2);
486   const char *end = strend(s1);
487   string2decimal(s1, &a, &end);
488   end = strend(s2);
489   string2decimal(s2, &b, &end);
490   decimal_mod(&a, &b, &c);
491   res = decimal_round(&c, &d, n, HALF_UP);
492   print_decimal(&d, orig, res, ex, s);
493 }
do_test_mx(int precision,int frac,const char * orig)494 void do_test_mx(int precision, int frac, const char *orig) {
495   char s[100];
496   sprintf(s, "%d, %d", precision, frac);
497   max_decimal(precision, frac, &a);
498   print_decimal(&a, orig, 0, 0, s);
499 }
500 
do_test_pr(const char * s1,int prec,int dec,const char * orig,int ex)501 static void do_test_pr(const char *s1, int prec, int dec, const char *orig,
502                        int ex) {
503   char s[100];
504   char s2[100];
505   int slen = sizeof(s2);
506 
507   sprintf(s, "'%s', %d, %d", s1, prec, dec);
508   const char *end = strend(s1);
509   string2decimal(s1, &a, &end);
510   const int res = decimal2string(&a, s2, &slen, prec, dec);
511   check_result_code(res, ex);
512   if (orig) {
513     EXPECT_STREQ(orig, s2) << " arguments were: " << s;
514   }
515 }
516 
do_test_widen_fraction(const char * s1,int increase,const char * orig)517 void do_test_widen_fraction(const char *s1, int increase, const char *orig) {
518   decimal_t a;
519   decimal_digit_t buf1[9];
520   a.buf = buf1;
521   a.len = array_elements(buf1);
522 
523   const char *end = strend(s1);
524   string2decimal(s1, &a, &end);
525   widen_fraction(a.frac + increase, &a);
526 
527   char s[100];
528   int slen = sizeof(s);
529   int result = decimal2string(&a, s, &slen);
530   EXPECT_EQ(result, 0);
531   EXPECT_STREQ(orig, s) << " arguments were: " << s1;
532 }
533 
do_test_sh(const char * s1,int shift,const char * orig,int ex)534 void do_test_sh(const char *s1, int shift, const char *orig, int ex) {
535   char s[100];
536   int res;
537   sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
538   const char *end = strend(s1);
539   string2decimal(s1, &a, &end);
540   res = decimal_shift(&a, shift);
541   print_decimal(&a, orig, res, ex, s);
542 }
543 
do_test_fr(const char * s1,const char * orig)544 void do_test_fr(const char *s1, const char *orig) {
545   char s[100];
546   sprintf(s, "'%s'", s1);
547   const char *end = strend(s1);
548   string2decimal(s1, &a, &end);
549   a.frac = decimal_actual_fraction(&a);
550   print_decimal(&a, orig, 0, 0, s);
551 }
552 
SetupDecimals()553 static void SetupDecimals() {
554   a.buf = buf1;
555   a.len = sizeof(buf1) / sizeof(dec1);
556   b.buf = buf2;
557   b.len = sizeof(buf2) / sizeof(dec1);
558   c.buf = buf3;
559   c.len = sizeof(buf3) / sizeof(dec1);
560 }
561 
562 class DecimalTest : public ::testing::Test {
563  protected:
SetUp()564   void SetUp() override { SetupDecimals(); }
565 };
566 
TEST_F(DecimalTest,String2Decimal)567 TEST_F(DecimalTest, String2Decimal) {
568   test_s2d("12345", "12345", 0);
569   test_s2d("12345.", "12345", 0);
570   test_s2d("123.45", "123.45", 0);
571   test_s2d("-123.45", "-123.45", 0);
572   test_s2d(".00012345000098765", "0.00012345000098765", 0);
573   test_s2d(".12345000098765", "0.12345000098765", 0);
574   test_s2d("-.000000012345000098765", "-0.000000012345000098765", 0);
575   test_s2d("1234500009876.5", "1234500009876.5", 0);
576   a.len = 1;
577   test_s2d("123450000098765", "98765", 2);
578   test_s2d("123450.000098765", "123450", 1);
579   a.len = sizeof(buf1) / sizeof(dec1);
580   test_s2d("123E5", "12300000", 0);
581   test_s2d("123E-2", "1.23", 0);
582 }
583 
TEST_F(DecimalTest,Decimal2Double)584 TEST_F(DecimalTest, Decimal2Double) {
585   test_d2f("12345", 0);
586   test_d2f("123.45", 0);
587   test_d2f("-123.45", 0);
588   test_d2f("0.00012345000098765", 0);
589   test_d2f("1234500009876.5", 0);
590 }
591 
TEST_F(DecimalTest,Double2Decimal)592 TEST_F(DecimalTest, Double2Decimal) {
593   test_f2d(12345, 0);
594   test_f2d(1.0 / 3, 0);
595   test_f2d(-123.45, 0);
596   test_f2d(0.00012345000098765, 0);
597   test_f2d(1234500009876.5, 0);
598 }
599 
TEST_F(DecimalTest,Ulonglong2Decimal)600 TEST_F(DecimalTest, Ulonglong2Decimal) {
601   test_ull2d(12345ULL, "12345", 0);
602   test_ull2d(0ULL, "0", 0);
603   test_ull2d(18446744073709551615ULL, "18446744073709551615", 0);
604 }
605 
TEST_F(DecimalTest,Decimal2Ulonglong)606 TEST_F(DecimalTest, Decimal2Ulonglong) {
607   test_d2ull("12345", "12345", 0);
608   test_d2ull("0", "0", 0);
609   /* ULLONG_MAX = 18446744073709551615ULL */
610   test_d2ull("18446744073709551615", "18446744073709551615", 0);
611   test_d2ull("18446744073709551616", "18446744073709551615", 2);
612   test_d2ull("-1", "0", 2);
613   test_d2ull("1.23", "1", 1);
614   test_d2ull("9999999999999999999999999.000", "18446744073709551615", 2);
615 }
616 
TEST_F(DecimalTest,Longlong2Decimal)617 TEST_F(DecimalTest, Longlong2Decimal) {
618   test_ll2d(-12345LL, "-12345", 0);
619   test_ll2d(-1LL, "-1", 0);
620   test_ll2d(-9223372036854775807LL, "-9223372036854775807", 0);
621   test_ll2d(9223372036854775808ULL, "-9223372036854775808", 0);
622 }
623 
TEST_F(DecimalTest,Decimal2Longlong)624 TEST_F(DecimalTest, Decimal2Longlong) {
625   /* LLONG_MAX = 9223372036854775807LL */
626   test_d2ll("18446744073709551615", "9223372036854775807", 2);
627   test_d2ll("-1", "-1", 0);
628   test_d2ll("-1.23", "-1", 1);
629   test_d2ll("-9223372036854775807", "-9223372036854775807", 0);
630   test_d2ll("-9223372036854775808", "-9223372036854775808", 0);
631   test_d2ll("9223372036854775808", "9223372036854775807", 2);
632 }
633 
TEST_F(DecimalTest,DoAdd)634 TEST_F(DecimalTest, DoAdd) {
635   test_da(".00012345000098765", "123.45", "123.45012345000098765", 0);
636   test_da(".1", ".45", "0.55", 0);
637   test_da("1234500009876.5", ".00012345000098765",
638           "1234500009876.50012345000098765", 0);
639   test_da("9999909999999.5", ".555", "9999910000000.055", 0);
640   test_da("99999999", "1", "100000000", 0);
641   test_da("989999999", "1", "990000000", 0);
642   test_da("999999999", "1", "1000000000", 0);
643   test_da("12345", "123.45", "12468.45", 0);
644   test_da("-12345", "-123.45", "-12468.45", 0);
645   test_ds("-12345", "123.45", "-12468.45", 0);
646   test_ds("12345", "-123.45", "12468.45", 0);
647 }
648 
TEST_F(DecimalTest,DoSub)649 TEST_F(DecimalTest, DoSub) {
650   test_ds(".00012345000098765", "123.45", "-123.44987654999901235", 0);
651   test_ds("1234500009876.5", ".00012345000098765",
652           "1234500009876.49987654999901235", 0);
653   test_ds("9999900000000.5", ".555", "9999899999999.945", 0);
654   test_ds("1111.5551", "1111.555", "0.0001", 0);
655   test_ds(".555", ".555", "0", 0);
656   test_ds("10000000", "1", "9999999", 0);
657   test_ds("1000001000", ".1", "1000000999.9", 0);
658   test_ds("1000000000", ".1", "999999999.9", 0);
659   test_ds("12345", "123.45", "12221.55", 0);
660   test_ds("-12345", "-123.45", "-12221.55", 0);
661   test_da("-12345", "123.45", "-12221.55", 0);
662   test_da("12345", "-123.45", "12221.55", 0);
663   test_ds("123.45", "12345", "-12221.55", 0);
664   test_ds("-123.45", "-12345", "12221.55", 0);
665   test_da("123.45", "-12345", "-12221.55", 0);
666   test_da("-123.45", "12345", "12221.55", 0);
667   test_da("5", "-6.0", "-1.0", 0);
668 }
669 
TEST_F(DecimalTest,DecimalMul)670 TEST_F(DecimalTest, DecimalMul) {
671   test_dm("12", "10", "120", 0);
672   test_dm("-123.456", "98765.4321", "-12193185.1853376", 0);
673   test_dm("-123456000000", "98765432100000", "-12193185185337600000000000", 0);
674   test_dm("123456", "987654321", "121931851853376", 0);
675   test_dm("123456", "9876543210", "1219318518533760", 0);
676   test_dm("123", "0.01", "1.23", 0);
677   test_dm("123", "0", "0", 0);
678 }
679 
TEST_F(DecimalTest,DecimalDiv)680 TEST_F(DecimalTest, DecimalDiv) {
681   test_dv("120", "10", "12.000000000", 0);
682   test_dv("123", "0.01", "12300.000000000", 0);
683   test_dv("120", "100000000000.00000", "0.000000001200000000", 0);
684   test_dv("123", "0", "", 4);
685   test_dv("0", "0", "", 4);
686   test_dv("-12193185.1853376", "98765.4321", "-123.456000000000000000", 0);
687   test_dv("121931851853376", "987654321", "123456.000000000", 0);
688   test_dv("0", "987", "0", 0);
689   test_dv("1", "3", "0.333333333", 0);
690   test_dv("1.000000000000", "3", "0.333333333333333333", 0);
691   test_dv("1", "1", "1.000000000", 0);
692   test_dv("0.0123456789012345678912345", "9999999999",
693           "0.000000000001234567890246913578148141", 0);
694   test_dv("10.333000000", "12.34500", "0.837019036046982584042122316", 0);
695   test_dv("10.000000000060", "2", "5.000000000030000000", 0);
696 }
697 
TEST_F(DecimalTest,DecimalMod)698 TEST_F(DecimalTest, DecimalMod) {
699   test_md("234", "10", "4", 0);
700   test_md("234.567", "10.555", "2.357", 0);
701   test_md("-234.567", "10.555", "-2.357", 0);
702   test_md("234.567", "-10.555", "2.357", 0);
703   c.buf[1] = 0x3ABECA;
704   test_md("99999999999999999999999999999999999999", "3", "0", 0);
705   if (c.buf[1] != 0x3ABECA) {
706     ADD_FAILURE() << "overflow " << c.buf[1];
707   }
708 }
709 
TEST_F(DecimalTest,Decimal2BinBin2Decimal)710 TEST_F(DecimalTest, Decimal2BinBin2Decimal) {
711   test_d2b2d("-10.55", 4, 2, "-10.55", 0);
712   test_d2b2d("0.0123456789012345678912345", 30, 25,
713              "0.0123456789012345678912345", 0);
714   test_d2b2d("12345", 5, 0, "12345", 0);
715   test_d2b2d("12345", 10, 3, "12345.000", 0);
716   test_d2b2d("123.45", 10, 3, "123.450", 0);
717   test_d2b2d("-123.45", 20, 10, "-123.4500000000", 0);
718   test_d2b2d(".00012345000098765", 15, 14, "0.00012345000098", 0);
719   test_d2b2d(".00012345000098765", 22, 20, "0.00012345000098765000", 0);
720   test_d2b2d(".12345000098765", 30, 20, "0.12345000098765000000", 0);
721   test_d2b2d("-.000000012345000098765", 30, 20, "-0.00000001234500009876", 0);
722   test_d2b2d("1234500009876.5", 30, 5, "1234500009876.50000", 0);
723   test_d2b2d("111111111.11", 10, 2, "11111111.11", 0);
724   test_d2b2d("000000000.01", 7, 3, "0.010", 0);
725   test_d2b2d("123.4", 10, 2, "123.40", 0);
726 }
727 
TEST_F(DecimalTest,DecimalCmp)728 TEST_F(DecimalTest, DecimalCmp) {
729   test_dc("12", "13", -1);
730   test_dc("13", "12", 1);
731   test_dc("-10", "10", -1);
732   test_dc("10", "-10", 1);
733   test_dc("-12", "-13", 1);
734   test_dc("0", "12", -1);
735   test_dc("-10", "0", -1);
736   test_dc("4", "4", 0);
737 }
738 
TEST_F(DecimalTest,DecimalRound)739 TEST_F(DecimalTest, DecimalRound) {
740   test_ro("5678.123451", -4, TRUNCATE, "0", 0);
741   test_ro("5678.123451", -3, TRUNCATE, "5000", 0);
742   test_ro("5678.123451", -2, TRUNCATE, "5600", 0);
743   test_ro("5678.123451", -1, TRUNCATE, "5670", 0);
744   test_ro("5678.123451", 0, TRUNCATE, "5678", 0);
745   test_ro("5678.123451", 1, TRUNCATE, "5678.1", 0);
746   test_ro("5678.123451", 2, TRUNCATE, "5678.12", 0);
747   test_ro("5678.123451", 3, TRUNCATE, "5678.123", 0);
748   test_ro("5678.123451", 4, TRUNCATE, "5678.1234", 0);
749   test_ro("5678.123451", 5, TRUNCATE, "5678.12345", 0);
750   test_ro("5678.123451", 6, TRUNCATE, "5678.123451", 0);
751   test_ro("-5678.123451", -4, TRUNCATE, "0", 0);
752   memset(buf2, 33, sizeof(buf2));
753   test_ro("99999999999999999999999999999999999999", -31, TRUNCATE,
754           "99999990000000000000000000000000000000", 0);
755   test_ro("15.1", 0, HALF_UP, "15", 0);
756   test_ro("15.5", 0, HALF_UP, "16", 0);
757   test_ro("15.9", 0, HALF_UP, "16", 0);
758   test_ro("-15.1", 0, HALF_UP, "-15", 0);
759   test_ro("-15.5", 0, HALF_UP, "-16", 0);
760   test_ro("-15.9", 0, HALF_UP, "-16", 0);
761   test_ro("15.1", 1, HALF_UP, "15.1", 0);
762   test_ro("-15.1", 1, HALF_UP, "-15.1", 0);
763   test_ro("15.17", 1, HALF_UP, "15.2", 0);
764   test_ro("15.4", -1, HALF_UP, "20", 0);
765   test_ro("-15.4", -1, HALF_UP, "-20", 0);
766   test_ro("5.4", -1, HALF_UP, "10", 0);
767   test_ro(".999", 0, HALF_UP, "1", 0);
768   memset(buf2, 33, sizeof(buf2));
769   test_ro("999999999", -9, HALF_UP, "1000000000", 0);
770   test_ro("15.1", 0, HALF_EVEN, "15", 0);
771   test_ro("15.5", 0, HALF_EVEN, "16", 0);
772   test_ro("14.5", 0, HALF_EVEN, "14", 0);
773   test_ro("15.9", 0, HALF_EVEN, "16", 0);
774   test_ro("15.1", 0, CEILING, "16", 0);
775   test_ro("-15.1", 0, CEILING, "-15", 0);
776   test_ro("15.1", 0, FLOOR, "15", 0);
777   test_ro("-15.1", 0, FLOOR, "-16", 0);
778   test_ro("999999999999999999999.999", 0, CEILING, "1000000000000000000000", 0);
779   test_ro("-999999999999999999999.999", 0, FLOOR, "-1000000000000000000000", 0);
780 
781   b.buf[0] = DIG_BASE + 1;
782   b.buf++;
783   test_ro(".3", 0, HALF_UP, "0", 0);
784   b.buf--;
785   if (b.buf[0] != DIG_BASE + 1) {
786     ADD_FAILURE() << "underflow " << b.buf[0];
787   }
788 }
789 
TEST_F(DecimalTest,FormatFunc)790 TEST_F(DecimalTest, FormatFunc) {
791   test_format("999999999999999999999999999999999999999999999999999999999999999",
792               "999999999999999999999999999999999999999999999999999999999999999",
793               42, "0.000000000000000000000000000000000000000000", 0);
794 }
795 
TEST_F(DecimalTest,MaxDecimal)796 TEST_F(DecimalTest, MaxDecimal) {
797   test_mx(1, 1, "0.9");
798   test_mx(1, 0, "9");
799   test_mx(2, 1, "9.9");
800   test_mx(4, 2, "99.99");
801   test_mx(6, 3, "999.999");
802   test_mx(8, 4, "9999.9999");
803   test_mx(10, 5, "99999.99999");
804   test_mx(12, 6, "999999.999999");
805   test_mx(14, 7, "9999999.9999999");
806   test_mx(16, 8, "99999999.99999999");
807   test_mx(18, 9, "999999999.999999999");
808   test_mx(20, 10, "9999999999.9999999999");
809   test_mx(20, 20, "0.99999999999999999999");
810   test_mx(20, 0, "99999999999999999999");
811   test_mx(40, 20, "99999999999999999999.99999999999999999999");
812 }
813 
TEST_F(DecimalTest,Decimal2String)814 TEST_F(DecimalTest, Decimal2String) {
815   test_pr("123.123", 0, 0, "123.123", 0);
816   /* For fixed precision, we no longer count the '.' here. */
817   test_pr("123.123", 6, 3, "123.123", 0);
818   test_pr("123.123", 8, 3, "00123.123", 0);
819   test_pr("123.123", 8, 4, "0123.1230", 0);
820   test_pr("123.123", 8, 5, "123.12300", 0);
821   test_pr("123.123", 8, 2, "000123.12", 1);
822   test_pr("123.123", 8, 6, "23.123000", 2);
823 }
824 
TEST_F(DecimalTest,WidenFraction)825 TEST_F(DecimalTest, WidenFraction) {
826   test_widen_fraction("123.0", 1, "123.00");
827   test_widen_fraction("1234567890.123456789", 1, "1234567890.1234567890");
828   test_widen_fraction("123.0", 0, "123.0");
829   test_widen_fraction("123.0", 4, "123.00000");
830 }
831 
TEST_F(DecimalTest,DecimalShift)832 TEST_F(DecimalTest, DecimalShift) {
833   test_sh("123.123", 1, "1231.23", 0);
834   test_sh("123457189.123123456789000", 1, "1234571891.23123456789", 0);
835   test_sh("123457189.123123456789000", 4, "1234571891231.23456789", 0);
836   test_sh("123457189.123123456789000", 8, "12345718912312345.6789", 0);
837   test_sh("123457189.123123456789000", 9, "123457189123123456.789", 0);
838   test_sh("123457189.123123456789000", 10, "1234571891231234567.89", 0);
839   test_sh("123457189.123123456789000", 17, "12345718912312345678900000", 0);
840   test_sh("123457189.123123456789000", 18, "123457189123123456789000000", 0);
841   test_sh("123457189.123123456789000", 19, "1234571891231234567890000000", 0);
842   test_sh("123457189.123123456789000", 26,
843           "12345718912312345678900000000000000", 0);
844   test_sh("123457189.123123456789000", 27,
845           "123457189123123456789000000000000000", 0);
846   test_sh("123457189.123123456789000", 28,
847           "1234571891231234567890000000000000000", 0);
848   test_sh("000000000000000000000000123457189.123123456789000", 26,
849           "12345718912312345678900000000000000", 0);
850   test_sh("00000000123457189.123123456789000", 27,
851           "123457189123123456789000000000000000", 0);
852   test_sh("00000000000000000123457189.123123456789000", 28,
853           "1234571891231234567890000000000000000", 0);
854   test_sh("123", 1, "1230", 0);
855   test_sh("123", 10, "1230000000000", 0);
856   test_sh(".123", 1, "1.23", 0);
857   test_sh(".123", 10, "1230000000", 0);
858   test_sh(".123", 14, "12300000000000", 0);
859   test_sh("000.000", 1000, "0", 0);
860   test_sh("000.", 1000, "0", 0);
861   test_sh(".000", 1000, "0", 0);
862   test_sh("1", 1000, "1", 2);
863   test_sh("123.123", -1, "12.3123", 0);
864   test_sh("123987654321.123456789000", -1, "12398765432.1123456789", 0);
865   test_sh("123987654321.123456789000", -2, "1239876543.21123456789", 0);
866   test_sh("123987654321.123456789000", -3, "123987654.321123456789", 0);
867   test_sh("123987654321.123456789000", -8, "1239.87654321123456789", 0);
868   test_sh("123987654321.123456789000", -9, "123.987654321123456789", 0);
869   test_sh("123987654321.123456789000", -10, "12.3987654321123456789", 0);
870   test_sh("123987654321.123456789000", -11, "1.23987654321123456789", 0);
871   test_sh("123987654321.123456789000", -12, "0.123987654321123456789", 0);
872   test_sh("123987654321.123456789000", -13, "0.0123987654321123456789", 0);
873   test_sh("123987654321.123456789000", -14, "0.00123987654321123456789", 0);
874   test_sh("00000087654321.123456789000", -14, "0.00000087654321123456789", 0);
875   a.len = 2;
876   test_sh("123.123", -2, "1.23123", 0);
877   test_sh("123.123", -3, "0.123123", 0);
878   test_sh("123.123", -6, "0.000123123", 0);
879   test_sh("123.123", -7, "0.0000123123", 0);
880   test_sh("123.123", -15, "0.000000000000123123", 0);
881   test_sh("123.123", -16, "0.000000000000012312", 1);
882   test_sh("123.123", -17, "0.000000000000001231", 1);
883   test_sh("123.123", -18, "0.000000000000000123", 1);
884   test_sh("123.123", -19, "0.000000000000000012", 1);
885   test_sh("123.123", -20, "0.000000000000000001", 1);
886   test_sh("123.123", -21, "0", 1);
887   test_sh(".000000000123", -1, "0.0000000000123", 0);
888   test_sh(".000000000123", -6, "0.000000000000000123", 0);
889   test_sh(".000000000123", -7, "0.000000000000000012", 1);
890   test_sh(".000000000123", -8, "0.000000000000000001", 1);
891   test_sh(".000000000123", -9, "0", 1);
892   test_sh(".000000000123", 1, "0.00000000123", 0);
893   test_sh(".000000000123", 8, "0.0123", 0);
894   test_sh(".000000000123", 9, "0.123", 0);
895   test_sh(".000000000123", 10, "1.23", 0);
896   test_sh(".000000000123", 17, "12300000", 0);
897   test_sh(".000000000123", 18, "123000000", 0);
898   test_sh(".000000000123", 19, "1230000000", 0);
899   test_sh(".000000000123", 20, "12300000000", 0);
900   test_sh(".000000000123", 21, "123000000000", 0);
901   test_sh(".000000000123", 22, "1230000000000", 0);
902   test_sh(".000000000123", 23, "12300000000000", 0);
903   test_sh(".000000000123", 24, "123000000000000", 0);
904   test_sh(".000000000123", 25, "1230000000000000", 0);
905   test_sh(".000000000123", 26, "12300000000000000", 0);
906   test_sh(".000000000123", 27, "123000000000000000", 0);
907   test_sh(".000000000123", 28, "0.000000000123", 2);
908   test_sh("123456789.987654321", -1, "12345678.998765432", 1);
909   test_sh("123456789.987654321", -2, "1234567.899876543", 1);
910   test_sh("123456789.987654321", -8, "1.234567900", 1);
911   test_sh("123456789.987654321", -9, "0.123456789987654321", 0);
912   test_sh("123456789.987654321", -10, "0.012345678998765432", 1);
913   test_sh("123456789.987654321", -17, "0.000000001234567900", 1);
914   test_sh("123456789.987654321", -18, "0.000000000123456790", 1);
915   test_sh("123456789.987654321", -19, "0.000000000012345679", 1);
916   test_sh("123456789.987654321", -26, "0.000000000000000001", 1);
917   test_sh("123456789.987654321", -27, "0", 1);
918   test_sh("123456789.987654321", 1, "1234567900", 1);
919   test_sh("123456789.987654321", 2, "12345678999", 1);
920   test_sh("123456789.987654321", 4, "1234567899877", 1);
921   test_sh("123456789.987654321", 8, "12345678998765432", 1);
922   test_sh("123456789.987654321", 9, "123456789987654321", 0);
923   test_sh("123456789.987654321", 10, "123456789.987654321", 2);
924   test_sh("123456789.987654321", 0, "123456789.987654321", 0);
925   a.len = sizeof(buf1) / sizeof(dec1);
926 }
927 
TEST_F(DecimalTest,DecimalActualFraction)928 TEST_F(DecimalTest, DecimalActualFraction) {
929   test_fr("1.123456789000000000", "1.123456789");
930   test_fr("1.12345678000000000", "1.12345678");
931   test_fr("1.1234567000000000", "1.1234567");
932   test_fr("1.123456000000000", "1.123456");
933   test_fr("1.12345000000000", "1.12345");
934   test_fr("1.1234000000000", "1.1234");
935   test_fr("1.123000000000", "1.123");
936   test_fr("1.12000000000", "1.12");
937   test_fr("1.1000000000", "1.1");
938   test_fr("1.000000000", "1");
939   test_fr("1.0", "1");
940   test_fr("10000000000000000000.0", "10000000000000000000");
941 }
942 
943 // Some test data from DBT-3.
944 static const char *decimal_testdata[] = {
945     "45983.16", "0.09",     "983",      "0.09",     "36.00",    "45983.16",
946     "0.09",     "0.1",      "8.00",     "13309.60", "0.10",     "28955.64",
947     "0",        "28.00",    "28955.64", "0.09",     "0",        "24.00",
948     "22824.48", "0.10",     "49620.16", "0.07",     "32.00",    "49620.16",
949     "0.07",     "0.0",      "38.00",    "44694.46", "0.00",     "45.00",
950     "4058",     "54058.05", "0.06",     "058",      "0.06",     "45.00",
951     "4058",     "0.0",      "49.00",    "796",      "46796.47", "73426.50",
952     "0.08",     "0",        "37.00",    "61998.31", "0.08",     "13608.60",
953     "0.07",     "12.00",    "13608.60", "0.07",     "0.0",      "9.00",
954     "11594.16", "0.08",     "81639.88", "0",        "46.00",    "81639.88",
955     "0.10",     "0",        "28.00",    "31809.96", "0.03",     "73943.82",
956     "0.08",     "38.00",    "73943.82", "0.08",     "0.0",      "35.00",
957     "43058.75", "0.06",     "6476.15",  "0",        "5.00",     "6476.15",
958     "0.04",     "0",        "28.00",    "47227.60", "0.05",     "64605.44",
959     "0.02",     "32.00",    "64605.44", "0.02",     "0.0",      "2.00",
960     "2210.32",  "0.09",     "6582.96",  "0",        "4.00",     "6582.96",
961     "0.09",     "0",        "44.00",    "79059.64", "0.05",     "9159.66",
962     "0.04",     "6.00",     "9159.66",  "0.04",     "0.0",      "31.00",
963     "40217.23", "0.09",     "47344.32", "0",        "32.00",    "47344.32",
964     "0.02",     "0",        "5.00",     "7532.30",  "0.05",     "41.00",
965     "28",       "75928.31", "0.09",     "41.00",    "75928.31", "0.09",
966     "0.0",      "24.00",    "32410.80", "32410.80", "0.02",     "68065.96",
967     "0",        "34.00",    "68065.96", "0.06",     "0",        "7.00",
968     "13418.23", "0.06",     "29004.25", "0.06",     "25.00",    "29004.25",
969     "0.06",     "0.0",      "34.00",    "65854.94", "0.08",     "47397.28",
970     "0",        "28.00",    "47397.28", "0.03",     "0",        "42.00",
971     "75043.92", "0.09",     "62105.20", "0.09",     "40.00",    "62105.20",
972     "0.09",     "0.0",      "39.00",    "70542.42", "0.05",     "78083.70",
973     "0",        "43.00",    "78083.70", "0.05",     "0",        "44.00",
974     "84252.52", "0.04",     "53782.08", "0.09",     "44.00",    "53782.08",
975     "0.09",     "0.0",      "26.00",    "43383.08", "0.08",     "82746.18",
976     "0",        "46.00",    "82746.18", "0.06",     "0",        "32.00",
977     "48338.88", "0.07",     "63360.93", "0.01",     "43.00",    "63360.93",
978     "0.01",     "0.0",      "40.00",    "54494.40", "0.06",     "21.00",
979     "75",       "40675.95", "0",        "21.00",    "40675.95", "0.05",
980     "0",        "26.00",    "42995.94", "0.03",     "39353.82", "0.00",
981     "22.00",    "39353.82", "0.00",     "0.0",      "21.00",    "27076.98",
982     "0.09",     "31.00"};
983 
BM_Decimal2Bin_10_2(size_t iters)984 static void BM_Decimal2Bin_10_2(size_t iters) {
985   StopBenchmarkTiming();
986   constexpr size_t num_elements = array_elements(decimal_testdata);
987   decimal_t decimals[num_elements];
988   decimal_digit_t decimal_buf[num_elements][9];
989 
990   for (size_t i = 0; i < num_elements; ++i) {
991     const char *end = strend(decimal_testdata[i]);
992     decimals[i].buf = decimal_buf[i];
993     decimals[i].len = array_elements(decimal_buf[i]);
994     int res = string2decimal(decimal_testdata[i], &decimals[i], &end);
995     ASSERT_EQ(E_DEC_OK, res) << decimal_testdata[i] << " wasn't converted";
996   }
997   StartBenchmarkTiming();
998 
999   int dummy = 0;
1000   for (size_t i = 0; i < iters; ++i) {
1001     uchar buf[100];
1002     decimal2bin(&decimals[i % num_elements], buf, 10, 2);
1003     dummy += buf[0];
1004   }
1005 
1006   ASSERT_NE(0, dummy);  // To keep the optimizer from removing the loop.
1007 }
BENCHMARK(BM_Decimal2Bin_10_2)1008 BENCHMARK(BM_Decimal2Bin_10_2)
1009 
1010 static void BM_Bin2Decimal_10_2(size_t iters) {
1011   StopBenchmarkTiming();
1012   constexpr size_t num_elements = array_elements(decimal_testdata);
1013   constexpr int bin_size = 5;
1014   ASSERT_EQ(bin_size, decimal_bin_size(10, 2)) << "Need to adjust bin_size";
1015   uchar packed_buf[num_elements][bin_size];
1016 
1017   decimal_t decimal;
1018   decimal_digit_t decimal_buf[9];
1019   decimal.buf = decimal_buf;
1020   decimal.len = array_elements(decimal_buf);
1021 
1022   for (size_t i = 0; i < num_elements; ++i) {
1023     const char *end = strend(decimal_testdata[i]);
1024     int res = string2decimal(decimal_testdata[i], &decimal, &end);
1025     ASSERT_EQ(E_DEC_OK, res) << decimal_testdata[i] << " wasn't converted";
1026     res = decimal2bin(&decimal, packed_buf[i], 10, 2);
1027     ASSERT_EQ(E_DEC_OK, res)
1028         << decimal_testdata[i] << " wasn't converted in stage 2";
1029   }
1030   StartBenchmarkTiming();
1031 
1032   size_t dummy = 0;
1033   for (size_t i = 0; i < iters; ++i) {
1034     bin2decimal(packed_buf[i % num_elements], &decimal, 10, 2);
1035     dummy += decimal_buf[0];
1036   }
1037 
1038   ASSERT_NE(static_cast<size_t>(-1),
1039             dummy);  // To keep the optimizer from removing the loop.
1040 }
BENCHMARK(BM_Bin2Decimal_10_2)1041 BENCHMARK(BM_Bin2Decimal_10_2)
1042 
1043 static void BM_Decimal2String(size_t iterations) {
1044   StopBenchmarkTiming();
1045   constexpr size_t num_elements = array_elements(decimal_testdata);
1046   decimal_t decimals[num_elements];
1047   decimal_digit_t decimal_buf[num_elements][9];
1048 
1049   for (size_t i = 0; i < num_elements; ++i) {
1050     const char *end = strend(decimal_testdata[i]);
1051     decimals[i].buf = decimal_buf[i];
1052     decimals[i].len = array_elements(decimal_buf[i]);
1053     int res = string2decimal(decimal_testdata[i], &decimals[i], &end);
1054     ASSERT_EQ(E_DEC_OK, res) << decimal_testdata[i] << " wasn't converted";
1055   }
1056   StartBenchmarkTiming();
1057 
1058   for (size_t i = 0; i < iterations; ++i) {
1059     for (const decimal_t &dec : decimals) {
1060       char buffer[20];
1061       int length = sizeof(buffer);
1062       decimal2string(&dec, buffer, &length);
1063     }
1064   }
1065 }
1066 BENCHMARK(BM_Decimal2String)
1067 
1068 struct DecimalToStringParam {
1069   const char *input_string;
1070   int buffer_size;
1071   const char *result_string;
1072   int error_code;
1073 };
1074 
1075 class DecimalToStringTest
1076     : public testing::TestWithParam<DecimalToStringParam> {
1077  protected:
SetUp()1078   void SetUp() override { SetupDecimals(); }
1079 };
1080 
TEST_P(DecimalToStringTest,DecimalToString)1081 TEST_P(DecimalToStringTest, DecimalToString) {
1082   const char *end = strend(GetParam().input_string);
1083   EXPECT_EQ(E_DEC_OK, string2decimal(GetParam().input_string, &a, &end));
1084 
1085   char buffer[DECIMAL_MAX_STR_LENGTH + 1];
1086   int length = GetParam().buffer_size;
1087   EXPECT_EQ(GetParam().error_code, decimal2string(&a, buffer, &length));
1088   EXPECT_EQ(strlen(GetParam().result_string), length);
1089   EXPECT_STREQ(GetParam().result_string, buffer);
1090 }
1091 
1092 // Tests how decimal2string() handles the case where the buffer is too small to
1093 // hold the full decimal value.
1094 static const DecimalToStringParam TO_STRING_OVERFLOW_TRUNCATE[] = {
1095     {"123.456", 2, "3", E_DEC_OVERFLOW},
1096     {"123.456", 3, "23", E_DEC_OVERFLOW},
1097     {"123.456", 4, "123", E_DEC_TRUNCATED},
1098     {"123.456", 5, "123", E_DEC_TRUNCATED},
1099     {"123.456", 6, "123.4", E_DEC_TRUNCATED},
1100     {"123.456", 7, "123.45", E_DEC_TRUNCATED},
1101     {"123.456", 8, "123.456", E_DEC_OK},
1102     {"1230000", 3, "00", E_DEC_OVERFLOW},
1103     {"1230000", 4, "000", E_DEC_OVERFLOW},
1104     {"1230000", 5, "0000", E_DEC_OVERFLOW},
1105     {"1230000", 6, "30000", E_DEC_OVERFLOW},
1106     {"0.12345", 2, "0", E_DEC_TRUNCATED},
1107     {"0.12345", 3, "0", E_DEC_TRUNCATED},
1108     {"0.12345", 4, "0.1", E_DEC_TRUNCATED},
1109     {"0.00000", 2, "0", E_DEC_TRUNCATED},
1110     {"0.00000", 3, "0", E_DEC_TRUNCATED},
1111     {"0.00000", 4, "0.0", E_DEC_TRUNCATED},
1112 };
1113 
1114 INSTANTIATE_TEST_SUITE_P(OverflowTruncate, DecimalToStringTest,
1115                          testing::ValuesIn(TO_STRING_OVERFLOW_TRUNCATE));
1116 
1117 }  // namespace decimal_unittest
1118