1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/one_shot_event.h"
7 #include "base/functional/bind.h"
8 #include "base/memory/raw_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/task/single_thread_task_runner.h"
11 #include "base/test/task_environment.h"
12 #include "base/test/test_simple_task_runner.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 void Increment(int* i) {
21 // |*did_delete_instance| will be set to true upon its destruction.
22 class RefCountedClass : public base::RefCounted<RefCountedClass> {
24 explicit RefCountedClass(bool* did_delete_instance)
25 : did_delete_instance_(did_delete_instance) {
26 DCHECK(!*did_delete_instance_);
28 RefCountedClass(const RefCountedClass&) = delete;
29 RefCountedClass& operator=(const RefCountedClass&) = delete;
31 void PerformTask() { did_perform_task_ = true; }
32 bool did_perform_task() const { return did_perform_task_; }
35 friend class base::RefCounted<RefCountedClass>;
37 ~RefCountedClass() { *did_delete_instance_ = true; }
39 const raw_ptr<bool> did_delete_instance_; // Not owned.
41 bool did_perform_task_ = false;
44 TEST(OneShotEventTest, RecordsSignal) {
46 EXPECT_FALSE(event.is_signaled());
48 EXPECT_TRUE(event.is_signaled());
51 TEST(OneShotEventTest, CallsQueueAsDistinctTask) {
53 scoped_refptr<base::TestSimpleTaskRunner> runner(
54 new base::TestSimpleTaskRunner);
56 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
57 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
58 EXPECT_EQ(0U, runner->NumPendingTasks());
61 auto pending_tasks = runner->TakePendingTasks();
62 ASSERT_EQ(2U, pending_tasks.size());
63 EXPECT_NE(pending_tasks[0].location.line_number(),
64 pending_tasks[1].location.line_number())
65 << "Make sure FROM_HERE is propagated.";
68 TEST(OneShotEventTest, CallsQueue) {
70 scoped_refptr<base::TestSimpleTaskRunner> runner(
71 new base::TestSimpleTaskRunner);
73 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
74 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
75 EXPECT_EQ(0U, runner->NumPendingTasks());
77 ASSERT_EQ(2U, runner->NumPendingTasks());
80 runner->RunPendingTasks();
84 TEST(OneShotEventTest, CallsAfterSignalDontRunInline) {
86 scoped_refptr<base::TestSimpleTaskRunner> runner(
87 new base::TestSimpleTaskRunner);
91 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
92 EXPECT_EQ(1U, runner->NumPendingTasks());
94 runner->RunPendingTasks();
98 TEST(OneShotEventTest, PostDefaultsToCurrentMessageLoop) {
100 scoped_refptr<base::TestSimpleTaskRunner> runner(
101 new base::TestSimpleTaskRunner);
102 base::test::SingleThreadTaskEnvironment task_environment;
106 event.Post(FROM_HERE, base::BindOnce(&Increment, &runner_i), runner);
107 event.Post(FROM_HERE, base::BindOnce(&Increment, &loop_i));
109 EXPECT_EQ(1U, runner->NumPendingTasks());
110 EXPECT_EQ(0, runner_i);
111 runner->RunPendingTasks();
112 EXPECT_EQ(1, runner_i);
113 EXPECT_EQ(0, loop_i);
114 base::RunLoop().RunUntilIdle();
115 EXPECT_EQ(1, loop_i);
118 void CheckSignaledAndPostIncrement(
120 const scoped_refptr<base::SingleThreadTaskRunner>& runner,
122 EXPECT_TRUE(event->is_signaled());
123 event->Post(FROM_HERE, base::BindOnce(&Increment, i), runner);
126 TEST(OneShotEventTest, IsSignaledAndPostsFromCallbackWork) {
128 scoped_refptr<base::TestSimpleTaskRunner> runner(
129 new base::TestSimpleTaskRunner);
132 event.Post(FROM_HERE,
133 base::BindOnce(&CheckSignaledAndPostIncrement, &event, runner, &i),
138 // CheckSignaledAndPostIncrement is queued on |runner|.
139 EXPECT_EQ(1U, runner->NumPendingTasks());
141 runner->RunPendingTasks();
142 // Increment is queued on |runner|.
143 EXPECT_EQ(1U, runner->NumPendingTasks());
145 runner->RunPendingTasks();
146 // Increment has run.
147 EXPECT_EQ(0U, runner->NumPendingTasks());
151 // Tests that OneShotEvent does not keep references to tasks once OneShotEvent
153 TEST(OneShotEventTest, DropsCallbackRefUponSignalled) {
154 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
155 bool did_delete_instance = false;
159 auto ref_counted_class =
160 base::MakeRefCounted<RefCountedClass>(&did_delete_instance);
161 event.Post(FROM_HERE,
162 base::BindOnce(&RefCountedClass::PerformTask, ref_counted_class),
165 runner->RunPendingTasks();
166 EXPECT_TRUE(ref_counted_class->did_perform_task());
169 // Once OneShotEvent doesn't have any queued events, it should have dropped
170 // all the references to the callbacks it received through Post().
171 EXPECT_TRUE(did_delete_instance);