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