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