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