/* Copyright (c) 2011, 2015, 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 as published by the Free Software Foundation; version 2 of the License. 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 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 Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "my_config.h" #include #include "test_utils.h" #include namespace my_decimal_unittest { using my_testing::chars_2_decimal; using my_testing::Server_initializer; using my_testing::Mock_error_handler; class DecimalTest : public ::testing::Test { protected: virtual void SetUp() { initializer.SetUp(); } virtual void TearDown() { initializer.TearDown(); } THD *thd() { return initializer.thd(); } Server_initializer initializer; my_decimal d1; my_decimal d2; }; TEST_F(DecimalTest, CopyAndCompare) { ulonglong val= 42; EXPECT_EQ(0, ulonglong2decimal(val, &d1)); d2= d1; // operator=() my_decimal d3(d1); // Copy constructor. EXPECT_EQ(0, my_decimal_cmp(&d1, &d2)); EXPECT_EQ(0, my_decimal_cmp(&d2, &d3)); EXPECT_EQ(0, my_decimal_cmp(&d3, &d1)); ulonglong val1, val2, val3; EXPECT_EQ(0, decimal2ulonglong(&d1, &val1)); EXPECT_EQ(0, decimal2ulonglong(&d2, &val2)); EXPECT_EQ(0, decimal2ulonglong(&d3, &val3)); EXPECT_EQ(val, val1); EXPECT_EQ(val, val2); EXPECT_EQ(val, val3); // The CTOR/operator=() generated by the compiler would fail here: val= 45; EXPECT_EQ(0, ulonglong2decimal(val, &d1)); EXPECT_EQ(1, my_decimal_cmp(&d1, &d2)); EXPECT_EQ(1, my_decimal_cmp(&d1, &d3)); } TEST_F(DecimalTest, RoundOverflow) { const char arg_str[]= "999999999"; String str(arg_str, &my_charset_bin); EXPECT_EQ(E_DEC_OK, string2my_decimal(E_DEC_FATAL_ERROR, &str, &d1)); d1.sanity_check(); for (int ix= 0; ix < DECIMAL_MAX_POSSIBLE_PRECISION; ++ix) { my_decimal d3; const int expect= (ix + str.length() <= DECIMAL_MAX_POSSIBLE_PRECISION) ? E_DEC_OK : E_DEC_TRUNCATED; const bool do_truncate= true; EXPECT_EQ(expect, my_decimal_round(E_DEC_FATAL_ERROR, &d1, ix, do_truncate, &d3)) << "ix:" << ix; d3.sanity_check(); EXPECT_EQ(0, my_decimal_cmp(&d1, &d3)); } } TEST_F(DecimalTest, Swap) { ulonglong val1= 1; ulonglong val2= 2; EXPECT_EQ(0, ulonglong2decimal(val1, &d1)); EXPECT_EQ(0, ulonglong2decimal(val2, &d2)); my_decimal d1copy(d1); my_decimal d2copy(d2); EXPECT_EQ(0, my_decimal_cmp(&d1, &d1copy)); EXPECT_EQ(0, my_decimal_cmp(&d2, &d2copy)); d1.swap(d2); EXPECT_EQ(0, my_decimal_cmp(&d2, &d1copy)); EXPECT_EQ(0, my_decimal_cmp(&d1, &d2copy)); } TEST_F(DecimalTest, Multiply) { const char arg1[]= "000000001." "10000000000000000000" "00000000000000000000" "00000000000000000000" "000000000000"; const char arg2[]= "1.75"; char buff[DECIMAL_MAX_STR_LENGTH]; int bufsz; my_decimal prod; EXPECT_EQ(E_DEC_OK, chars_2_decimal(arg1, &d1)); EXPECT_EQ(E_DEC_OK, chars_2_decimal(arg2, &d2)); // Limit the precision, otherwise "1.75" will be truncated to "1." set_if_smaller(d1.frac, NOT_FIXED_DEC); set_if_smaller(d2.frac, NOT_FIXED_DEC); EXPECT_EQ(0, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, &prod, &d1, &d2)); EXPECT_EQ(NOT_FIXED_DEC, d1.frac); EXPECT_EQ(2, d2.frac); EXPECT_EQ(NOT_FIXED_DEC, prod.frac); bufsz= sizeof(buff); EXPECT_EQ(0, decimal2string(&prod, buff, &bufsz, 0, 0, 0)); EXPECT_STREQ("1.9250000000000000000000000000000", buff); } /* This is a simple iterative implementation based on addition and subtraction, for verifying the result of decimal_mod(). decimal_mod() says: DESCRIPTION the modulus R in R = M mod N is defined as 0 <= |R| < |M| sign R == sign M R = M - k*N, where k is integer thus, there's no requirement for M or N to be integers */ int decimal_modulo(uint mask, my_decimal *res, const my_decimal *m, const my_decimal *n) { my_decimal abs_m(*m); my_decimal abs_n(*n); abs_m.sign(false); abs_n.sign(false); my_decimal r; my_decimal k1(abs_n); my_decimal kn(decimal_zero); my_decimal next_r(abs_m); int ret; do { r= next_r; my_decimal res; if ((ret= my_decimal_add(E_DEC_FATAL_ERROR, &res, &k1, &kn)) != E_DEC_OK) { ADD_FAILURE(); return ret; } kn= res; if ((ret= my_decimal_sub(E_DEC_FATAL_ERROR, &next_r, &abs_m, &kn) != E_DEC_OK)) { ADD_FAILURE(); return ret; } } while (my_decimal_cmp(&next_r, &decimal_zero) >= 0); r.sign(m->sign()); *res= r; return 0; } struct Mod_data { const char *a; const char *b; const char *result; }; Mod_data mod_test_input[]= { { "234" , "10", "4" }, { "234.567" , "10.555", "2.357" }, { "-234.567", "10.555", "-2.357" }, { "234.567" , "-10.555", "2.357" }, { "-234.567", "-10.555", "-2.357" }, { "999" , "0.1", "0.0" }, { "999" , "0.7", "0.1" }, { "10" , "123", "10" }, { NULL, NULL, NULL} }; TEST_F(DecimalTest, Modulo) { my_decimal expected_result; my_decimal xxx_result; my_decimal mod_result; char buff_x[DECIMAL_MAX_STR_LENGTH]; char buff_m[DECIMAL_MAX_STR_LENGTH]; for (Mod_data *pd= mod_test_input; pd->a; ++pd) { int bufsz_x= sizeof(buff_x); int bufsz_m= sizeof(buff_m); EXPECT_EQ(0, chars_2_decimal(pd->a, &d1)); EXPECT_EQ(0, chars_2_decimal(pd->b, &d2)); EXPECT_EQ(0, chars_2_decimal(pd->result, &expected_result)); EXPECT_EQ(0, my_decimal_mod(E_DEC_FATAL_ERROR, &mod_result, &d1, &d2)); EXPECT_EQ(0, decimal2string(&mod_result, buff_m, &bufsz_m, 0, 0, 0)); EXPECT_EQ(0, my_decimal_cmp(&expected_result, &mod_result)) << " a:" << pd->a << " b:" << pd->b << " expected:" << pd->result << " got mod:" << buff_m ; EXPECT_EQ(0, decimal_modulo(E_DEC_FATAL_ERROR, &xxx_result, &d1, &d2)); EXPECT_EQ(0, decimal2string(&xxx_result, buff_x, &bufsz_x, 0, 0, 0)); EXPECT_EQ(0, my_decimal_cmp(&expected_result, &xxx_result)) << " a:" << pd->a << " b:" << pd->b << " expected:" << pd->result << " got mod:" << buff_m << " got xxx:" << buff_x ; } } // Verifies that decimal_mul() does not return negative zero. TEST_F(DecimalTest, NegativeZeroMultiply) { EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d1)); EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d2)); EXPECT_EQ(0, my_decimal_cmp(&d1, &decimal_zero)); EXPECT_EQ(0, my_decimal_cmp(&d2, &decimal_zero)); d1.sign(true); my_decimal product; EXPECT_EQ(E_DEC_OK, decimal_mul(&d1, &d2, &product)); EXPECT_FALSE(product.sign()); EXPECT_EQ(0, my_decimal_cmp(&product, &decimal_zero)); } // Verifies that decimal_add() *does* return negative zero. TEST_F(DecimalTest, NegativeZeroAdd) { EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d1)); EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d2)); EXPECT_EQ(0, my_decimal_cmp(&d1, &decimal_zero)); EXPECT_EQ(0, my_decimal_cmp(&d2, &decimal_zero)); d1.sign(true); d2.sign(true); my_decimal sum; EXPECT_EQ(E_DEC_OK, decimal_add(&d1, &d2, &sum)); EXPECT_TRUE(sum.sign()); // This one will DBUG_ASSERT // EXPECT_EQ(0, my_decimal_cmp(&sum, &decimal_zero)); } TEST_F(DecimalTest, BinaryConversion) { const int prec= 60; const int scale= 0; EXPECT_EQ(E_DEC_OK, chars_2_decimal("000000000", &d1)); int binary_size= my_decimal_get_binary_size(prec, scale); uchar *bin= new uchar[binary_size]; // Convert to binary, and back. EXPECT_EQ(E_DEC_OK, my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, &d1, bin, prec, scale)); EXPECT_EQ(E_DEC_OK, binary2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, bin, &d2, prec, scale)); EXPECT_GT(d2.precision(), 0U); EXPECT_EQ(0, my_decimal_cmp(&d1, &d2)); // 0.0 * 0.0 my_decimal product; EXPECT_EQ(E_DEC_OK, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, &product, &d2, &d2)); // 0.0 * (-0.0) my_decimal neg_prod; my_decimal d3(d2); d3.sign(true); EXPECT_EQ(E_DEC_OK, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, &neg_prod, &d2, &d3)); delete[] bin; } }