blob: 655cb46779e4404d489a674fac96feb8b104784d [file] [log] [blame]
cfredrica0464eb2021-07-24 01:26:39 +00001// Copyright 2021 The Chromium Authors. All rights reserved.
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/bind.h"
8#include "base/callback.h"
9#include "base/callback_helpers.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
15namespace {
16
17TEST(BarrierCallbackTest, ChecksImmediatelyForZeroCallbacks) {
18 EXPECT_CHECK_DEATH(base::BarrierCallback<bool>(0, base::DoNothing()));
19}
20
21TEST(BarrierCallbackTest, RunAfterNumCallbacks) {
22 bool done = false;
23 auto barrier_callback = base::BarrierCallback<int>(
24 3, base::BindLambdaForTesting([&done](std::vector<int> results) {
25 EXPECT_THAT(results, testing::ElementsAre(1, 3, 2));
26 done = true;
27 }));
28 EXPECT_FALSE(done);
29
30 barrier_callback.Run(1);
31 EXPECT_FALSE(done);
32
33 barrier_callback.Run(3);
34 EXPECT_FALSE(done);
35
36 barrier_callback.Run(2);
37 EXPECT_TRUE(done);
38}
39
40template <typename... Args>
41class DestructionIndicator {
42 public:
43 // Sets `*destructed` to true in destructor.
44 explicit DestructionIndicator(bool* destructed) : destructed_(destructed) {
45 *destructed_ = false;
46 }
47
48 ~DestructionIndicator() { *destructed_ = true; }
49
50 void DoNothing(Args...) {}
51
52 private:
53 bool* destructed_;
54};
55
56TEST(BarrierCallbackTest, ReleasesDoneCallbackWhenDone) {
57 bool done_destructed = false;
58 auto barrier_callback = base::BarrierCallback(
59 1,
60 base::BindOnce(&DestructionIndicator<std::vector<bool>>::DoNothing,
61 std::make_unique<DestructionIndicator<std::vector<bool>>>(
62 &done_destructed)));
63 EXPECT_FALSE(done_destructed);
64 barrier_callback.Run(true);
65 EXPECT_TRUE(done_destructed);
66}
67
68// Tests a case when `done_callback` resets the `barrier_callback`.
69// `barrier_callback` is a RepeatingCallback holding the `done_callback`.
70// `done_callback` holds a reference back to the `barrier_callback`. When
71// `barrier_callback` is Run() it calls `done_callback` which erases the
72// `barrier_callback` while still inside of its Run(). The Run() implementation
73// (in base::BarrierCallback) must not try use itself after executing
74// ResetBarrierCallback() or this test would crash inside Run().
75TEST(BarrierCallbackTest, KeepingCallbackAliveUntilDone) {
76 base::RepeatingCallback<void(bool)> barrier_callback;
77 barrier_callback = base::BarrierCallback<bool>(
78 1, base::BindLambdaForTesting(
79 [&barrier_callback](std::vector<bool> results) {
80 barrier_callback = base::RepeatingCallback<void(bool)>();
81 EXPECT_THAT(results, testing::ElementsAre(true));
82 }));
83 barrier_callback.Run(true);
84 EXPECT_TRUE(barrier_callback.is_null());
85}
86
87TEST(BarrierCallbackTest, SupportsMoveonlyTypes) {
88 class MoveOnly {
89 public:
90 MoveOnly() = default;
91 MoveOnly(MoveOnly&&) = default;
92 MoveOnly& operator=(MoveOnly&&) = default;
93 };
94
95 // No need to assert anything here, since if BarrierCallback didn't work with
96 // move-only types, this wouldn't compile.
97 auto barrier_callback = base::BarrierCallback<MoveOnly>(1, base::DoNothing());
98 barrier_callback.Run(MoveOnly());
99}
100
101} // namespace