text: /* 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 <gtest/gtest.h>
  
  #include "test_utils.h"
  
  #include <my_decimal.h>
  
  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;
  }
  
  }
  