implement to() conversions for std::chrono to timespec/timeval
[folly.git] / folly / chrono / test / ConvTest.cpp
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <folly/chrono/Conv.h>
17
18 #include <folly/portability/GTest.h>
19
20 using namespace folly;
21 using namespace std::chrono;
22 using namespace std::chrono_literals;
23
24 namespace {
25 /**
26  * A helper function to create a time_point even if the input duration type has
27  * finer resolution than the clock duration type.
28  */
29 template <typename Clock, typename Duration>
30 typename Clock::time_point createTimePoint(const Duration& d) {
31   return typename Clock::time_point(
32       std::chrono::duration_cast<typename Clock::duration>(d));
33 }
34 } // namespace
35
36 TEST(Conv, timespecToStdChrono) {
37   struct timespec ts;
38
39   ts.tv_sec = 0;
40   ts.tv_nsec = 10;
41   EXPECT_EQ(10ns, to<nanoseconds>(ts));
42   EXPECT_EQ(0us, to<microseconds>(ts));
43   EXPECT_EQ(0ms, to<milliseconds>(ts));
44   EXPECT_EQ(0s, to<seconds>(ts));
45
46   ts.tv_sec = 1;
47   ts.tv_nsec = 10;
48   EXPECT_EQ(1000000010ns, to<nanoseconds>(ts));
49   EXPECT_EQ(1000000us, to<microseconds>(ts));
50   EXPECT_EQ(1000ms, to<milliseconds>(ts));
51   EXPECT_EQ(1s, to<seconds>(ts));
52   EXPECT_EQ(
53       createTimePoint<system_clock>(1000000010ns),
54       to<system_clock::time_point>(ts));
55   EXPECT_EQ(
56       createTimePoint<steady_clock>(1000000010ns),
57       to<steady_clock::time_point>(ts));
58
59   // Test a non-canonical value with tv_nsec larger than 1 second
60   ts.tv_sec = 5;
61   ts.tv_nsec = 3219876543;
62   // Beware about using std::chrono_literals suffixes with very literals:
63   // older versions of GCC are buggy and would truncate these to 32-bits.
64   EXPECT_EQ(8219876543LL, to<nanoseconds>(ts).count());
65   EXPECT_EQ(8219876us, to<microseconds>(ts));
66   EXPECT_EQ(8219ms, to<milliseconds>(ts));
67   EXPECT_EQ(8s, to<seconds>(ts));
68   EXPECT_EQ(
69       createTimePoint<system_clock>(nanoseconds(8219876543LL)),
70       to<system_clock::time_point>(ts));
71   EXPECT_EQ(
72       createTimePoint<steady_clock>(nanoseconds(8219876543LL)),
73       to<steady_clock::time_point>(ts));
74
75   // Test negative values
76   // When going to coarser grained types these should be rounded up towards 0.
77   ts.tv_sec = -5;
78   ts.tv_nsec = 123456;
79   EXPECT_EQ(-4999876544, to<nanoseconds>(ts).count());
80   EXPECT_EQ(-4999876544, duration_cast<nanoseconds>(-5s + 123456ns).count());
81   EXPECT_EQ(-4999876, to<microseconds>(ts).count());
82   EXPECT_EQ(-4999876, duration_cast<microseconds>(-5s + 123456ns).count());
83   EXPECT_EQ(-4999, to<milliseconds>(ts).count());
84   EXPECT_EQ(-4999, duration_cast<milliseconds>(-5s + 123456ns).count());
85   EXPECT_EQ(-4s, to<seconds>(ts));
86   EXPECT_EQ(-4, duration_cast<seconds>(-5s + 123456ns).count());
87   ts.tv_sec = -7200;
88   ts.tv_nsec = 123456;
89   EXPECT_EQ(-1h, to<hours>(ts));
90   EXPECT_EQ(
91       -1,
92       duration_cast<hours>(seconds{ts.tv_sec} + nanoseconds{ts.tv_nsec})
93           .count());
94   ts.tv_sec = -7000;
95   ts.tv_nsec = 123456;
96   EXPECT_EQ(-1h, to<hours>(ts));
97   EXPECT_EQ(
98       -1,
99       duration_cast<hours>(seconds{ts.tv_sec} + nanoseconds{ts.tv_nsec})
100           .count());
101   ts.tv_sec = -7201;
102   ts.tv_nsec = 123456;
103   EXPECT_EQ(-2h, to<hours>(ts));
104   EXPECT_EQ(
105       -2,
106       duration_cast<hours>(seconds{ts.tv_sec} + nanoseconds{ts.tv_nsec})
107           .count());
108
109   // Test converions to floating point durations
110   ts.tv_sec = 1;
111   ts.tv_nsec = 500000000;
112   EXPECT_EQ(1.5, to<duration<double>>(ts).count());
113   ts.tv_sec = -1;
114   ts.tv_nsec = 500000000;
115   EXPECT_EQ(-0.5, to<duration<double>>(ts).count());
116   ts.tv_sec = -1;
117   ts.tv_nsec = -500000000;
118   EXPECT_EQ(-1.5, to<duration<double>>(ts).count());
119   ts.tv_sec = 1;
120   ts.tv_nsec = 500000000;
121   auto doubleNanos = to<duration<double, std::nano>>(ts);
122   EXPECT_EQ(1500000000, doubleNanos.count());
123   ts.tv_sec = 90;
124   ts.tv_nsec = 0;
125   auto doubleMinutes = to<duration<double, std::ratio<60>>>(ts);
126   EXPECT_EQ(1.5, doubleMinutes.count());
127 }
128
129 TEST(Conv, timespecToStdChronoOverflow) {
130   struct timespec ts;
131
132   // All of our boundary conditions below assume time_t is int64_t.
133   // This is true on most modern platforms.
134   if (!std::is_same<decltype(ts.tv_sec), int64_t>::value) {
135     LOG(INFO) << "skipping most overflow tests: time_t is not int64_t";
136   } else {
137     // Test the upper boundary of conversion to uint64_t nanoseconds
138     using nsec_u64 = std::chrono::duration<uint64_t, std::nano>;
139     ts.tv_sec = 18446744073;
140     ts.tv_nsec = 709551615;
141     EXPECT_EQ(std::numeric_limits<uint64_t>::max(), to<nsec_u64>(ts).count());
142
143     ts.tv_nsec += 1;
144     EXPECT_THROW(to<nsec_u64>(ts), std::range_error);
145
146     // Test the lower boundary of conversion to uint64_t nanoseconds
147     ts.tv_sec = 0;
148     ts.tv_nsec = 0;
149     EXPECT_EQ(0, to<nsec_u64>(ts).count());
150     ts.tv_sec = -1;
151     ts.tv_nsec = 0;
152     EXPECT_THROW(to<nsec_u64>(ts), std::range_error);
153
154     // Test the upper boundary of conversion to int64_t microseconds
155     using usec_i64 = std::chrono::duration<int64_t, std::micro>;
156     ts.tv_sec = 9223372036854LL;
157     ts.tv_nsec = 775807000;
158     EXPECT_EQ(std::numeric_limits<int64_t>::max(), to<usec_i64>(ts).count());
159
160     ts.tv_nsec += 1;
161     EXPECT_THROW(to<usec_i64>(ts), std::range_error);
162
163     // Test the lower boundary of conversion to int64_t microseconds
164     ts.tv_sec = -9223372036855LL;
165     ts.tv_nsec = 224192000;
166     EXPECT_EQ(std::numeric_limits<int64_t>::min(), to<usec_i64>(ts).count());
167
168     ts.tv_nsec -= 1;
169     EXPECT_THROW(to<usec_i64>(ts), std::range_error);
170
171     // Test the boundaries of conversion to int32_t seconds
172     using sec_i32 = std::chrono::duration<int32_t>;
173     ts.tv_sec = 2147483647;
174     ts.tv_nsec = 0;
175     EXPECT_EQ(std::numeric_limits<int32_t>::max(), to<sec_i32>(ts).count());
176     ts.tv_nsec = 1000000000;
177     EXPECT_THROW(to<sec_i32>(ts), std::range_error);
178     ts.tv_sec = -2147483648;
179     ts.tv_nsec = 0;
180     EXPECT_EQ(std::numeric_limits<int32_t>::min(), to<sec_i32>(ts).count());
181     ts.tv_sec = -2147483649;
182     ts.tv_nsec = 999999999;
183     EXPECT_THROW(to<sec_i32>(ts), std::range_error);
184     ts.tv_sec = -2147483649;
185     ts.tv_nsec = 0;
186     EXPECT_THROW(to<sec_i32>(ts), std::range_error);
187     ts.tv_sec = -2147483650;
188     ts.tv_nsec = 0;
189     EXPECT_THROW(to<sec_i32>(ts), std::range_error);
190
191     // Test the upper boundary of conversion to uint32_t hours
192     using hours_u32 = std::chrono::duration<uint32_t, std::ratio<3600>>;
193     ts.tv_sec = 15461882262000LL;
194     ts.tv_nsec = 0;
195     EXPECT_EQ(std::numeric_limits<uint32_t>::max(), to<hours_u32>(ts).count());
196     ts.tv_sec = 15461882265599LL;
197     EXPECT_EQ(std::numeric_limits<uint32_t>::max(), to<hours_u32>(ts).count());
198     ts.tv_sec = 15461882265600LL;
199     EXPECT_THROW(to<hours_u32>(ts), std::range_error);
200
201     using nsec_i64 = std::chrono::duration<int64_t, std::nano>;
202     ts.tv_sec = std::numeric_limits<int64_t>::max();
203     ts.tv_nsec = std::numeric_limits<int64_t>::max();
204     EXPECT_THROW(to<nsec_i64>(ts), std::range_error);
205
206     ts.tv_sec = std::numeric_limits<int64_t>::min();
207     ts.tv_nsec = std::numeric_limits<int64_t>::min();
208     EXPECT_THROW(to<nsec_i64>(ts), std::range_error);
209
210     // Test some non-normal inputs near the int64_t limit
211     ts.tv_sec = 0;
212     ts.tv_nsec = std::numeric_limits<int64_t>::min();
213     EXPECT_EQ(std::numeric_limits<int64_t>::min(), to<nsec_i64>(ts).count());
214     ts.tv_sec = -1;
215     ts.tv_nsec = std::numeric_limits<int64_t>::min() + std::nano::den;
216     EXPECT_EQ(std::numeric_limits<int64_t>::min(), to<nsec_i64>(ts).count());
217     ts.tv_sec = -1;
218     ts.tv_nsec = std::numeric_limits<int64_t>::min() + std::nano::den - 1;
219     EXPECT_THROW(to<nsec_i64>(ts), std::range_error);
220
221     ts.tv_sec = 0;
222     ts.tv_nsec = std::numeric_limits<int64_t>::max();
223     EXPECT_EQ(std::numeric_limits<int64_t>::max(), to<nsec_i64>(ts).count());
224     ts.tv_sec = 1;
225     ts.tv_nsec = std::numeric_limits<int64_t>::max() - std::nano::den;
226     EXPECT_EQ(std::numeric_limits<int64_t>::max(), to<nsec_i64>(ts).count());
227     ts.tv_sec = 1;
228     ts.tv_nsec = std::numeric_limits<int64_t>::max() - std::nano::den + 1;
229     EXPECT_THROW(to<nsec_i64>(ts), std::range_error);
230   }
231
232   // Theoretically conversion is representable in the output type,
233   // but we normalize the input first, and normalization would trigger an
234   // overflow.
235   using hours_u64 = std::chrono::duration<uint64_t, std::ratio<3600>>;
236   ts.tv_sec = std::numeric_limits<decltype(ts.tv_sec)>::max();
237   ts.tv_nsec = 1000000000;
238   EXPECT_THROW(to<hours_u64>(ts), std::range_error);
239   // If we drop it back down to the normal range it should succeed
240   ts.tv_nsec = 999999999;
241   EXPECT_EQ(
242       std::numeric_limits<decltype(ts.tv_sec)>::max() / 3600,
243       to<hours_u64>(ts).count());
244 }
245
246 TEST(Conv, timevalToStdChrono) {
247   struct timeval tv;
248
249   tv.tv_sec = 0;
250   tv.tv_usec = 10;
251   EXPECT_EQ(10000ns, to<nanoseconds>(tv));
252   EXPECT_EQ(10us, to<microseconds>(tv));
253   EXPECT_EQ(0ms, to<milliseconds>(tv));
254   EXPECT_EQ(0s, to<seconds>(tv));
255
256   tv.tv_sec = 1;
257   tv.tv_usec = 10;
258   EXPECT_EQ(1000010000ns, to<nanoseconds>(tv));
259   EXPECT_EQ(1000010us, to<microseconds>(tv));
260   EXPECT_EQ(1000ms, to<milliseconds>(tv));
261   EXPECT_EQ(1s, to<seconds>(tv));
262   EXPECT_EQ(
263       createTimePoint<system_clock>(1000010000ns),
264       to<system_clock::time_point>(tv));
265   EXPECT_EQ(
266       createTimePoint<steady_clock>(1000010000ns),
267       to<steady_clock::time_point>(tv));
268
269   // Test a non-canonical value with tv_usec larger than 1 second
270   tv.tv_sec = 5;
271   tv.tv_usec = 3219876;
272   EXPECT_EQ(8219876000LL, to<nanoseconds>(tv).count());
273   EXPECT_EQ(8219876us, to<microseconds>(tv));
274   EXPECT_EQ(8219ms, to<milliseconds>(tv));
275   EXPECT_EQ(8s, to<seconds>(tv));
276   EXPECT_EQ(
277       createTimePoint<system_clock>(nanoseconds(8219876000LL)),
278       to<system_clock::time_point>(tv));
279   EXPECT_EQ(
280       createTimePoint<steady_clock>(nanoseconds(8219876000LL)),
281       to<steady_clock::time_point>(tv));
282
283   // Test for overflow.
284   if (std::numeric_limits<decltype(tv.tv_sec)>::max() >=
285       std::numeric_limits<int64_t>::max()) {
286     // Use our own type alias here rather than std::chrono::nanoseconds
287     // to ensure we have 64-bit rep type.
288     using nsec_i64 = std::chrono::duration<int64_t, std::nano>;
289     tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
290     tv.tv_usec = std::numeric_limits<decltype(tv.tv_usec)>::max();
291     EXPECT_THROW(to<nsec_i64>(tv), std::range_error);
292
293     tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
294     tv.tv_usec = std::numeric_limits<decltype(tv.tv_usec)>::max();
295     EXPECT_THROW(to<nsec_i64>(tv), std::range_error);
296   }
297 }
298
299 TEST(Conv, stdChronoToTimespec) {
300   auto ts = to<struct timespec>(10ns);
301   EXPECT_EQ(0, ts.tv_sec);
302   EXPECT_EQ(10, ts.tv_nsec);
303
304   // We don't use std::chrono_literals suffixes here since older
305   // gcc versions silently truncate the literals to 32-bits.
306   ts = to<struct timespec>(nanoseconds(987654321012LL));
307   EXPECT_EQ(987, ts.tv_sec);
308   EXPECT_EQ(654321012, ts.tv_nsec);
309
310   ts = to<struct timespec>(nanoseconds(-987654321012LL));
311   EXPECT_EQ(-988, ts.tv_sec);
312   EXPECT_EQ(345678988, ts.tv_nsec);
313
314   ts = to<struct timespec>(microseconds(987654321012LL));
315   EXPECT_EQ(987654, ts.tv_sec);
316   EXPECT_EQ(321012000, ts.tv_nsec);
317
318   ts = to<struct timespec>(milliseconds(987654321012LL));
319   EXPECT_EQ(987654321, ts.tv_sec);
320   EXPECT_EQ(12000000, ts.tv_nsec);
321
322   ts = to<struct timespec>(seconds(987654321012LL));
323   EXPECT_EQ(987654321012, ts.tv_sec);
324   EXPECT_EQ(0, ts.tv_nsec);
325
326   ts = to<struct timespec>(10h);
327   EXPECT_EQ(36000, ts.tv_sec);
328   EXPECT_EQ(0, ts.tv_nsec);
329
330   ts = to<struct timespec>(createTimePoint<steady_clock>(123ns));
331   EXPECT_EQ(0, ts.tv_sec);
332   EXPECT_EQ(123, ts.tv_nsec);
333
334   ts = to<struct timespec>(createTimePoint<system_clock>(123ns));
335   EXPECT_EQ(0, ts.tv_sec);
336   EXPECT_EQ(123, ts.tv_nsec);
337 }
338
339 TEST(Conv, stdChronoToTimespecOverflow) {
340   EXPECT_THROW(to<uint8_t>(1234), std::range_error);
341
342   struct timespec ts;
343   if (!std::is_same<decltype(ts.tv_sec), int64_t>::value) {
344     LOG(INFO) << "skipping most overflow tests: time_t is not int64_t";
345   } else {
346     // Check for overflow converting from uint64_t seconds to time_t
347     using sec_u64 = duration<uint64_t>;
348     ts = to<struct timespec>(sec_u64(9223372036854775807ULL));
349     EXPECT_EQ(ts.tv_sec, 9223372036854775807ULL);
350     EXPECT_EQ(ts.tv_nsec, 0);
351
352     EXPECT_THROW(
353         to<struct timespec>(sec_u64(9223372036854775808ULL)), std::range_error);
354
355     // Check for overflow converting from int64_t hours to time_t
356     using hours_i64 = duration<int64_t, std::ratio<3600>>;
357     ts = to<struct timespec>(hours_i64(2562047788015215LL));
358     EXPECT_EQ(ts.tv_sec, 9223372036854774000LL);
359     EXPECT_EQ(ts.tv_nsec, 0);
360     EXPECT_THROW(
361         to<struct timespec>(hours_i64(2562047788015216LL)), std::range_error);
362   }
363
364   // Test for overflow.
365   // Use a custom hours type using time_t as the underlying storage type to
366   // guarantee that we can overflow.
367   using hours_timet = std::chrono::duration<time_t, std::ratio<3600>>;
368   EXPECT_THROW(
369       to<struct timespec>(hours_timet(std::numeric_limits<time_t>::max())),
370       std::range_error);
371 }
372
373 TEST(Conv, stdChronoToTimeval) {
374   auto tv = to<struct timeval>(10ns);
375   EXPECT_EQ(0, tv.tv_sec);
376   EXPECT_EQ(0, tv.tv_usec);
377
378   tv = to<struct timeval>(10us);
379   EXPECT_EQ(0, tv.tv_sec);
380   EXPECT_EQ(10, tv.tv_usec);
381
382   tv = to<struct timeval>(nanoseconds(987654321012LL));
383   EXPECT_EQ(987, tv.tv_sec);
384   EXPECT_EQ(654321, tv.tv_usec);
385
386   tv = to<struct timeval>(nanoseconds(-987654321012LL));
387   EXPECT_EQ(-988, tv.tv_sec);
388   EXPECT_EQ(345679, tv.tv_usec);
389
390   tv = to<struct timeval>(microseconds(987654321012LL));
391   EXPECT_EQ(987654, tv.tv_sec);
392   EXPECT_EQ(321012, tv.tv_usec);
393
394   tv = to<struct timeval>(milliseconds(987654321012LL));
395   EXPECT_EQ(987654321, tv.tv_sec);
396   EXPECT_EQ(12000, tv.tv_usec);
397
398   tv = to<struct timeval>(seconds(987654321012LL));
399   EXPECT_EQ(987654321012, tv.tv_sec);
400   EXPECT_EQ(0, tv.tv_usec);
401
402   // Try converting fractional seconds
403   tv = to<struct timeval>(duration<double>{3.456789});
404   EXPECT_EQ(3, tv.tv_sec);
405   EXPECT_EQ(456789, tv.tv_usec);
406   tv = to<struct timeval>(duration<double>{-3.456789});
407   EXPECT_EQ(-4, tv.tv_sec);
408   EXPECT_EQ(543211, tv.tv_usec);
409
410   // Try converting fractional hours
411   tv = to<struct timeval>(duration<double, std::ratio<3600>>{3.456789});
412   EXPECT_EQ(12444, tv.tv_sec);
413   // The usec field is generally off-by-one due to
414   // floating point rounding error
415   EXPECT_NEAR(440400, tv.tv_usec, 1);
416   tv = to<struct timeval>(duration<double, std::ratio<3600>>{-3.456789});
417   EXPECT_EQ(-12445, tv.tv_sec);
418   EXPECT_NEAR(559600, tv.tv_usec, 1);
419
420   // Try converting fractional milliseconds
421   tv = to<struct timeval>(duration<double, std::milli>{9123.456789});
422   EXPECT_EQ(9, tv.tv_sec);
423   EXPECT_EQ(123456, tv.tv_usec);
424   tv = to<struct timeval>(duration<double, std::milli>{-9123.456789});
425   EXPECT_EQ(-10, tv.tv_sec);
426   EXPECT_NEAR(876544, tv.tv_usec, 1);
427
428   tv = to<struct timeval>(duration<uint32_t, std::ratio<3600>>{3});
429   EXPECT_EQ(10800, tv.tv_sec);
430   EXPECT_EQ(0, tv.tv_usec);
431
432   tv = to<struct timeval>(duration<uint32_t, std::nano>{3123});
433   EXPECT_EQ(0, tv.tv_sec);
434   EXPECT_EQ(3, tv.tv_usec);
435   tv = to<struct timeval>(duration<int32_t, std::nano>{-3123});
436   EXPECT_EQ(-1, tv.tv_sec);
437   EXPECT_EQ(999997, tv.tv_usec);
438
439   tv = to<struct timeval>(createTimePoint<steady_clock>(123us));
440   EXPECT_EQ(0, tv.tv_sec);
441   EXPECT_EQ(123, tv.tv_usec);
442
443   tv = to<struct timeval>(createTimePoint<system_clock>(123us));
444   EXPECT_EQ(0, tv.tv_sec);
445   EXPECT_EQ(123, tv.tv_usec);
446 }