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