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