blob: e6f80d13f37298878795bf66119f5ab4e9beada2 [file] [log] [blame]
// Copyright 2018 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.
#ifndef SRC_LIB_TESTING_LOOP_FIXTURE_REAL_LOOP_FIXTURE_H_
#define SRC_LIB_TESTING_LOOP_FIXTURE_REAL_LOOP_FIXTURE_H_
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fit/function.h>
#include <lib/zx/time.h>
#include <gtest/gtest.h>
#include "src/lib/fxl/macros.h"
namespace gtest {
// An extension of gtest's testing::Test class which sets up a message loop,
// async::Loop, for the test. This fixture is meant to be used for
// multi-process tests.
//
// This allows, for example, a test to conveniently excercise FIDL, as FIDL
// bindings post waits to the thread-local dispatcher.
//
// Example:
//
// #include "foo.fidl.h"
//
// class TestFoo : public Foo {
// public:
// explicit TestFoo(InterfaceRequest<Foo> request)
// : binding_(this, std::move(request) {}
//
// // Foo implementation here.
//
// private:
// Binding<Foo> binding_;
// };
//
// // Creates a gtest fixture that creates a message loop on this thread.
// class TestBar : public RealLoopFixture { /* ... */ };
//
// TEST_F(TestBar, TestCase) {
// // Do all FIDL-y stuff here and asynchronously quit.
//
// RunLoop();
//
// // Check results from FIDL-y stuff here.
// }
class RealLoopFixture : public ::testing::Test {
protected:
RealLoopFixture();
~RealLoopFixture() override;
// Returns the loop's asynchronous dispatch interface.
async_dispatcher_t* dispatcher();
// Runs the loop until it is exited.
void RunLoop();
// Runs the loop for at most |timeout|. Returns |true| if the timeout has been
// reached.
bool RunLoopWithTimeout(zx::duration timeout = zx::sec(1));
// Runs the loop until the condition returns true.
//
// |step| specifies the interval at which this method should wake up to poll
// |condition|. If |step| is |zx::duration::infinite()|, no polling timer is
// set. Instead, the condition is checked initially and after anything happens
// on the loop (e.g. a task executes). This is useful when the caller knows
// that |condition| will be made true by a task running on the loop. This will
// generally be the case unless |condition| is made true on a different
// thread.
void RunLoopUntil(fit::function<bool()> condition, zx::duration step = zx::msec(10));
// Runs the loop until the condition returns true or the timeout is reached.
// Returns |true| if the condition was met, and |false| if the timeout was
// reached.
//
// |step| specifies the interval at which this method should wake up to poll
// |condition|. If |step| is |zx::duration::infinite()|, no polling timer is
// set. Instead, the condition is checked initially and after anything happens
// on the loop (e.g. a task executes). This is useful when the caller knows
// that |condition| will be made true by a task running on the loop. This will
// generally be the case unless |condition| is made true on a different
// thread.
bool RunLoopWithTimeoutOrUntil(fit::function<bool()> condition, zx::duration timeout = zx::sec(1),
zx::duration step = zx::msec(10));
// Runs the message loop until idle.
void RunLoopUntilIdle();
// Quits the loop.
void QuitLoop();
// Creates a closure that quits the test message loop when executed.
fit::closure QuitLoopClosure();
private:
// The message loop for the test.
async::Loop loop_;
FXL_DISALLOW_COPY_AND_ASSIGN(RealLoopFixture);
};
} // namespace gtest
#endif // SRC_LIB_TESTING_LOOP_FIXTURE_REAL_LOOP_FIXTURE_H_