xref: /aosp_15_r20/external/cronet/third_party/libc++/src/test/libcxx/time/time.zone/time.zone.db/zones.pass.cpp (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: no-filesystem, no-localization, no-tzdb
11 
12 // XFAIL: libcpp-has-no-incomplete-tzdb
13 // XFAIL: availability-tzdb-missing
14 
15 // <chrono>
16 
17 // Tests the IANA database zones parsing and operations.
18 // This is not part of the public tzdb interface.
19 // The test uses private implementation headers.
20 // ADDITIONAL_COMPILE_FLAGS: -I %S/../../../../../src/include
21 
22 #include <cassert>
23 #include <chrono>
24 #include <fstream>
25 #include <string>
26 #include <string_view>
27 #include <variant>
28 
29 #include "assert_macros.h"
30 #include "concat_macros.h"
31 #include "filesystem_test_helper.h"
32 #include "test_tzdb.h"
33 
34 // headers in the dylib
35 #include "tzdb/types_private.h"
36 #include "tzdb/tzdb_private.h"
37 #include "tzdb/time_zone_private.h"
38 
39 scoped_test_env env;
40 [[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
41 const std::filesystem::path file                 = env.create_file("zoneinfo/tzdata.zi");
42 
__libcpp_tzdb_directory()43 std::string_view std::chrono::__libcpp_tzdb_directory() {
44   static std::string result = dir.string();
45   return result;
46 }
47 
write(std::string_view input)48 static void write(std::string_view input) {
49   static int version = 0;
50 
51   std::ofstream f{file};
52   f << "# version " << version++ << '\n';
53   f.write(input.data(), input.size());
54 }
55 
parse(std::string_view input)56 static const std::chrono::tzdb& parse(std::string_view input) {
57   write(input);
58   return std::chrono::reload_tzdb();
59 }
60 
continuations(const std::chrono::time_zone & time_zone)61 static const std::vector<std::chrono::__tz::__continuation>& continuations(const std::chrono::time_zone& time_zone) {
62   return time_zone.__implementation().__continuations();
63 }
64 
test_exception(std::string_view input,std::string_view what)65 static void test_exception(std::string_view input, [[maybe_unused]] std::string_view what) {
66   write(input);
67 
68   TEST_VALIDATE_EXCEPTION(
69       std::runtime_error,
70       [&]([[maybe_unused]] const std::runtime_error& e) {
71         TEST_LIBCPP_REQUIRE(
72             e.what() == what,
73             TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
74       },
75       TEST_IGNORE_NODISCARD std::chrono::reload_tzdb());
76 }
77 
test_invalid()78 static void test_invalid() {
79   test_exception("Z", "corrupt tzdb: expected whitespace");
80 
81   test_exception("Z ", "corrupt tzdb: expected a string");
82 
83   test_exception("Z n", "corrupt tzdb: expected whitespace");
84 
85   test_exception("Z n ", "corrupt tzdb: expected a digit");
86   test_exception("Z n x", "corrupt tzdb: expected a digit");
87   test_exception("Z n +", "corrupt tzdb: expected a digit");
88 
89   test_exception("Z n 0", "corrupt tzdb: expected whitespace");
90 
91   test_exception("Z n 0 ", "corrupt tzdb: expected a string");
92 
93   test_exception("Z n 0 r", "corrupt tzdb: expected whitespace");
94 
95   test_exception("Z n 0 r ", "corrupt tzdb: expected a string");
96 }
97 
test_name()98 static void test_name() {
99   const std::chrono::tzdb& result = parse(
100       R"(
101 Z n 0 r f
102 )");
103   assert(result.zones.size() == 1);
104   assert(result.zones[0].name() == "n");
105 }
106 
test_stdoff()107 static void test_stdoff() {
108   const std::chrono::tzdb& result = parse(
109       R"(
110 # Based on the examples in the man page.
111 # Note the input is not expected to have fractional seconds, they are truncated.
112 Zo na 2 r f
113 Zon nb 2:00 r f
114 Zone nc 01:28:14 r f
115 zONE nd 00:19:32.10 r f
116 zoNe ne 12:00 r f
117 Z nf 15:00 r f
118 Z ng 24:00 r f
119 Z nh 260:00 r f
120 Z ni -2:30 r f
121 Z nj - r f
122 )");
123 
124   assert(result.zones.size() == 10);
125   for (std::size_t i = 0; i < result.zones.size(); ++i)
126     assert(continuations(result.zones[0]).size() == 1);
127 
128   assert(continuations(result.zones[0])[0].__stdoff == std::chrono::hours(2));
129   assert(continuations(result.zones[1])[0].__stdoff == std::chrono::hours(2));
130   assert(continuations(result.zones[2])[0].__stdoff ==
131          std::chrono::hours(1) + std::chrono::minutes(28) + std::chrono::seconds(14));
132   assert(continuations(result.zones[3])[0].__stdoff == std::chrono::minutes(19) + std::chrono::seconds(32));
133   assert(continuations(result.zones[4])[0].__stdoff == std::chrono::hours(12));
134   assert(continuations(result.zones[5])[0].__stdoff == std::chrono::hours(15));
135   assert(continuations(result.zones[6])[0].__stdoff == std::chrono::hours(24));
136   assert(continuations(result.zones[7])[0].__stdoff == std::chrono::hours(260));
137   assert(continuations(result.zones[8])[0].__stdoff == -(std::chrono::hours(2) + std::chrono::minutes(30)));
138   assert(continuations(result.zones[9])[0].__stdoff == std::chrono::hours(0)); // The man page expresses it in hours
139 }
140 
test_rules()141 static void test_rules() {
142   const std::chrono::tzdb& result = parse(
143       R"(
144 Z na 0 - f
145 Z nb 0 r f
146 Z nc 0 2d f
147 Z nd 0 2:00s f
148 Z ne 0 0 f
149 Z nf 0 0:00:01 f
150 Z ng 0 -0:00:01 f
151 )");
152 
153   assert(result.zones.size() == 7);
154   for (std::size_t i = 0; i < result.zones.size(); ++i)
155     assert(continuations(result.zones[0]).size() == 1);
156 
157   assert(std::holds_alternative<std::monostate>(continuations(result.zones[0])[0].__rules));
158   assert(std::get<std::string>(continuations(result.zones[1])[0].__rules) == "r");
159 
160   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[2])[0].__rules).__time ==
161          std::chrono::hours(2));
162   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[2])[0].__rules).__is_dst == true);
163 
164   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[3])[0].__rules).__time ==
165          std::chrono::hours(2));
166   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[3])[0].__rules).__is_dst == false);
167 
168   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[4])[0].__rules).__time ==
169          std::chrono::hours(0));
170   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[4])[0].__rules).__is_dst == false);
171 
172   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[5])[0].__rules).__time ==
173          std::chrono::seconds(1));
174   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[5])[0].__rules).__is_dst == true);
175 
176   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[6])[0].__rules).__time ==
177          -std::chrono::seconds(1));
178   assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[6])[0].__rules).__is_dst == true);
179 }
180 
test_format()181 static void test_format() {
182   const std::chrono::tzdb& result = parse(
183       R"(
184 Z n 0 r f
185 )");
186   assert(result.zones.size() == 1);
187   assert(continuations(result.zones[0]).size() == 1);
188   assert(continuations(result.zones[0])[0].__format == "f");
189 }
190 
test_until()191 static void test_until() {
192   const std::chrono::tzdb& result = parse(
193       R"(
194 Z na 0 r f
195 Z nb 0 r f 1000
196 Z nc 0 r f -1000 N
197 Z nd 0 r f ma S 31
198 Z ne 0 r f 0 jA LASTw
199 Z nf 0 r f -42 jUN m<=1
200 Z ng 0 r f 42 jul Su>=12
201 Z nh 0 r f 42 JUl 1 2w
202 Z ni 0 r f 42 July 1 01:28:14u
203 Z nj 0 r f 42 Jul 1 -
204 )");
205   assert(result.zones.size() == 10);
206   for (std::size_t i = 0; i < result.zones.size(); ++i)
207     assert(continuations(result.zones[0]).size() == 1);
208 
209   std::chrono::__tz::__constrained_weekday r;
210 
211   assert(continuations(result.zones[0])[0].__year == std::chrono::year::min());
212   assert(continuations(result.zones[0])[0].__in == std::chrono::January);
213   assert(std::get<std::chrono::day>(continuations(result.zones[0])[0].__on) == std::chrono::day(1));
214   assert(continuations(result.zones[0])[0].__at.__time == std::chrono::seconds(0));
215   assert(continuations(result.zones[0])[0].__at.__clock == std::chrono::__tz::__clock::__local);
216 
217   assert(continuations(result.zones[1])[0].__year == std::chrono::year(1000));
218   assert(continuations(result.zones[1])[0].__in == std::chrono::January);
219   assert(std::get<std::chrono::day>(continuations(result.zones[1])[0].__on) == std::chrono::day(1));
220   assert(continuations(result.zones[1])[0].__at.__time == std::chrono::seconds(0));
221   assert(continuations(result.zones[1])[0].__at.__clock == std::chrono::__tz::__clock::__local);
222 
223   assert(continuations(result.zones[2])[0].__year == std::chrono::year(-1000));
224   assert(continuations(result.zones[2])[0].__in == std::chrono::November);
225   assert(std::get<std::chrono::day>(continuations(result.zones[2])[0].__on) == std::chrono::day(1));
226   assert(continuations(result.zones[2])[0].__at.__time == std::chrono::seconds(0));
227   assert(continuations(result.zones[2])[0].__at.__clock == std::chrono::__tz::__clock::__local);
228 
229   assert(continuations(result.zones[3])[0].__year == std::chrono::year::max());
230   assert(continuations(result.zones[3])[0].__in == std::chrono::September);
231   assert(std::get<std::chrono::day>(continuations(result.zones[3])[0].__on) == std::chrono::day(31));
232   assert(continuations(result.zones[3])[0].__at.__time == std::chrono::seconds(0));
233   assert(continuations(result.zones[3])[0].__at.__clock == std::chrono::__tz::__clock::__local);
234 
235   assert(continuations(result.zones[4])[0].__year == std::chrono::year(0));
236   assert(continuations(result.zones[4])[0].__in == std::chrono::January);
237   assert(std::get<std::chrono::weekday_last>(continuations(result.zones[4])[0].__on) ==
238          std::chrono::weekday_last{std::chrono::Wednesday});
239   assert(continuations(result.zones[4])[0].__at.__time == std::chrono::seconds(0));
240   assert(continuations(result.zones[4])[0].__at.__clock == std::chrono::__tz::__clock::__local);
241 
242   assert(continuations(result.zones[5])[0].__year == std::chrono::year(-42));
243   assert(continuations(result.zones[5])[0].__in == std::chrono::June);
244   r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[5])[0].__on);
245   assert(r.__weekday == std::chrono::Monday);
246   assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__le);
247   assert(r.__day == std::chrono::day(1));
248   assert(continuations(result.zones[5])[0].__at.__time == std::chrono::seconds(0));
249   assert(continuations(result.zones[5])[0].__at.__clock == std::chrono::__tz::__clock::__local);
250 
251   assert(continuations(result.zones[6])[0].__year == std::chrono::year(42));
252   assert(continuations(result.zones[6])[0].__in == std::chrono::July);
253   r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[6])[0].__on);
254   assert(r.__weekday == std::chrono::Sunday);
255   assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
256   assert(r.__day == std::chrono::day(12));
257   assert(continuations(result.zones[6])[0].__at.__time == std::chrono::seconds(0));
258   assert(continuations(result.zones[6])[0].__at.__clock == std::chrono::__tz::__clock::__local);
259 
260   assert(continuations(result.zones[7])[0].__year == std::chrono::year(42));
261   assert(continuations(result.zones[7])[0].__in == std::chrono::July);
262   assert(std::get<std::chrono::day>(continuations(result.zones[7])[0].__on) == std::chrono::day(1));
263   assert(continuations(result.zones[7])[0].__at.__time == std::chrono::hours(2));
264   assert(continuations(result.zones[7])[0].__at.__clock == std::chrono::__tz::__clock::__local);
265 
266   assert(continuations(result.zones[8])[0].__year == std::chrono::year(42));
267   assert(continuations(result.zones[8])[0].__in == std::chrono::July);
268   assert(std::get<std::chrono::day>(continuations(result.zones[8])[0].__on) == std::chrono::day(1));
269   assert(continuations(result.zones[8])[0].__at.__time ==
270          std::chrono::hours(1) + std::chrono::minutes(28) + std::chrono::seconds(14));
271   assert(continuations(result.zones[8])[0].__at.__clock == std::chrono::__tz::__clock::__universal);
272 
273   assert(continuations(result.zones[9])[0].__year == std::chrono::year(42));
274   assert(continuations(result.zones[9])[0].__in == std::chrono::July);
275   assert(std::get<std::chrono::day>(continuations(result.zones[9])[0].__on) == std::chrono::day(1));
276   assert(continuations(result.zones[9])[0].__at.__time == std::chrono::hours(0)); // The man page expresses it in hours
277   assert(continuations(result.zones[9])[0].__at.__clock == std::chrono::__tz::__clock::__local);
278 }
279 
test_continuation()280 static void test_continuation() {
281   const std::chrono::tzdb& result = parse(
282       R"(
283 Z na 0 r f
284 0 r f 1000
285 0 r f -1000 N
286 0 r f ma S 31
287 0 r f 0 Ja lastW
288 0 r f -42 Jun M<=1
289 0 r f 42 Jul Su>=12
290 0 r f 42 Jul 1 2w
291 0 r f 42 Jul 1 01:28:14u
292 0 r f 42 Jul 1 -
293 )");
294 
295   assert(result.zones.size() == 1);
296   assert(continuations(result.zones[0]).size() == 10);
297 
298   std::chrono::__tz::__constrained_weekday r;
299 
300   assert(continuations(result.zones[0])[0].__year == std::chrono::year::min());
301   assert(continuations(result.zones[0])[0].__in == std::chrono::January);
302   assert(std::get<std::chrono::day>(continuations(result.zones[0])[0].__on) == std::chrono::day(1));
303   assert(continuations(result.zones[0])[0].__at.__time == std::chrono::seconds(0));
304   assert(continuations(result.zones[0])[0].__at.__clock == std::chrono::__tz::__clock::__local);
305 
306   assert(continuations(result.zones[0])[1].__year == std::chrono::year(1000));
307   assert(continuations(result.zones[0])[1].__in == std::chrono::January);
308   assert(std::get<std::chrono::day>(continuations(result.zones[0])[1].__on) == std::chrono::day(1));
309   assert(continuations(result.zones[0])[1].__at.__time == std::chrono::seconds(0));
310   assert(continuations(result.zones[0])[1].__at.__clock == std::chrono::__tz::__clock::__local);
311 
312   assert(continuations(result.zones[0])[2].__year == std::chrono::year(-1000));
313   assert(continuations(result.zones[0])[2].__in == std::chrono::November);
314   assert(std::get<std::chrono::day>(continuations(result.zones[0])[2].__on) == std::chrono::day(1));
315   assert(continuations(result.zones[0])[2].__at.__time == std::chrono::seconds(0));
316   assert(continuations(result.zones[0])[2].__at.__clock == std::chrono::__tz::__clock::__local);
317 
318   assert(continuations(result.zones[0])[3].__year == std::chrono::year::max());
319   assert(continuations(result.zones[0])[3].__in == std::chrono::September);
320   assert(std::get<std::chrono::day>(continuations(result.zones[0])[3].__on) == std::chrono::day(31));
321   assert(continuations(result.zones[0])[3].__at.__time == std::chrono::seconds(0));
322   assert(continuations(result.zones[0])[3].__at.__clock == std::chrono::__tz::__clock::__local);
323 
324   assert(continuations(result.zones[0])[4].__year == std::chrono::year(0));
325   assert(continuations(result.zones[0])[4].__in == std::chrono::January);
326   assert(std::get<std::chrono::weekday_last>(continuations(result.zones[0])[4].__on) ==
327          std::chrono::weekday_last{std::chrono::Wednesday});
328   assert(continuations(result.zones[0])[4].__at.__time == std::chrono::seconds(0));
329   assert(continuations(result.zones[0])[4].__at.__clock == std::chrono::__tz::__clock::__local);
330 
331   assert(continuations(result.zones[0])[5].__year == std::chrono::year(-42));
332   assert(continuations(result.zones[0])[5].__in == std::chrono::June);
333   r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[0])[5].__on);
334   assert(r.__weekday == std::chrono::Monday);
335   assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__le);
336   assert(r.__day == std::chrono::day(1));
337   assert(continuations(result.zones[0])[5].__at.__time == std::chrono::seconds(0));
338   assert(continuations(result.zones[0])[5].__at.__clock == std::chrono::__tz::__clock::__local);
339 
340   assert(continuations(result.zones[0])[6].__year == std::chrono::year(42));
341   assert(continuations(result.zones[0])[6].__in == std::chrono::July);
342   r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[0])[6].__on);
343   assert(r.__weekday == std::chrono::Sunday);
344   assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
345   assert(r.__day == std::chrono::day(12));
346   assert(continuations(result.zones[0])[6].__at.__time == std::chrono::seconds(0));
347   assert(continuations(result.zones[0])[6].__at.__clock == std::chrono::__tz::__clock::__local);
348 
349   assert(continuations(result.zones[0])[7].__year == std::chrono::year(42));
350   assert(continuations(result.zones[0])[7].__in == std::chrono::July);
351   assert(std::get<std::chrono::day>(continuations(result.zones[0])[7].__on) == std::chrono::day(1));
352   assert(continuations(result.zones[0])[7].__at.__time == std::chrono::hours(2));
353   assert(continuations(result.zones[0])[7].__at.__clock == std::chrono::__tz::__clock::__local);
354 
355   assert(continuations(result.zones[0])[8].__year == std::chrono::year(42));
356   assert(continuations(result.zones[0])[8].__in == std::chrono::July);
357   assert(std::get<std::chrono::day>(continuations(result.zones[0])[8].__on) == std::chrono::day(1));
358   assert(continuations(result.zones[0])[8].__at.__time ==
359          std::chrono::hours(1) + std::chrono::minutes(28) + std::chrono::seconds(14));
360   assert(continuations(result.zones[0])[8].__at.__clock == std::chrono::__tz::__clock::__universal);
361 
362   assert(continuations(result.zones[0])[9].__year == std::chrono::year(42));
363   assert(continuations(result.zones[0])[9].__in == std::chrono::July);
364   assert(std::get<std::chrono::day>(continuations(result.zones[0])[9].__on) == std::chrono::day(1));
365   assert(continuations(result.zones[0])[9].__at.__time == std::chrono::hours(0)); // The man page expresses it in hours
366   assert(continuations(result.zones[0])[9].__at.__clock == std::chrono::__tz::__clock::__local);
367 }
368 
main(int,const char **)369 int main(int, const char**) {
370   test_invalid();
371   test_name();
372   test_stdoff();
373   test_rules();
374   test_format();
375   test_until();
376 
377   test_continuation();
378 
379   return 0;
380 }
381