1 /* Copyright (C) 2014 InfiniDB, Inc.
2
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License
5 as published by the Free Software Foundation; version 2 of
6 the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA. */
17
18 /**
19 * $Id$
20 */
21
22 #include <iostream>
23 #include <string>
24 using namespace std;
25
26 #include <cppunit/extensions/HelperMacros.h>
27
28 #include "dataconvert.h"
29 #include "funchelpers.h"
30 using namespace funcexp;
31 using namespace dataconvert;
32 #define MAX_DAY_NUMBER 3652424L
33
34 #include "functioncolumn.h"
35 #include "intervalcolumn.h"
36 using namespace execplan;
37
38 #include "timeextract.h"
39
40 class FuncExpTest : public CppUnit::TestFixture
41 {
42
43 CPPUNIT_TEST_SUITE( FuncExpTest );
44
45 CPPUNIT_TEST( fe_getnumbertest );
46 CPPUNIT_TEST( fe_strtodatetest );
47 CPPUNIT_TEST( fe_dateaddtest );
48 CPPUNIT_TEST( fe_daynametest );
49 CPPUNIT_TEST( fe_fromunixtimetest );
50 CPPUNIT_TEST_SUITE_END();
51
52 private:
53
54 public:
setUp()55 void setUp()
56 {
57 }
58
tearDown()59 void tearDown()
60 {
61 }
62
show_datetime_debugs(const string & nm,const DateTime & d1)63 void show_datetime_debugs( const string& nm, const DateTime& d1 )
64 {
65 cout << nm << ".day = " << setw(10) << d1.day << endl;
66 cout << nm << ".month = " << setw(10) << d1.month << endl;
67 cout << nm << ".year = " << setw(10) << d1.year << endl;
68 cout << nm << ".hour = " << setw(10) << d1.hour << endl;
69 cout << nm << ".minute = " << setw(10) << d1.minute << endl;
70 cout << nm << ".second = " << setw(10) << d1.second << endl;
71 cout << nm << ".msecond = " << setw(10) << d1.msecond << endl;
72 }
73
fe_strtodatetest()74 void fe_strtodatetest()
75 {
76 struct DateCheck
77 {
78 const char* inputstr;
79 const char* formatstr;
80 DateTime date;
81 };
82
83 DateCheck date_tests[] =
84 {
85 { "2009", "%Y", DateTime(2009, 0, 0, 0, 0, 0, 0) },
86 { " 2009", "%Y", DateTime(2009, 0, 0, 0, 0, 0, 0) },
87 { " 2009", " %Y", DateTime(2009, 0, 0, 0, 0, 0, 0) },
88 { "jan", "%b", DateTime(0, 1, 0, 0, 0, 0, 0) },
89 { "2009feb", "%Y%b", DateTime(2009, 2, 0, 0, 0, 0, 0) },
90 { " 2009 ApR", " %Y %b", DateTime(2009, 4, 0, 0, 0, 0, 0) },
91 { "200910", "%Y%m", DateTime(2009, 10, 0, 0, 0, 0, 0) },
92 { " 2009 10", " %Y %m", DateTime(2009, 10, 0, 0, 0, 0, 0) },
93 { "200910", "%Y%c", DateTime(2009, 10, 0, 0, 0, 0, 0) },
94 { " 2009 10", " %Y %c", DateTime(2009, 10, 0, 0, 0, 0, 0) },
95 { "01,5,2013", "%d,%m,%Y", DateTime(2013, 5, 1, 0, 0, 0, 0) },
96 { "01,5,2013", "%e,%m,%Y", DateTime(2013, 5, 1, 0, 0, 0, 0) },
97 { "7,5th,2012", "%m,%D,%Y", DateTime(2012, 7, 5, 0, 0, 0, 0) },
98 { "a09:30:17", "a%h:%i", DateTime(0, 0, 0, 9, 30, 0, 0) },
99 { "a09:30:17", "%h:%i", DateTime(0, 0, 0, 0, 0, 0, 0) },
100 { "9:30.170", "%h:%i.%f", DateTime(0, 0, 0, 9, 30, 0, 170000) },
101 { "178546 17", "%f %H", DateTime(0, 0, 0, 17, 0, 0, 178546) },
102 { "2009march415", "%Y%b", DateTime(2009, 3, 0, 0, 0, 0, 0) },
103 { " 2009 July", " %Y %b", DateTime(2009, 7, 0, 0, 0, 0, 0) },
104 { "09 pm", "%h %p", DateTime(0, 0, 0, 21, 0, 0, 0) },
105 { "09:13:14pm", "%r", DateTime(0, 0, 0, 9, 13, 14, 0) },
106 { "12:13:14am", "%r", DateTime(0, 0, 0, 12, 13, 14, 0) },
107 { "92", " %Y", DateTime(1992, 0, 0, 0, 0, 0, 0) },
108 { "9", " %Y", DateTime(2009, 0, 0, 0, 0, 0, 0) },
109 { "2013 31", "%Y %j", DateTime(2013, 1, 31, 0, 0, 0, 0) },
110 { "2013 1 3", "%Y %U %w", DateTime(2013, 1, 9, 0, 0, 0, 0) },
111 { "2013 1 3", "%Y %u %w", DateTime(2013, 1, 9, 0, 0, 0, 0) },
112 { "2007 1 3", "%Y %U %w", DateTime(2007, 1, 10, 0, 0, 0, 0) },
113 { "2007 1 3", "%Y %u %w", DateTime(2007, 1, 3, 0, 0, 0, 0) },
114 { "2013 1 3", "%X %V %w", DateTime(2013, 1, 9, 0, 0, 0, 0) },
115 { "2013 1 3", "%X %v %w", DateTime(2013, 1, 9, 0, 0, 0, 0) },
116 { "2007 1 3", "%X %V %w", DateTime(2007, 1, 10, 0, 0, 0, 0) },
117 { "2007 1 3", "%X %v %w", DateTime(2007, 1, 3, 0, 0, 0, 0) },
118 { "33:30.170", "%h:%i.%f", DateTime(0, 0, 0, 0, 0, 0, 0) },
119 { "01,25,2013", "%d,%m,%Y", DateTime(0, 0, 0, 0, 0, 0, 0) },
120 { "%09:30:17", "%%%h:%i:%s", DateTime(0, 0, 0, 9, 30, 17, 0) },
121 { "2009 foobar", "%Y", DateTime(2009, 0, 0, 0, 0, 0, 0) },
122 { "2009-12-31", "%h:%i:%s %p", DateTime(0, 0, 0, 0, 0, 0, 0) },
123 { "12:00:01 AM", "%h:%i:%s %p", DateTime(0, 0, 0, 0, 0, 1, 0) },
124 { "12:00:01 PM", "%h:%i:%s %p", DateTime(0, 0, 0, 12, 0, 1, 0) },
125 { "11:00:01 PM", "%h:%i:%s %p", DateTime(0, 0, 0, 23, 0, 1, 0) },
126 { "11:00:01 AM", "%h:%i:%s %p", DateTime(0, 0, 0, 11, 0, 1, 0) },
127 { "10000-01-02", "%Y:%m:%d", DateTime(0, 0, 0, 0, 0, 0, 0) },
128 };
129
130 for (unsigned i = 0; i < sizeof(date_tests) / sizeof(DateCheck); i++)
131 {
132 DateTime dt;
133 dt.year = 0;
134 dt.month = 0;
135 dt.day = 0;
136 dt.hour = 0;
137 dt.minute = 0;
138 dt.second = 0;
139 dt.msecond = 0;
140
141 TimeExtractor extractor;
142 int ret = extractor.extractTime(date_tests[i].inputstr, date_tests[i].formatstr, dt);
143
144 if ( ret != 0 )
145 cout << "Extractor reported error for "
146 << date_tests[i].inputstr << "," << date_tests[i].formatstr << endl;
147
148 bool check = ((*(reinterpret_cast<uint64_t*> (&date_tests[i].date))) ==
149 ((*(reinterpret_cast<uint64_t*> (&dt)))));
150
151 if (!check)
152 {
153 printf("For input \"%s\", format \"%s\", check 0x%016lx vs 0x%016lx\n",
154 date_tests[i].inputstr,
155 date_tests[i].formatstr,
156 *(reinterpret_cast<uint64_t*> (&dt)),
157 *(reinterpret_cast<uint64_t*>(&date_tests[i].date)) );
158 show_datetime_debugs("check", dt);
159 show_datetime_debugs("ref", date_tests[i].date);
160 }
161
162 CPPUNIT_ASSERT( check );
163 }
164
165 }
166
fe_getnumbertest()167 void fe_getnumbertest()
168 {
169 const int MAX_VALS = 5;
170 struct Check
171 {
172 const char* str;
173 int numvals;
174 int vals[MAX_VALS];
175 };
176
177 Check tests[] =
178 {
179 { " ", 0, {} },
180 { "0", 1, {0} },
181 { "0.0", 2, {0, 0} },
182 { "0:0.0", 3, {0, 0, 0} },
183 { "-0", 1, {0} },
184 { "0000-000", 1, {0} },
185 { "-2", 1, {-2} },
186 { "2223", 1, {2223} },
187 { "37", 1, {37} },
188 { "393", 1, {393} },
189 { "39-3", 1, {39} },
190 { "17-", 1, {17} },
191 { "10.2303", 2, {10, 2303} },
192 { "20:10.2303", 3, {20, 10, 2303} },
193 { "17:37", 2, {17, 37} },
194 };
195
196 int a1[MAX_VALS] = { 0xdeadbeef };
197
198 for (unsigned i = 0; i < sizeof(tests) / sizeof(Check); i++)
199 {
200 int rc1 = helpers::getNumbers(tests[i].str, a1, execplan::OP_ADD);
201
202 cout << "For input \"" << tests[i].str << "\", numbers = " << rc1 << ",[";
203
204 bool check = true;
205
206 if (rc1 != tests[i].numvals)
207 check = false;
208
209 for (int j = 0; j < rc1; ++j)
210 {
211 if (j > 0)
212 cout << ',';
213
214 cout << a1[j];
215
216 if (a1[j] != tests[i].vals[j])
217 {
218 check = false;
219 }
220 }
221
222 cout << ']' << endl;
223
224 CPPUNIT_ASSERT( check );
225 }
226 }
227
fe_dateaddtest()228 void fe_dateaddtest()
229 {
230 struct DateCheck
231 {
232 const char* intervalstr;
233 IntervalColumn::interval_type unit;
234 OpType funcType;
235 DateTime date;
236 DateTime ref;
237 };
238
239 DateCheck date_tests[] =
240 {
241 { "111111:22", IntervalColumn::INTERVAL_YEAR_MONTH, execplan::OP_ADD, DateTime(1997, 01, 01, 0, 0, 0, 0), DateTime(0, 0, 0, 0, 0, 0, 0) },
242 { "-30", IntervalColumn::INTERVAL_DAY, execplan::OP_ADD, DateTime(2013, 3, 1, 0, 0, 0, 0), DateTime(2013, 1, 30, 0, 0, 0, 0) },
243 };
244
245 for (unsigned i = 0; i < sizeof(date_tests) / sizeof(DateCheck); i++)
246 {
247 DateTime dt;
248
249 uint64_t timeval = *(reinterpret_cast<uint64_t*> (&date_tests[i].date));
250 uint64_t value = helpers::dateAdd( timeval, date_tests[i].intervalstr, date_tests[i].unit, false, date_tests[i].funcType );
251
252 *(reinterpret_cast<uint64_t*> (&dt)) = value;
253
254 bool check = ( value == *(reinterpret_cast<uint64_t*> (&date_tests[i].ref)));
255
256 if (!check)
257 {
258 printf("For interval \"%s\", check 0x%016lx vs 0x%016lx\n",
259 date_tests[i].intervalstr,
260 *(reinterpret_cast<uint64_t*> (&dt)),
261 *(reinterpret_cast<uint64_t*>(&date_tests[i].ref)) );
262 show_datetime_debugs("check", dt);
263 show_datetime_debugs("ref", date_tests[i].ref);
264 }
265
266 CPPUNIT_ASSERT( check );
267 }
268 }
269
fe_daynametest()270 void fe_daynametest()
271 {
272 struct DateCheck
273 {
274 DateTime date;
275 const char* dayname;
276 };
277
278 DateCheck date_tests[] =
279 {
280 { DateTime(1997, 01, 01, 0, 0, 0, 0), "Wednesday" },
281 };
282
283 for (unsigned i = 0; i < sizeof(date_tests) / sizeof(DateCheck); i++)
284 {
285 boost::gregorian::date d(date_tests[i].date.year, date_tests[i].date.month, date_tests[i].date.day);
286 uint32_t dayofweek = helpers::calc_mysql_weekday(date_tests[i].date.year, date_tests[i].date.month, date_tests[i].date.day, false);
287
288 bool check = ( strcmp( helpers::weekdayFullNames[dayofweek].c_str(), date_tests[i].dayname ) == 0 );
289
290 if (!check)
291 {
292 printf("For date %s, check %s vs %s\n",
293 to_simple_string(d).c_str(),
294 helpers::weekdayFullNames[dayofweek].c_str(),
295 date_tests[i].dayname );
296 }
297
298 CPPUNIT_ASSERT( check );
299 }
300 }
301
getDateTime(int64_t val)302 DateTime getDateTime(int64_t val)
303 {
304 if (val < 0 || val > helpers::TIMESTAMP_MAX_VALUE)
305 return 0;
306
307 DateTime dt;
308
309 struct tm tmp_tm;
310 time_t tmp_t = (time_t)val;
311 localtime_r(&tmp_t, &tmp_tm);
312
313 //to->neg=0;
314 dt.year = (int64_t) ((tmp_tm.tm_year + 1900) % 10000);
315 dt.month = (int64_t) tmp_tm.tm_mon + 1;
316 dt.day = (int64_t) tmp_tm.tm_mday;
317 dt.hour = (int64_t) tmp_tm.tm_hour;
318 dt.minute = (int64_t) tmp_tm.tm_min;
319 dt.second = (int64_t) tmp_tm.tm_sec;
320 dt.msecond = 0;
321 return dt;
322 }
323
fe_fromunixtimetest()324 void fe_fromunixtimetest()
325 {
326 struct DateCheck
327 {
328 int64_t ts;
329 const char* formatstr;
330 const char* refstr;
331 };
332
333 DateCheck date_tests[] =
334 {
335 { -26, "%H:%i:%s", "NULL" },
336 { 26, "%H:%i:%s", "18:00:26" },
337 { 0, "%H:%i:%s", "18:00:00" },
338 };
339
340 for (unsigned i = 0; i < sizeof(date_tests) / sizeof(DateCheck); i++)
341 {
342 bool check = false;
343 string ret;
344 DateTime dt = getDateTime(date_tests[i].ts);
345
346 if (*reinterpret_cast<int64_t*>(&dt) == 0)
347 {
348 check = ( strcmp( date_tests[i].refstr, "NULL" ) == 0 );
349 }
350 else
351 {
352 ret = helpers::IDB_date_format(dt, date_tests[i].formatstr);
353 check = ( strcmp( date_tests[i].refstr, ret.c_str() ) == 0 );
354 }
355
356 if (!check)
357 {
358 printf("For timestamp %ld, check %s vs %s\n",
359 date_tests[i].ts,
360 ret.c_str(),
361 date_tests[i].refstr );
362 }
363
364 CPPUNIT_ASSERT( check );
365 }
366 }
367
368 };
369
370 CPPUNIT_TEST_SUITE_REGISTRATION( FuncExpTest );
371
372 #include <cppunit/extensions/TestFactoryRegistry.h>
373 #include <cppunit/ui/text/TestRunner.h>
374
main(int argc,char ** argv)375 int main( int argc, char** argv)
376 {
377 CppUnit::TextUi::TestRunner runner;
378 CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry();
379 runner.addTest( registry.makeTest() );
380 bool wasSuccessful = runner.run( "", false );
381 return (wasSuccessful ? 0 : 1);
382 }
383
384
385
386