1 /* Copyright (c) 2005 CrystalClear Software, Inc.
2  * Use, modification and distribution is subject to the
3  * Boost Software License, Version 1.0. (See accompanying
4  * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
5  * Author: Jeff Garland, Bart Garst
6  * $Date$
7  */
8 
9 #include "boost/date_time/gregorian/gregorian.hpp"
10 #include "boost/date_time/posix_time/posix_time.hpp"
11 #include "../testfrmwk.hpp"
12 #include <iostream>
13 #include <sstream>
14 #include <string>
15 #include <vector>
16 
17 // for tests that are expected to fail and throw exceptions
18 template<class temporal_type, class exception_type>
failure_test(temporal_type component,const std::string & input,exception_type const &,boost::posix_time::time_input_facet * facet)19 bool failure_test(temporal_type component,
20                   const std::string& input,
21                   exception_type const& /*except*/,
22                   boost::posix_time::time_input_facet* facet)
23 {
24   using namespace boost::posix_time;
25   bool result = false;
26   std::istringstream iss(input);
27   iss.exceptions(std::ios_base::failbit); // turn on exceptions
28   iss.imbue(std::locale(std::locale::classic(), facet));
29   try {
30     iss >> component;
31   }
32   catch(exception_type& e) {
33     std::cout << "Expected exception caught: \""
34               << e.what() << "\"" << std::endl;
35     result = iss.fail(); // failbit must be set to pass test
36   }
37   catch(...) {
38     result = false;
39   }
40 
41   return result;
42 }
43 
44 // for tests that are expected to fail quietly
45 template<class temporal_type>
failure_test(temporal_type component,const std::string & input,boost::posix_time::time_input_facet * facet)46 bool failure_test(temporal_type component,
47                   const std::string& input,
48                   boost::posix_time::time_input_facet* facet)
49 {
50   using namespace boost::posix_time;
51   std::istringstream iss(input);
52   /* leave exceptions turned off
53    * iss.exceptions(std::ios_base::failbit); */
54   iss.imbue(std::locale(std::locale::classic(), facet));
55   try {
56     iss >> component;
57   }
58   catch(...) {
59     std::cout << "Caught unexpected exception" << std::endl;
60     return false;
61   }
62 
63   return iss.fail(); // failbit must be set to pass test
64 }
65 
66 using namespace boost::gregorian;
67 using namespace boost::posix_time;
68 
69 
70 void
do_all_tests()71 do_all_tests()
72 {
73 
74 #if defined(USE_DATE_TIME_PRE_1_33_FACET_IO) // skip this file
75   check("No tests run for this compiler. Incompatible IO", true);
76 #else
77 
78   // set up initial objects
79   time_duration td = hours(0);
80   ptime pt(not_a_date_time);
81   time_period tp(pt, td);
82   // exceptions for failure_tests
83   std::ios_base::failure e_failure("default");
84 
85   /* test ptime, time_duration, time_period.
86    * test all formats.
87    * test for bad input.
88    * test special values.
89    * do not test custom names (done in gregorian).
90    *
91    * format flags to test H,M,S,s,F,f,j
92    */
93 
94   // default format tests: time_duration, ptime
95   std::istringstream iss("09:59:01.321987654321 2005-Jan-15 10:15:03.123456789123");
96   iss >> td;
97   iss >> pt;
98 #if defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
99   check_equal("Default format time_duration", td, time_duration(9,59,1,321987654));
100   check_equal("Default format ptime", pt, ptime(date(2005,01,15),time_duration(10,15,3,123456789)));
101 #else
102   check_equal("Default format time_duration", td, time_duration(9,59,1,321987));
103   check_equal("Default format ptime", pt, ptime(date(2005,01,15),time_duration(10,15,3,123456)));
104 #endif
105 
106   // test all flags that appear in time_input_facet
107   iss.str("12:34:56 2005-Jan-15 12:34:56");
108   iss >> td;
109   iss >> pt;
110   check_equal("Default format time_duration no frac_sec", td, time_duration(12,34,56));
111   // the following test insures %F parsing stops at the appropriate point
112   check_equal("Default format ptime", pt, ptime(date(2005,01,15),time_duration(12,34,56)));
113 
114   iss.str("14:13:12 extra stuff"); // using default %H:%M:%S%F format
115   iss >> td;
116   check_equal("Default frac_sec format time_duration", td, time_duration(14,13,12));
117 
118   time_input_facet* facet = new time_input_facet();
119   std::locale loc(std::locale::classic(), facet);
120   facet->time_duration_format("%H:%M:%S""%f");
121   iss.imbue(loc);
122 
123   iss.str("14:13:12.0 extra stuff");
124   iss >> td;
125   check_equal("Required-frac_sec format time_duration", td, time_duration(14,13,12));
126 
127   iss.str("12");
128   facet->time_duration_format("%H");
129   iss >> td;
130   check_equal("Hours format", td, hours(12));
131 
132   iss.str("05");
133   facet->time_duration_format("%M");
134   iss >> td;
135   check_equal("Minutes format", td, minutes(5));
136 
137   iss.str("45");
138   facet->time_duration_format("%S");
139   iss >> td;
140   check_equal("Seconds w/o frac_sec format", td, seconds(45));
141 
142   iss.str("10.01");
143   facet->time_duration_format("%s");
144   iss >> td;
145 #if defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
146   check_equal("Seconds w/ frac_sec format", td, time_duration(0,0,10,10000000));
147 #else
148   check_equal("Seconds w/ frac_sec format", td, time_duration(0,0,10,10000));
149 #endif
150 
151   iss.str("2005-105T23:59");
152   facet->format("%Y-%jT%H:%M"); // extended ordinal format
153   iss >> pt;
154   check_equal("Extended Ordinal format", pt, ptime(date(2005,4,15),time_duration(23,59,0)));
155 
156   /* this is not implemented yet. The flags: %I & %p are not parsed
157   iss.str("2005-Jun-14 03:15:00 PM");
158   facet->format("%Y-%b-%d %I:%M:%S %p");
159   iss >> pt;
160   check_equal("12 hour time format (AM/PM)", pt, ptime(date(2005,6,14),time_duration(15,15,0)));
161   */
162 
163   iss.str("2005-Jun-14 15:15:00 %d");
164   facet->format("%Y-%b-%d %H:%M:%S %%d");
165   iss >> pt;
166   check_equal("Literal '%' in format", pt, ptime(date(2005,6,14),time_duration(15,15,0)));
167   iss.str("15:15:00 %d");
168   facet->time_duration_format("%H:%M:%S %%d");
169   iss >> td;
170   check_equal("Literal '%' in time_duration format", td, time_duration(15,15,0));
171   iss.str("2005-Jun-14 15:15:00 %14");
172   facet->format("%Y-%b-%d %H:%M:%S %%%d"); // %% => % & %d => day_of_month
173   iss >> pt;
174   check_equal("Multiple literal '%'s in format", pt, ptime(date(2005,6,14),time_duration(15,15,0)));
175   iss.str("15:15:00 %15");
176   facet->time_duration_format("%H:%M:%S %%%M");
177   iss >> td;
178   check_equal("Multiple literal '%'s in time_duration format", td, time_duration(15,15,0));
179 
180   { /****** iso format tests (and custom 'scrunched-together formats) ******/
181     time_input_facet *facet = new time_input_facet();
182     facet->set_iso_format();
183     facet->time_duration_format("%H""%M""%S""%F"); // iso format
184     std::stringstream ss;
185     ss.imbue(std::locale(std::locale::classic(), facet));
186     ptime pt(not_a_date_time);
187     time_duration td(not_a_date_time);
188     date d(2002,Oct,17);
189 #if defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
190     time_duration td2(23,12,17,123450000);
191 #else
192     time_duration td2(23,12,17,123450);
193 #endif
194     ptime result(d, td2);
195 
196     ss.str("20021017T231217.12345");
197     ss >> pt;
198     check_equal("iso_format ptime", pt, result);
199     ss.str("");
200     facet->set_iso_extended_format();
201     ss.str("2002-10-17 23:12:17.12345");
202     ss >> pt;
203     check_equal("iso_extended_format ptime", pt, result);
204     ss.str("");
205     ss.str("231217.12345");
206     ss >> td;
207     check_equal("iso_format time_duration", td, td2);
208     ss.str("");
209     ss.str("-infinity");
210     ss >> td;
211     check_equal("iso_format time_duration (special_value)",
212         td, time_duration(neg_infin));
213     ss.str("");
214     // the above tests prove correct parsing of time values in these formats.
215     // these tests show they also handle special_values & exceptions properly
216     time_duration nadt(not_a_date_time);
217     ss.exceptions(std::ios_base::failbit); // we need exceptions turned on here
218     int count = 0;
219     try {
220       facet->time_duration_format("%H""%M""%S""%F");
221       ss.str("not-a-date-time");
222       ++count;
223       ss >> td;
224       check_equal("special value w/ hours flag", td, nadt);
225       ss.str("");
226       facet->time_duration_format("%M""%S""%F");
227       ss.str("not-a-date-time");
228       ++count;
229       ss >> td;
230       check_equal("special value w/ minutes flag", td, nadt);
231       ss.str("");
232       facet->time_duration_format("%S""%F");
233       ss.str("not-a-date-time");
234       ++count;
235       ss >> td;
236       check_equal("special value w/ seconds flag", td, nadt);
237       ss.str("");
238       facet->time_duration_format("%s");
239       ss.str("not-a-date-time");
240       ++count;
241       ss >> td;
242       check_equal("special value w/ sec w/frac_sec (always) flag", td, nadt);
243       ss.str("");
244       facet->time_duration_format("%f");
245       ss.str("not-a-date-time");
246       ++count;
247       ss >> td;
248       check_equal("special value w/ frac_sec (always) flag", td, nadt);
249       ss.str("");
250     }
251     catch(...) {
252       // any exception is a failure
253       std::stringstream msg;
254       msg << "special_values with scrunched formats failed at test" << count;
255       check(msg.str(), false);
256     }
257     // exception tests
258     std::ios_base::failure exc("failure");
259     check("failure test w/ hours flag",
260         failure_test(td, "bad_input", exc, new time_input_facet("%H""%M""%S""%F")));
261     check("silent failure test w/ hours flag",
262         failure_test(td, "bad_input", new time_input_facet("%H""%M""%S""%F")));
263     check("failure test w/ minute flag",
264         failure_test(td, "bad_input", exc, new time_input_facet("%M""%S""%F")));
265     check("silent failure test w/ minute flag",
266         failure_test(td, "bad_input", new time_input_facet("%M""%S""%F")));
267     check("failure test w/ second flag",
268         failure_test(td, "bad_input", exc, new time_input_facet("%S""%F")));
269     check("silent failure test w/ second flag",
270         failure_test(td, "bad_input", new time_input_facet("%S""%F")));
271     check("failure test w/ sec w/frac (always) flag",
272         failure_test(td, "bad_input", exc, new time_input_facet("%s")));
273     check("silent failure test w/ sec w/frac (always) flag",
274         failure_test(td, "bad_input", new time_input_facet("%s")));
275     check("failure test w/ frac_sec flag",
276         failure_test(td, "bad_input", exc, new time_input_facet("%f")));
277     check("silent failure test w/ frac_sec flag",
278         failure_test(td, "bad_input", new time_input_facet("%f")));
279 
280   }
281   // special_values tests. prove the individual flags catch special_values
282   // NOTE: these flags all by themselves will not parse a complete ptime,
283   // these are *specific* special_values tests
284   iss.str("+infinity -infinity");
285   facet->format("%H");
286   facet->time_duration_format("%H");
287   iss >> pt;
288   iss >> td;
289   check_equal("Special value: ptime %H flag", pt, ptime(pos_infin));
290   check_equal("Special value: time_duration %H flag", td, time_duration(neg_infin));
291 
292   iss.str("not-a-date-time +infinity");
293   facet->format("%M");
294   facet->time_duration_format("%M");
295   iss >> pt;
296   iss >> td;
297   check_equal("Special value: ptime %M flag", pt, ptime(not_a_date_time));
298   check_equal("Special value: time_duration %M flag", td, time_duration(pos_infin));
299 
300   iss.str("-infinity not-a-date-time ");
301   facet->format("%S");
302   facet->time_duration_format("%S");
303   iss >> pt;
304   iss >> td;
305   check_equal("Special value: ptime %S flag", pt, ptime(neg_infin));
306   check_equal("Special value: time_duration %S flag", td, time_duration(not_a_date_time));
307 
308   iss.str("+infinity -infinity");
309   facet->format("%s");
310   facet->time_duration_format("%s");
311   iss >> pt;
312   iss >> td;
313   check_equal("Special value: ptime %s flag", pt, ptime(pos_infin));
314   check_equal("Special value: time_duration %s flag", td, time_duration(neg_infin));
315 
316   iss.str("not-a-date-time +infinity");
317   facet->format("%j");
318   facet->time_duration_format("%f");
319   iss >> pt;
320   iss >> td;
321   check_equal("Special value: ptime %j flag", pt, ptime(not_a_date_time));
322   check_equal("Special value: time_duration %f flag", td, time_duration(pos_infin));
323 
324   // time_period tests - the time_period_parser is thoroughly tested in gregorian tests
325   // default period format is closed range so last ptime is included in peiod
326   iss.str("[2005-Jan-01 00:00:00/2005-Dec-31 23:59:59]");
327   facet->format(time_input_facet::default_time_input_format); // reset format
328   iss >> tp;
329   check("Time period, default formats",
330       (tp.begin() == ptime(date(2005,1,1),hours(0))) &&
331       (tp.last() == ptime(date(2005,12,31),time_duration(23,59,59))) &&
332       (tp.end() == ptime(date(2005,12,31),time_duration(23,59,59,1))) );
333   {
334     std::stringstream ss;
335     ptime pt(not_a_date_time);
336     ptime pt2 = second_clock::local_time();
337     ptime pt3(neg_infin);
338     ptime pt4(pos_infin);
339     time_period tp(pt2, pt); // ptime/nadt
340     time_period tp2(pt, pt); // nadt/nadt
341     time_period tp3(pt3, pt4);
342     ss << tp;
343     ss >> tp2;
344     check_equal("Special values period (reversibility test)", tp, tp2);
345     ss.str("[-infinity/+infinity]");
346     ss >> tp2;
347     check_equal("Special values period (infinities)", tp3, tp2);
348   }
349 
350   // Failure tests
351   // faliure tests for date elements tested in gregorian tests
352   time_input_facet* facet2 = new time_input_facet();
353   facet2->time_duration_format("%H:%M:%S""%f");
354   check("Failure test: Missing frac_sec with %f flag (w/exceptions)",
355         failure_test(td, "14:13:12 extra stuff", e_failure, facet2));
356   time_input_facet* facet3 = new time_input_facet();
357   facet3->time_duration_format("%H:%M:%S""%f");
358   check("Failure test: Missing frac_sec with %f flag (no exceptions)",
359         failure_test(td, "14:13:12 extra stuff", facet3));
360 
361   // Reversable format tests
362   time_duration td_io(10,11,12,1234567);
363   ptime pt_io(date(2004,03,15), td_io);
364   time_facet* otp_facet = new time_facet();
365   time_input_facet* inp_facet = new time_input_facet();
366   std::stringstream ss;
367   std::locale loc2(std::locale::classic(), otp_facet);
368   ss.imbue(std::locale(loc2, inp_facet)); // imbue locale containing both facets
369 
370   ss.str("");
371   ss << pt_io; // stream out pt_io
372   ss >> pt;
373   check_equal("Stream out one ptime then into another: default format", pt_io, pt);
374   ss.str("");
375   ss << td_io; // stream out td_io
376   ss >> td;
377   check_equal("Stream out one time_duration then into another: default format", td_io, td);
378 
379   td_io = time_duration(1,29,59); // no frac_sec, default format has %F
380   pt_io = ptime(date(2004,2,29), td_io); // leap year
381   ss.str("");
382   ss << pt_io; // stream out pt_io
383   ss >> pt;
384   check_equal("Stream out one ptime then into another: default format", pt_io, pt);
385   ss.str("");
386   ss << td_io; // stream out td_io
387   ss >> td;
388   check_equal("Stream out one time_duration then into another: default format", td_io, td);
389 
390   td_io = time_duration(13,05,0); // no seconds as the next formats won't use them
391   pt_io = ptime(date(2004,2,29), td_io); // leap year
392   otp_facet->format("%Y-%jT%H:%M"); // extended ordinal
393   inp_facet->format("%Y-%jT%H:%M");
394   ss.str("");
395   ss << pt_io; // stream out pt_io
396   ss >> pt;
397   check_equal("Stream out one ptime then into another: extended ordinal format", pt_io, pt);
398 
399   otp_facet->format("Time: %H:%M, Date: %B %d, %Y"); // custom format with extra words
400   inp_facet->format("Time: %H:%M, Date: %B %d, %Y");
401   ss.str("");
402   ss << pt_io; // stream out pt_io
403   ss >> pt;
404   check_equal("Stream out one ptime then into another: custom format (" + ss.str() + ")", pt_io, pt);
405 
406   {
407     // fully parameterized constructor - compile only test, all other features tested in gregorian
408     boost::date_time::format_date_parser<date, char> fdp("%Y-%b-%d", std::locale::classic());
409     special_values_parser svp; // default constructor
410     period_parser pp; // default constructor
411     boost::date_time::date_generator_parser<date, char> dgp; // default constructor
412     time_input_facet tif("%Y-%m-%d %H:%M:%s", fdp, svp, pp, dgp);
413   }
414 #endif // USE_DATE_TIME_PRE_1_33_FACET_IO
415 
416 }
417 
418 
419 
main()420 int main(){
421 
422   try {  //wrap all the tests -- we don't expect an exception
423     do_all_tests();
424   }
425   catch(std::exception& e) {
426     std::string failure("std::exception caught: ");
427     failure += e.what();
428     check(failure, false);
429   }
430   catch(...) {
431     check("Unknown exception caught -- failing", false);
432   }
433   return printTestStats();
434 }
435 
436