blob: 19daa4ffc8e41e4b9d68d902761c4c122c81f8b2 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 "lib/gtest/test_with_message_loop.h"
#include "lib/fxl/functional/make_copyable.h"
#include "lib/fxl/logging.h"
namespace gtest {
namespace {
bool RunGivenLoopWithTimeout(fsl::MessageLoop* message_loop,
fxl::TimeDelta timeout) {
// This cannot be a local variable because the delayed task below can execute
// after this function returns.
auto canceled = std::make_shared<bool>(false);
bool timed_out = false;
message_loop->task_runner()->PostDelayedTask(
[message_loop, canceled, &timed_out] {
if (*canceled) {
return;
}
timed_out = true;
message_loop->QuitNow();
},
timeout);
message_loop->Run();
// Another task can call QuitNow() on the message loop, which exits the
// message loop before the delayed task executes, in which case |timed_out| is
// still false here because the delayed task hasn't run yet.
// Since the message loop isn't destroyed then (as it usually would after
// QuitNow()), and presumably can be reused after this function returns we
// still need to prevent the delayed task to quit it again at some later time
// using the canceled pointer.
if (!timed_out) {
*canceled = true;
}
return timed_out;
}
bool RunGivenLoopUntilWithTimeout(fsl::MessageLoop* message_loop,
std::function<bool()> condition,
fxl::TimeDelta timeout,
fxl::TimeDelta step) {
const fxl::TimePoint deadline = timeout == fxl::TimeDelta::FromSeconds(0)
? fxl::TimePoint::Max()
: fxl::TimePoint::Now() + timeout;
while (fxl::TimePoint::Now() < deadline) {
if (condition()) {
return true;
}
RunGivenLoopWithTimeout(message_loop, step);
}
return condition();
}
} // namespace
TestWithMessageLoop::TestWithMessageLoop() = default;
TestWithMessageLoop::~TestWithMessageLoop() = default;
void TestWithMessageLoop::RunLoop() {
message_loop_.Run();
}
bool TestWithMessageLoop::RunLoopWithTimeout(fxl::TimeDelta timeout) {
return RunGivenLoopWithTimeout(&message_loop_, timeout);
}
bool TestWithMessageLoop::RunLoopUntilWithTimeout(
std::function<bool()> condition,
fxl::TimeDelta timeout,
fxl::TimeDelta step) {
return RunGivenLoopUntilWithTimeout(&message_loop_, std::move(condition),
timeout, step);
}
bool TestWithMessageLoop::RunLoopUntil(std::function<bool()> condition,
fxl::TimeDelta step) {
return RunGivenLoopUntilWithTimeout(&message_loop_, std::move(condition),
fxl::TimeDelta::FromSeconds(0), step);
}
void TestWithMessageLoop::RunLoopUntilIdle() {
message_loop_.RunUntilIdle();
}
fxl::Closure TestWithMessageLoop::MakeQuitTask() {
return [this] { message_loop_.PostQuitTask(); };
}
fxl::Closure TestWithMessageLoop::MakeQuitTaskOnce() {
return fxl::MakeCopyable([this, called = false]() mutable {
if (!called) {
called = true;
message_loop_.PostQuitTask();
}
});
}
} // namespace gtest