用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1043 lines
35 KiB

/* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
NOTE: This is a more-or-less direct port of the main() program
in strings/decimal.c to a Google Test.
*/
#include "my_config.h"
#include <gtest/gtest.h>
#include <math.h>
#include "decimal.h"
#include "m_string.h"
#include "my_inttypes.h"
#include "my_macros.h"
#include "sql/my_decimal.h"
#include "unittest/gunit/benchmark.h"
namespace decimal_unittest {
#define DIG_PER_DEC1 9
#define DIG_BASE 1000000000
#define ROUND_UP(X) (((X) + DIG_PER_DEC1 - 1) / DIG_PER_DEC1)
typedef decimal_digit_t dec1;
int full = 0;
decimal_t a, b, c;
decimal_digit_t buf1[50], buf2[50], buf3[50];
void dump_decimal(decimal_t *d) {
int i;
printf("/* intg=%d, frac=%d, sign=%d, buf[]={", d->intg, d->frac, d->sign);
for (i = 0; i < ROUND_UP(d->frac) + ROUND_UP(d->intg) - 1; i++)
printf("%09d, ", d->buf[i]);
printf("%09d} */ ", d->buf[i]);
}
/*
The purpose of all these define wrappers is to get a "call stack"
whenever some EXPECT_XX generates a failure. A sample error message:
# .../unittest/gunit/decimal-t.cc:134: FailureValue of: s
# Actual: "0"
# Expected: orig
# Which is: "1000000000"
# arguments were: '999999999', -9, HALF_UP
# Google Test trace:
# .../unittest/gunit/decimal-t.cc:387:
# .../unittest/gunit/decimal-t.cc:686:
*/
#define check_result_code(p1, p2) \
{ \
SCOPED_TRACE(""); \
do_check_result_code(p1, p2); \
}
#define print_decimal(p1, p2, p3, p4, p5) \
{ \
SCOPED_TRACE(""); \
do_print_decimal(p1, p2, p3, p4, p5); \
}
#define test_s2d(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_s2d(p1, p2, p3); \
}
#define test_d2f(p1, p2) \
{ \
SCOPED_TRACE(""); \
do_test_d2f(p1, p2); \
}
#define test_d2b2d(p1, p2, p3, p4, p5) \
{ \
SCOPED_TRACE(""); \
do_test_d2b2d(p1, p2, p3, p4, p5); \
}
#define test_f2d(p1, p2) \
{ \
SCOPED_TRACE(""); \
do_test_f2d(p1, p2); \
}
#define test_ull2d(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_ull2d(p1, p2, p3); \
}
#define test_ll2d(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_ll2d(p1, p2, p3); \
}
#define test_d2ull(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_d2ull(p1, p2, p3); \
}
#define test_d2ll(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_d2ll(p1, p2, p3); \
}
#define test_da(p1, p2, p3, p4) \
{ \
SCOPED_TRACE(""); \
do_test_da(p1, p2, p3, p4); \
}
#define test_ds(p1, p2, p3, p4) \
{ \
SCOPED_TRACE(""); \
do_test_ds(p1, p2, p3, p4); \
}
#define test_dc(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_dc(p1, p2, p3); \
}
#define test_dm(p1, p2, p3, p4) \
{ \
SCOPED_TRACE(""); \
do_test_dm(p1, p2, p3, p4); \
}
#define test_dv(p1, p2, p3, p4) \
{ \
SCOPED_TRACE(""); \
do_test_dv(p1, p2, p3, p4); \
}
#define test_md(p1, p2, p3, p4) \
{ \
SCOPED_TRACE(""); \
do_test_md(p1, p2, p3, p4); \
}
#define test_ro(p1, p2, p3, p4, p5) \
{ \
SCOPED_TRACE(""); \
do_test_ro(p1, p2, p3, p4, p5); \
}
#define test_format(p1, p2, p3, p4, p5) \
{ \
SCOPED_TRACE(""); \
do_test_format(p1, p2, p3, p4, p5); \
}
#define test_mx(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_mx(p1, p2, p3); \
}
#define test_pr(p1, p2, p3, p4, p5, p6) \
{ \
SCOPED_TRACE(""); \
do_test_pr(p1, p2, p3, p4, p5, p6); \
}
#define test_widen_fraction(p1, p2, p3) \
{ \
SCOPED_TRACE(""); \
do_test_widen_fraction(p1, p2, p3); \
}
#define test_sh(p1, p2, p3, p4) \
{ \
SCOPED_TRACE(""); \
do_test_sh(p1, p2, p3, p4); \
}
#define test_fr(p1, p2) \
{ \
SCOPED_TRACE(""); \
do_test_fr(p1, p2); \
}
void do_check_result_code(int actual, int want) { EXPECT_EQ(want, actual); }
void do_print_decimal(decimal_t *d, const char *orig, int actual, int want,
const char *msg) {
char s[100];
int slen = sizeof(s);
if (full) dump_decimal(d);
decimal2string(d, s, &slen, 0, 0, 0);
check_result_code(actual, want);
if (orig) {
EXPECT_STREQ(orig, s) << " arguments were: " << msg;
}
}
void test_d2s() {
char s[100];
int slen, res;
/***********************************/
printf("==== decimal2string ====\n");
a.buf[0] = 12345;
a.intg = 5;
a.frac = 0;
a.sign = 0;
slen = sizeof(s);
res = decimal2string(&a, s, &slen, 0, 0, 0);
dump_decimal(&a);
printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
a.buf[1] = 987000000;
a.frac = 3;
slen = sizeof(s);
res = decimal2string(&a, s, &slen, 0, 0, 0);
dump_decimal(&a);
printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
a.sign = 1;
slen = sizeof(s);
res = decimal2string(&a, s, &slen, 0, 0, 0);
dump_decimal(&a);
printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
slen = 8;
res = decimal2string(&a, s, &slen, 0, 0, 0);
dump_decimal(&a);
printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
slen = 5;
res = decimal2string(&a, s, &slen, 0, 0, 0);
dump_decimal(&a);
printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
a.buf[0] = 987000000;
a.frac = 3;
a.intg = 0;
slen = sizeof(s);
res = decimal2string(&a, s, &slen, 0, 0, 0);
dump_decimal(&a);
printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
}
void do_test_s2d(const char *s, const char *orig, int ex) {
char s1[100];
int res;
sprintf(s1, "'%s'", s);
const char *end = strend(s);
res = string2decimal(s, &a, &end);
print_decimal(&a, orig, res, ex, s1);
}
void do_test_d2f(const char *s, int ex) {
char s1[100];
double x;
int res;
sprintf(s1, "'%s'", s);
const char *end = strend(s);
string2decimal(s, &a, &end);
res = decimal2double(&a, &x);
if (full) dump_decimal(&a);
check_result_code(res, ex);
}
void do_test_d2b2d(const char *str, int p, int s, const char *orig, int ex) {
char s1[100];
char s2[100 * 2];
uchar buf[100];
int res, i, size = decimal_bin_size(p, s);
sprintf(s1, "'%s'", str);
const char *end = strend(str);
string2decimal(str, &a, &end);
res = decimal2bin(&a, buf, p, s);
sprintf(s2, "%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size);
if (full) {
printf("0x");
for (i = 0; i < size; i++) printf("%02x", ((uchar *)buf)[i]);
}
res = bin2decimal(buf, &a, p, s);
print_decimal(&a, orig, res, ex, s2);
}
void do_test_f2d(double from, int ex) {
int res;
char s1[100];
res = double2decimal(from, &a);
sprintf(s1, "%-40.*f => res=%d ", DBL_DIG - 2, from, res);
print_decimal(&a, 0, res, ex, s1);
}
void do_test_ull2d(ulonglong from, const char *orig, int ex) {
char s[100];
char s1[100 * 2];
int res;
res = ulonglong2decimal(from, &a);
longlong10_to_str(from, s, 10);
sprintf(s1, "%-40s => res=%d ", s, res);
print_decimal(&a, orig, res, ex, s1);
}
void do_test_ll2d(longlong from, const char *orig, int ex) {
char s[100];
char s1[100 * 2];
int res;
res = longlong2decimal(from, &a);
longlong10_to_str(from, s, -10);
sprintf(s1, "%-40s => res=%d ", s, res);
print_decimal(&a, orig, res, ex, s1);
}
void do_test_d2ull(const char *s, const char *orig, int ex) {
char s1[100];
char s2[100 * 2];
ulonglong x;
int res;
const char *end = strend(s);
string2decimal(s, &a, &end);
res = decimal2ulonglong(&a, &x);
if (full) dump_decimal(&a);
longlong10_to_str(x, s1, 10);
sprintf(s2, "%-40s => res=%d %s\n", s, res, s1);
check_result_code(res, ex);
if (orig) {
EXPECT_STREQ(orig, s1) << " arguments were: " << s2;
}
}
void do_test_d2ll(const char *s, const char *orig, int ex) {
char s1[100];
char s2[100 * 2];
longlong x;
int res;
const char *end = strend(s);
string2decimal(s, &a, &end);
res = decimal2longlong(&a, &x);
if (full) dump_decimal(&a);
longlong10_to_str(x, s1, -10);
sprintf(s2, "%-40s => res=%d %s\n", s, res, s1);
check_result_code(res, ex);
if (orig) {
EXPECT_STREQ(orig, s1) << " arguments were: " << s2;
}
}
void do_test_da(const char *s1, const char *s2, const char *orig, int ex) {
char s[100];
int res;
sprintf(s, "'%s' + '%s'", s1, s2);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
end = strend(s2);
string2decimal(s2, &b, &end);
res = decimal_add(&a, &b, &c);
print_decimal(&c, orig, res, ex, s);
}
void do_test_ds(const char *s1, const char *s2, const char *orig, int ex) {
char s[100];
int res;
sprintf(s, "'%s' - '%s'", s1, s2);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
end = strend(s2);
string2decimal(s2, &b, &end);
res = decimal_sub(&a, &b, &c);
print_decimal(&c, orig, res, ex, s);
}
void do_test_dc(const char *s1, const char *s2, int orig) {
char s[100];
int res;
sprintf(s, "'%s' <=> '%s'", s1, s2);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
end = strend(s2);
string2decimal(s2, &b, &end);
res = decimal_cmp(&a, &b);
EXPECT_EQ(orig, res) << " arguments were: " << s;
}
void do_test_dm(const char *s1, const char *s2, const char *orig, int ex) {
char s[100];
int res;
sprintf(s, "'%s' * '%s'", s1, s2);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
end = strend(s2);
string2decimal(s2, &b, &end);
res = decimal_mul(&a, &b, &c);
print_decimal(&c, orig, res, ex, s);
}
void do_test_dv(const char *s1, const char *s2, const char *orig, int ex) {
char s[100];
int res;
sprintf(s, "'%s' / '%s'", s1, s2);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
end = strend(s2);
string2decimal(s2, &b, &end);
res = decimal_div(&a, &b, &c, 5);
check_result_code(res, ex);
if (res != E_DEC_DIV_ZERO) print_decimal(&c, orig, res, ex, s);
}
void do_test_md(const char *s1, const char *s2, const char *orig, int ex) {
char s[100];
int res;
sprintf(s, "'%s' %% '%s'", s1, s2);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
end = strend(s2);
string2decimal(s2, &b, &end);
res = decimal_mod(&a, &b, &c);
check_result_code(res, ex);
if (res != E_DEC_DIV_ZERO) print_decimal(&c, orig, res, ex, s);
}
const char *round_mode[] = {"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING",
"FLOOR"};
void do_test_ro(const char *s1, int n, decimal_round_mode mode,
const char *orig, int ex) {
char s[100];
int res;
sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
res = decimal_round(&a, &b, n, mode);
print_decimal(&b, orig, res, ex, s);
}
void do_test_format(const char *s1, const char *s2, int n, const char *orig,
int ex) {
char s[200];
decimal_t a, b, c, d;
decimal_digit_t buf1[9], buf2[9], buf3[9], buf4[9];
int res;
a.buf = buf1;
b.buf = buf2;
c.buf = buf3;
d.buf = buf4;
a.len = sizeof(buf1) / sizeof(dec1);
b.len = sizeof(buf2) / sizeof(dec1);
c.len = sizeof(buf3) / sizeof(dec1);
d.len = sizeof(buf4) / sizeof(dec1);
sprintf(s, "'%s' %% '%s'", s1, s2);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
end = strend(s2);
string2decimal(s2, &b, &end);
decimal_mod(&a, &b, &c);
res = decimal_round(&c, &d, n, HALF_UP);
print_decimal(&d, orig, res, ex, s);
}
void do_test_mx(int precision, int frac, const char *orig) {
char s[100];
sprintf(s, "%d, %d", precision, frac);
max_decimal(precision, frac, &a);
print_decimal(&a, orig, 0, 0, s);
}
void do_test_pr(const char *s1, int prec, int dec, char filler,
const char *orig, int ex) {
char s[100];
char s2[100];
int slen = sizeof(s2);
int res;
if (filler)
sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler);
else
sprintf(s, "'%s', %d, %d, '\\0'", s1, prec, dec);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
res = decimal2string(&a, s2, &slen, prec, dec, filler);
check_result_code(res, ex);
if (orig) {
EXPECT_STREQ(orig, s2) << " arguments were: " << s;
}
}
void do_test_widen_fraction(const char *s1, int increase, const char *orig) {
decimal_t a;
decimal_digit_t buf1[9];
a.buf = buf1;
a.len = array_elements(buf1);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
widen_fraction(a.frac + increase, &a);
char s[100];
int slen = sizeof(s);
int result = decimal2string(&a, s, &slen, 0, 0, 0);
EXPECT_EQ(result, 0);
EXPECT_STREQ(orig, s) << " arguments were: " << s1;
}
void do_test_sh(const char *s1, int shift, const char *orig, int ex) {
char s[100];
int res;
sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
const char *end = strend(s1);
string2decimal(s1, &a, &end);
res = decimal_shift(&a, shift);
print_decimal(&a, orig, res, ex, s);
}
void do_test_fr(const char *s1, const char *orig) {
char s[100];
sprintf(s, "'%s'", s1);
const char *end = strend(s1);
string2decimal(s1, &a, &end);
a.frac = decimal_actual_fraction(&a);
print_decimal(&a, orig, 0, 0, s);
}
class DecimalTest : public ::testing::Test {
protected:
virtual void SetUp() {
a.buf = buf1;
a.len = sizeof(buf1) / sizeof(dec1);
b.buf = buf2;
b.len = sizeof(buf2) / sizeof(dec1);
c.buf = buf3;
c.len = sizeof(buf3) / sizeof(dec1);
}
};
TEST_F(DecimalTest, String2Decimal) {
test_s2d("12345", "12345", 0);
test_s2d("12345.", "12345", 0);
test_s2d("123.45", "123.45", 0);
test_s2d("-123.45", "-123.45", 0);
test_s2d(".00012345000098765", "0.00012345000098765", 0);
test_s2d(".12345000098765", "0.12345000098765", 0);
test_s2d("-.000000012345000098765", "-0.000000012345000098765", 0);
test_s2d("1234500009876.5", "1234500009876.5", 0);
a.len = 1;
test_s2d("123450000098765", "98765", 2);
test_s2d("123450.000098765", "123450", 1);
a.len = sizeof(buf1) / sizeof(dec1);
test_s2d("123E5", "12300000", 0);
test_s2d("123E-2", "1.23", 0);
}
TEST_F(DecimalTest, Decimal2Double) {
test_d2f("12345", 0);
test_d2f("123.45", 0);
test_d2f("-123.45", 0);
test_d2f("0.00012345000098765", 0);
test_d2f("1234500009876.5", 0);
}
TEST_F(DecimalTest, Double2Decimal) {
test_f2d(12345, 0);
test_f2d(1.0 / 3, 0);
test_f2d(-123.45, 0);
test_f2d(0.00012345000098765, 0);
test_f2d(1234500009876.5, 0);
}
TEST_F(DecimalTest, Ulonglong2Decimal) {
test_ull2d(12345ULL, "12345", 0);
test_ull2d(0ULL, "0", 0);
test_ull2d(18446744073709551615ULL, "18446744073709551615", 0);
}
TEST_F(DecimalTest, Decimal2Ulonglong) {
test_d2ull("12345", "12345", 0);
test_d2ull("0", "0", 0);
/* ULLONG_MAX = 18446744073709551615ULL */
test_d2ull("18446744073709551615", "18446744073709551615", 0);
test_d2ull("18446744073709551616", "18446744073709551615", 2);
test_d2ull("-1", "0", 2);
test_d2ull("1.23", "1", 1);
test_d2ull("9999999999999999999999999.000", "18446744073709551615", 2);
}
TEST_F(DecimalTest, Longlong2Decimal) {
test_ll2d(-12345LL, "-12345", 0);
test_ll2d(-1LL, "-1", 0);
test_ll2d(-9223372036854775807LL, "-9223372036854775807", 0);
test_ll2d(9223372036854775808ULL, "-9223372036854775808", 0);
}
TEST_F(DecimalTest, Decimal2Longlong) {
/* LLONG_MAX = 9223372036854775807LL */
test_d2ll("18446744073709551615", "9223372036854775807", 2);
test_d2ll("-1", "-1", 0);
test_d2ll("-1.23", "-1", 1);
test_d2ll("-9223372036854775807", "-9223372036854775807", 0);
test_d2ll("-9223372036854775808", "-9223372036854775808", 0);
test_d2ll("9223372036854775808", "9223372036854775807", 2);
}
TEST_F(DecimalTest, DoAdd) {
test_da(".00012345000098765", "123.45", "123.45012345000098765", 0);
test_da(".1", ".45", "0.55", 0);
test_da("1234500009876.5", ".00012345000098765",
"1234500009876.50012345000098765", 0);
test_da("9999909999999.5", ".555", "9999910000000.055", 0);
test_da("99999999", "1", "100000000", 0);
test_da("989999999", "1", "990000000", 0);
test_da("999999999", "1", "1000000000", 0);
test_da("12345", "123.45", "12468.45", 0);
test_da("-12345", "-123.45", "-12468.45", 0);
test_ds("-12345", "123.45", "-12468.45", 0);
test_ds("12345", "-123.45", "12468.45", 0);
}
TEST_F(DecimalTest, DoSub) {
test_ds(".00012345000098765", "123.45", "-123.44987654999901235", 0);
test_ds("1234500009876.5", ".00012345000098765",
"1234500009876.49987654999901235", 0);
test_ds("9999900000000.5", ".555", "9999899999999.945", 0);
test_ds("1111.5551", "1111.555", "0.0001", 0);
test_ds(".555", ".555", "0", 0);
test_ds("10000000", "1", "9999999", 0);
test_ds("1000001000", ".1", "1000000999.9", 0);
test_ds("1000000000", ".1", "999999999.9", 0);
test_ds("12345", "123.45", "12221.55", 0);
test_ds("-12345", "-123.45", "-12221.55", 0);
test_da("-12345", "123.45", "-12221.55", 0);
test_da("12345", "-123.45", "12221.55", 0);
test_ds("123.45", "12345", "-12221.55", 0);
test_ds("-123.45", "-12345", "12221.55", 0);
test_da("123.45", "-12345", "-12221.55", 0);
test_da("-123.45", "12345", "12221.55", 0);
test_da("5", "-6.0", "-1.0", 0);
}
TEST_F(DecimalTest, DecimalMul) {
test_dm("12", "10", "120", 0);
test_dm("-123.456", "98765.4321", "-12193185.1853376", 0);
test_dm("-123456000000", "98765432100000", "-12193185185337600000000000", 0);
test_dm("123456", "987654321", "121931851853376", 0);
test_dm("123456", "9876543210", "1219318518533760", 0);
test_dm("123", "0.01", "1.23", 0);
test_dm("123", "0", "0", 0);
}
TEST_F(DecimalTest, DecimalDiv) {
test_dv("120", "10", "12.000000000", 0);
test_dv("123", "0.01", "12300.000000000", 0);
test_dv("120", "100000000000.00000", "0.000000001200000000", 0);
test_dv("123", "0", "", 4);
test_dv("0", "0", "", 4);
test_dv("-12193185.1853376", "98765.4321", "-123.456000000000000000", 0);
test_dv("121931851853376", "987654321", "123456.000000000", 0);
test_dv("0", "987", "0", 0);
test_dv("1", "3", "0.333333333", 0);
test_dv("1.000000000000", "3", "0.333333333333333333", 0);
test_dv("1", "1", "1.000000000", 0);
test_dv("0.0123456789012345678912345", "9999999999",
"0.000000000001234567890246913578148141", 0);
test_dv("10.333000000", "12.34500", "0.837019036046982584042122316", 0);
test_dv("10.000000000060", "2", "5.000000000030000000", 0);
}
TEST_F(DecimalTest, DecimalMod) {
test_md("234", "10", "4", 0);
test_md("234.567", "10.555", "2.357", 0);
test_md("-234.567", "10.555", "-2.357", 0);
test_md("234.567", "-10.555", "2.357", 0);
c.buf[1] = 0x3ABECA;
test_md("99999999999999999999999999999999999999", "3", "0", 0);
if (c.buf[1] != 0x3ABECA) {
ADD_FAILURE() << "overflow " << c.buf[1];
}
}
TEST_F(DecimalTest, Decimal2BinBin2Decimal) {
test_d2b2d("-10.55", 4, 2, "-10.55", 0);
test_d2b2d("0.0123456789012345678912345", 30, 25,
"0.0123456789012345678912345", 0);
test_d2b2d("12345", 5, 0, "12345", 0);
test_d2b2d("12345", 10, 3, "12345.000", 0);
test_d2b2d("123.45", 10, 3, "123.450", 0);
test_d2b2d("-123.45", 20, 10, "-123.4500000000", 0);
test_d2b2d(".00012345000098765", 15, 14, "0.00012345000098", 0);
test_d2b2d(".00012345000098765", 22, 20, "0.00012345000098765000", 0);
test_d2b2d(".12345000098765", 30, 20, "0.12345000098765000000", 0);
test_d2b2d("-.000000012345000098765", 30, 20, "-0.00000001234500009876", 0);
test_d2b2d("1234500009876.5", 30, 5, "1234500009876.50000", 0);
test_d2b2d("111111111.11", 10, 2, "11111111.11", 0);
test_d2b2d("000000000.01", 7, 3, "0.010", 0);
test_d2b2d("123.4", 10, 2, "123.40", 0);
}
TEST_F(DecimalTest, DecimalCmp) {
test_dc("12", "13", -1);
test_dc("13", "12", 1);
test_dc("-10", "10", -1);
test_dc("10", "-10", 1);
test_dc("-12", "-13", 1);
test_dc("0", "12", -1);
test_dc("-10", "0", -1);
test_dc("4", "4", 0);
}
TEST_F(DecimalTest, DecimalRound) {
test_ro("5678.123451", -4, TRUNCATE, "0", 0);
test_ro("5678.123451", -3, TRUNCATE, "5000", 0);
test_ro("5678.123451", -2, TRUNCATE, "5600", 0);
test_ro("5678.123451", -1, TRUNCATE, "5670", 0);
test_ro("5678.123451", 0, TRUNCATE, "5678", 0);
test_ro("5678.123451", 1, TRUNCATE, "5678.1", 0);
test_ro("5678.123451", 2, TRUNCATE, "5678.12", 0);
test_ro("5678.123451", 3, TRUNCATE, "5678.123", 0);
test_ro("5678.123451", 4, TRUNCATE, "5678.1234", 0);
test_ro("5678.123451", 5, TRUNCATE, "5678.12345", 0);
test_ro("5678.123451", 6, TRUNCATE, "5678.123451", 0);
test_ro("-5678.123451", -4, TRUNCATE, "0", 0);
memset(buf2, 33, sizeof(buf2));
test_ro("99999999999999999999999999999999999999", -31, TRUNCATE,
"99999990000000000000000000000000000000", 0);
test_ro("15.1", 0, HALF_UP, "15", 0);
test_ro("15.5", 0, HALF_UP, "16", 0);
test_ro("15.9", 0, HALF_UP, "16", 0);
test_ro("-15.1", 0, HALF_UP, "-15", 0);
test_ro("-15.5", 0, HALF_UP, "-16", 0);
test_ro("-15.9", 0, HALF_UP, "-16", 0);
test_ro("15.1", 1, HALF_UP, "15.1", 0);
test_ro("-15.1", 1, HALF_UP, "-15.1", 0);
test_ro("15.17", 1, HALF_UP, "15.2", 0);
test_ro("15.4", -1, HALF_UP, "20", 0);
test_ro("-15.4", -1, HALF_UP, "-20", 0);
test_ro("5.4", -1, HALF_UP, "10", 0);
test_ro(".999", 0, HALF_UP, "1", 0);
memset(buf2, 33, sizeof(buf2));
test_ro("999999999", -9, HALF_UP, "1000000000", 0);
test_ro("15.1", 0, HALF_EVEN, "15", 0);
test_ro("15.5", 0, HALF_EVEN, "16", 0);
test_ro("14.5", 0, HALF_EVEN, "14", 0);
test_ro("15.9", 0, HALF_EVEN, "16", 0);
test_ro("15.1", 0, CEILING, "16", 0);
test_ro("-15.1", 0, CEILING, "-15", 0);
test_ro("15.1", 0, FLOOR, "15", 0);
test_ro("-15.1", 0, FLOOR, "-16", 0);
test_ro("999999999999999999999.999", 0, CEILING, "1000000000000000000000", 0);
test_ro("-999999999999999999999.999", 0, FLOOR, "-1000000000000000000000", 0);
b.buf[0] = DIG_BASE + 1;
b.buf++;
test_ro(".3", 0, HALF_UP, "0", 0);
b.buf--;
if (b.buf[0] != DIG_BASE + 1) {
ADD_FAILURE() << "underflow " << b.buf[0];
}
}
TEST_F(DecimalTest, FormatFunc) {
test_format("999999999999999999999999999999999999999999999999999999999999999",
"999999999999999999999999999999999999999999999999999999999999999",
42, "0.000000000000000000000000000000000000000000", 0);
}
TEST_F(DecimalTest, MaxDecimal) {
test_mx(1, 1, "0.9");
test_mx(1, 0, "9");
test_mx(2, 1, "9.9");
test_mx(4, 2, "99.99");
test_mx(6, 3, "999.999");
test_mx(8, 4, "9999.9999");
test_mx(10, 5, "99999.99999");
test_mx(12, 6, "999999.999999");
test_mx(14, 7, "9999999.9999999");
test_mx(16, 8, "99999999.99999999");
test_mx(18, 9, "999999999.999999999");
test_mx(20, 10, "9999999999.9999999999");
test_mx(20, 20, "0.99999999999999999999");
test_mx(20, 0, "99999999999999999999");
test_mx(40, 20, "99999999999999999999.99999999999999999999");
}
TEST_F(DecimalTest, Decimal2String) {
test_pr("123.123", 0, 0, 0, "123.123", 0);
/* For fixed precision, we no longer count the '.' here. */
test_pr("123.123", 6, 3, '0', "123.123", 0);
test_pr("123.123", 8, 3, '0', "00123.123", 0);
test_pr("123.123", 8, 4, '0', "0123.1230", 0);
test_pr("123.123", 8, 5, '0', "123.12300", 0);
test_pr("123.123", 8, 2, '0', "000123.12", 1);
test_pr("123.123", 8, 6, '0', "23.123000", 2);
}
TEST_F(DecimalTest, WidenFraction) {
test_widen_fraction("123.0", 1, "123.00");
test_widen_fraction("1234567890.123456789", 1, "1234567890.1234567890");
test_widen_fraction("123.0", 0, "123.0");
test_widen_fraction("123.0", 4, "123.00000");
}
TEST_F(DecimalTest, DecimalShift) {
test_sh("123.123", 1, "1231.23", 0);
test_sh("123457189.123123456789000", 1, "1234571891.23123456789", 0);
test_sh("123457189.123123456789000", 4, "1234571891231.23456789", 0);
test_sh("123457189.123123456789000", 8, "12345718912312345.6789", 0);
test_sh("123457189.123123456789000", 9, "123457189123123456.789", 0);
test_sh("123457189.123123456789000", 10, "1234571891231234567.89", 0);
test_sh("123457189.123123456789000", 17, "12345718912312345678900000", 0);
test_sh("123457189.123123456789000", 18, "123457189123123456789000000", 0);
test_sh("123457189.123123456789000", 19, "1234571891231234567890000000", 0);
test_sh("123457189.123123456789000", 26,
"12345718912312345678900000000000000", 0);
test_sh("123457189.123123456789000", 27,
"123457189123123456789000000000000000", 0);
test_sh("123457189.123123456789000", 28,
"1234571891231234567890000000000000000", 0);
test_sh("000000000000000000000000123457189.123123456789000", 26,
"12345718912312345678900000000000000", 0);
test_sh("00000000123457189.123123456789000", 27,
"123457189123123456789000000000000000", 0);
test_sh("00000000000000000123457189.123123456789000", 28,
"1234571891231234567890000000000000000", 0);
test_sh("123", 1, "1230", 0);
test_sh("123", 10, "1230000000000", 0);
test_sh(".123", 1, "1.23", 0);
test_sh(".123", 10, "1230000000", 0);
test_sh(".123", 14, "12300000000000", 0);
test_sh("000.000", 1000, "0", 0);
test_sh("000.", 1000, "0", 0);
test_sh(".000", 1000, "0", 0);
test_sh("1", 1000, "1", 2);
test_sh("123.123", -1, "12.3123", 0);
test_sh("123987654321.123456789000", -1, "12398765432.1123456789", 0);
test_sh("123987654321.123456789000", -2, "1239876543.21123456789", 0);
test_sh("123987654321.123456789000", -3, "123987654.321123456789", 0);
test_sh("123987654321.123456789000", -8, "1239.87654321123456789", 0);
test_sh("123987654321.123456789000", -9, "123.987654321123456789", 0);
test_sh("123987654321.123456789000", -10, "12.3987654321123456789", 0);
test_sh("123987654321.123456789000", -11, "1.23987654321123456789", 0);
test_sh("123987654321.123456789000", -12, "0.123987654321123456789", 0);
test_sh("123987654321.123456789000", -13, "0.0123987654321123456789", 0);
test_sh("123987654321.123456789000", -14, "0.00123987654321123456789", 0);
test_sh("00000087654321.123456789000", -14, "0.00000087654321123456789", 0);
a.len = 2;
test_sh("123.123", -2, "1.23123", 0);
test_sh("123.123", -3, "0.123123", 0);
test_sh("123.123", -6, "0.000123123", 0);
test_sh("123.123", -7, "0.0000123123", 0);
test_sh("123.123", -15, "0.000000000000123123", 0);
test_sh("123.123", -16, "0.000000000000012312", 1);
test_sh("123.123", -17, "0.000000000000001231", 1);
test_sh("123.123", -18, "0.000000000000000123", 1);
test_sh("123.123", -19, "0.000000000000000012", 1);
test_sh("123.123", -20, "0.000000000000000001", 1);
test_sh("123.123", -21, "0", 1);
test_sh(".000000000123", -1, "0.0000000000123", 0);
test_sh(".000000000123", -6, "0.000000000000000123", 0);
test_sh(".000000000123", -7, "0.000000000000000012", 1);
test_sh(".000000000123", -8, "0.000000000000000001", 1);
test_sh(".000000000123", -9, "0", 1);
test_sh(".000000000123", 1, "0.00000000123", 0);
test_sh(".000000000123", 8, "0.0123", 0);
test_sh(".000000000123", 9, "0.123", 0);
test_sh(".000000000123", 10, "1.23", 0);
test_sh(".000000000123", 17, "12300000", 0);
test_sh(".000000000123", 18, "123000000", 0);
test_sh(".000000000123", 19, "1230000000", 0);
test_sh(".000000000123", 20, "12300000000", 0);
test_sh(".000000000123", 21, "123000000000", 0);
test_sh(".000000000123", 22, "1230000000000", 0);
test_sh(".000000000123", 23, "12300000000000", 0);
test_sh(".000000000123", 24, "123000000000000", 0);
test_sh(".000000000123", 25, "1230000000000000", 0);
test_sh(".000000000123", 26, "12300000000000000", 0);
test_sh(".000000000123", 27, "123000000000000000", 0);
test_sh(".000000000123", 28, "0.000000000123", 2);
test_sh("123456789.987654321", -1, "12345678.998765432", 1);
test_sh("123456789.987654321", -2, "1234567.899876543", 1);
test_sh("123456789.987654321", -8, "1.234567900", 1);
test_sh("123456789.987654321", -9, "0.123456789987654321", 0);
test_sh("123456789.987654321", -10, "0.012345678998765432", 1);
test_sh("123456789.987654321", -17, "0.000000001234567900", 1);
test_sh("123456789.987654321", -18, "0.000000000123456790", 1);
test_sh("123456789.987654321", -19, "0.000000000012345679", 1);
test_sh("123456789.987654321", -26, "0.000000000000000001", 1);
test_sh("123456789.987654321", -27, "0", 1);
test_sh("123456789.987654321", 1, "1234567900", 1);
test_sh("123456789.987654321", 2, "12345678999", 1);
test_sh("123456789.987654321", 4, "1234567899877", 1);
test_sh("123456789.987654321", 8, "12345678998765432", 1);
test_sh("123456789.987654321", 9, "123456789987654321", 0);
test_sh("123456789.987654321", 10, "123456789.987654321", 2);
test_sh("123456789.987654321", 0, "123456789.987654321", 0);
a.len = sizeof(buf1) / sizeof(dec1);
}
TEST_F(DecimalTest, DecimalActualFraction) {
test_fr("1.123456789000000000", "1.123456789");
test_fr("1.12345678000000000", "1.12345678");
test_fr("1.1234567000000000", "1.1234567");
test_fr("1.123456000000000", "1.123456");
test_fr("1.12345000000000", "1.12345");
test_fr("1.1234000000000", "1.1234");
test_fr("1.123000000000", "1.123");
test_fr("1.12000000000", "1.12");
test_fr("1.1000000000", "1.1");
test_fr("1.000000000", "1");
test_fr("1.0", "1");
test_fr("10000000000000000000.0", "10000000000000000000");
}
// Some test data from DBT-3.
static const char *decimal_testdata[] = {
"45983.16", "0.09", "983", "0.09", "36.00", "45983.16",
"0.09", "0.1", "8.00", "13309.60", "0.10", "28955.64",
"0", "28.00", "28955.64", "0.09", "0", "24.00",
"22824.48", "0.10", "49620.16", "0.07", "32.00", "49620.16",
"0.07", "0.0", "38.00", "44694.46", "0.00", "45.00",
"4058", "54058.05", "0.06", "058", "0.06", "45.00",
"4058", "0.0", "49.00", "796", "46796.47", "73426.50",
"0.08", "0", "37.00", "61998.31", "0.08", "13608.60",
"0.07", "12.00", "13608.60", "0.07", "0.0", "9.00",
"11594.16", "0.08", "81639.88", "0", "46.00", "81639.88",
"0.10", "0", "28.00", "31809.96", "0.03", "73943.82",
"0.08", "38.00", "73943.82", "0.08", "0.0", "35.00",
"43058.75", "0.06", "6476.15", "0", "5.00", "6476.15",
"0.04", "0", "28.00", "47227.60", "0.05", "64605.44",
"0.02", "32.00", "64605.44", "0.02", "0.0", "2.00",
"2210.32", "0.09", "6582.96", "0", "4.00", "6582.96",
"0.09", "0", "44.00", "79059.64", "0.05", "9159.66",
"0.04", "6.00", "9159.66", "0.04", "0.0", "31.00",
"40217.23", "0.09", "47344.32", "0", "32.00", "47344.32",
"0.02", "0", "5.00", "7532.30", "0.05", "41.00",
"28", "75928.31", "0.09", "41.00", "75928.31", "0.09",
"0.0", "24.00", "32410.80", "32410.80", "0.02", "68065.96",
"0", "34.00", "68065.96", "0.06", "0", "7.00",
"13418.23", "0.06", "29004.25", "0.06", "25.00", "29004.25",
"0.06", "0.0", "34.00", "65854.94", "0.08", "47397.28",
"0", "28.00", "47397.28", "0.03", "0", "42.00",
"75043.92", "0.09", "62105.20", "0.09", "40.00", "62105.20",
"0.09", "0.0", "39.00", "70542.42", "0.05", "78083.70",
"0", "43.00", "78083.70", "0.05", "0", "44.00",
"84252.52", "0.04", "53782.08", "0.09", "44.00", "53782.08",
"0.09", "0.0", "26.00", "43383.08", "0.08", "82746.18",
"0", "46.00", "82746.18", "0.06", "0", "32.00",
"48338.88", "0.07", "63360.93", "0.01", "43.00", "63360.93",
"0.01", "0.0", "40.00", "54494.40", "0.06", "21.00",
"75", "40675.95", "0", "21.00", "40675.95", "0.05",
"0", "26.00", "42995.94", "0.03", "39353.82", "0.00",
"22.00", "39353.82", "0.00", "0.0", "21.00", "27076.98",
"0.09", "31.00"};
static void BM_Decimal2Bin_10_2(size_t iters) {
StopBenchmarkTiming();
constexpr size_t num_elements = array_elements(decimal_testdata);
decimal_t decimals[num_elements];
decimal_digit_t decimal_buf[num_elements][9];
for (size_t i = 0; i < num_elements; ++i) {
const char *end = strend(decimal_testdata[i]);
decimals[i].buf = decimal_buf[i];
decimals[i].len = array_elements(decimal_buf[i]);
int res = string2decimal(decimal_testdata[i], &decimals[i], &end);
ASSERT_EQ(E_DEC_OK, res) << decimal_testdata[i] << " wasn't converted";
}
StartBenchmarkTiming();
int dummy = 0;
for (size_t i = 0; i < iters; ++i) {
uchar buf[100];
decimal2bin(&decimals[i % num_elements], buf, 10, 2);
dummy += buf[0];
}
ASSERT_NE(0, dummy); // To keep the optimizer from removing the loop.
}
BENCHMARK(BM_Decimal2Bin_10_2)
static void BM_Bin2Decimal_10_2(size_t iters) {
StopBenchmarkTiming();
constexpr size_t num_elements = array_elements(decimal_testdata);
constexpr int bin_size = 5;
ASSERT_EQ(bin_size, decimal_bin_size(10, 2)) << "Need to adjust bin_size";
uchar packed_buf[num_elements][bin_size];
decimal_t decimal;
decimal_digit_t decimal_buf[9];
decimal.buf = decimal_buf;
decimal.len = array_elements(decimal_buf);
for (size_t i = 0; i < num_elements; ++i) {
const char *end = strend(decimal_testdata[i]);
int res = string2decimal(decimal_testdata[i], &decimal, &end);
ASSERT_EQ(E_DEC_OK, res) << decimal_testdata[i] << " wasn't converted";
res = decimal2bin(&decimal, packed_buf[i], 10, 2);
ASSERT_EQ(E_DEC_OK, res)
<< decimal_testdata[i] << " wasn't converted in stage 2";
}
StartBenchmarkTiming();
size_t dummy = 0;
for (size_t i = 0; i < iters; ++i) {
bin2decimal(packed_buf[i % num_elements], &decimal, 10, 2);
dummy += decimal_buf[0];
}
ASSERT_NE(static_cast<size_t>(-1),
dummy); // To keep the optimizer from removing the loop.
}
BENCHMARK(BM_Bin2Decimal_10_2)
} // namespace decimal_unittest