1 /* Copyright (c) 2011, 2021, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
22 
23 #include "my_config.h"
24 #include <gtest/gtest.h>
25 
26 #include "test_utils.h"
27 
28 #include <my_decimal.h>
29 
30 namespace my_decimal_unittest {
31 
32 using my_testing::chars_2_decimal;
33 using my_testing::Server_initializer;
34 using my_testing::Mock_error_handler;
35 
36 class DecimalTest : public ::testing::Test
37 {
38 protected:
SetUp()39   virtual void SetUp() { initializer.SetUp(); }
TearDown()40   virtual void TearDown() { initializer.TearDown(); }
41 
thd()42   THD *thd() { return initializer.thd(); }
43 
44   Server_initializer initializer;
45 
46   my_decimal d1;
47   my_decimal d2;
48 };
49 
50 
TEST_F(DecimalTest,CopyAndCompare)51 TEST_F(DecimalTest, CopyAndCompare)
52 {
53   ulonglong val= 42;
54   EXPECT_EQ(0, ulonglong2decimal(val, &d1));
55 
56   d2= d1;                                       // operator=()
57   my_decimal d3(d1);                            // Copy constructor.
58 
59   EXPECT_EQ(0, my_decimal_cmp(&d1, &d2));
60   EXPECT_EQ(0, my_decimal_cmp(&d2, &d3));
61   EXPECT_EQ(0, my_decimal_cmp(&d3, &d1));
62 
63   ulonglong val1, val2, val3;
64   EXPECT_EQ(0, decimal2ulonglong(&d1, &val1));
65   EXPECT_EQ(0, decimal2ulonglong(&d2, &val2));
66   EXPECT_EQ(0, decimal2ulonglong(&d3, &val3));
67   EXPECT_EQ(val, val1);
68   EXPECT_EQ(val, val2);
69   EXPECT_EQ(val, val3);
70 
71   // The CTOR/operator=() generated by the compiler would fail here:
72   val= 45;
73   EXPECT_EQ(0, ulonglong2decimal(val, &d1));
74   EXPECT_EQ(1, my_decimal_cmp(&d1, &d2));
75   EXPECT_EQ(1, my_decimal_cmp(&d1, &d3));
76 }
77 
78 
TEST_F(DecimalTest,RoundOverflow)79 TEST_F(DecimalTest, RoundOverflow)
80 {
81   const char arg_str[]= "999999999";
82   String str(arg_str, &my_charset_bin);
83 
84   EXPECT_EQ(E_DEC_OK,
85             string2my_decimal(E_DEC_FATAL_ERROR, &str, &d1));
86   d1.sanity_check();
87 
88   for (int ix= 0; ix < DECIMAL_MAX_POSSIBLE_PRECISION; ++ix)
89   {
90     my_decimal d3;
91     const int expect=
92       (ix + str.length() <= DECIMAL_MAX_POSSIBLE_PRECISION) ?
93       E_DEC_OK : E_DEC_TRUNCATED;
94     const bool do_truncate= true;
95     EXPECT_EQ(expect,
96               my_decimal_round(E_DEC_FATAL_ERROR, &d1, ix, do_truncate, &d3))
97       << "ix:" << ix;
98     d3.sanity_check();
99     EXPECT_EQ(0, my_decimal_cmp(&d1, &d3));
100   }
101 }
102 
103 
TEST_F(DecimalTest,Swap)104 TEST_F(DecimalTest, Swap)
105 {
106   ulonglong val1= 1;
107   ulonglong val2= 2;
108   EXPECT_EQ(0, ulonglong2decimal(val1, &d1));
109   EXPECT_EQ(0, ulonglong2decimal(val2, &d2));
110   my_decimal d1copy(d1);
111   my_decimal d2copy(d2);
112   EXPECT_EQ(0, my_decimal_cmp(&d1, &d1copy));
113   EXPECT_EQ(0, my_decimal_cmp(&d2, &d2copy));
114   d1.swap(d2);
115   EXPECT_EQ(0, my_decimal_cmp(&d2, &d1copy));
116   EXPECT_EQ(0, my_decimal_cmp(&d1, &d2copy));
117 }
118 
119 
120 
TEST_F(DecimalTest,Multiply)121 TEST_F(DecimalTest, Multiply)
122 {
123   const char arg1[]=
124     "000000001."
125     "10000000000000000000" "00000000000000000000" "00000000000000000000"
126     "000000000000";
127   const char arg2[]= "1.75";
128   char buff[DECIMAL_MAX_STR_LENGTH];
129   int bufsz;
130   my_decimal prod;
131 
132   EXPECT_EQ(E_DEC_OK, chars_2_decimal(arg1, &d1));
133   EXPECT_EQ(E_DEC_OK, chars_2_decimal(arg2, &d2));
134 
135   // Limit the precision, otherwise "1.75" will be truncated to "1."
136   set_if_smaller(d1.frac, NOT_FIXED_DEC);
137   set_if_smaller(d2.frac, NOT_FIXED_DEC);
138   EXPECT_EQ(0, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
139                               &prod, &d1, &d2));
140   EXPECT_EQ(NOT_FIXED_DEC, d1.frac);
141   EXPECT_EQ(2, d2.frac);
142   EXPECT_EQ(NOT_FIXED_DEC, prod.frac);
143   bufsz= sizeof(buff);
144   EXPECT_EQ(0, decimal2string(&prod, buff, &bufsz, 0, 0, 0));
145   EXPECT_STREQ("1.9250000000000000000000000000000", buff);
146 }
147 
148 
149 /*
150   This is a simple iterative implementation based on addition and subtraction,
151   for verifying the result of decimal_mod().
152 
153   decimal_mod() says:
154   DESCRIPTION
155     the modulus R in    R = M mod N
156     is defined as
157 
158     0 <= |R| < |M|
159     sign R == sign M
160     R = M - k*N, where k is integer
161 
162     thus, there's no requirement for M or N to be integers
163  */
decimal_modulo(uint mask,my_decimal * res,const my_decimal * m,const my_decimal * n)164 int decimal_modulo(uint mask,
165                    my_decimal *res,
166                    const my_decimal *m,
167                    const my_decimal *n)
168 {
169   my_decimal abs_m(*m);
170   my_decimal abs_n(*n);
171   abs_m.sign(false);
172   abs_n.sign(false);
173 
174   my_decimal r;
175   my_decimal k1(abs_n);
176   my_decimal kn(decimal_zero);
177   my_decimal next_r(abs_m);
178   int ret;
179   do
180   {
181     r= next_r;
182 
183     my_decimal res;
184     if ((ret= my_decimal_add(E_DEC_FATAL_ERROR, &res, &k1, &kn)) != E_DEC_OK)
185     {
186       ADD_FAILURE();
187       return ret;
188     }
189     kn= res;
190 
191     if ((ret= my_decimal_sub(E_DEC_FATAL_ERROR,
192                              &next_r, &abs_m, &kn) != E_DEC_OK))
193     {
194       ADD_FAILURE();
195       return ret;
196     }
197   } while (my_decimal_cmp(&next_r, &decimal_zero) >= 0);
198   r.sign(m->sign());
199   *res= r;
200   return 0;
201 }
202 
203 
204 struct Mod_data
205 {
206   const char *a;
207   const char *b;
208   const char *result;
209 };
210 
211 Mod_data mod_test_input[]=
212 {
213   { "234"     , "10",      "4"      },
214   { "234.567" , "10.555",  "2.357"  },
215   { "-234.567", "10.555",  "-2.357" },
216   { "234.567" , "-10.555", "2.357"  },
217   { "-234.567", "-10.555", "-2.357" },
218   { "999"     , "0.1",     "0.0"    },
219   { "999"     , "0.7",     "0.1"    },
220   { "10"      , "123",     "10"     },
221   { NULL, NULL, NULL}
222 };
223 
224 
TEST_F(DecimalTest,Modulo)225 TEST_F(DecimalTest, Modulo)
226 {
227   my_decimal expected_result;
228   my_decimal xxx_result;
229   my_decimal mod_result;
230   char buff_x[DECIMAL_MAX_STR_LENGTH];
231   char buff_m[DECIMAL_MAX_STR_LENGTH];
232 
233   for (Mod_data *pd= mod_test_input; pd->a; ++pd)
234   {
235     int bufsz_x= sizeof(buff_x);
236     int bufsz_m= sizeof(buff_m);
237 
238     EXPECT_EQ(0, chars_2_decimal(pd->a, &d1));
239     EXPECT_EQ(0, chars_2_decimal(pd->b, &d2));
240     EXPECT_EQ(0, chars_2_decimal(pd->result, &expected_result));
241 
242     EXPECT_EQ(0, my_decimal_mod(E_DEC_FATAL_ERROR, &mod_result, &d1, &d2));
243     EXPECT_EQ(0, decimal2string(&mod_result, buff_m, &bufsz_m, 0, 0, 0));
244     EXPECT_EQ(0, my_decimal_cmp(&expected_result, &mod_result))
245       << " a:" << pd->a
246       << " b:" << pd->b
247       << " expected:" << pd->result
248       << " got mod:" << buff_m
249       ;
250 
251     EXPECT_EQ(0, decimal_modulo(E_DEC_FATAL_ERROR, &xxx_result, &d1, &d2));
252     EXPECT_EQ(0, decimal2string(&xxx_result, buff_x, &bufsz_x, 0, 0, 0));
253     EXPECT_EQ(0, my_decimal_cmp(&expected_result, &xxx_result))
254       << " a:" << pd->a
255       << " b:" << pd->b
256       << " expected:" << pd->result
257       << " got mod:" << buff_m
258       << " got xxx:" << buff_x
259       ;
260   }
261 }
262 
263 
264 // Verifies that decimal_mul() does not return negative zero.
TEST_F(DecimalTest,NegativeZeroMultiply)265 TEST_F(DecimalTest, NegativeZeroMultiply)
266 {
267   EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d1));
268   EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d2));
269   EXPECT_EQ(0, my_decimal_cmp(&d1, &decimal_zero));
270   EXPECT_EQ(0, my_decimal_cmp(&d2, &decimal_zero));
271   d1.sign(true);
272   my_decimal product;
273   EXPECT_EQ(E_DEC_OK, decimal_mul(&d1, &d2, &product));
274   EXPECT_FALSE(product.sign());
275   EXPECT_EQ(0, my_decimal_cmp(&product, &decimal_zero));
276 }
277 
278 
279 // Verifies that decimal_add() *does* return negative zero.
TEST_F(DecimalTest,NegativeZeroAdd)280 TEST_F(DecimalTest, NegativeZeroAdd)
281 {
282   EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d1));
283   EXPECT_EQ(E_DEC_OK, chars_2_decimal("0.0", &d2));
284   EXPECT_EQ(0, my_decimal_cmp(&d1, &decimal_zero));
285   EXPECT_EQ(0, my_decimal_cmp(&d2, &decimal_zero));
286   d1.sign(true);
287   d2.sign(true);
288   my_decimal sum;
289   EXPECT_EQ(E_DEC_OK, decimal_add(&d1, &d2, &sum));
290   EXPECT_TRUE(sum.sign());
291   // This one will DBUG_ASSERT
292   // EXPECT_EQ(0, my_decimal_cmp(&sum, &decimal_zero));
293 }
294 
295 
TEST_F(DecimalTest,BinaryConversion)296 TEST_F(DecimalTest, BinaryConversion)
297 {
298   const int prec= 60;
299   const int scale= 0;
300   EXPECT_EQ(E_DEC_OK, chars_2_decimal("000000000", &d1));
301   int binary_size= my_decimal_get_binary_size(prec, scale);
302   uchar *bin= new uchar[binary_size];
303 
304   // Convert to binary, and back.
305   EXPECT_EQ(E_DEC_OK, my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
306                                         &d1, bin, prec, scale));
307   EXPECT_EQ(E_DEC_OK, binary2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
308                                         bin, &d2, prec, scale));
309   EXPECT_GT(d2.precision(), 0U);
310   EXPECT_EQ(0, my_decimal_cmp(&d1, &d2));
311 
312   // 0.0 * 0.0
313   my_decimal product;
314   EXPECT_EQ(E_DEC_OK, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
315                                      &product, &d2, &d2));
316   // 0.0 * (-0.0)
317   my_decimal neg_prod;
318   my_decimal d3(d2);
319   d3.sign(true);
320   EXPECT_EQ(E_DEC_OK, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
321                                      &neg_prod, &d2, &d3));
322   delete[] bin;
323 }
324 
325 }
326