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