blob: 3d98940128deedf87d7451348abdb15dd06d32e0 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2021 The Chromium Authors
cfredrica0464ebf2021-07-24 01:26:392// 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
Avi Drissman63e1f992023-01-13 18:54:437#include "base/functional/bind.h"
8#include "base/functional/callback.h"
Keishi Hattori0e45c022021-11-27 09:25:529#include "base/memory/raw_ptr.h"
cfredrica0464ebf2021-07-24 01:26:3910#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
15namespace {
16
cfredriceaafc6b2021-07-27 21:12:0117TEST(BarrierCallbackTest, RunsImmediatelyForZeroCallbacks) {
Elias0b42cfc12022-08-08 20:04:3118 bool done = false;
cfredriceaafc6b2021-07-27 21:12:0119 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
27TEST(BarrierCallbackTest, ErrorToCallCallbackWithZeroCallbacks) {
cfredricc8cdd1d2021-08-11 00:01:4828 auto barrier_callback =
Daniel Cheng714d043f2021-09-27 14:00:4229 base::BarrierCallback<int>(0, base::BindOnce([](std::vector<int>) {}));
cfredriceaafc6b2021-07-27 21:12:0130 EXPECT_FALSE(barrier_callback.is_null());
31
32 EXPECT_CHECK_DEATH(barrier_callback.Run(3));
cfredrica0464ebf2021-07-24 01:26:3933}
34
35TEST(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
Roland Bock6269edb2022-01-04 19:34:1554TEST(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
cfredrica0464ebf2021-07-24 01:26:3977template <typename... Args>
78class DestructionIndicator {
79 public:
80 // Sets `*destructed` to true in destructor.
81 explicit DestructionIndicator(bool* destructed) : destructed_(destructed) {
82 *destructed_ = false;
83 }
84
85 ~DestructionIndicator() { *destructed_ = true; }
86
87 void DoNothing(Args...) {}
88
89 private:
Keishi Hattori0e45c022021-11-27 09:25:5290 raw_ptr<bool> destructed_;
cfredrica0464ebf2021-07-24 01:26:3991};
92
93TEST(BarrierCallbackTest, ReleasesDoneCallbackWhenDone) {
94 bool done_destructed = false;
cfredricc8cdd1d2021-08-11 00:01:4895 auto barrier_callback = base::BarrierCallback<bool>(
cfredrica0464ebf2021-07-24 01:26:3996 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().
112TEST(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
124TEST(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.
cfredricc8cdd1d2021-08-11 00:01:48134 auto barrier_callback = base::BarrierCallback<MoveOnly>(
Daniel Cheng714d043f2021-09-27 14:00:42135 1, base::BindOnce([](std::vector<MoveOnly>) {}));
cfredrica0464ebf2021-07-24 01:26:39136 barrier_callback.Run(MoveOnly());
cfredricc8cdd1d2021-08-11 00:01:48137
138 auto barrier_callback2 = base::BarrierCallback<MoveOnly>(
Daniel Cheng714d043f2021-09-27 14:00:42139 1, base::BindOnce([](const std::vector<MoveOnly>&) {}));
cfredricc8cdd1d2021-08-11 00:01:48140 barrier_callback2.Run(MoveOnly());
141}
142
143TEST(BarrierCallbackTest, SupportsConstRefResults) {
144 auto barrier_callback = base::BarrierCallback<int>(
Daniel Cheng714d043f2021-09-27 14:00:42145 1, base::BindOnce([](const std::vector<int>&) {}));
cfredricc8cdd1d2021-08-11 00:01:48146
147 barrier_callback.Run(1);
148}
149
150TEST(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&>(
Daniel Cheng714d043f2021-09-27 14:00:42159 1, base::BindOnce([](std::vector<Referenceable>) {}));
cfredricc8cdd1d2021-08-11 00:01:48160 barrier_callback.Run(ref);
161
162 auto barrier_callback2 = base::BarrierCallback<const Referenceable&>(
Daniel Cheng714d043f2021-09-27 14:00:42163 1, base::BindOnce([](const std::vector<Referenceable>&) {}));
cfredricc8cdd1d2021-08-11 00:01:48164 barrier_callback2.Run(ref);
cfredrica0464ebf2021-07-24 01:26:39165}
166
167} // namespace