1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
17 #include "gtest/gtest.h"
18 #include "pw_chrono/system_clock.h"
19 #include "pw_preprocessor/util.h"
21 using namespace std::chrono_literals;
23 namespace pw::chrono {
28 // Functions defined in system_clock_facade_test_c.c which call the API from C.
29 pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_CallNow();
30 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_CallTimeElapsed(
31 pw_chrono_SystemClock_TimePoint last_time,
32 pw_chrono_SystemClock_TimePoint current_time);
34 pw_chrono_SystemClock_Nanoseconds pw_chrono_SystemClock_CallDurationToNsFloor(
35 pw_chrono_SystemClock_Duration ticks);
39 // While testing that the clock ticks (i.e. moves forward) we want to ensure a
40 // failure can be reported instead of deadlocking the test until it passes.
41 // Given that there isn't really a good heuristic for this we instead make some
42 // wild assumptions to bound the maximum busy loop iterations.
43 // - Assume our clock is < 6Ghz
44 // - Assume we can check the clock in a single cycle
45 // - Wait for up to 1/10th of a second @ 6Ghz, this may be a long period on a
46 // slower (i.e. real) machine.
47 constexpr uint64_t kMaxIterations = 6'000'000'000 / 10;
49 TEST(SystemClock, Now) {
50 const SystemClock::time_point start_time = SystemClock::now();
51 // Verify the clock moves forward.
52 bool clock_moved_forward = false;
53 for (uint64_t i = 0; i < kMaxIterations; ++i) {
54 if (SystemClock::now() > start_time) {
55 clock_moved_forward = true;
59 EXPECT_TRUE(clock_moved_forward);
62 TEST(VirtualSystemClock, Now) {
63 auto& clock = VirtualSystemClock::RealClock();
64 const SystemClock::time_point start_time = clock.now();
65 // Verify the clock moves forward.
66 bool clock_moved_forward = false;
67 for (uint64_t i = 0; i < kMaxIterations; ++i) {
68 if (clock.now() > start_time) {
69 clock_moved_forward = true;
73 EXPECT_TRUE(clock_moved_forward);
76 TEST(SystemClock, NowInC) {
77 const pw_chrono_SystemClock_TimePoint start_time =
78 pw_chrono_SystemClock_CallNow();
79 // Verify the clock moves forward.
80 bool clock_moved_forward = false;
81 for (uint64_t i = 0; i < kMaxIterations; ++i) {
82 if (pw_chrono_SystemClock_CallNow().duration_since_epoch.ticks >
83 start_time.duration_since_epoch.ticks) {
84 clock_moved_forward = true;
88 EXPECT_TRUE(clock_moved_forward);
91 TEST(SystemClock, TimeElapsedInC) {
92 const pw_chrono_SystemClock_TimePoint first = pw_chrono_SystemClock_CallNow();
93 const pw_chrono_SystemClock_TimePoint last = pw_chrono_SystemClock_CallNow();
94 static_assert(SystemClock::is_monotonic);
95 EXPECT_GE(0, pw_chrono_SystemClock_CallTimeElapsed(last, first).ticks);
98 TEST(SystemClock, DurationCastInC) {
99 // We can't control the SystemClock's period configuration, so just in case
100 // 42 hours cannot be accurately expressed in integer ticks, round the
101 // duration w/ floor.
102 static constexpr auto kRoundedArbitraryDuration =
103 std::chrono::floor<SystemClock::duration>(42h);
104 static constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
105 PW_SYSTEM_CLOCK_H_FLOOR(42);
107 std::chrono::floor<std::chrono::nanoseconds>(kRoundedArbitraryDuration)
109 pw_chrono_SystemClock_CallDurationToNsFloor(
110 kRoundedArbitraryDurationInC));
114 } // namespace pw::chrono