1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/barrier_callback.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
TEST(BarrierCallbackTest, RunsImmediatelyForZeroCallbacks) {
bool done = false;
auto barrier_callback = base::BarrierCallback<int>(
0, base::BindLambdaForTesting([&done](std::vector<int> results) {
EXPECT_THAT(results, testing::IsEmpty());
done = true;
}));
EXPECT_TRUE(done);
}
TEST(BarrierCallbackTest, ErrorToCallCallbackWithZeroCallbacks) {
auto barrier_callback =
base::BarrierCallback<int>(0, base::BindOnce([](std::vector<int>) {}));
EXPECT_FALSE(barrier_callback.is_null());
EXPECT_CHECK_DEATH(barrier_callback.Run(3));
}
TEST(BarrierCallbackTest, RunAfterNumCallbacks) {
bool done = false;
auto barrier_callback = base::BarrierCallback<int>(
3, base::BindLambdaForTesting([&done](std::vector<int> results) {
EXPECT_THAT(results, testing::ElementsAre(1, 3, 2));
done = true;
}));
EXPECT_FALSE(done);
barrier_callback.Run(1);
EXPECT_FALSE(done);
barrier_callback.Run(3);
EXPECT_FALSE(done);
barrier_callback.Run(2);
EXPECT_TRUE(done);
}
TEST(BarrierCallbackTest, CopiesShareState) {
bool done = false;
const auto barrier_callback = base::BarrierCallback<int>(
3, base::BindLambdaForTesting([&done](std::vector<int> results) {
EXPECT_THAT(results, testing::ElementsAre(1, 3, 2));
done = true;
}));
EXPECT_FALSE(done);
const auto barrier_copy1 = barrier_callback;
const auto barrier_copy2 = barrier_callback;
const auto barrier_copy3 = barrier_callback;
barrier_copy1.Run(1);
EXPECT_FALSE(done);
barrier_copy2.Run(3);
EXPECT_FALSE(done);
barrier_copy3.Run(2);
EXPECT_TRUE(done);
}
template <typename... Args>
class DestructionIndicator {
public:
// Sets `*destructed` to true in destructor.
explicit DestructionIndicator(bool* destructed) : destructed_(destructed) {
*destructed_ = false;
}
~DestructionIndicator() { *destructed_ = true; }
void DoNothing(Args...) {}
private:
raw_ptr<bool> destructed_;
};
TEST(BarrierCallbackTest, ReleasesDoneCallbackWhenDone) {
bool done_destructed = false;
auto barrier_callback = base::BarrierCallback<bool>(
1,
base::BindOnce(&DestructionIndicator<std::vector<bool>>::DoNothing,
std::make_unique<DestructionIndicator<std::vector<bool>>>(
&done_destructed)));
EXPECT_FALSE(done_destructed);
barrier_callback.Run(true);
EXPECT_TRUE(done_destructed);
}
// Tests a case when `done_callback` resets the `barrier_callback`.
// `barrier_callback` is a RepeatingCallback holding the `done_callback`.
// `done_callback` holds a reference back to the `barrier_callback`. When
// `barrier_callback` is Run() it calls `done_callback` which erases the
// `barrier_callback` while still inside of its Run(). The Run() implementation
// (in base::BarrierCallback) must not try use itself after executing
// ResetBarrierCallback() or this test would crash inside Run().
TEST(BarrierCallbackTest, KeepingCallbackAliveUntilDone) {
base::RepeatingCallback<void(bool)> barrier_callback;
barrier_callback = base::BarrierCallback<bool>(
1, base::BindLambdaForTesting(
[&barrier_callback](std::vector<bool> results) {
barrier_callback = base::RepeatingCallback<void(bool)>();
EXPECT_THAT(results, testing::ElementsAre(true));
}));
barrier_callback.Run(true);
EXPECT_TRUE(barrier_callback.is_null());
}
TEST(BarrierCallbackTest, SupportsMoveonlyTypes) {
class MoveOnly {
public:
MoveOnly() = default;
MoveOnly(MoveOnly&&) = default;
MoveOnly& operator=(MoveOnly&&) = default;
};
// No need to assert anything here, since if BarrierCallback didn't work with
// move-only types, this wouldn't compile.
auto barrier_callback = base::BarrierCallback<MoveOnly>(
1, base::BindOnce([](std::vector<MoveOnly>) {}));
barrier_callback.Run(MoveOnly());
auto barrier_callback2 = base::BarrierCallback<MoveOnly>(
1, base::BindOnce([](const std::vector<MoveOnly>&) {}));
barrier_callback2.Run(MoveOnly());
}
TEST(BarrierCallbackTest, SupportsConstRefResults) {
auto barrier_callback = base::BarrierCallback<int>(
1, base::BindOnce([](const std::vector<int>&) {}));
barrier_callback.Run(1);
}
TEST(BarrierCallbackTest, SupportsReferenceTypes) {
class Referenceable {
// Must be copyable.
};
Referenceable ref;
// No need to assert anything here, since if BarrierCallback didn't work with
// by-reference args, this wouldn't compile.
auto barrier_callback = base::BarrierCallback<const Referenceable&>(
1, base::BindOnce([](std::vector<Referenceable>) {}));
barrier_callback.Run(ref);
auto barrier_callback2 = base::BarrierCallback<const Referenceable&>(
1, base::BindOnce([](const std::vector<Referenceable>&) {}));
barrier_callback2.Run(ref);
}
} // namespace
|