xref: /llvm-project/libcxx/test/libcxx/input.output/filesystems/convert_file_time.pass.cpp (revision 5d31360d710a9aa2a1bee4ea9bcdc4cd0ea0a72f)
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