sequence_bound_unittest.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  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. #include "base/threading/sequence_bound.h"
  5. #include <functional>
  6. #include <utility>
  7. #include "base/memory/raw_ptr.h"
  8. #include "base/run_loop.h"
  9. #include "base/test/bind.h"
  10. #include "base/test/task_environment.h"
  11. #include "base/threading/sequenced_task_runner_handle.h"
  12. #include "build/build_config.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace base {
  15. class SequenceBoundTest : public ::testing::Test {
  16. public:
  17. // Helpful values that our test classes use.
  18. enum Value {
  19. kInitialValue = 0,
  20. kDifferentValue = 1,
  21. // Values used by the Derived class.
  22. kDerivedCtorValue = 111,
  23. kDerivedDtorValue = 222,
  24. // Values used by the Other class.
  25. kOtherCtorValue = 333,
  26. kOtherDtorValue = 444,
  27. };
  28. void TearDown() override {
  29. // Make sure that any objects owned by `SequenceBound` have been destroyed
  30. // to avoid tripping leak detection.
  31. RunLoop run_loop;
  32. task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
  33. run_loop.Run();
  34. }
  35. // Do-nothing base class, just so we can test assignment of derived classes.
  36. // It introduces a virtual destructor, so that casting derived classes to
  37. // Base should still use the appropriate (virtual) destructor.
  38. class Base {
  39. public:
  40. virtual ~Base() {}
  41. };
  42. // Handy class to set an int ptr to different values, to verify that things
  43. // are being run properly.
  44. class Derived : public Base {
  45. public:
  46. Derived(Value* ptr) : ptr_(ptr) { *ptr_ = kDerivedCtorValue; }
  47. ~Derived() override { *ptr_ = kDerivedDtorValue; }
  48. void SetValue(Value value) { *ptr_ = value; }
  49. raw_ptr<Value> ptr_;
  50. };
  51. // Another base class, which sets ints to different values.
  52. class Other {
  53. public:
  54. Other(Value* ptr) : ptr_(ptr) { *ptr = kOtherCtorValue; }
  55. virtual ~Other() { *ptr_ = kOtherDtorValue; }
  56. void SetValue(Value value) { *ptr_ = value; }
  57. raw_ptr<Value> ptr_;
  58. };
  59. class MultiplyDerived : public Other, public Derived {
  60. public:
  61. MultiplyDerived(Value* ptr1, Value* ptr2) : Other(ptr1), Derived(ptr2) {}
  62. };
  63. // TODO(dcheng): This isn't used, but upcasting to a virtual base class is
  64. // unsafe and is currently unchecked! Add these safety checks back in.
  65. struct VirtuallyDerived : public virtual Base {};
  66. base::test::TaskEnvironment task_environment_;
  67. scoped_refptr<base::SequencedTaskRunner> task_runner_ =
  68. base::SequencedTaskRunnerHandle::Get();
  69. Value value_ = kInitialValue;
  70. };
  71. class BoxedValue {
  72. public:
  73. explicit BoxedValue(int initial_value) : value_(initial_value) {}
  74. BoxedValue(const BoxedValue&) = delete;
  75. BoxedValue& operator=(const BoxedValue&) = delete;
  76. ~BoxedValue() {
  77. if (destruction_callback_)
  78. std::move(destruction_callback_).Run();
  79. }
  80. void set_destruction_callback(base::OnceClosure callback) {
  81. destruction_callback_ = std::move(callback);
  82. }
  83. int value() const { return value_; }
  84. void set_value(int value) { value_ = value; }
  85. private:
  86. int value_ = 0;
  87. base::OnceClosure destruction_callback_;
  88. };
  89. #if BUILDFLAG(IS_IOS) && !TARGET_OS_SIMULATOR
  90. #define MAYBE_ConstructAsyncCallReset FLAKY_ConstructAsyncCallReset
  91. #else
  92. #define MAYBE_ConstructAsyncCallReset ConstructAsyncCallReset
  93. #endif
  94. // https://crbug.com/899779 tracks test flakiness on iOS.
  95. TEST_F(SequenceBoundTest, MAYBE_ConstructAsyncCallReset) {
  96. auto derived = SequenceBound<Derived>(task_runner_, &value_);
  97. EXPECT_FALSE(derived.is_null());
  98. EXPECT_TRUE(derived);
  99. // Nothing should happen until we run the message loop.
  100. EXPECT_EQ(value_, kInitialValue);
  101. base::RunLoop().RunUntilIdle();
  102. EXPECT_EQ(value_, kDerivedCtorValue);
  103. // Post now that the object has been constructed.
  104. derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
  105. EXPECT_EQ(value_, kDerivedCtorValue);
  106. base::RunLoop().RunUntilIdle();
  107. EXPECT_EQ(value_, kDifferentValue);
  108. // Reset it, and make sure that destruction is posted. The owner should
  109. // report that it is null immediately.
  110. derived.Reset();
  111. EXPECT_TRUE(derived.is_null());
  112. EXPECT_FALSE(derived);
  113. EXPECT_EQ(value_, kDifferentValue);
  114. base::RunLoop().RunUntilIdle();
  115. EXPECT_EQ(value_, kDerivedDtorValue);
  116. }
  117. TEST_F(SequenceBoundTest, PostBeforeConstruction) {
  118. // Construct an object and post a message to it, before construction has been
  119. // run on |task_runner_|.
  120. auto derived = SequenceBound<Derived>(task_runner_, &value_);
  121. derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
  122. EXPECT_EQ(value_, kInitialValue);
  123. // Both construction and SetValue should run.
  124. base::RunLoop().RunUntilIdle();
  125. EXPECT_EQ(value_, kDifferentValue);
  126. }
  127. TEST_F(SequenceBoundTest, MoveConstructionFromSameClass) {
  128. // Verify that we can move-construct with the same class.
  129. auto derived_old = SequenceBound<Derived>(task_runner_, &value_);
  130. auto derived_new = std::move(derived_old);
  131. EXPECT_TRUE(derived_old.is_null());
  132. EXPECT_FALSE(derived_new.is_null());
  133. base::RunLoop().RunUntilIdle();
  134. EXPECT_EQ(value_, kDerivedCtorValue);
  135. // Verify that |derived_new| owns the object now, and that the virtual
  136. // destructor is called.
  137. derived_new.Reset();
  138. EXPECT_EQ(value_, kDerivedCtorValue);
  139. base::RunLoop().RunUntilIdle();
  140. EXPECT_EQ(value_, kDerivedDtorValue);
  141. }
  142. TEST_F(SequenceBoundTest, MoveConstructionFromDerivedClass) {
  143. // Verify that we can move-construct to a base class from a derived class.
  144. auto derived = SequenceBound<Derived>(task_runner_, &value_);
  145. SequenceBound<Base> base(std::move(derived));
  146. EXPECT_TRUE(derived.is_null());
  147. EXPECT_FALSE(base.is_null());
  148. base::RunLoop().RunUntilIdle();
  149. EXPECT_EQ(value_, kDerivedCtorValue);
  150. // Verify that |base| owns the object now, and that destruction still destroys
  151. // Derived properly.
  152. base.Reset();
  153. EXPECT_EQ(value_, kDerivedCtorValue);
  154. base::RunLoop().RunUntilIdle();
  155. EXPECT_EQ(value_, kDerivedDtorValue);
  156. }
  157. TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksLeftSuper) {
  158. // Verify that everything works when we're casting around in ways that might
  159. // change the address. We cast to the left side of MultiplyDerived and then
  160. // reset the owner. ASAN will catch free() errors.
  161. Value value2 = kInitialValue;
  162. auto mderived =
  163. SequenceBound<MultiplyDerived>(task_runner_, &value_, &value2);
  164. base::RunLoop().RunUntilIdle();
  165. EXPECT_EQ(value_, kOtherCtorValue);
  166. EXPECT_EQ(value2, kDerivedCtorValue);
  167. SequenceBound<Other> other = std::move(mderived);
  168. other.Reset();
  169. base::RunLoop().RunUntilIdle();
  170. // Both destructors should have run.
  171. EXPECT_EQ(value_, kOtherDtorValue);
  172. EXPECT_EQ(value2, kDerivedDtorValue);
  173. }
  174. TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksRightSuper) {
  175. // Verify that everything works when we're casting around in ways that might
  176. // change the address. We cast to the right side of MultiplyDerived and then
  177. // reset the owner. ASAN will catch free() errors.
  178. Value value2 = kInitialValue;
  179. auto mderived =
  180. SequenceBound<MultiplyDerived>(task_runner_, &value_, &value2);
  181. base::RunLoop().RunUntilIdle();
  182. EXPECT_EQ(value_, kOtherCtorValue);
  183. EXPECT_EQ(value2, kDerivedCtorValue);
  184. SequenceBound<Base> base = std::move(mderived);
  185. base.Reset();
  186. base::RunLoop().RunUntilIdle();
  187. // Both destructors should have run.
  188. EXPECT_EQ(value_, kOtherDtorValue);
  189. EXPECT_EQ(value2, kDerivedDtorValue);
  190. }
  191. TEST_F(SequenceBoundTest, MoveAssignmentFromSameClass) {
  192. // Test move-assignment using the same classes.
  193. auto derived_old = SequenceBound<Derived>(task_runner_, &value_);
  194. SequenceBound<Derived> derived_new;
  195. derived_new = std::move(derived_old);
  196. EXPECT_TRUE(derived_old.is_null());
  197. EXPECT_FALSE(derived_new.is_null());
  198. base::RunLoop().RunUntilIdle();
  199. EXPECT_EQ(value_, kDerivedCtorValue);
  200. // Verify that |derived_new| owns the object now. Also verifies that move
  201. // assignment from the same class deletes the outgoing object.
  202. derived_new = SequenceBound<Derived>();
  203. EXPECT_EQ(value_, kDerivedCtorValue);
  204. base::RunLoop().RunUntilIdle();
  205. EXPECT_EQ(value_, kDerivedDtorValue);
  206. }
  207. TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClass) {
  208. // Move-assignment from a derived class to a base class.
  209. auto derived = SequenceBound<Derived>(task_runner_, &value_);
  210. SequenceBound<Base> base;
  211. base = std::move(derived);
  212. EXPECT_TRUE(derived.is_null());
  213. EXPECT_FALSE(base.is_null());
  214. base::RunLoop().RunUntilIdle();
  215. EXPECT_EQ(value_, kDerivedCtorValue);
  216. // Verify that |base| owns the object now, and that destruction still destroys
  217. // Derived properly.
  218. base.Reset();
  219. EXPECT_EQ(value_, kDerivedCtorValue);
  220. base::RunLoop().RunUntilIdle();
  221. EXPECT_EQ(value_, kDerivedDtorValue);
  222. }
  223. TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClassDestroysOldObject) {
  224. // Verify that move-assignment from a derived class runs the dtor of the
  225. // outgoing object.
  226. auto derived = SequenceBound<Derived>(task_runner_, &value_);
  227. Value value1 = kInitialValue;
  228. Value value2 = kInitialValue;
  229. auto mderived =
  230. SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
  231. base::RunLoop().RunUntilIdle();
  232. EXPECT_EQ(value_, kDerivedCtorValue);
  233. // Assign |mderived|, and verify that the original object in |derived| is
  234. // destroyed properly.
  235. derived = std::move(mderived);
  236. base::RunLoop().RunUntilIdle();
  237. EXPECT_EQ(value_, kDerivedDtorValue);
  238. // Delete |derived|, since it has pointers to local vars.
  239. derived.Reset();
  240. base::RunLoop().RunUntilIdle();
  241. }
  242. TEST_F(SequenceBoundTest, MultiplyDerivedPostToLeftBaseClass) {
  243. // Cast and call methods on the left base class.
  244. Value value1 = kInitialValue;
  245. Value value2 = kInitialValue;
  246. auto mderived =
  247. SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
  248. // Cast to Other, the left base.
  249. SequenceBound<Other> other(std::move(mderived));
  250. other.AsyncCall(&Other::SetValue).WithArgs(kDifferentValue);
  251. base::RunLoop().RunUntilIdle();
  252. EXPECT_EQ(value1, kDifferentValue);
  253. EXPECT_EQ(value2, kDerivedCtorValue);
  254. other.Reset();
  255. base::RunLoop().RunUntilIdle();
  256. }
  257. TEST_F(SequenceBoundTest, MultiplyDerivedPostToRightBaseClass) {
  258. // Cast and call methods on the right base class.
  259. Value value1 = kInitialValue;
  260. Value value2 = kInitialValue;
  261. auto mderived =
  262. SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
  263. SequenceBound<Derived> derived(std::move(mderived));
  264. derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
  265. base::RunLoop().RunUntilIdle();
  266. EXPECT_EQ(value1, kOtherCtorValue);
  267. EXPECT_EQ(value2, kDifferentValue);
  268. derived.Reset();
  269. base::RunLoop().RunUntilIdle();
  270. }
  271. TEST_F(SequenceBoundTest, MoveConstructionFromNullWorks) {
  272. // Verify that this doesn't crash.
  273. SequenceBound<Derived> derived1;
  274. SequenceBound<Derived> derived2(std::move(derived1));
  275. }
  276. TEST_F(SequenceBoundTest, MoveAssignmentFromNullWorks) {
  277. // Verify that this doesn't crash.
  278. SequenceBound<Derived> derived1;
  279. SequenceBound<Derived> derived2;
  280. derived2 = std::move(derived1);
  281. }
  282. TEST_F(SequenceBoundTest, ResetOnNullObjectWorks) {
  283. // Verify that this doesn't crash.
  284. SequenceBound<Derived> derived;
  285. derived.Reset();
  286. }
  287. TEST_F(SequenceBoundTest, LvalueConstructionParameter) {
  288. // Note here that |value_ptr| is an lvalue, while |&value| would be an rvalue.
  289. Value value = kInitialValue;
  290. Value* value_ptr = &value;
  291. SequenceBound<Derived> derived(task_runner_, value_ptr);
  292. {
  293. derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
  294. base::RunLoop run_loop;
  295. task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
  296. run_loop.Run();
  297. EXPECT_EQ(value, kDifferentValue);
  298. }
  299. {
  300. derived.Reset();
  301. base::RunLoop run_loop;
  302. task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
  303. run_loop.Run();
  304. EXPECT_EQ(value, kDerivedDtorValue);
  305. }
  306. }
  307. TEST_F(SequenceBoundTest, PostTaskWithThisObject) {
  308. constexpr int kTestValue1 = 42;
  309. constexpr int kTestValue2 = 42;
  310. base::SequenceBound<BoxedValue> value(task_runner_, kTestValue1);
  311. base::RunLoop loop;
  312. value.PostTaskWithThisObject(base::BindLambdaForTesting(
  313. [&](const BoxedValue& v) { EXPECT_EQ(kTestValue1, v.value()); }));
  314. value.PostTaskWithThisObject(base::BindLambdaForTesting(
  315. [&](BoxedValue* v) { v->set_value(kTestValue2); }));
  316. value.PostTaskWithThisObject(
  317. base::BindLambdaForTesting([&](const BoxedValue& v) {
  318. EXPECT_EQ(kTestValue2, v.value());
  319. loop.Quit();
  320. }));
  321. loop.Run();
  322. }
  323. TEST_F(SequenceBoundTest, SynchronouslyResetForTest) {
  324. base::SequenceBound<BoxedValue> value(task_runner_, 0);
  325. bool destroyed = false;
  326. value.AsyncCall(&BoxedValue::set_destruction_callback)
  327. .WithArgs(base::BindLambdaForTesting([&] { destroyed = true; }));
  328. value.SynchronouslyResetForTest();
  329. EXPECT_TRUE(destroyed);
  330. }
  331. TEST_F(SequenceBoundTest, SmallObject) {
  332. class EmptyClass {};
  333. SequenceBound<EmptyClass> value(task_runner_);
  334. // Test passes if SequenceBound constructor does not crash in AlignedAlloc().
  335. }
  336. TEST_F(SequenceBoundTest, SelfMoveAssign) {
  337. class EmptyClass {};
  338. SequenceBound<EmptyClass> value(task_runner_);
  339. EXPECT_FALSE(value.is_null());
  340. // Clang has a warning for self-move, so be clever.
  341. auto& actually_the_same_value = value;
  342. value = std::move(actually_the_same_value);
  343. // Note: in general, moved-from objects are in a valid but undefined state.
  344. // This is merely a test that self-move doesn't result in something bad
  345. // happening; this is not an assertion that self-move will always have this
  346. // behavior.
  347. EXPECT_TRUE(value.is_null());
  348. }
  349. namespace {
  350. class NoArgsVoidReturn {
  351. public:
  352. void Method() {
  353. if (loop_)
  354. loop_->Quit();
  355. }
  356. void ConstMethod() const {
  357. if (loop_)
  358. loop_->Quit();
  359. }
  360. void set_loop(RunLoop* loop) { loop_ = loop; }
  361. private:
  362. RunLoop* loop_ = nullptr;
  363. };
  364. class NoArgsIntReturn {
  365. public:
  366. int Method() { return 123; }
  367. int ConstMethod() const { return 456; }
  368. };
  369. class IntArgVoidReturn {
  370. public:
  371. IntArgVoidReturn(int* method_called_with, int* const_method_called_with)
  372. : method_called_with_(method_called_with),
  373. const_method_called_with_(const_method_called_with) {}
  374. void Method(int x) {
  375. *method_called_with_ = x;
  376. if (loop_)
  377. loop_->Quit();
  378. }
  379. void ConstMethod(int x) const {
  380. *const_method_called_with_ = x;
  381. if (loop_)
  382. loop_->Quit();
  383. }
  384. void set_loop(RunLoop* loop) { loop_ = loop; }
  385. private:
  386. const raw_ptr<int> method_called_with_;
  387. const raw_ptr<int> const_method_called_with_;
  388. raw_ptr<RunLoop> loop_ = nullptr;
  389. };
  390. class IntArgIntReturn {
  391. public:
  392. int Method(int x) { return -x; }
  393. int ConstMethod(int x) const { return -x; }
  394. };
  395. } // namespace
  396. TEST_F(SequenceBoundTest, AsyncCallNoArgsNoThen) {
  397. SequenceBound<NoArgsVoidReturn> s(task_runner_);
  398. {
  399. RunLoop loop;
  400. s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
  401. s.AsyncCall(&NoArgsVoidReturn::Method);
  402. loop.Run();
  403. }
  404. {
  405. RunLoop loop;
  406. s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
  407. s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
  408. loop.Run();
  409. }
  410. }
  411. TEST_F(SequenceBoundTest, AsyncCallIntArgNoThen) {
  412. int method_called_with = 0;
  413. int const_method_called_with = 0;
  414. SequenceBound<IntArgVoidReturn> s(task_runner_, &method_called_with,
  415. &const_method_called_with);
  416. {
  417. RunLoop loop;
  418. s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
  419. s.AsyncCall(&IntArgVoidReturn::Method).WithArgs(123);
  420. loop.Run();
  421. EXPECT_EQ(123, method_called_with);
  422. }
  423. {
  424. RunLoop loop;
  425. s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
  426. s.AsyncCall(&IntArgVoidReturn::ConstMethod).WithArgs(456);
  427. loop.Run();
  428. EXPECT_EQ(456, const_method_called_with);
  429. }
  430. }
  431. TEST_F(SequenceBoundTest, AsyncCallNoArgsVoidThen) {
  432. SequenceBound<NoArgsVoidReturn> s(task_runner_);
  433. {
  434. RunLoop loop;
  435. s.AsyncCall(&NoArgsVoidReturn::Method).Then(BindLambdaForTesting([&]() {
  436. loop.Quit();
  437. }));
  438. loop.Run();
  439. }
  440. {
  441. RunLoop loop;
  442. s.AsyncCall(&NoArgsVoidReturn::ConstMethod)
  443. .Then(BindLambdaForTesting([&]() { loop.Quit(); }));
  444. loop.Run();
  445. }
  446. }
  447. TEST_F(SequenceBoundTest, AsyncCallNoArgsIntThen) {
  448. SequenceBound<NoArgsIntReturn> s(task_runner_);
  449. {
  450. RunLoop loop;
  451. s.AsyncCall(&NoArgsIntReturn::Method)
  452. .Then(BindLambdaForTesting([&](int result) {
  453. EXPECT_EQ(123, result);
  454. loop.Quit();
  455. }));
  456. loop.Run();
  457. }
  458. {
  459. RunLoop loop;
  460. s.AsyncCall(&NoArgsIntReturn::ConstMethod)
  461. .Then(BindLambdaForTesting([&](int result) {
  462. EXPECT_EQ(456, result);
  463. loop.Quit();
  464. }));
  465. loop.Run();
  466. }
  467. }
  468. TEST_F(SequenceBoundTest, AsyncCallWithArgsVoidThen) {
  469. int method_called_with = 0;
  470. int const_method_called_with = 0;
  471. SequenceBound<IntArgVoidReturn> s(task_runner_, &method_called_with,
  472. &const_method_called_with);
  473. {
  474. RunLoop loop;
  475. s.AsyncCall(&IntArgVoidReturn::Method)
  476. .WithArgs(123)
  477. .Then(BindLambdaForTesting([&] { loop.Quit(); }));
  478. loop.Run();
  479. EXPECT_EQ(123, method_called_with);
  480. }
  481. {
  482. RunLoop loop;
  483. s.AsyncCall(&IntArgVoidReturn::ConstMethod)
  484. .WithArgs(456)
  485. .Then(BindLambdaForTesting([&] { loop.Quit(); }));
  486. loop.Run();
  487. EXPECT_EQ(456, const_method_called_with);
  488. }
  489. }
  490. TEST_F(SequenceBoundTest, AsyncCallWithArgsIntThen) {
  491. SequenceBound<IntArgIntReturn> s(task_runner_);
  492. {
  493. RunLoop loop;
  494. s.AsyncCall(&IntArgIntReturn::Method)
  495. .WithArgs(123)
  496. .Then(BindLambdaForTesting([&](int result) {
  497. EXPECT_EQ(-123, result);
  498. loop.Quit();
  499. }));
  500. loop.Run();
  501. }
  502. {
  503. RunLoop loop;
  504. s.AsyncCall(&IntArgIntReturn::ConstMethod)
  505. .WithArgs(456)
  506. .Then(BindLambdaForTesting([&](int result) {
  507. EXPECT_EQ(-456, result);
  508. loop.Quit();
  509. }));
  510. loop.Run();
  511. }
  512. }
  513. TEST_F(SequenceBoundTest, AsyncCallIsConstQualified) {
  514. // Tests that both const and non-const methods may be called through a
  515. // const-qualified SequenceBound.
  516. const SequenceBound<NoArgsVoidReturn> s(task_runner_);
  517. s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
  518. s.AsyncCall(&NoArgsVoidReturn::Method);
  519. }
  520. class IgnoreResultTestHelperWithNoArgs {
  521. public:
  522. explicit IgnoreResultTestHelperWithNoArgs(RunLoop* loop, bool* called)
  523. : loop_(loop), called_(called) {}
  524. int ConstMethod() const {
  525. if (loop_) {
  526. loop_->Quit();
  527. }
  528. if (called_) {
  529. *called_ = true;
  530. }
  531. return 0;
  532. }
  533. int Method() {
  534. if (loop_) {
  535. loop_->Quit();
  536. }
  537. if (called_) {
  538. *called_ = true;
  539. }
  540. return 0;
  541. }
  542. private:
  543. const raw_ptr<RunLoop> loop_ = nullptr;
  544. const raw_ptr<bool> called_ = nullptr;
  545. };
  546. TEST_F(SequenceBoundTest, AsyncCallIgnoreResultNoArgs) {
  547. {
  548. RunLoop loop;
  549. SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, &loop,
  550. nullptr);
  551. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod));
  552. loop.Run();
  553. }
  554. {
  555. RunLoop loop;
  556. SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, &loop,
  557. nullptr);
  558. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method));
  559. loop.Run();
  560. }
  561. }
  562. TEST_F(SequenceBoundTest, AsyncCallIgnoreResultThen) {
  563. {
  564. RunLoop loop;
  565. bool called = false;
  566. SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, nullptr,
  567. &called);
  568. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod))
  569. .Then(BindLambdaForTesting([&] { loop.Quit(); }));
  570. loop.Run();
  571. EXPECT_TRUE(called);
  572. }
  573. {
  574. RunLoop loop;
  575. bool called = false;
  576. SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, nullptr,
  577. &called);
  578. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method))
  579. .Then(BindLambdaForTesting([&] { loop.Quit(); }));
  580. loop.Run();
  581. EXPECT_TRUE(called);
  582. }
  583. }
  584. class IgnoreResultTestHelperWithArgs {
  585. public:
  586. IgnoreResultTestHelperWithArgs(RunLoop* loop, int& value)
  587. : loop_(loop), value_(value) {}
  588. int ConstMethod(int arg) const {
  589. value_ = arg;
  590. if (loop_) {
  591. loop_->Quit();
  592. }
  593. return arg;
  594. }
  595. int Method(int arg) {
  596. value_ = arg;
  597. if (loop_) {
  598. loop_->Quit();
  599. }
  600. return arg;
  601. }
  602. private:
  603. const raw_ptr<RunLoop> loop_ = nullptr;
  604. int& value_;
  605. };
  606. TEST_F(SequenceBoundTest, AsyncCallIgnoreResultWithArgs) {
  607. {
  608. RunLoop loop;
  609. int result = 0;
  610. SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, &loop,
  611. std::ref(result));
  612. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
  613. .WithArgs(60);
  614. loop.Run();
  615. EXPECT_EQ(60, result);
  616. }
  617. {
  618. RunLoop loop;
  619. int result = 0;
  620. SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, &loop,
  621. std::ref(result));
  622. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
  623. .WithArgs(06);
  624. loop.Run();
  625. EXPECT_EQ(06, result);
  626. }
  627. }
  628. TEST_F(SequenceBoundTest, AsyncCallIgnoreResultWithArgsThen) {
  629. {
  630. RunLoop loop;
  631. int result = 0;
  632. SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, nullptr,
  633. std::ref(result));
  634. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
  635. .WithArgs(60)
  636. .Then(BindLambdaForTesting([&] { loop.Quit(); }));
  637. loop.Run();
  638. EXPECT_EQ(60, result);
  639. }
  640. {
  641. RunLoop loop;
  642. int result = 0;
  643. SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, nullptr,
  644. std::ref(result));
  645. s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
  646. .WithArgs(06)
  647. .Then(BindLambdaForTesting([&] { loop.Quit(); }));
  648. loop.Run();
  649. EXPECT_EQ(06, result);
  650. }
  651. }
  652. // TODO(dcheng): Maybe use the nocompile harness here instead of being
  653. // "clever"...
  654. TEST_F(SequenceBoundTest, NoCompileTests) {
  655. // TODO(dcheng): Test calling WithArgs() on a method that takes no arguments.
  656. // Given:
  657. // class C {
  658. // void F();
  659. // };
  660. //
  661. // Then:
  662. // SequenceBound<C> s(...);
  663. // s.AsyncCall(&C::F).WithArgs(...);
  664. //
  665. // should not compile.
  666. //
  667. // TODO(dcheng): Test calling Then() before calling WithArgs().
  668. // Given:
  669. // class C {
  670. // void F(int);
  671. // };
  672. //
  673. // Then:
  674. // SequenceBound<C> s(...);
  675. // s.AsyncCall(&C::F).Then(...).WithArgs(...);
  676. //
  677. // should not compile.
  678. //
  679. }
  680. class SequenceBoundDeathTest : public ::testing::Test {
  681. protected:
  682. void TearDown() override {
  683. // Make sure that any objects owned by `SequenceBound` have been destroyed
  684. // to avoid tripping leak detection.
  685. RunLoop run_loop;
  686. task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
  687. run_loop.Run();
  688. }
  689. // Death tests use fork(), which can interact (very) poorly with threads.
  690. test::SingleThreadTaskEnvironment task_environment_;
  691. scoped_refptr<SequencedTaskRunner> task_runner_ =
  692. base::SequencedTaskRunnerHandle::Get();
  693. };
  694. TEST_F(SequenceBoundDeathTest, AsyncCallIntArgNoWithArgsShouldCheck) {
  695. SequenceBound<IntArgIntReturn> s(task_runner_);
  696. EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method), "");
  697. }
  698. TEST_F(SequenceBoundDeathTest, AsyncCallIntReturnNoThenShouldCheck) {
  699. {
  700. SequenceBound<NoArgsIntReturn> s(task_runner_);
  701. EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&NoArgsIntReturn::Method), "");
  702. }
  703. {
  704. SequenceBound<IntArgIntReturn> s(task_runner_);
  705. EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method).WithArgs(0),
  706. "");
  707. }
  708. }
  709. } // namespace base