1 | //===-- flang/unittests/Runtime/Time.cpp ----------------------------===// |
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 | #ifndef __clang__ // 16.0.3 lacks <charconv> |
10 | |
11 | #include "gtest/gtest.h" |
12 | #include "flang/Runtime/time-intrinsic.h" |
13 | #include <algorithm> |
14 | #include <cctype> |
15 | #include <cerrno> |
16 | #include <string> |
17 | |
18 | using namespace Fortran::runtime; |
19 | |
20 | TEST(TimeIntrinsics, CpuTime) { |
21 | // We can't really test that we get the "right" result for CPU_TIME, but we |
22 | // can have a smoke test to see that we get something reasonable on the |
23 | // platforms where we expect to support it. |
24 | double start{RTNAME(CpuTime)()}; |
25 | ASSERT_GE(start, 0.0); |
26 | |
27 | // Loop until we get a different value from CpuTime. If we don't get one |
28 | // before we time out, then we should probably look into an implementation |
29 | // for CpuTime with a better timer resolution. |
30 | for (double end = start; end == start; end = RTNAME(CpuTime)()) { |
31 | ASSERT_GE(end, 0.0); |
32 | ASSERT_GE(end, start); |
33 | } |
34 | } |
35 | |
36 | using count_t = std::int64_t; |
37 | |
38 | TEST(TimeIntrinsics, SystemClock) { |
39 | // We can't really test that we get the "right" result for SYSTEM_CLOCK, but |
40 | // we can have a smoke test to see that we get something reasonable on the |
41 | // platforms where we expect to support it. |
42 | |
43 | // The value of the count rate and max will vary by platform, but they should |
44 | // always be strictly positive if we have a working implementation of |
45 | // SYSTEM_CLOCK. |
46 | EXPECT_GT(RTNAME(SystemClockCountRate)(), 0); |
47 | |
48 | count_t max1{RTNAME(SystemClockCountMax)(1)}; |
49 | EXPECT_GT(max1, 0); |
50 | EXPECT_LE(max1, static_cast<count_t>(0x7f)); |
51 | count_t start1{RTNAME(SystemClockCount)(1)}; |
52 | EXPECT_GE(start1, 0); |
53 | EXPECT_LE(start1, max1); |
54 | |
55 | count_t max2{RTNAME(SystemClockCountMax)(2)}; |
56 | EXPECT_GT(max2, 0); |
57 | EXPECT_LE(max2, static_cast<count_t>(0x7fff)); |
58 | count_t start2{RTNAME(SystemClockCount)(2)}; |
59 | EXPECT_GE(start2, 0); |
60 | EXPECT_LE(start2, max2); |
61 | |
62 | count_t max4{RTNAME(SystemClockCountMax)(4)}; |
63 | EXPECT_GT(max4, 0); |
64 | EXPECT_LE(max4, static_cast<count_t>(0x7fffffff)); |
65 | count_t start4{RTNAME(SystemClockCount)(4)}; |
66 | EXPECT_GE(start4, 0); |
67 | EXPECT_LE(start4, max4); |
68 | |
69 | count_t max8{RTNAME(SystemClockCountMax)(8)}; |
70 | EXPECT_GT(max8, 0); |
71 | count_t start8{RTNAME(SystemClockCount)(8)}; |
72 | EXPECT_GE(start8, 0); |
73 | EXPECT_LT(start8, max8); |
74 | |
75 | count_t max16{RTNAME(SystemClockCountMax)(16)}; |
76 | EXPECT_GT(max16, 0); |
77 | count_t start16{RTNAME(SystemClockCount)(16)}; |
78 | EXPECT_GE(start16, 0); |
79 | EXPECT_LT(start16, max16); |
80 | |
81 | // Loop until we get a different value from SystemClockCount. If we don't get |
82 | // one before we time out, then we should probably look into an implementation |
83 | // for SystemClokcCount with a better timer resolution on this platform. |
84 | for (count_t end{start8}; end == start8; end = RTNAME(SystemClockCount)(8)) { |
85 | EXPECT_GE(end, 0); |
86 | EXPECT_LE(end, max8); |
87 | EXPECT_GE(end, start8); |
88 | } |
89 | } |
90 | |
91 | TEST(TimeIntrinsics, DateAndTime) { |
92 | constexpr std::size_t bufferSize{16}; |
93 | std::string date(bufferSize, 'Z'), time(bufferSize, 'Z'), |
94 | zone(bufferSize, 'Z'); |
95 | RTNAME(DateAndTime) |
96 | (date.data(), date.size(), time.data(), time.size(), zone.data(), zone.size(), |
97 | /*source=*/nullptr, /*line=*/0, /*values=*/nullptr); |
98 | auto isBlank = [](const std::string &s) -> bool { |
99 | return std::all_of( |
100 | s.begin(), s.end(), [](char c) { return std::isblank(c); }); |
101 | }; |
102 | // Validate date is blank or YYYYMMDD. |
103 | if (isBlank(date)) { |
104 | EXPECT_TRUE(true); |
105 | } else { |
106 | count_t number{-1}; |
107 | // Use stol to allow GCC 7.5 to build tests |
108 | number = std::stol(date); |
109 | ASSERT_TRUE(errno != ERANGE); |
110 | EXPECT_GE(number, 0); |
111 | auto year = number / 10000; |
112 | auto month = (number - year * 10000) / 100; |
113 | auto day = number % 100; |
114 | // Do not assume anything about the year, the test could be |
115 | // run on system with fake/outdated dates. |
116 | EXPECT_LE(month, 12); |
117 | EXPECT_GT(month, 0); |
118 | EXPECT_LE(day, 31); |
119 | EXPECT_GT(day, 0); |
120 | } |
121 | |
122 | // Validate time is hhmmss.sss or blank. |
123 | std::string acceptedPattern("hhmmss.sss" ); |
124 | if (isBlank(time)) { |
125 | EXPECT_TRUE(true); |
126 | } else { |
127 | count_t number{-1}; |
128 | // Use stol to allow GCC 7.5 to build tests |
129 | auto dotPosition = acceptedPattern.find('.'); |
130 | number = std::stol(time.substr(0, dotPosition)); |
131 | ASSERT_TRUE(errno != ERANGE); |
132 | ASSERT_GE(number, 0); |
133 | auto hours = number / 10000; |
134 | auto minutes = (number - hours * 10000) / 100; |
135 | auto seconds = number % 100; |
136 | EXPECT_LE(hours, 23); |
137 | EXPECT_LE(minutes, 59); |
138 | // Accept 60 for leap seconds. |
139 | EXPECT_LE(seconds, 60); |
140 | EXPECT_EQ(time.substr(dotPosition, 1), "." ); |
141 | |
142 | count_t milliseconds{-1}; |
143 | milliseconds = std::stol(time.substr(dotPosition + 1, 3)); |
144 | ASSERT_TRUE(errno != ERANGE); |
145 | EXPECT_GE(milliseconds, 0); |
146 | EXPECT_LE(milliseconds, 999); |
147 | } |
148 | |
149 | // Validate zone is +hhmm or -hhmm or blank. |
150 | if (isBlank(zone)) { |
151 | EXPECT_TRUE(true); |
152 | } else { |
153 | ASSERT_TRUE(zone.size() > 1); |
154 | EXPECT_TRUE(zone[0] == '+' || zone[0] == '-'); |
155 | count_t number{-1}; |
156 | // Use stol to allow GCC 7.5 to build tests |
157 | number = std::stol(zone.substr(1, 4)); |
158 | ASSERT_TRUE(errno != ERANGE); |
159 | ASSERT_GE(number, 0); |
160 | auto hours = number / 100; |
161 | auto minutes = number % 100; |
162 | EXPECT_LE(hours, 23); |
163 | EXPECT_LE(minutes, 59); |
164 | } |
165 | } |
166 | #endif // __clang__ |
167 | |