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
18using namespace Fortran::runtime;
19
20TEST(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
36using count_t = std::int64_t;
37
38TEST(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
91TEST(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

source code of flang/unittests/Runtime/Time.cpp