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