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