@@ -72,13 +72,60 @@ std::pair<std::time_t, std::time_t> GetSymlinkTimes(path const& p) {
72
72
return {st.st_atime , st.st_mtime };
73
73
}
74
74
75
- inline bool TimeIsRepresentableAsTimeT (file_time_type tp) {
75
+ namespace {
76
+ bool TestSupportsNegativeTimes () {
77
+ using namespace std ::chrono;
78
+ std::error_code ec;
79
+ std::time_t old_write_time, new_write_time;
80
+ { // WARNING: Do not assert in this scope.
81
+ scoped_test_env env;
82
+ const path file = env.create_file (" file" , 42 );
83
+ old_write_time = LastWriteTime (file);
84
+ file_time_type tp (seconds (-5 ));
85
+ fs::last_write_time (file, tp, ec);
86
+ new_write_time = LastWriteTime (file);
87
+ }
88
+ return !ec && new_write_time <= -5 ;
89
+ }
90
+
91
+ bool TestSupportsMaxTime () {
76
92
using namespace std ::chrono;
77
93
using Lim = std::numeric_limits<std::time_t >;
78
- auto sec = duration_cast<seconds>(tp.time_since_epoch ()).count ();
79
- return (sec >= Lim::min () && sec <= Lim::max ());
94
+ auto max_sec = duration_cast<seconds>(file_time_type::max ().time_since_epoch ()).count ();
95
+ if (max_sec > Lim::max ()) return false ;
96
+ std::error_code ec;
97
+ std::time_t old_write_time, new_write_time;
98
+ { // WARNING: Do not assert in this scope.
99
+ scoped_test_env env;
100
+ const path file = env.create_file (" file" , 42 );
101
+ old_write_time = LastWriteTime (file);
102
+ file_time_type tp = file_time_type::max ();
103
+ fs::last_write_time (file, tp, ec);
104
+ new_write_time = LastWriteTime (file);
105
+ }
106
+ return !ec && new_write_time > max_sec - 1 ;
80
107
}
81
108
109
+ static const bool SupportsNegativeTimes = TestSupportsNegativeTimes();
110
+ static const bool SupportsMaxTime = TestSupportsMaxTime();
111
+
112
+ } // end namespace
113
+
114
+ // Check if a time point is representable on a given filesystem. Check that:
115
+ // (A) 'tp' is representable as a time_t
116
+ // (B) 'tp' is non-negative or the filesystem supports negative times.
117
+ // (C) 'tp' is not 'file_time_type::max()' or the filesystem supports the max
118
+ // value.
119
+ inline bool TimeIsRepresentableByFilesystem (file_time_type tp) {
120
+ using namespace std ::chrono;
121
+ using Lim = std::numeric_limits<std::time_t >;
122
+ auto sec = duration_cast<seconds>(tp.time_since_epoch ()).count ();
123
+ auto microsec = duration_cast<microseconds>(tp.time_since_epoch ()).count ();
124
+ if (sec < Lim::min () || sec > Lim::max ()) return false ;
125
+ else if (microsec < 0 && !SupportsNegativeTimes) return false ;
126
+ else if (tp == file_time_type::max () && !SupportsMaxTime) return false ;
127
+ return true ;
128
+ }
82
129
83
130
TEST_SUITE (exists_test_suite)
84
131
@@ -214,15 +261,17 @@ TEST_CASE(set_last_write_time_dynamic_env_test)
214
261
215
262
file_time_type got_time = last_write_time (TC.p );
216
263
217
- TEST_CHECK (got_time != old_time);
218
- if (TC.new_time < epoch_time) {
219
- TEST_CHECK (got_time <= TC.new_time );
220
- TEST_CHECK (got_time > TC.new_time - Sec (1 ));
221
- } else {
222
- TEST_CHECK (got_time <= TC.new_time + Sec (1 ));
223
- TEST_CHECK (got_time >= TC.new_time - Sec (1 ));
264
+ if (TimeIsRepresentableByFilesystem (TC.new_time )) {
265
+ TEST_CHECK (got_time != old_time);
266
+ if (TC.new_time < epoch_time) {
267
+ TEST_CHECK (got_time <= TC.new_time );
268
+ TEST_CHECK (got_time > TC.new_time - Sec (1 ));
269
+ } else {
270
+ TEST_CHECK (got_time <= TC.new_time + Sec (1 ));
271
+ TEST_CHECK (got_time >= TC.new_time - Sec (1 ));
272
+ }
273
+ TEST_CHECK (LastAccessTime (TC.p ) == old_times.first );
224
274
}
225
- TEST_CHECK (LastAccessTime (TC.p ) == old_times.first );
226
275
}
227
276
}
228
277
@@ -269,36 +318,26 @@ TEST_CASE(test_write_min_time)
269
318
const path p = env.create_file (" file" , 42 );
270
319
271
320
std::error_code ec = GetTestEC ();
272
- file_time_type last_time = last_write_time (p);
273
321
file_time_type new_time = file_time_type::min ();
274
322
275
323
last_write_time (p, new_time, ec);
276
324
file_time_type tt = last_write_time (p);
277
325
278
- if (!TimeIsRepresentableAsTimeT (new_time)) {
279
- TEST_CHECK (ec);
280
- TEST_CHECK (ec != GetTestEC ());
281
- TEST_CHECK (tt == last_time);
282
- } else {
326
+ if (TimeIsRepresentableByFilesystem (new_time)) {
283
327
TEST_CHECK (!ec);
284
328
TEST_CHECK (tt >= new_time);
285
329
TEST_CHECK (tt < new_time + Sec (1 ));
286
330
}
287
331
288
332
ec = GetTestEC ();
289
333
last_write_time (p, Clock::now ());
290
- last_time = last_write_time (p);
291
334
292
335
new_time = file_time_type::min () + MicroSec (1 );
293
336
294
337
last_write_time (p, new_time, ec);
295
338
tt = last_write_time (p);
296
339
297
- if (!TimeIsRepresentableAsTimeT (new_time)) {
298
- TEST_CHECK (ec);
299
- TEST_CHECK (ec != GetTestEC ());
300
- TEST_CHECK (tt == last_time);
301
- } else {
340
+ if (TimeIsRepresentableByFilesystem (new_time)) {
302
341
TEST_CHECK (!ec);
303
342
TEST_CHECK (tt >= new_time);
304
343
TEST_CHECK (tt < new_time + Sec (1 ));
@@ -317,18 +356,13 @@ TEST_CASE(test_write_min_max_time)
317
356
const path p = env.create_file (" file" , 42 );
318
357
319
358
std::error_code ec = GetTestEC ();
320
- file_time_type last_time = last_write_time (p);
321
359
file_time_type new_time = file_time_type::max ();
322
360
323
361
ec = GetTestEC ();
324
362
last_write_time (p, new_time, ec);
325
363
file_time_type tt = last_write_time (p);
326
364
327
- if (!TimeIsRepresentableAsTimeT (new_time)) {
328
- TEST_CHECK (ec);
329
- TEST_CHECK (ec != GetTestEC ());
330
- TEST_CHECK (tt == last_time);
331
- } else {
365
+ if (TimeIsRepresentableByFilesystem (new_time)) {
332
366
TEST_CHECK (!ec);
333
367
TEST_CHECK (tt > new_time - Sec (1 ));
334
368
TEST_CHECK (tt <= new_time);
0 commit comments