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 Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include <gtest/gtest.h>
26 #include "test_utils.h"
27
28 #include "decimal.h"
29 #include "my_decimal.h"
30 #include "my_time.h"
31 #include "mysql_time.h"
32 #include "sql_time.h"
33 #include "m_ctype.h"
34
35 #include "item.h"
36 #include "item_timefunc.h"
37
38 #include <string.h>
39 #include <sstream>
40 #include <string>
41
42 namespace item_timefunc_unittest {
43
44 using my_testing::Server_initializer;
45
46 class ItemTimeFuncTest : public ::testing::Test
47 {
48 protected:
SetUp()49 virtual void SetUp()
50 {
51 initializer.SetUp();
52 }
53
TearDown()54 virtual void TearDown() { initializer.TearDown(); }
55
thd()56 THD *thd() { return initializer.thd(); }
57
58 Server_initializer initializer;
59 };
60
TEST_F(ItemTimeFuncTest,dateAddInterval)61 TEST_F(ItemTimeFuncTest, dateAddInterval)
62 {
63 Item_int *arg0= new Item_int(20130122145221LL); // 2013-01-22 14:52:21
64 Item_decimal *arg1= new Item_decimal(0.1234567, 8, 7);
65 Item *item=
66 new Item_date_add_interval(POS(),
67 arg0, arg1, INTERVAL_SECOND_MICROSECOND, false);
68 Parse_context pc(thd(), thd()->lex->current_select());
69 EXPECT_FALSE(item->itemize(&pc, &item));
70 EXPECT_FALSE(item->fix_fields(thd(), NULL));
71
72 // The below result is not correct, see Bug#16198372
73 EXPECT_DOUBLE_EQ(20130122145222.234567, item->val_real());
74 }
75
76 struct test_data
77 {
78 const char *secs;
79 unsigned int hour;
80 unsigned int minute;
81 unsigned int second;
82 unsigned long second_part;
83 };
84
operator <<(::std::ostream & os,const struct test_data & data)85 ::std::ostream& operator<<(::std::ostream& os, const struct test_data& data) {
86 return os << data.secs;
87 }
88
89
90 class ItemTimeFuncTestP : public ::testing::TestWithParam<test_data>
91 {
92 protected:
SetUp()93 virtual void SetUp()
94 {
95 initializer.SetUp();
96 m_t= GetParam();
97 }
98
TearDown()99 virtual void TearDown() { initializer.TearDown(); }
100
thd()101 THD *thd() { return initializer.thd(); }
102
103 Server_initializer initializer;
104 test_data m_t;
105 };
106
107 const test_data test_values[]=
108 {
109 { "0.1234564", 0, 0, 0, 123456 },
110 { "0.1234567", 0, 0, 0, 123457 },
111 { "0.1234", 0, 0, 0, 123400 },
112 { "12.1234567", 0, 0, 12, 123457},
113 { "123", 0, 2, 3, 0 },
114 { "2378.3422349", 0, 39, 38, 342235 },
115 { "3020398.999999999", 838, 59, 59, 0 },
116 { "3020399", 838, 59, 59, 0 },
117 { "99999999.99999999", 838, 59, 59, 0 }
118 };
119
120 INSTANTIATE_TEST_CASE_P(a, ItemTimeFuncTestP,
121 ::testing::ValuesIn(test_values));
122
123 /**
124 Test member function of @c Item_time_func
125
126 @param item item of a sub-class of @c Item_time_func
127 @param ltime time structure that contains the expected result
128 @param decimals number of significant decimals in the expected result
129 */
testItemTimeFunctions(Item_time_func * item,MYSQL_TIME * ltime,int decimals)130 void testItemTimeFunctions(Item_time_func *item, MYSQL_TIME *ltime,
131 int decimals)
132 {
133 long long int mysql_time=
134 10000 * ltime->hour + 100 * ltime->minute + ltime->second;
135 EXPECT_EQ(mysql_time, item->val_int());
136
137 long long int packed= TIME_to_longlong_packed(ltime);
138 EXPECT_EQ(packed, item->val_time_temporal());
139
140 double d= mysql_time + ltime->second_part / 1000000.0;
141 EXPECT_DOUBLE_EQ(d, item->val_real());
142
143 my_decimal decval1, decval2;
144 my_decimal *dec= item->val_decimal(&decval1);
145 double2decimal(d, &decval2);
146 EXPECT_EQ(0, my_decimal_cmp(dec, &decval2));
147
148 char s[20];
149 sprintf(s, "%02d:%02d:%02d", ltime->hour, ltime->minute, ltime->second);
150 if (ltime->second_part > 0) { // Avoid trailing zeroes
151 int decs= ltime->second_part;
152 while (decs % 10 == 0)
153 decs /= 10;
154 sprintf(s + strlen(s), ".%d", decs);
155 }
156 else if (decimals > 0)
157 // There were decimals, but they have disappeared due to overflow
158 sprintf(s + strlen(s), ".000000");
159 String timeStr(20);
160 EXPECT_STREQ(s, item->val_str(&timeStr)->c_ptr());
161
162 MYSQL_TIME ldate;
163 //> Second argument of Item_func_time::get_date is not used for anything
164 item->get_date(&ldate, 0);
165 // Todo: Should check that year, month, and day is relative to current date
166 EXPECT_EQ(ltime->hour % 24, ldate.hour);
167 EXPECT_EQ(ltime->minute, ldate.minute);
168 EXPECT_EQ(ltime->second, ldate.second);
169 EXPECT_EQ(ltime->second_part, ldate.second_part);
170
171 // Todo: Item_time_func::save_in_field is not tested
172 }
173
TEST_P(ItemTimeFuncTestP,secToTime)174 TEST_P(ItemTimeFuncTestP, secToTime)
175 {
176 Item_decimal *sec=
177 new Item_decimal(POS(), m_t.secs, strlen(m_t.secs), &my_charset_latin1_bin);
178 Item_func_sec_to_time *time= new Item_func_sec_to_time(POS(), sec);
179
180 Parse_context pc(thd(), thd()->lex->current_select());
181 Item *item;
182 EXPECT_FALSE(time->itemize(&pc, &item));
183 EXPECT_EQ(time, item);
184 EXPECT_FALSE(time->fix_fields(thd(), NULL));
185
186 MYSQL_TIME ltime;
187 time->get_time(<ime);
188 EXPECT_EQ(0U, ltime.year);
189 EXPECT_EQ(0U, ltime.month);
190 EXPECT_EQ(0U, ltime.day);
191 EXPECT_EQ(m_t.hour, ltime.hour);
192 EXPECT_EQ(m_t.minute, ltime.minute);
193 EXPECT_EQ(m_t.second, ltime.second);
194 EXPECT_EQ(m_t.second_part, ltime.second_part);
195
196 testItemTimeFunctions(time, <ime, sec->decimals);
197 }
198
199 }
200