blob: fcb929a64601952bbebae5ae6edbf3f2534275c4 [file] [log] [blame]
kylechardde7d232020-11-16 17:35:091// Copyright 2020 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/bind_post_task.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/sequence_checker_impl.h"
10#include "base/sequenced_task_runner.h"
11#include "base/test/task_environment.h"
12#include "base/threading/sequenced_task_runner_handle.h"
13#include "base/threading/thread.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace base {
17namespace {
18
19void SetBool(bool* variable, bool value) {
20 *variable = value;
21}
22
23void SetInt(int* variable, int value) {
24 *variable = value;
25}
26
kylechar4ac8b3c2021-02-16 18:39:3427void SetIntFromUniquePtr(int* variable, std::unique_ptr<int> value) {
28 *variable = *value;
29}
30
kylechardde7d232020-11-16 17:35:0931int Multiply(int value) {
32 return value * 5;
33}
34
35void ClearReference(OnceClosure callback) {}
36
37class SequenceRestrictionChecker {
38 public:
39 explicit SequenceRestrictionChecker(bool& set_on_destroy)
40 : set_on_destroy_(set_on_destroy) {}
41
42 ~SequenceRestrictionChecker() {
43 EXPECT_TRUE(checker_.CalledOnValidSequence());
44 set_on_destroy_ = true;
45 }
46
47 void Run() { EXPECT_TRUE(checker_.CalledOnValidSequence()); }
48
49 private:
50 SequenceCheckerImpl checker_;
51 bool& set_on_destroy_;
52};
53
54} // namespace
55
56class BindPostTaskTest : public testing::Test {
57 protected:
58 test::SingleThreadTaskEnvironment task_environment_;
59 scoped_refptr<SequencedTaskRunner> task_runner_ =
60 SequencedTaskRunnerHandle::Get();
61};
62
63TEST_F(BindPostTaskTest, OnceClosure) {
64 bool val = false;
65 OnceClosure cb = BindOnce(&SetBool, &val, true);
66 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
67
68 std::move(post_cb).Run();
69 EXPECT_FALSE(val);
70
71 RunLoop().RunUntilIdle();
72 EXPECT_TRUE(val);
73}
74
75TEST_F(BindPostTaskTest, OnceCallback) {
76 OnceCallback<void(bool*, bool)> cb = BindOnce(&SetBool);
77 OnceCallback<void(bool*, bool)> post_cb =
78 BindPostTask(task_runner_, std::move(cb));
79
80 bool val = false;
81 std::move(post_cb).Run(&val, true);
82 EXPECT_FALSE(val);
83
84 RunLoop().RunUntilIdle();
85 EXPECT_TRUE(val);
86}
87
kylechar4ac8b3c2021-02-16 18:39:3488TEST_F(BindPostTaskTest, OnceWithBoundMoveOnlyArg) {
89 int val = 0;
90 OnceClosure cb =
91 BindOnce(&SetIntFromUniquePtr, &val, std::make_unique<int>(10));
92 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
93
94 std::move(post_cb).Run();
95 EXPECT_EQ(val, 0);
96
97 RunLoop().RunUntilIdle();
98 EXPECT_EQ(val, 10);
99}
100
101TEST_F(BindPostTaskTest, OnceWithUnboundMoveOnlyArg) {
102 int val = 0;
103 OnceCallback<void(std::unique_ptr<int>)> cb =
104 BindOnce(&SetIntFromUniquePtr, &val);
105 OnceCallback<void(std::unique_ptr<int>)> post_cb =
106 BindPostTask(task_runner_, std::move(cb));
107
108 std::move(post_cb).Run(std::make_unique<int>(10));
109 EXPECT_EQ(val, 0);
110
111 RunLoop().RunUntilIdle();
112 EXPECT_EQ(val, 10);
113}
114
kylechardde7d232020-11-16 17:35:09115TEST_F(BindPostTaskTest, OnceWithIgnoreResult) {
116 OnceCallback<void(int)> post_cb =
117 BindPostTask(task_runner_, BindOnce(IgnoreResult(&Multiply)));
118 std::move(post_cb).Run(1);
119 RunLoop().RunUntilIdle();
120}
121
122TEST_F(BindPostTaskTest, OnceThen) {
123 int value = 0;
124
125 // Multiply() returns an int and SetInt() takes an int as a parameter.
126 OnceClosure then_cb =
127 BindOnce(&Multiply, 5)
128 .Then(BindPostTask(task_runner_, BindOnce(&SetInt, &value)));
129
130 std::move(then_cb).Run();
131 EXPECT_EQ(value, 0);
132 RunLoop().RunUntilIdle();
133 EXPECT_EQ(value, 25);
134}
135
136// Ensure that the input callback is run/destroyed on the correct thread even if
137// the callback returned from BindPostTask() is run on a different thread.
138TEST_F(BindPostTaskTest, OnceRunDestroyedOnBound) {
139 Thread target_thread("testing");
140 ASSERT_TRUE(target_thread.Start());
141
142 // SequenceRestrictionChecker checks it's creation, Run() and deletion all
143 // happen on the main thread.
144 bool destroyed = false;
145 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
146
147 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is run
148 // on a different thread which triggers a PostTask() back to the test main
149 // thread to invoke `cb` which runs SequenceRestrictionChecker::Run(). After
150 // `cb` has been invoked `checker` is destroyed along with the BindState.
151 OnceClosure cb =
152 BindOnce(&SequenceRestrictionChecker::Run, std::move(checker));
153 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
154 target_thread.task_runner()->PostTask(FROM_HERE, std::move(post_cb));
155
156 target_thread.FlushForTesting();
157 EXPECT_FALSE(destroyed);
158 RunLoop().RunUntilIdle();
159 EXPECT_TRUE(destroyed);
160}
161
162// Ensure that the input callback is destroyed on the correct thread even if the
163// callback returned from BindPostTask() is destroyed without being run on a
164// different thread.
165TEST_F(BindPostTaskTest, OnceNotRunDestroyedOnBound) {
166 Thread target_thread("testing");
167 ASSERT_TRUE(target_thread.Start());
168
169 // SequenceRestrictionChecker checks it's creation and deletion all happen on
170 // the test main thread.
171 bool destroyed = false;
172 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
173
174 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is
175 // deleted on a different thread which triggers a PostTask() back to the test
176 // main thread to destroy `cb` and `checker`.
177 OnceClosure cb =
178 BindOnce(&SequenceRestrictionChecker::Run, std::move(checker));
179 OnceClosure post_cb = BindPostTask(task_runner_, std::move(cb));
180 target_thread.task_runner()->PostTask(
181 FROM_HERE, BindOnce(&ClearReference, std::move(post_cb)));
182
183 target_thread.FlushForTesting();
184 EXPECT_FALSE(destroyed);
185 RunLoop().RunUntilIdle();
186 EXPECT_TRUE(destroyed);
187}
188
kylechar4ac8b3c2021-02-16 18:39:34189TEST_F(BindPostTaskTest, RepeatingClosure) {
190 bool val = false;
191 RepeatingClosure cb = BindRepeating(&SetBool, &val, true);
192 RepeatingClosure post_cb = BindPostTask(task_runner_, std::move(cb));
193
194 post_cb.Run();
195 EXPECT_FALSE(val);
196
197 RunLoop().RunUntilIdle();
198 EXPECT_TRUE(val);
199
200 val = false;
201 post_cb.Run();
202 EXPECT_FALSE(val);
203
204 RunLoop().RunUntilIdle();
205 EXPECT_TRUE(val);
206}
207
208TEST_F(BindPostTaskTest, RepeatingCallback) {
209 RepeatingCallback<void(bool*, bool)> cb = BindRepeating(&SetBool);
210 RepeatingCallback<void(bool*, bool)> post_cb =
211 BindPostTask(task_runner_, std::move(cb));
212
213 bool val = false;
214 post_cb.Run(&val, true);
215 EXPECT_FALSE(val);
216
217 RunLoop().RunUntilIdle();
218 EXPECT_TRUE(val);
219
220 post_cb.Run(&val, false);
221 EXPECT_TRUE(val);
222
223 RunLoop().RunUntilIdle();
224 EXPECT_FALSE(val);
225}
226
227TEST_F(BindPostTaskTest, RepeatingWithUnboundMoveOnlyArg) {
228 int val = 0;
229 RepeatingCallback<void(std::unique_ptr<int>)> cb =
230 BindRepeating(&SetIntFromUniquePtr, &val);
231 RepeatingCallback<void(std::unique_ptr<int>)> post_cb =
232 BindPostTask(task_runner_, std::move(cb));
233
234 post_cb.Run(std::make_unique<int>(10));
235 EXPECT_EQ(val, 0);
236
237 RunLoop().RunUntilIdle();
238 EXPECT_EQ(val, 10);
239
240 post_cb.Run(std::make_unique<int>(20));
241 EXPECT_EQ(val, 10);
242
243 RunLoop().RunUntilIdle();
244 EXPECT_EQ(val, 20);
245}
246
247TEST_F(BindPostTaskTest, RepeatingWithIgnoreResult) {
248 RepeatingCallback<void(int)> post_cb =
249 BindPostTask(task_runner_, BindRepeating(IgnoreResult(&Multiply)));
250 std::move(post_cb).Run(1);
251 RunLoop().RunUntilIdle();
252}
253
254TEST_F(BindPostTaskTest, RepeatingThen) {
255 int value = 0;
256
257 // Multiply() returns an int and SetInt() takes an int as a parameter.
258 RepeatingCallback<void(int)> then_cb = BindRepeating(&Multiply).Then(
259 BindPostTask(task_runner_, BindRepeating(&SetInt, &value)));
260
261 then_cb.Run(5);
262 EXPECT_EQ(value, 0);
263 RunLoop().RunUntilIdle();
264 EXPECT_EQ(value, 25);
265
266 then_cb.Run(10);
267 EXPECT_EQ(value, 25);
268 RunLoop().RunUntilIdle();
269 EXPECT_EQ(value, 50);
270}
271
272// Ensure that the input callback is run/destroyed on the correct thread even if
273// the callback returned from BindPostTask() is run on a different thread.
274TEST_F(BindPostTaskTest, RepeatingRunDestroyedOnBound) {
275 Thread target_thread("testing");
276 ASSERT_TRUE(target_thread.Start());
277
278 // SequenceRestrictionChecker checks it's creation, Run() and deletion all
279 // happen on the main thread.
280 bool destroyed = false;
281 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
282
283 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is run
284 // on a different thread which triggers a PostTask() back to the test main
285 // thread to invoke `cb` which runs SequenceRestrictionChecker::Run(). After
286 // `cb` has been invoked `checker` is destroyed along with the BindState.
287 RepeatingClosure cb =
288 BindRepeating(&SequenceRestrictionChecker::Run, std::move(checker));
289 RepeatingClosure post_cb = BindPostTask(task_runner_, std::move(cb));
290 target_thread.task_runner()->PostTask(FROM_HERE, std::move(post_cb));
291
292 target_thread.FlushForTesting();
293 EXPECT_FALSE(destroyed);
294 RunLoop().RunUntilIdle();
295 EXPECT_TRUE(destroyed);
296}
297
298// Ensure that the input callback is destroyed on the correct thread even if the
299// callback returned from BindPostTask() is destroyed without being run on a
300// different thread.
301TEST_F(BindPostTaskTest, RepeatingNotRunDestroyedOnBound) {
302 Thread target_thread("testing");
303 ASSERT_TRUE(target_thread.Start());
304
305 // SequenceRestrictionChecker checks it's creation and deletion all happen on
306 // the test main thread.
307 bool destroyed = false;
308 auto checker = std::make_unique<SequenceRestrictionChecker>(destroyed);
309
310 // `checker` is owned by `cb` which is wrapped in `post_cb`. `post_cb` is
311 // deleted on a different thread which triggers a PostTask() back to the test
312 // main thread to destroy `cb` and `checker`.
313 RepeatingClosure cb =
314 BindRepeating(&SequenceRestrictionChecker::Run, std::move(checker));
315 RepeatingClosure post_cb = BindPostTask(task_runner_, std::move(cb));
316 target_thread.task_runner()->PostTask(
317 FROM_HERE, BindRepeating(&ClearReference, std::move(post_cb)));
318
319 target_thread.FlushForTesting();
320 EXPECT_FALSE(destroyed);
321 RunLoop().RunUntilIdle();
322 EXPECT_TRUE(destroyed);
323}
324
kylechardde7d232020-11-16 17:35:09325} // namespace base