blob: 0e6c45f4ae6e53e2cd57357910cc6a29f380b6e9 [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.
#include "peridot/bin/ledger/testing/blocking_callback_waiter.h"
#include <memory>
#include <lib/fit/function.h>
#include "gtest/gtest.h"
namespace ledger {
namespace {
class FakeLoopController : public LoopController {
public:
FakeLoopController(fit::function<void()> on_run,
fit::function<void()> on_stop)
: on_run_(std::move(on_run)), on_stop_(std::move(on_stop)) {}
FakeLoopController(const FakeLoopController&) = delete;
FakeLoopController& operator=(const FakeLoopController&) = delete;
void RunLoop() override { on_run_(); };
void StopLoop() override { on_stop_(); };
std::unique_ptr<SubLoop> StartNewLoop() override {
FXL_NOTREACHED();
return nullptr;
}
std::unique_ptr<CallbackWaiter> NewWaiter() override {
return std::make_unique<BlockingCallbackWaiter>(this);
}
async_dispatcher_t* dispatcher() override {
FXL_NOTREACHED();
return nullptr;
}
bool RunLoopUntil(fit::function<bool()> /* condition */) override {
FXL_NOTREACHED();
return false;
}
void RunLoopFor(zx::duration /* duration */) override { FXL_NOTREACHED(); }
private:
fit::function<void()> on_run_;
fit::function<void()> on_stop_;
};
TEST(BlockingCallbackWaiterTest, PreCall) {
size_t nb_run = 0;
size_t nb_stop = 0;
FakeLoopController loop_controller([&] { ++nb_run; }, [&] { ++nb_stop; });
auto waiter = loop_controller.NewWaiter();
auto callback = waiter->GetCallback();
callback();
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_EQ(0u, nb_run);
EXPECT_EQ(0u, nb_stop);
}
TEST(BlockingCallbackWaiterTest, MultipleGetCallback) {
size_t nb_run = 0;
size_t nb_stop = 0;
FakeLoopController loop_controller([&] { ++nb_run; }, [&] { ++nb_stop; });
auto waiter = loop_controller.NewWaiter();
waiter->GetCallback()();
waiter->GetCallback()();
ASSERT_TRUE(waiter->RunUntilCalled());
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_EQ(0u, nb_run);
EXPECT_EQ(0u, nb_stop);
}
TEST(BlockingCallbackWaiterTest, PostCall) {
size_t nb_run = 0;
size_t nb_stop = 0;
std::unique_ptr<fit::closure> callback;
FakeLoopController loop_controller(
[&] {
++nb_run;
if (callback) {
(*callback)();
}
},
[&] { ++nb_stop; });
auto waiter = loop_controller.NewWaiter();
callback = std::make_unique<fit::closure>(waiter->GetCallback());
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_EQ(1u, nb_run);
EXPECT_EQ(1u, nb_stop);
// loop_controller must outlive the waiter.
callback.reset();
}
TEST(BlockingCallbackWaiterTest, MultipleRunUntilCalled) {
size_t nb_run = 0;
size_t nb_stop = 0;
std::unique_ptr<fit::closure> callback;
FakeLoopController loop_controller(
[&] {
++nb_run;
if (callback) {
(*callback)();
}
},
[&] { ++nb_stop; });
auto waiter = loop_controller.NewWaiter();
callback = std::make_unique<fit::closure>(waiter->GetCallback());
ASSERT_TRUE(waiter->RunUntilCalled());
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_EQ(2u, nb_run);
EXPECT_EQ(2u, nb_stop);
// loop_controller must outlive the waiter.
callback.reset();
}
TEST(BlockingCallbackWaiterTest, InterleaveRunUntilCalledAndCall) {
size_t nb_run = 0;
size_t nb_stop = 0;
std::unique_ptr<fit::closure> callback;
FakeLoopController loop_controller(
[&] {
++nb_run;
if (callback) {
(*callback)();
}
},
[&] { ++nb_stop; });
auto waiter = loop_controller.NewWaiter();
callback = std::make_unique<fit::closure>(waiter->GetCallback());
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_EQ(1u, nb_run);
EXPECT_EQ(1u, nb_stop);
(*callback)();
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_EQ(1u, nb_run);
EXPECT_EQ(1u, nb_stop);
// loop_controller must outlive the waiter.
callback.reset();
}
TEST(BlockingCallbackWaiterTest, NotCalledYet) {
FakeLoopController loop_controller([] {}, [] {});
auto waiter = loop_controller.NewWaiter();
auto callback = waiter->GetCallback();
EXPECT_TRUE(waiter->NotCalledYet());
callback();
EXPECT_FALSE(waiter->NotCalledYet());
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_TRUE(waiter->NotCalledYet());
callback();
callback();
EXPECT_FALSE(waiter->NotCalledYet());
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_FALSE(waiter->NotCalledYet());
ASSERT_TRUE(waiter->RunUntilCalled());
EXPECT_TRUE(waiter->NotCalledYet());
}
TEST(BlockingCallbackWaiterTest, FailedWhenNoCallbackIsAlive) {
std::unique_ptr<fit::closure> on_run_callback;
FakeLoopController loop_controller(
[&] {
if (on_run_callback) {
(*on_run_callback)();
}
},
[] {});
auto waiter = loop_controller.NewWaiter();
EXPECT_FALSE(waiter->RunUntilCalled());
fit::closure callback = waiter->GetCallback();
callback = nullptr;
EXPECT_FALSE(waiter->RunUntilCalled());
callback = waiter->GetCallback();
on_run_callback = std::make_unique<fit::closure>([&] { callback = nullptr; });
EXPECT_FALSE(waiter->RunUntilCalled());
}
} // namespace
} // namespace ledger