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
10 // UNSUPPORTED: availability-filesystem-missing
11
12 // <filesystem>
13
14 // typedef TrivialClock file_time_type;
15
16 // ADDITIONAL_COMPILE_FLAGS: -I %{libcxx-dir}/src -Wno-macro-redefined
17
18 #include <cassert>
19 #include <chrono>
20 #include <cstddef>
21 #include <filesystem>
22 #include <limits>
23 #include <string>
24 #include <type_traits>
25
26 #include "filesystem/time_utils.h"
27
28 #ifndef __SIZEOF_INT128__
29 #define TEST_HAS_NO_INT128_T
30 #endif
31
32 using namespace std::chrono;
33 namespace fs = std::filesystem;
34 using fs::file_time_type;
35 using fs::detail::time_util;
36
37 #ifdef TEST_HAS_NO_INT128_T
38 static_assert(sizeof(fs::file_time_type::rep) <= 8, "");
39 #endif
40
41 enum TestKind { TK_128Bit, TK_64Bit, TK_32Bit, TK_FloatingPoint };
42
43 template <class TimeT>
getTimeTTestKind()44 constexpr TestKind getTimeTTestKind() {
45 if (sizeof(TimeT) == 8 && !std::is_floating_point<TimeT>::value)
46 return TK_64Bit;
47 else if (sizeof(TimeT) == 4 && !std::is_floating_point<TimeT>::value)
48 return TK_32Bit;
49 else if (std::is_floating_point<TimeT>::value)
50 return TK_FloatingPoint;
51 else
52 assert(false && "test kind not supported");
53 }
54 template <class FileTimeT>
getFileTimeTestKind()55 constexpr TestKind getFileTimeTestKind() {
56 using Rep = typename FileTimeT::rep;
57 if (std::is_floating_point<Rep>::value)
58 return TK_FloatingPoint;
59 else if (sizeof(Rep) == 16)
60 return TK_128Bit;
61 else if (sizeof(Rep) == 8)
62 return TK_64Bit;
63 else
64 assert(false && "test kind not supported");
65 }
66
67 template <class FileTimeT, class TimeT, class TimeSpecT,
68 class Base = time_util<FileTimeT, TimeT, TimeSpecT>,
69 TestKind = getTimeTTestKind<TimeT>(),
70 TestKind = getFileTimeTestKind<FileTimeT>()>
71 struct test_case;
72
73 template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
74 struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_64Bit, TK_128Bit>
75 : public Base {
76
77 using Base::convert_from_timespec;
78 using Base::convert_to_timespec;
79 using Base::is_representable;
80 using Base::max_nsec;
81 using Base::max_seconds;
82 using Base::min_nsec_timespec;
83 using Base::min_seconds;
84
85 static constexpr auto max_time_t = std::numeric_limits<TimeT>::max();
86 static constexpr auto min_time_t = std::numeric_limits<TimeT>::min();
87
test_timespectest_case88 static constexpr bool test_timespec() {
89 static_assert(is_representable(TimeSpecT{max_time_t, 0}), "");
90 static_assert(is_representable(TimeSpecT{max_time_t, 999999999}), "");
91 static_assert(is_representable(TimeSpecT{max_time_t, 1000000000}), "");
92 static_assert(is_representable(TimeSpecT{max_time_t, max_nsec}), "");
93
94 static_assert(is_representable(TimeSpecT{min_time_t, 0}), "");
95 static_assert(is_representable(TimeSpecT{min_time_t, 999999999}), "");
96 static_assert(is_representable(TimeSpecT{min_time_t, 1000000000}), "");
97 static_assert(is_representable(TimeSpecT{min_time_t, min_nsec_timespec}),
98 "");
99
100 return true;
101 }
102
test_file_time_typetest_case103 static constexpr bool test_file_time_type() {
104 // This kinda sucks. Oh well.
105 static_assert(!Base::is_representable(FileTimeT::max()), "");
106 static_assert(!Base::is_representable(FileTimeT::min()), "");
107 return true;
108 }
109
check_round_triptest_case110 static constexpr bool check_round_trip(TimeSpecT orig) {
111 TimeSpecT new_ts = {};
112 FileTimeT out = convert_from_timespec(orig);
113 assert(convert_to_timespec(new_ts, out));
114 return new_ts.tv_sec == orig.tv_sec && new_ts.tv_nsec == orig.tv_nsec;
115 }
116
test_convert_timespectest_case117 static constexpr bool test_convert_timespec() {
118 static_assert(check_round_trip({0, 0}), "");
119 static_assert(check_round_trip({0, 1}), "");
120 static_assert(check_round_trip({1, 1}), "");
121 static_assert(check_round_trip({-1, 1}), "");
122 static_assert(check_round_trip({max_time_t, max_nsec}), "");
123 static_assert(check_round_trip({max_time_t, 123}), "");
124 static_assert(check_round_trip({min_time_t, min_nsec_timespec}), "");
125 static_assert(check_round_trip({min_time_t, 123}), "");
126 return true;
127 }
128
testtest_case129 static bool test() {
130 static_assert(test_timespec(), "");
131 static_assert(test_file_time_type(), "");
132 static_assert(test_convert_timespec(), "");
133 return true;
134 }
135 };
136
137 template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
138 struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_32Bit, TK_128Bit>
139 : public test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_64Bit, TK_128Bit> {
140
141 };
142
143 template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
144 struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_64Bit, TK_64Bit>
145 : public Base {
146
147 using Base::convert_from_timespec;
148 using Base::is_representable;
149 using Base::max_nsec;
150 using Base::max_seconds;
151 using Base::min_nsec_timespec;
152 using Base::min_seconds;
153
154 static constexpr auto max_time_t = std::numeric_limits<TimeT>::max();
155 static constexpr auto min_time_t = std::numeric_limits<TimeT>::min();
156
test_timespectest_case157 static constexpr bool test_timespec() {
158 static_assert(is_representable(TimeSpecT{max_seconds, max_nsec}), "");
159 static_assert(!is_representable(TimeSpecT{max_seconds + 1, 0}), "");
160 static_assert(!is_representable(TimeSpecT{max_seconds, max_nsec + 1}), "");
161 static_assert(!is_representable(TimeSpecT{max_time_t, 0}), "");
162 static_assert(is_representable(TimeSpecT{min_seconds, 0}), "");
163 static_assert(
164 is_representable(TimeSpecT{min_seconds - 1, min_nsec_timespec}), "");
165 static_assert(
166 is_representable(TimeSpecT{min_seconds - 1, min_nsec_timespec + 1}),
167 "");
168 static_assert(
169 !is_representable(TimeSpecT{min_seconds - 1, min_nsec_timespec - 1}),
170 "");
171 static_assert(!is_representable(TimeSpecT{min_time_t, 999999999}), "");
172 return true;
173 }
174
test_file_time_typetest_case175 static constexpr bool test_file_time_type() {
176 static_assert(Base::is_representable(FileTimeT::max()), "");
177 static_assert(Base::is_representable(FileTimeT::min()), "");
178 return true;
179 }
180
test_convert_timespectest_case181 static constexpr bool test_convert_timespec() {
182 static_assert(convert_from_timespec(TimeSpecT{max_seconds, max_nsec}) ==
183 FileTimeT::max(),
184 "");
185 static_assert(convert_from_timespec(TimeSpecT{max_seconds, max_nsec - 1}) <
186 FileTimeT::max(),
187 "");
188 static_assert(convert_from_timespec(TimeSpecT{max_seconds - 1, 999999999}) <
189 FileTimeT::max(),
190 "");
191 static_assert(convert_from_timespec(TimeSpecT{
192 min_seconds - 1, min_nsec_timespec}) == FileTimeT::min(),
193 "");
194 static_assert(convert_from_timespec(
195 TimeSpecT{min_seconds - 1, min_nsec_timespec + 1}) >
196 FileTimeT::min(),
197 "");
198 static_assert(convert_from_timespec(TimeSpecT{min_seconds, 0}) >
199 FileTimeT::min(),
200 "");
201 return true;
202 }
203
testtest_case204 static bool test() {
205 static_assert(test_timespec(), "");
206 static_assert(test_file_time_type(), "");
207 static_assert(test_convert_timespec(), "");
208 return true;
209 }
210 };
211
212 template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
213 struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_32Bit, TK_64Bit>
214 : public Base {
215 static constexpr auto max_time_t = std::numeric_limits<TimeT>::max();
216 static constexpr auto min_time_t = std::numeric_limits<TimeT>::min();
217
218 using Base::convert_from_timespec;
219 using Base::is_representable;
220 using Base::max_nsec;
221 using Base::max_seconds;
222 using Base::min_nsec_timespec;
223 using Base::min_seconds;
224
test_timespectest_case225 static constexpr bool test_timespec() {
226 static_assert(is_representable(TimeSpecT{max_time_t, 999999999}), "");
227 static_assert(is_representable(TimeSpecT{max_time_t, 1000000000}), "");
228 static_assert(is_representable(TimeSpecT{min_time_t, 0}), "");
229 return true;
230 }
231
test_file_time_typetest_case232 static constexpr bool test_file_time_type() {
233 static_assert(!is_representable(FileTimeT::max()), "");
234 static_assert(!is_representable(FileTimeT::min()), "");
235 static_assert(is_representable(FileTimeT(seconds(max_time_t))), "");
236 static_assert(is_representable(FileTimeT(seconds(min_time_t))), "");
237 return true;
238 }
239
test_convert_timespectest_case240 static constexpr bool test_convert_timespec() {
241 // FIXME add tests for 32 bit builds
242 return true;
243 }
244
testtest_case245 static bool test() {
246 static_assert(test_timespec(), "");
247 static_assert(test_file_time_type(), "");
248 static_assert(test_convert_timespec(), "");
249 return true;
250 }
251 };
252
253 template <class FileTimeT, class TimeT, class TimeSpec, class Base,
254 TestKind FileTimeTKind>
255 struct test_case<FileTimeT, TimeT, TimeSpec, Base, TK_FloatingPoint,
256 FileTimeTKind> : public Base {
257
testtest_case258 static bool test() { return true; }
259 };
260
261 template <class TimeT, class NSecT = long>
262 struct TestTimeSpec {
263 TimeT tv_sec;
264 NSecT tv_nsec;
265 };
266
267 template <class Dur>
268 struct TestClock {
269 typedef Dur duration;
270 typedef typename duration::rep rep;
271 typedef typename duration::period period;
272 typedef std::chrono::time_point<TestClock> time_point;
273 static constexpr const bool is_steady = false;
274
nowTestClock275 static time_point now() noexcept { return {}; }
276 };
277
278 template <class IntType, class Period = std::micro>
279 using TestFileTimeT = time_point<TestClock<duration<IntType, Period> > >;
280
main(int,char **)281 int main(int, char**) {
282 { assert((test_case<file_time_type, time_t, struct timespec>::test())); }
283 {
284 assert((test_case<TestFileTimeT<std::int64_t>, std::int64_t,
285 TestTimeSpec<std::int64_t, long> >::test()));
286 }
287 {
288 assert((test_case<TestFileTimeT<long long>, std::int32_t,
289 TestTimeSpec<std::int32_t, std::int32_t> >::test()));
290 }
291 {
292 // Test that insane platforms like ppc64 linux, which use long double as time_t,
293 // at least compile.
294 assert((test_case<TestFileTimeT<long double>, double,
295 TestTimeSpec<long double, long> >::test()));
296 }
297 #ifndef TEST_HAS_NO_INT128_T
298 {
299 assert((test_case<TestFileTimeT<__int128_t, std::nano>, std::int64_t,
300 TestTimeSpec<std::int64_t, long> >::test()));
301 }
302 {
303 assert((test_case<TestFileTimeT<__int128_t, std::nano>, std::int32_t,
304 TestTimeSpec<std::int32_t, std::int32_t> >::test()));
305 }
306 #endif
307
308 return 0;
309 }
310