| Index: base/message_loop/message_pump_mac_unittest.cc
|
| diff --git a/base/message_loop/message_pump_mac_unittest.cc b/base/message_loop/message_pump_mac_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..17c70c8a6cbe32e577a10c035d87d74fb9e5aadf
|
| --- /dev/null
|
| +++ b/base/message_loop/message_pump_mac_unittest.cc
|
| @@ -0,0 +1,108 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/message_loop/message_pump_mac.h"
|
| +
|
| +#include "base/mac/scoped_cftyperef.h"
|
| +#include "base/macros.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace base {
|
| +
|
| +class TestMessagePumpCFRunLoopBase {
|
| + public:
|
| + bool TestCanInvalidateTimers() {
|
| + return MessagePumpCFRunLoopBase::CanInvalidateCFRunLoopTimers();
|
| + }
|
| + static void SetTimerValid(CFRunLoopTimerRef timer, bool valid) {
|
| + MessagePumpCFRunLoopBase::ChromeCFRunLoopTimerSetValid(timer, valid);
|
| + }
|
| +
|
| + static void PerformTimerCallback(CFRunLoopTimerRef timer, void* info) {
|
| + TestMessagePumpCFRunLoopBase* self =
|
| + static_cast<TestMessagePumpCFRunLoopBase*>(info);
|
| + self->timer_callback_called_ = true;
|
| +
|
| + if (self->invalidate_timer_in_callback_) {
|
| + SetTimerValid(timer, false);
|
| + }
|
| + }
|
| +
|
| + bool invalidate_timer_in_callback_;
|
| +
|
| + bool timer_callback_called_;
|
| +};
|
| +
|
| +TEST(MessagePumpMacTest, TestCanInvalidateTimers) {
|
| + TestMessagePumpCFRunLoopBase message_pump_test;
|
| +
|
| + // Catch whether or not the use of private API ever starts failing.
|
| + EXPECT_TRUE(message_pump_test.TestCanInvalidateTimers());
|
| +}
|
| +
|
| +TEST(MessagePumpMacTest, TestInvalidatedTimerReuse) {
|
| + TestMessagePumpCFRunLoopBase message_pump_test;
|
| +
|
| + CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
|
| + timer_context.info = &message_pump_test;
|
| + const CFTimeInterval kCFTimeIntervalMax =
|
| + std::numeric_limits<CFTimeInterval>::max();
|
| + ScopedCFTypeRef<CFRunLoopTimerRef> test_timer(CFRunLoopTimerCreate(
|
| + NULL, // allocator
|
| + kCFTimeIntervalMax, // fire time
|
| + kCFTimeIntervalMax, // interval
|
| + 0, // flags
|
| + 0, // priority
|
| + TestMessagePumpCFRunLoopBase::PerformTimerCallback, &timer_context));
|
| + CFRunLoopAddTimer(CFRunLoopGetCurrent(), test_timer,
|
| + kMessageLoopExclusiveRunLoopMode);
|
| +
|
| + // Sanity check.
|
| + EXPECT_TRUE(CFRunLoopTimerIsValid(test_timer));
|
| +
|
| + // Confirm that the timer fires as expected, and that it's not a one-time-use
|
| + // timer (those timers are invalidated after they fire).
|
| + CFAbsoluteTime next_fire_time = CFAbsoluteTimeGetCurrent() + 0.01;
|
| + CFRunLoopTimerSetNextFireDate(test_timer, next_fire_time);
|
| + message_pump_test.timer_callback_called_ = false;
|
| + message_pump_test.invalidate_timer_in_callback_ = false;
|
| + CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0.02, true);
|
| + EXPECT_TRUE(message_pump_test.timer_callback_called_);
|
| + EXPECT_TRUE(CFRunLoopTimerIsValid(test_timer));
|
| +
|
| + // As a repeating timer, the timer should have a new fire date set in the
|
| + // future.
|
| + EXPECT_GT(CFRunLoopTimerGetNextFireDate(test_timer), next_fire_time);
|
| +
|
| + // Try firing the timer, and invalidating it within its callback.
|
| + next_fire_time = CFAbsoluteTimeGetCurrent() + 0.01;
|
| + CFRunLoopTimerSetNextFireDate(test_timer, next_fire_time);
|
| + message_pump_test.timer_callback_called_ = false;
|
| + message_pump_test.invalidate_timer_in_callback_ = true;
|
| + CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0.02, true);
|
| + EXPECT_TRUE(message_pump_test.timer_callback_called_);
|
| + EXPECT_FALSE(CFRunLoopTimerIsValid(test_timer));
|
| +
|
| + // The CFRunLoop believes the timer is invalid, so it should not have a
|
| + // fire date.
|
| + EXPECT_EQ(0, CFRunLoopTimerGetNextFireDate(test_timer));
|
| +
|
| + // Now mark the timer as valid and confirm that it still fires correctly.
|
| + TestMessagePumpCFRunLoopBase::SetTimerValid(test_timer, true);
|
| + EXPECT_TRUE(CFRunLoopTimerIsValid(test_timer));
|
| + next_fire_time = CFAbsoluteTimeGetCurrent() + 0.01;
|
| + CFRunLoopTimerSetNextFireDate(test_timer, next_fire_time);
|
| + message_pump_test.timer_callback_called_ = false;
|
| + message_pump_test.invalidate_timer_in_callback_ = false;
|
| + CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0.02, true);
|
| + EXPECT_TRUE(message_pump_test.timer_callback_called_);
|
| + EXPECT_TRUE(CFRunLoopTimerIsValid(test_timer));
|
| +
|
| + // Confirm that the run loop again gave it a new fire date in the future.
|
| + EXPECT_GT(CFRunLoopTimerGetNextFireDate(test_timer), next_fire_time);
|
| +
|
| + CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), test_timer,
|
| + kMessageLoopExclusiveRunLoopMode);
|
| +}
|
| +} // namespace base
|
|
|