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