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