1 // Copyright 2018 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/threading/sequence_bound.h"
6
7 #include "base/macros.h"
8 #include "base/run_loop.h"
9 #include "base/test/bind_test_util.h"
10 #include "base/test/task_environment.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "build/build_config.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16
17 class SequenceBoundTest : public ::testing::Test {
18 public:
19 // Helpful values that our test classes use.
20 enum Value {
21 kInitialValue = 0,
22 kDifferentValue = 1,
23
24 // Values used by the Derived class.
25 kDerivedCtorValue = 111,
26 kDerivedDtorValue = 222,
27
28 // Values used by the Other class.
29 kOtherCtorValue = 333,
30 kOtherDtorValue = 444,
31 };
32
SetUp()33 void SetUp() override { task_runner_ = base::ThreadTaskRunnerHandle::Get(); }
34
TearDown()35 void TearDown() override { task_environment_.RunUntilIdle(); }
36
37 // Do-nothing base class, just so we can test assignment of derived classes.
38 // It introduces a virtual destructor, so that casting derived classes to
39 // Base should still use the appropriate (virtual) destructor.
40 class Base {
41 public:
~Base()42 virtual ~Base() {}
43 };
44
45 // Handy class to set an int ptr to different values, to verify that things
46 // are being run properly.
47 class Derived : public Base {
48 public:
Derived(Value * ptr)49 Derived(Value* ptr) : ptr_(ptr) { *ptr_ = kDerivedCtorValue; }
~Derived()50 ~Derived() override { *ptr_ = kDerivedDtorValue; }
SetValue(Value value)51 void SetValue(Value value) { *ptr_ = value; }
52 Value* ptr_;
53 };
54
55 // Another base class, which sets ints to different values.
56 class Other {
57 public:
Other(Value * ptr)58 Other(Value* ptr) : ptr_(ptr) { *ptr = kOtherCtorValue; }
~Other()59 virtual ~Other() { *ptr_ = kOtherDtorValue; }
SetValue(Value value)60 void SetValue(Value value) { *ptr_ = value; }
61 Value* ptr_;
62 };
63
64 class MultiplyDerived : public Other, public Derived {
65 public:
MultiplyDerived(Value * ptr1,Value * ptr2)66 MultiplyDerived(Value* ptr1, Value* ptr2) : Other(ptr1), Derived(ptr2) {}
67 };
68
69 struct VirtuallyDerived : public virtual Base {};
70
71 base::test::TaskEnvironment task_environment_;
72 scoped_refptr<base::SequencedTaskRunner> task_runner_;
73 Value value_ = kInitialValue;
74 };
75
76 class BoxedValue {
77 public:
BoxedValue(int initial_value)78 explicit BoxedValue(int initial_value) : value_(initial_value) {}
79
~BoxedValue()80 ~BoxedValue() {
81 if (destruction_callback_)
82 std::move(destruction_callback_).Run();
83 }
84
set_destruction_callback(base::OnceClosure callback)85 void set_destruction_callback(base::OnceClosure callback) {
86 destruction_callback_ = std::move(callback);
87 }
88
value() const89 int value() const { return value_; }
set_value(int value)90 void set_value(int value) { value_ = value; }
91
92 private:
93 int value_ = 0;
94 base::OnceClosure destruction_callback_;
95
96 DISALLOW_COPY_AND_ASSIGN(BoxedValue);
97 };
98
99 #if defined(OS_IOS) && !TARGET_OS_SIMULATOR
100 #define MAYBE_ConstructThenPostThenReset FLAKY_ConstructThenPostThenReset
101 #else
102 #define MAYBE_ConstructThenPostThenReset ConstructThenPostThenReset
103 #endif
104 // https://crbug.com/899779 tracks test flakiness on iOS.
TEST_F(SequenceBoundTest,MAYBE_ConstructThenPostThenReset)105 TEST_F(SequenceBoundTest, MAYBE_ConstructThenPostThenReset) {
106 auto derived = SequenceBound<Derived>(task_runner_, &value_);
107 EXPECT_FALSE(derived.is_null());
108 EXPECT_TRUE(derived);
109
110 // Nothing should happen until we run the message loop.
111 EXPECT_EQ(value_, kInitialValue);
112 base::RunLoop().RunUntilIdle();
113 EXPECT_EQ(value_, kDerivedCtorValue);
114
115 // Post now that the object has been constructed.
116 derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue);
117 EXPECT_EQ(value_, kDerivedCtorValue);
118 base::RunLoop().RunUntilIdle();
119 EXPECT_EQ(value_, kDifferentValue);
120
121 // Reset it, and make sure that destruction is posted. The owner should
122 // report that it is null immediately.
123 derived.Reset();
124 EXPECT_TRUE(derived.is_null());
125 EXPECT_FALSE(derived);
126 EXPECT_EQ(value_, kDifferentValue);
127 base::RunLoop().RunUntilIdle();
128 EXPECT_EQ(value_, kDerivedDtorValue);
129 }
130
TEST_F(SequenceBoundTest,PostBeforeConstruction)131 TEST_F(SequenceBoundTest, PostBeforeConstruction) {
132 // Construct an object and post a message to it, before construction has been
133 // run on |task_runner_|.
134 auto derived = SequenceBound<Derived>(task_runner_, &value_);
135 derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue);
136 EXPECT_EQ(value_, kInitialValue);
137 // Both construction and SetValue should run.
138 base::RunLoop().RunUntilIdle();
139 EXPECT_EQ(value_, kDifferentValue);
140 }
141
TEST_F(SequenceBoundTest,MoveConstructionFromSameClass)142 TEST_F(SequenceBoundTest, MoveConstructionFromSameClass) {
143 // Verify that we can move-construct with the same class.
144 auto derived_old = SequenceBound<Derived>(task_runner_, &value_);
145 auto derived_new = std::move(derived_old);
146 EXPECT_TRUE(derived_old.is_null());
147 EXPECT_FALSE(derived_new.is_null());
148 base::RunLoop().RunUntilIdle();
149 EXPECT_EQ(value_, kDerivedCtorValue);
150
151 // Verify that |derived_new| owns the object now, and that the virtual
152 // destructor is called.
153 derived_new.Reset();
154 EXPECT_EQ(value_, kDerivedCtorValue);
155 base::RunLoop().RunUntilIdle();
156 EXPECT_EQ(value_, kDerivedDtorValue);
157 }
158
TEST_F(SequenceBoundTest,MoveConstructionFromDerivedClass)159 TEST_F(SequenceBoundTest, MoveConstructionFromDerivedClass) {
160 // Verify that we can move-construct to a base class from a derived class.
161 auto derived = SequenceBound<Derived>(task_runner_, &value_);
162 SequenceBound<Base> base(std::move(derived));
163 EXPECT_TRUE(derived.is_null());
164 EXPECT_FALSE(base.is_null());
165 base::RunLoop().RunUntilIdle();
166 EXPECT_EQ(value_, kDerivedCtorValue);
167
168 // Verify that |base| owns the object now, and that destruction still destroys
169 // Derived properly.
170 base.Reset();
171 EXPECT_EQ(value_, kDerivedCtorValue);
172 base::RunLoop().RunUntilIdle();
173 EXPECT_EQ(value_, kDerivedDtorValue);
174 }
175
TEST_F(SequenceBoundTest,MultiplyDerivedDestructionWorksLeftSuper)176 TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksLeftSuper) {
177 // Verify that everything works when we're casting around in ways that might
178 // change the address. We cast to the left side of MultiplyDerived and then
179 // reset the owner. ASAN will catch free() errors.
180 Value value2 = kInitialValue;
181 auto mderived =
182 SequenceBound<MultiplyDerived>(task_runner_, &value_, &value2);
183 base::RunLoop().RunUntilIdle();
184 EXPECT_EQ(value_, kOtherCtorValue);
185 EXPECT_EQ(value2, kDerivedCtorValue);
186 SequenceBound<Other> other = std::move(mderived);
187
188 other.Reset();
189 base::RunLoop().RunUntilIdle();
190
191 // Both destructors should have run.
192 EXPECT_EQ(value_, kOtherDtorValue);
193 EXPECT_EQ(value2, kDerivedDtorValue);
194 }
195
TEST_F(SequenceBoundTest,MultiplyDerivedDestructionWorksRightSuper)196 TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksRightSuper) {
197 // Verify that everything works when we're casting around in ways that might
198 // change the address. We cast to the right side of MultiplyDerived and then
199 // reset the owner. ASAN will catch free() errors.
200 Value value2 = kInitialValue;
201 auto mderived =
202 SequenceBound<MultiplyDerived>(task_runner_, &value_, &value2);
203 base::RunLoop().RunUntilIdle();
204 EXPECT_EQ(value_, kOtherCtorValue);
205 EXPECT_EQ(value2, kDerivedCtorValue);
206 SequenceBound<Base> base = std::move(mderived);
207
208 base.Reset();
209 base::RunLoop().RunUntilIdle();
210
211 // Both destructors should have run.
212 EXPECT_EQ(value_, kOtherDtorValue);
213 EXPECT_EQ(value2, kDerivedDtorValue);
214 }
215
TEST_F(SequenceBoundTest,MoveAssignmentFromSameClass)216 TEST_F(SequenceBoundTest, MoveAssignmentFromSameClass) {
217 // Test move-assignment using the same classes.
218 auto derived_old = SequenceBound<Derived>(task_runner_, &value_);
219 SequenceBound<Derived> derived_new;
220
221 derived_new = std::move(derived_old);
222 EXPECT_TRUE(derived_old.is_null());
223 EXPECT_FALSE(derived_new.is_null());
224 base::RunLoop().RunUntilIdle();
225 EXPECT_EQ(value_, kDerivedCtorValue);
226
227 // Verify that |derived_new| owns the object now. Also verifies that move
228 // assignment from the same class deletes the outgoing object.
229 derived_new = SequenceBound<Derived>();
230 EXPECT_EQ(value_, kDerivedCtorValue);
231 base::RunLoop().RunUntilIdle();
232 EXPECT_EQ(value_, kDerivedDtorValue);
233 }
234
TEST_F(SequenceBoundTest,MoveAssignmentFromDerivedClass)235 TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClass) {
236 // Move-assignment from a derived class to a base class.
237 auto derived = SequenceBound<Derived>(task_runner_, &value_);
238 SequenceBound<Base> base;
239
240 base = std::move(derived);
241 EXPECT_TRUE(derived.is_null());
242 EXPECT_FALSE(base.is_null());
243 base::RunLoop().RunUntilIdle();
244 EXPECT_EQ(value_, kDerivedCtorValue);
245
246 // Verify that |base| owns the object now, and that destruction still destroys
247 // Derived properly.
248 base.Reset();
249 EXPECT_EQ(value_, kDerivedCtorValue);
250 base::RunLoop().RunUntilIdle();
251 EXPECT_EQ(value_, kDerivedDtorValue);
252 }
253
TEST_F(SequenceBoundTest,MoveAssignmentFromDerivedClassDestroysOldObject)254 TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClassDestroysOldObject) {
255 // Verify that move-assignment from a derived class runs the dtor of the
256 // outgoing object.
257 auto derived = SequenceBound<Derived>(task_runner_, &value_);
258
259 Value value1 = kInitialValue;
260 Value value2 = kInitialValue;
261 auto mderived =
262 SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
263 base::RunLoop().RunUntilIdle();
264
265 EXPECT_EQ(value_, kDerivedCtorValue);
266
267 // Assign |mderived|, and verify that the original object in |derived| is
268 // destroyed properly.
269 derived = std::move(mderived);
270 base::RunLoop().RunUntilIdle();
271 EXPECT_EQ(value_, kDerivedDtorValue);
272
273 // Delete |derived|, since it has pointers to local vars.
274 derived.Reset();
275 base::RunLoop().RunUntilIdle();
276 }
277
TEST_F(SequenceBoundTest,MultiplyDerivedPostToLeftBaseClass)278 TEST_F(SequenceBoundTest, MultiplyDerivedPostToLeftBaseClass) {
279 // Cast and call methods on the left base class.
280 Value value1 = kInitialValue;
281 Value value2 = kInitialValue;
282 auto mderived =
283 SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
284
285 // Cast to Other, the left base.
286 SequenceBound<Other> other(std::move(mderived));
287 other.Post(FROM_HERE, &Other::SetValue, kDifferentValue);
288
289 base::RunLoop().RunUntilIdle();
290
291 EXPECT_EQ(value1, kDifferentValue);
292 EXPECT_EQ(value2, kDerivedCtorValue);
293
294 other.Reset();
295 base::RunLoop().RunUntilIdle();
296 }
297
TEST_F(SequenceBoundTest,MultiplyDerivedPostToRightBaseClass)298 TEST_F(SequenceBoundTest, MultiplyDerivedPostToRightBaseClass) {
299 // Cast and call methods on the right base class.
300 Value value1 = kInitialValue;
301 Value value2 = kInitialValue;
302 auto mderived =
303 SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
304
305 SequenceBound<Derived> derived(std::move(mderived));
306 derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue);
307
308 base::RunLoop().RunUntilIdle();
309
310 EXPECT_EQ(value1, kOtherCtorValue);
311 EXPECT_EQ(value2, kDifferentValue);
312
313 derived.Reset();
314 base::RunLoop().RunUntilIdle();
315 }
316
TEST_F(SequenceBoundTest,MoveConstructionFromNullWorks)317 TEST_F(SequenceBoundTest, MoveConstructionFromNullWorks) {
318 // Verify that this doesn't crash.
319 SequenceBound<Derived> derived1;
320 SequenceBound<Derived> derived2(std::move(derived1));
321 }
322
TEST_F(SequenceBoundTest,MoveAssignmentFromNullWorks)323 TEST_F(SequenceBoundTest, MoveAssignmentFromNullWorks) {
324 // Verify that this doesn't crash.
325 SequenceBound<Derived> derived1;
326 SequenceBound<Derived> derived2;
327 derived2 = std::move(derived1);
328 }
329
TEST_F(SequenceBoundTest,ResetOnNullObjectWorks)330 TEST_F(SequenceBoundTest, ResetOnNullObjectWorks) {
331 // Verify that this doesn't crash.
332 SequenceBound<Derived> derived;
333 derived.Reset();
334 }
335
TEST_F(SequenceBoundTest,IsVirtualBaseClassOf)336 TEST_F(SequenceBoundTest, IsVirtualBaseClassOf) {
337 // Check that is_virtual_base_of<> works properly.
338
339 // Neither |Base| nor |Derived| is a virtual base of the other.
340 static_assert(!internal::is_virtual_base_of<Base, Derived>::value,
341 "|Base| shouldn't be a virtual base of |Derived|");
342 static_assert(!internal::is_virtual_base_of<Derived, Base>::value,
343 "|Derived| shouldn't be a virtual base of |Base|");
344
345 // |Base| should be a virtual base class of |VirtuallyDerived|, but not the
346 // other way.
347 static_assert(internal::is_virtual_base_of<Base, VirtuallyDerived>::value,
348 "|Base| should be a virtual base of |VirtuallyDerived|");
349 static_assert(!internal::is_virtual_base_of<VirtuallyDerived, Base>::value,
350 "|VirtuallyDerived shouldn't be a virtual base of |Base|");
351 }
352
TEST_F(SequenceBoundTest,LvalueConstructionParameter)353 TEST_F(SequenceBoundTest, LvalueConstructionParameter) {
354 // Note here that |value_ptr| is an lvalue, while |&value| would be an rvalue.
355 Value value = kInitialValue;
356 Value* value_ptr = &value;
357 SequenceBound<Derived> derived(task_runner_, value_ptr);
358 {
359 derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue);
360 base::RunLoop run_loop;
361 task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
362 run_loop.Run();
363 EXPECT_EQ(value, kDifferentValue);
364 }
365 {
366 derived.Reset();
367 base::RunLoop run_loop;
368 task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
369 run_loop.Run();
370 EXPECT_EQ(value, kDerivedDtorValue);
371 }
372 }
373
TEST_F(SequenceBoundTest,PostTaskWithThisObject)374 TEST_F(SequenceBoundTest, PostTaskWithThisObject) {
375 constexpr int kTestValue1 = 42;
376 constexpr int kTestValue2 = 42;
377 base::SequenceBound<BoxedValue> value(task_runner_, kTestValue1);
378 base::RunLoop loop;
379 value.PostTaskWithThisObject(
380 FROM_HERE, base::BindLambdaForTesting([&](const BoxedValue& v) {
381 EXPECT_EQ(kTestValue1, v.value());
382 }));
383 value.PostTaskWithThisObject(
384 FROM_HERE, base::BindLambdaForTesting(
385 [&](BoxedValue* v) { v->set_value(kTestValue2); }));
386 value.PostTaskWithThisObject(
387 FROM_HERE, base::BindLambdaForTesting([&](const BoxedValue& v) {
388 EXPECT_EQ(kTestValue2, v.value());
389 loop.Quit();
390 }));
391 loop.Run();
392 }
393
TEST_F(SequenceBoundTest,ResetWithCallbackAfterDestruction)394 TEST_F(SequenceBoundTest, ResetWithCallbackAfterDestruction) {
395 base::SequenceBound<BoxedValue> value(task_runner_, 0);
396
397 // Verify that the callback passed to ResetWithCallbackAfterDestruction always
398 // does happen *after* destruction.
399 bool destroyed = false;
400 value.Post(FROM_HERE, &BoxedValue::set_destruction_callback,
401 base::BindLambdaForTesting([&] { destroyed = true; }));
402
403 base::RunLoop loop;
404 value.ResetWithCallbackAfterDestruction(base::BindLambdaForTesting([&] {
405 EXPECT_TRUE(destroyed);
406 loop.Quit();
407 }));
408 loop.Run();
409 }
410
411 } // namespace base
412