Line data Source code
1 : /*
2 : * Present - Date/Time Library
3 : *
4 : * Tests for the Date C++ class and C-compatible methods
5 : *
6 : * Licensed under the MIT License.
7 : * For details, see LICENSE.
8 : */
9 :
10 : #include "catch.hpp"
11 : #include "test-utils.hpp"
12 :
13 : #include "present.h"
14 :
15 : /**
16 : * Shortcut macro to compare year, month, and day all in one.
17 : * Expects that the Date is "d".
18 : */
19 : #define IS(test_year, test_month, test_day) \
20 : REQUIRE_FALSE(d.has_error); \
21 : CHECK(d.data_.year == test_year); \
22 : CHECK(d.data_.month == test_month); \
23 : CHECK(d.data_.day == test_day);
24 :
25 : /**
26 : * Shortcut macro to check if there's a certain error.
27 : * Expects that the Date is "d".
28 : */
29 : #define IS_ERROR(eRR_tYPE) \
30 : CHECK(d.has_error); \
31 : CHECK(d.errors.eRR_tYPE);
32 :
33 :
34 : /**
35 : * This test case tests all the overloads of the "create" method (which also
36 : * tests the C "Date_from_..." functions).
37 : */
38 6 : TEST_CASE("Date creators", "[date]") {
39 : Date d;
40 :
41 5 : SECTION("creating from a year") {
42 1 : d = Date::create(1902);
43 1 : IS(1902, 1, 1);
44 1 : d = Date::create(1999);
45 1 : IS(1999, 1, 1);
46 1 : d = Date::create(2003);
47 1 : IS(2003, 1, 1);
48 1 : d = Date::create(2040);
49 1 : IS(2040, 1, 1);
50 1 : d = Date::create(9999);
51 1 : IS(9999, 1, 1);
52 :
53 1 : d = Date_from_year(1995);
54 1 : IS(1995, 1, 1);
55 :
56 1 : Date_ptr_from_year(&d, 1960);
57 1 : IS(1960, 1, 1);
58 5 : }
59 :
60 5 : SECTION("creating from a year and month") {
61 1 : d = Date::create(1999, 1);
62 1 : IS(1999, 1, 1);
63 1 : d = Date::create(1999, 2);
64 1 : IS(1999, 2, 1);
65 1 : d = Date::create(1999, 12);
66 1 : IS(1999, 12, 1);
67 1 : d = Date::create(1999, 13);
68 1 : IS_ERROR(month_out_of_range);
69 1 : d = Date::create(1999, 0);
70 1 : IS_ERROR(month_out_of_range);
71 :
72 1 : d = Date_from_year_month(1995, 4);
73 1 : IS(1995, 4, 1);
74 1 : d = Date_from_year_month(1969, -3);
75 1 : IS_ERROR(month_out_of_range);
76 :
77 1 : Date_ptr_from_year_month(&d, 1960, 7);
78 1 : IS(1960, 7, 1);
79 1 : Date_ptr_from_year_month(&d, 1902, -1);
80 1 : IS_ERROR(month_out_of_range);
81 5 : }
82 :
83 5 : SECTION("creating from a year, month, and day") {
84 1 : d = Date::create(1999, 1, 1);
85 1 : IS(1999, 1, 1);
86 1 : d = Date::create(1999, 1, 2);
87 1 : IS(1999, 1, 2);
88 1 : d = Date::create(1999, 1, 0);
89 1 : IS_ERROR(day_out_of_range);
90 : // Jan.
91 1 : d = Date::create(1999, 1, 31);
92 1 : IS(1999, 1, 31);
93 1 : d = Date::create(1999, 1, 32);
94 1 : IS_ERROR(day_out_of_range);
95 : // Feb. (without and with leap years)
96 1 : d = Date::create(1999, 2, 28);
97 1 : IS(1999, 2, 28);
98 1 : d = Date::create(1999, 2, 29);
99 1 : IS_ERROR(day_out_of_range);
100 1 : d = Date::create(2000, 2, 28);
101 1 : IS(2000, 2, 28);
102 1 : d = Date::create(2000, 2, 29);
103 1 : IS(2000, 2, 29);
104 1 : d = Date::create(2000, 2, 30);
105 1 : IS_ERROR(day_out_of_range);
106 : // Apr.
107 1 : d = Date::create(1999, 4, 30);
108 1 : IS(1999, 4, 30);
109 1 : d = Date::create(1999, 4, 31);
110 1 : IS_ERROR(day_out_of_range);
111 :
112 1 : d = Date_from_year_month_day(2006, 11, 13);
113 1 : IS(2006, 11, 13);
114 1 : d = Date_from_year_month_day(1990, 1, -1);
115 1 : IS_ERROR(day_out_of_range);
116 :
117 1 : Date_ptr_from_year_month_day(&d, 1991, 3, 4);
118 1 : IS(1991, 3, 4);
119 1 : Date_ptr_from_year_month_day(&d, 1990, 1, -2);
120 1 : IS_ERROR(day_out_of_range);
121 5 : }
122 :
123 5 : SECTION("creating from a year and a day") {
124 1 : d = Date::from_year_day(2000, 1);
125 1 : IS(2000, 1, 1);
126 1 : d = Date::from_year_day(2000, 2);
127 1 : IS(2000, 1, 2);
128 1 : d = Date::from_year_day(2000, 31);
129 1 : IS(2000, 1, 31);
130 1 : d = Date::from_year_day(2000, 32);
131 1 : IS(2000, 2, 1);
132 1 : d = Date::from_year_day(2000, 60);
133 1 : IS(2000, 2, 29);
134 1 : d = Date::from_year_day(2000, 365);
135 1 : IS(2000, 12, 30);
136 1 : d = Date::from_year_day(2000, 366);
137 1 : IS(2000, 12, 31);
138 :
139 1 : d = Date_from_year_day(1990, 1);
140 1 : IS(1990, 1, 1);
141 :
142 1 : Date_ptr_from_year_day(&d, 1969, 4);
143 1 : IS(1969, 1, 4);
144 5 : }
145 :
146 5 : SECTION("creating from a year, a week, and a day") {
147 : // Each of these has a matching test for week_of_year and
148 : // day_of_week down in the "week_of_year and day_of_week
149 : // edge cases" test case.
150 :
151 1 : d = Date::from_year_week_day(2016, 31, DAY_OF_WEEK_WEDNESDAY);
152 1 : IS(2016, 8, 3);
153 :
154 : // In 2004, the first week of the year started in the end of 2003
155 1 : d = Date::from_year_week_day(2004, 1, DAY_OF_WEEK_MONDAY);
156 1 : IS(2003, 12, 29);
157 :
158 : // But not in 2007
159 1 : d = Date::from_year_week_day(2007, 1, DAY_OF_WEEK_MONDAY);
160 1 : IS(2007, 1, 1);
161 :
162 : // The last week of 2005 was week 52
163 1 : d = Date::from_year_week_day(2005, 52, DAY_OF_WEEK_MONDAY);
164 1 : IS(2005, 12, 26);
165 :
166 : // It rolls over into 2006
167 1 : d = Date::from_year_week_day(2005, 52, DAY_OF_WEEK_SUNDAY);
168 1 : IS(2006, 1, 1);
169 :
170 : // Even if we use the wrong Sunday
171 1 : d = Date::from_year_week_day(2005, 52, DAY_OF_WEEK_SUNDAY_COMPAT);
172 1 : IS(2006, 1, 1);
173 :
174 : // 2005 didn't have a week 53
175 1 : d = Date::from_year_week_day(2005, 53, DAY_OF_WEEK_MONDAY);
176 1 : IS_ERROR(week_of_year_out_of_range);
177 :
178 : // 2009 did, though
179 1 : d = Date::from_year_week_day(2009, 53, DAY_OF_WEEK_MONDAY);
180 1 : IS(2009, 12, 28);
181 :
182 : // And it rolls over into 2010
183 1 : d = Date::from_year_week_day(2009, 53, DAY_OF_WEEK_FRIDAY);
184 1 : IS(2010, 1, 1);
185 :
186 : // But 2009 didn't have a week 54
187 1 : d = Date::from_year_week_day(2009, 54, DAY_OF_WEEK_MONDAY);
188 1 : IS_ERROR(week_of_year_out_of_range);
189 :
190 : // 1992 has a week 53, and it was a leap year starting on Wed.
191 : // It also spilled over into 1993
192 1 : d = Date::from_year_week_day(1992, 53, DAY_OF_WEEK_SUNDAY);
193 1 : IS(1993, 1, 3);
194 :
195 : // 1995 started on a Sunday, and does not have 53 weeks
196 1 : d = Date::from_year_week_day(1995, 53, DAY_OF_WEEK_MONDAY);
197 1 : IS_ERROR(week_of_year_out_of_range);
198 :
199 : // And nobody should have weeks less than 1
200 1 : d = Date::from_year_week_day(1999, 0, DAY_OF_WEEK_MONDAY);
201 1 : IS_ERROR(week_of_year_out_of_range);
202 1 : d = Date::from_year_week_day(1999, -1, DAY_OF_WEEK_MONDAY);
203 1 : IS_ERROR(week_of_year_out_of_range);
204 :
205 : // Nor days of the week outside 0 to 7
206 1 : d = Date::from_year_week_day(2007, 1, 8);
207 1 : IS_ERROR(day_of_week_out_of_range);
208 1 : d = Date::from_year_week_day(2007, 1, -1);
209 1 : IS_ERROR(day_of_week_out_of_range);
210 :
211 1 : d = Date_from_year_week_day(2016, 31, DAY_OF_WEEK_WEDNESDAY);
212 1 : IS(2016, 8, 3);
213 1 : d = Date_from_year_week_day(1999, 0, DAY_OF_WEEK_MONDAY);
214 1 : IS_ERROR(week_of_year_out_of_range);
215 1 : d = Date_from_year_week_day(1990, 1, -1);
216 1 : IS_ERROR(day_of_week_out_of_range);
217 :
218 1 : Date_ptr_from_year_week_day(&d, 2016, 31, DAY_OF_WEEK_WEDNESDAY);
219 1 : IS(2016, 8, 3);
220 1 : Date_ptr_from_year_week_day(&d, 1996, -1, DAY_OF_WEEK_THURSDAY);
221 1 : IS_ERROR(week_of_year_out_of_range);
222 1 : Date_ptr_from_year_week_day(&d, 1968, 2, -3);
223 1 : IS_ERROR(day_of_week_out_of_range);
224 5 : }
225 5 : }
226 :
227 2 : TEST_CASE("Date accessors", "[date]") {
228 1 : Date d1 = Date::create(1902, 1, 1);
229 1 : Date d2 = Date::create(2011, 4, 19);
230 1 : Date d3 = Date::create(2000, 2, 29);
231 1 : Date d4 = Date::create(2000, 3, 1);
232 1 : Date d5 = Date::create(1995, 1, 1);
233 :
234 : // Check year
235 1 : CHECK(d1.year() == 1902);
236 1 : CHECK(d2.year() == 2011);
237 1 : CHECK(d3.year() == 2000);
238 1 : CHECK(d4.year() == 2000);
239 1 : CHECK(d5.year() == 1995);
240 :
241 : // Check month
242 1 : CHECK(d1.month() == 1);
243 1 : CHECK(d2.month() == 4);
244 1 : CHECK(d3.month() == 2);
245 1 : CHECK(d4.month() == 3);
246 1 : CHECK(d5.month() == 1);
247 :
248 : // Check day
249 1 : CHECK(d1.day() == 1);
250 1 : CHECK(d2.day() == 19);
251 1 : CHECK(d3.day() == 29);
252 1 : CHECK(d4.day() == 1);
253 1 : CHECK(d5.day() == 1);
254 :
255 : // Check day_of_year
256 1 : CHECK(d1.day_of_year() == 1);
257 1 : CHECK(d2.day_of_year() == 109);
258 1 : CHECK(d3.day_of_year() == 60);
259 1 : CHECK(d4.day_of_year() == 61);
260 1 : CHECK(d5.day_of_year() == 1);
261 :
262 : // Check week_of_year
263 : PresentWeekYear weekyear;
264 :
265 1 : weekyear = d1.week_of_year();
266 1 : CHECK(weekyear.week == 1);
267 1 : CHECK(weekyear.year == 1902);
268 :
269 1 : weekyear = d2.week_of_year();
270 1 : CHECK(weekyear.week == 16);
271 1 : CHECK(weekyear.year == 2011);
272 :
273 1 : weekyear = d3.week_of_year();
274 1 : CHECK(weekyear.week == 9);
275 1 : CHECK(weekyear.year == 2000);
276 :
277 1 : weekyear = d4.week_of_year();
278 1 : CHECK(weekyear.week == 9);
279 1 : CHECK(weekyear.year == 2000);
280 :
281 1 : weekyear = d5.week_of_year();
282 1 : CHECK(weekyear.week == 52);
283 1 : CHECK(weekyear.year == 1994);
284 :
285 : // Check day_of_week
286 1 : CHECK(d1.day_of_week() == DAY_OF_WEEK_WEDNESDAY);
287 1 : CHECK(d2.day_of_week() == DAY_OF_WEEK_TUESDAY);
288 1 : CHECK(d3.day_of_week() == DAY_OF_WEEK_TUESDAY);
289 1 : CHECK(d4.day_of_week() == DAY_OF_WEEK_WEDNESDAY);
290 1 : CHECK(d5.day_of_week() == DAY_OF_WEEK_SUNDAY);
291 1 : }
292 :
293 2 : TEST_CASE("Date 'week_of_year' and 'day_of_week' edge cases",
294 : "[date]") {
295 : Date d;
296 :
297 : // More tests for week_of_year and day_of_week
298 : // (all of these match the tests for from_year_week_day; see that section
299 : // for explanations of each)
300 1 : d = Date::create(2016, 8, 3);
301 1 : CHECK(d.week_of_year().week == 31);
302 1 : CHECK(d.week_of_year().year == 2016);
303 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_WEDNESDAY);
304 :
305 1 : d = Date::create(2003, 12, 29);
306 1 : CHECK(d.week_of_year().week == 1);
307 1 : CHECK(d.week_of_year().year == 2004);
308 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_MONDAY);
309 :
310 1 : d = Date::create(2007, 1, 1);
311 1 : CHECK(d.week_of_year().week == 1);
312 1 : CHECK(d.week_of_year().year == 2007);
313 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_MONDAY);
314 :
315 1 : d = Date::create(2005, 12, 26);
316 1 : CHECK(d.week_of_year().week == 52);
317 1 : CHECK(d.week_of_year().year == 2005);
318 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_MONDAY);
319 :
320 1 : d = Date::create(2006, 1, 1);
321 1 : CHECK(d.week_of_year().week == 52);
322 1 : CHECK(d.week_of_year().year == 2005);
323 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_SUNDAY);
324 :
325 1 : d = Date::create(2009, 12, 28);
326 1 : CHECK(d.week_of_year().week == 53);
327 1 : CHECK(d.week_of_year().year == 2009);
328 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_MONDAY);
329 :
330 1 : d = Date::create(2010, 1, 1);
331 1 : CHECK(d.week_of_year().week == 53);
332 1 : CHECK(d.week_of_year().year == 2009);
333 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_FRIDAY);
334 :
335 1 : d = Date::create(1993, 1, 3);
336 1 : CHECK(d.week_of_year().week == 53);
337 1 : CHECK(d.week_of_year().year == 1992);
338 1 : CHECK(d.day_of_week() == DAY_OF_WEEK_SUNDAY);
339 1 : }
340 :
341 2 : TEST_CASE("Date 'difference' functions", "[date]") {
342 1 : Date d1 = Date::create(2010, 1, 1);
343 1 : Date d2 = Date::create(2010, 1, 2);
344 :
345 1 : DayDelta exp_diff = DayDelta::from_days(1);
346 1 : CHECK(d1.difference(d2) == -exp_diff);
347 1 : CHECK(d2.difference(d1) == exp_diff);
348 1 : CHECK(d1.absolute_difference(d2) == exp_diff);
349 1 : CHECK(d2.absolute_difference(d1) == exp_diff);
350 1 : }
351 :
352 2 : TEST_CASE("Date arithmetic operators", "[date]") {
353 1 : DayDelta days4 = DayDelta::from_days(4);
354 1 : MonthDelta months3 = MonthDelta::from_months(3);
355 : Date d;
356 :
357 1 : d = Date::create(2005, 12, 27);
358 1 : d += days4;
359 1 : IS(2005, 12, 31);
360 :
361 1 : d = Date::create(2005, 12, 28);
362 1 : d += days4;
363 1 : IS(2006, 1, 1);
364 :
365 1 : d = Date::create(2028, 1, 6);
366 1 : d -= days4;
367 1 : IS(2028, 1, 2);
368 1 : d -= days4;
369 1 : IS(2027, 12, 29);
370 :
371 1 : d = Date::create(1994, 9, 6);
372 1 : d += months3;
373 1 : IS(1994, 12, 6);
374 1 : d += months3;
375 1 : IS(1995, 3, 6);
376 :
377 1 : d = Date::create(1989, 4, 19);
378 1 : d -= months3;
379 1 : IS(1989, 1, 19);
380 1 : d -= months3;
381 1 : IS(1988, 10, 19);
382 :
383 1 : d = Date::create(2000, 1, 1) + DayDelta::from_weeks(1);
384 1 : IS(2000, 1, 8);
385 1 : d = DayDelta::from_weeks(2) + Date::create(2000, 2, 1);
386 1 : IS(2000, 2, 15);
387 :
388 1 : d = Date::create(2019, 5, 6) - DayDelta::from_days(6);
389 1 : IS(2019, 4, 30);
390 :
391 2 : d = Date::create(2000, 1, 1) + MonthDelta::from_years(13) +
392 3 : MonthDelta::from_months(4);
393 1 : IS(2013, 5, 1);
394 1 : d = MonthDelta::from_months(7) + Date::create(2013, 3, 3);
395 1 : IS(2013, 10, 3);
396 :
397 1 : d = Date::create(2018, 9, 4) - MonthDelta::from_months(3);
398 1 : IS(2018, 6, 4);
399 1 : }
400 :
401 2 : TEST_CASE("Date comparison operators", "[date]") {
402 1 : Date d1 = Date::create(2100, 1, 1),
403 1 : d2 = Date::create(2100, 1, 27),
404 1 : d3 = Date::create(2100, 3, 1),
405 1 : d4 = Date::create(2101, 1, 1),
406 1 : d5 = Date::create(2101, 1, 1);
407 :
408 1 : CHECK(Date::compare(d1, d1) == 0);
409 1 : CHECK(Date::compare(d5, d5) == 0);
410 1 : CHECK(Date::compare(d1, d2) < 0);
411 1 : CHECK(Date::compare(d3, d2) > 0);
412 :
413 1 : CHECK(d1 == d1);
414 1 : CHECK(d4 == d5);
415 1 : CHECK(!(d1 == d2));
416 1 : CHECK(d3 != d4);
417 1 : CHECK(d3 != d5);
418 :
419 1 : CHECK(d1 < d2);
420 1 : CHECK(d1 < d3);
421 1 : CHECK(d1 < d4);
422 1 : CHECK(d2 < d3);
423 1 : CHECK(d2 < d4);
424 1 : CHECK(d3 < d4);
425 1 : CHECK(!(d4 < d5));
426 1 : CHECK(!(d2 < d1));
427 :
428 1 : CHECK(d1 <= d1);
429 1 : CHECK(d1 <= d2);
430 1 : CHECK(d1 <= d3);
431 1 : CHECK(d3 <= d5);
432 1 : CHECK(d4 <= d5);
433 1 : CHECK(d5 <= d4);
434 1 : CHECK(!(d2 <= d1));
435 :
436 1 : CHECK(d2 > d1);
437 1 : CHECK(d3 > d1);
438 1 : CHECK(d4 > d1);
439 1 : CHECK(d3 > d2);
440 1 : CHECK(d4 > d2);
441 1 : CHECK(!(d4 > d5));
442 1 : CHECK(!(d1 > d2));
443 :
444 1 : CHECK(d1 >= d1);
445 1 : CHECK(d2 >= d1);
446 1 : CHECK(d3 >= d1);
447 1 : CHECK(d4 >= d1);
448 1 : CHECK(d3 >= d2);
449 1 : CHECK(d4 >= d2);
450 1 : CHECK(d4 >= d3);
451 1 : CHECK(d4 >= d5);
452 1 : CHECK(!(d1 >= d2));
453 4 : }
454 :
|