blob: 4a61ec271eec3f1f94c32dff674594f60e5c495a [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/fxl/functional/auto_call.h"
#include "lib/fxl/functional/closure.h"
#include <memory>
#include "gtest/gtest.h"
namespace fxl {
namespace {
void incr_arg(int* p) { *p += 1; }
TEST(AutoCallTest, NullConstructor) {
{
fxl::AutoCall<fxl::Closure> c(nullptr);
// No crash is a successful test.
}
}
TEST(AutoCallTest, Basic) {
int var = 0;
{
auto do_incr = fxl::MakeAutoCall([&var]() { incr_arg(&var); });
EXPECT_EQ(var, 0);
}
EXPECT_EQ(var, 1);
}
TEST(AutoCallTest, Cancel) {
int var = 0;
{
auto do_incr = fxl::MakeAutoCall([&var]() { incr_arg(&var); });
EXPECT_EQ(var, 0);
do_incr.cancel();
EXPECT_EQ(var, 0);
// Once cancelled, call has no effect.
do_incr.call();
EXPECT_EQ(var, 0);
}
EXPECT_EQ(var, 0);
}
TEST(AutoCallTest, Call) {
int var = 0;
{
auto do_incr = fxl::MakeAutoCall([&var]() { incr_arg(&var); });
EXPECT_EQ(var, 0);
do_incr.call();
EXPECT_EQ(var, 1);
// Call is effective only once.
do_incr.call();
EXPECT_EQ(var, 1);
}
EXPECT_EQ(var, 1);
}
TEST(AutoCallTest, RecursiveCall) {
int var = 0;
{
auto do_incr = fxl::MakeAutoCall<fxl::Closure>([]() { /* no-op */ });
do_incr = fxl::MakeAutoCall<fxl::Closure>([&do_incr, &var]() {
incr_arg(&var);
do_incr.call();
});
EXPECT_EQ(var, 0);
do_incr.call();
EXPECT_EQ(var, 1);
}
EXPECT_EQ(var, 1);
}
TEST(AutoCallTest, MoveConstructBasic) {
int var = 0;
{
auto do_incr = fxl::MakeAutoCall([&var]() { incr_arg(&var); });
auto do_incr2(std::move(do_incr));
EXPECT_EQ(var, 0);
}
EXPECT_EQ(var, 1);
}
TEST(AutoCallTest, MoveConstructFromCancelled) {
int var = 0;
{
auto do_incr = fxl::MakeAutoCall([&var]() { incr_arg(&var); });
do_incr.cancel();
auto do_incr2(std::move(do_incr));
EXPECT_EQ(var, 0);
}
EXPECT_EQ(var, 0);
}
TEST(AutoCallTest, MoveConstructFromCalled) {
int var = 0;
{
auto do_incr = fxl::MakeAutoCall([&var]() { incr_arg(&var); });
EXPECT_EQ(var, 0);
do_incr.call();
EXPECT_EQ(var, 1);
// Must not be called again, since do_incr has triggered already.
auto do_incr2(std::move(do_incr));
}
EXPECT_EQ(var, 1);
}
TEST(AutoCallTest, MoveAssignBasic) {
int var1 = 0, var2 = 0;
{
auto do_incr =
fxl::MakeAutoCall<fxl::Closure>([&var1]() { incr_arg(&var1); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
auto do_incr2 =
fxl::MakeAutoCall<fxl::Closure>([&var2]() { incr_arg(&var2); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
// do_incr2 is moved-to, so its associated function is called.
do_incr2 = std::move(do_incr);
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 1);
}
EXPECT_EQ(var1, 1);
EXPECT_EQ(var2, 1);
}
TEST(AutoCallTest, MoveAssignWiderScope) {
int var1 = 0, var2 = 0;
{
auto do_incr =
fxl::MakeAutoCall<fxl::Closure>([&var1]() { incr_arg(&var1); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
{
auto do_incr2 =
fxl::MakeAutoCall<fxl::Closure>([&var2]() { incr_arg(&var2); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
// do_incr is moved-to, so its associated function is called.
do_incr = std::move(do_incr2);
EXPECT_EQ(var1, 1);
EXPECT_EQ(var2, 0);
}
// do_incr2 is out of scope but has been moved so its function is not
// called.
EXPECT_EQ(var1, 1);
EXPECT_EQ(var2, 0);
}
EXPECT_EQ(var1, 1);
EXPECT_EQ(var2, 1);
}
TEST(AutoCallTest, MoveAssignFromCancelled) {
int var1 = 0, var2 = 0;
{
auto do_incr =
fxl::MakeAutoCall<fxl::Closure>([&var1]() { incr_arg(&var1); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
auto do_incr2 =
fxl::MakeAutoCall<fxl::Closure>([&var2]() { incr_arg(&var2); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
do_incr.cancel();
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
// do_incr2 is moved-to, so its associated function is called.
do_incr2 = std::move(do_incr);
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 1);
}
// do_incr was cancelled, this state is preserved by the move.
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 1);
}
TEST(AutoCallTest, MoveAssignFromCalled) {
int var1 = 0, var2 = 0;
{
auto do_incr =
fxl::MakeAutoCall<fxl::Closure>([&var1]() { incr_arg(&var1); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
auto do_incr2 =
fxl::MakeAutoCall<fxl::Closure>([&var2]() { incr_arg(&var2); });
EXPECT_EQ(var1, 0);
EXPECT_EQ(var2, 0);
do_incr.call();
EXPECT_EQ(var1, 1);
EXPECT_EQ(var2, 0);
// do_incr2 is moved-to, so its associated function is called.
do_incr2 = std::move(do_incr);
EXPECT_EQ(var1, 1);
EXPECT_EQ(var2, 1);
}
// do_incr was called already, this state is preserved by the move.
EXPECT_EQ(var1, 1);
EXPECT_EQ(var2, 1);
}
} // namespace
} // namespace fxl