1 /*
2  * Copyright 2019 Content Management AG
3  * All rights reserved.
4  *
5  * author: Max Kellermann <mk@cm4all.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * - Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * - Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the
17  * distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23  * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "time/ISO8601.hxx"
34 
35 #include <gtest/gtest.h>
36 
37 static constexpr struct {
38 	const char *s;
39 	time_t t;
40 	std::chrono::system_clock::duration d;
41 } parse_tests[] = {
42 	/* full ISO8601 */
43 	{ "1970-01-01T00:00:00Z", 0, std::chrono::seconds(1) },
44 	{ "1970-01-01T00:00:01Z", 1, std::chrono::seconds(1) },
45 	{ "2019-02-04T16:46:41Z", 1549298801, std::chrono::seconds(1) },
46 	{ "2018-12-31T23:59:59Z", 1546300799, std::chrono::seconds(1) },
47 	{ "2019-01-01T00:00:00Z", 1546300800, std::chrono::seconds(1) },
48 
49 	/* full month */
50 	{ "1970-01", 0, std::chrono::hours(24 * 31) },
51 	{ "2019-02", 1548979200, std::chrono::hours(24 * 28) },
52 	{ "2019-01", 1546300800, std::chrono::hours(24 * 31) },
53 
54 	/* only date */
55 	{ "1970-01-01", 0, std::chrono::hours(24) },
56 	{ "2019-02-04", 1549238400, std::chrono::hours(24) },
57 	{ "2018-12-31", 1546214400, std::chrono::hours(24) },
58 	{ "2019-01-01", 1546300800, std::chrono::hours(24) },
59 
60 	/* date with time zone */
61 	{ "2019-02-04Z", 1549238400, std::chrono::hours(24) },
62 
63 	/* without time zone */
64 	{ "2019-02-04T16:46:41", 1549298801, std::chrono::seconds(1) },
65 
66 	/* without seconds */
67 	{ "2019-02-04T16:46", 1549298760, std::chrono::minutes(1) },
68 	{ "2019-02-04T16:46Z", 1549298760, std::chrono::minutes(1) },
69 
70 	/* without minutes */
71 	{ "2019-02-04T16", 1549296000, std::chrono::hours(1) },
72 	{ "2019-02-04T16Z", 1549296000, std::chrono::hours(1) },
73 
74 	/* with time zone */
75 	{ "2019-02-04T16:46:41+02", 1549291601, std::chrono::seconds(1) },
76 	{ "2019-02-04T16:46:41+0200", 1549291601, std::chrono::seconds(1) },
77 	{ "2019-02-04T16:46:41+02:00", 1549291601, std::chrono::seconds(1) },
78 	{ "2019-02-04T16:46:41-0200", 1549306001, std::chrono::seconds(1) },
79 
80 	/* without field separators */
81 	{ "19700101T000000Z", 0, std::chrono::seconds(1) },
82 	{ "19700101T000001Z", 1, std::chrono::seconds(1) },
83 	{ "20190204T164641Z", 1549298801, std::chrono::seconds(1) },
84 	{ "19700101", 0, std::chrono::hours(24) },
85 	{ "20190204", 1549238400, std::chrono::hours(24) },
86 	{ "20190204T1646", 1549298760, std::chrono::minutes(1) },
87 	{ "20190204T16", 1549296000, std::chrono::hours(1) },
88 };
89 
TEST(ISO8601,Parse)90 TEST(ISO8601, Parse)
91 {
92 #ifdef _WIN32
93 	// TODO: re-enable when ParseISO8601() has been implemented on Windows
94 	GTEST_SKIP();
95 #endif
96 
97 	for (const auto &i : parse_tests) {
98 		const auto result = ParseISO8601(i.s);
99 		EXPECT_EQ(std::chrono::system_clock::to_time_t(result.first), i.t);
100 		EXPECT_EQ(result.second, i.d);
101 	}
102 }
103