1 /* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
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
TEST_F(DecimalTest,BinaryConversion)264 TEST_F(DecimalTest, BinaryConversion)
265 {
266 const int prec= 60;
267 const int scale= 0;
268 EXPECT_EQ(E_DEC_OK, chars_2_decimal("000000000", &d1));
269 int binary_size= my_decimal_get_binary_size(prec, scale);
270 uchar *bin= new uchar[binary_size];
271
272 // Convert to binary, and back.
273 EXPECT_EQ(E_DEC_OK, my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
274 &d1, bin, prec, scale));
275 EXPECT_EQ(E_DEC_OK, binary2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
276 bin, &d2, prec, scale));
277 EXPECT_GT(d2.precision(), 0U);
278 EXPECT_EQ(0, my_decimal_cmp(&d1, &d2));
279
280 // 0.0 * 0.0
281 my_decimal product;
282 EXPECT_EQ(E_DEC_OK, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
283 &product, &d2, &d2));
284 // 0.0 * (-0.0)
285 my_decimal neg_prod;
286 my_decimal d3(d2);
287 d3.sign(true);
288 EXPECT_EQ(E_DEC_OK, my_decimal_mul(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
289 &neg_prod, &d2, &d3));
290 delete[] bin;
291 }
292
293 }
294