Add absl::MockClock, a gMock implementation of absl::Clock for writing tests PiperOrigin-RevId: 1004832177
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index fdd4ae1..5b24d67 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake
@@ -520,6 +520,7 @@ "status/internal/status_matchers.h" "strings/cordz_test_helpers.h" "strings/cord_test_helpers.h" + "time/mock_clock.h" ) if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD_REQUIRED)
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel index 347e24b..7408def 100644 --- a/absl/time/BUILD.bazel +++ b/absl/time/BUILD.bazel
@@ -92,6 +92,23 @@ ) cc_library( + name = "mock_clock", + testonly = True, + hdrs = ["mock_clock.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = ["//visibility:public"], + deps = [ + ":clock_interface", + ":time", + "//absl/base:config", + "//absl/base:core_headers", + "//absl/synchronization", + "@googletest//:gtest", + ], +) + +cc_library( name = "simulated_clock", testonly = True, srcs = [ @@ -175,6 +192,24 @@ ) cc_test( + name = "mock_clock_test", + srcs = [ + "mock_clock_test.cc", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":clock_interface", + ":mock_clock", + ":time", + "//absl/base:core_headers", + "//absl/synchronization", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + +cc_test( name = "simulated_clock_test", srcs = [ "simulated_clock_test.cc",
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index 79b99e8..709632d 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt
@@ -168,6 +168,41 @@ absl_cc_library( NAME + mock_clock + HDRS + "mock_clock.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::clock_interface + absl::config + absl::core_headers + absl::synchronization + absl::time + GTest::gmock + GTest::gtest + PUBLIC + TESTONLY +) + +absl_cc_test( + NAME + mock_clock_test + SRCS + "mock_clock_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::clock_interface + absl::core_headers + absl::mock_clock + absl::synchronization + absl::time + GTest::gmock_main +) + +absl_cc_library( + NAME simulated_clock HDRS "simulated_clock.h"
diff --git a/absl/time/mock_clock.h b/absl/time/mock_clock.h new file mode 100644 index 0000000..3a1d151 --- /dev/null +++ b/absl/time/mock_clock.h
@@ -0,0 +1,76 @@ +// Copyright 2026 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: mock_clock.h +// ----------------------------------------------------------------------------- + +#ifndef ABSL_TIME_MOCK_CLOCK_H_ +#define ABSL_TIME_MOCK_CLOCK_H_ + +#include "gmock/gmock.h" +#include "absl/base/config.h" +#include "absl/base/macros.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/clock_interface.h" +#include "absl/time/time.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +// A gMock implementation of absl::Clock. +// +// This class is appropriate for testing single-threaded uses of +// absl::Clock, particularly when calling +// absl::Clock::Sleep(). absl::MockClock::Sleep() (by default) simply +// advances simulated time and returns. +// +// For multithreaded testing, consider using absl::SimulatedClock. +class MockClock : public absl::Clock { + public: + explicit MockClock(absl::Time now) : now_(now) { + ON_CALL(*this, TimeNow()) + .WillByDefault(testing::Invoke(this, &MockClock::current_time)); + ON_CALL(*this, Sleep(testing::A<absl::Duration>())) + .WillByDefault(testing::Invoke(this, &MockClock::SleepTime)); + ON_CALL(*this, SleepUntil(testing::A<absl::Time>())) + .WillByDefault(testing::Invoke(this, &MockClock::SetTime)); + } + + MockClock() : MockClock(absl::UnixEpoch()) {} + + MOCK_METHOD(absl::Time, TimeNow, (), (override)); + MOCK_METHOD(void, Sleep, (absl::Duration d), (override)); + MOCK_METHOD(void, SleepUntil, (absl::Time wakeup_time), (override)); + MOCK_METHOD(bool, AwaitWithDeadline, + (absl::Mutex* mu, const absl::Condition& cond, + absl::Time wakeup_time), + (override)); + + absl::Time current_time() const { return now_; } + + // Set the mock time to 'timestamp'. + void SetTime(absl::Time timestamp) { now_ = timestamp; } + + // Advance the mock time and return immediately. + void SleepTime(absl::Duration d) { now_ += d; } + + private: + absl::Time now_; // The mock time. +}; + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_MOCK_CLOCK_H_
diff --git a/absl/time/mock_clock_test.cc b/absl/time/mock_clock_test.cc new file mode 100644 index 0000000..006f232 --- /dev/null +++ b/absl/time/mock_clock_test.cc
@@ -0,0 +1,42 @@ +// Copyright 2026 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/mock_clock.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/time/time.h" + +namespace { + +using ::testing::A; + +TEST(MockClock, SatisfiesExpectations) { + absl::MockClock mock_clock; + const absl::Duration kDuration = absl::Seconds(100); + const absl::Time kWakeupTime = absl::UnixEpoch() + kDuration; + EXPECT_CALL(mock_clock, TimeNow()).Times(2); + EXPECT_CALL(mock_clock, Sleep(A<absl::Duration>())); + EXPECT_CALL(mock_clock, SleepUntil(A<absl::Time>())); + + EXPECT_EQ(absl::UnixEpoch(), mock_clock.TimeNow()); + mock_clock.Sleep(kDuration); + EXPECT_EQ(kWakeupTime, mock_clock.TimeNow()); + mock_clock.SleepUntil(kWakeupTime); + + absl::MockClock mock_clock_init(absl::UnixEpoch() + kDuration); + EXPECT_EQ(mock_clock_init.current_time(), absl::UnixEpoch() + kDuration); +} + +} // namespace