1 // Copyright (c) 2011 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/cancelable_callback.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/location.h" 10 #include "base/memory/ref_counted.h" 11 #include "base/run_loop.h" 12 #include "base/single_thread_task_runner.h" 13 #include "base/thread_task_runner_handle.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace base { 17 namespace { 18 19 class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> { 20 private: 21 friend class RefCountedThreadSafe<TestRefCounted>; 22 ~TestRefCounted() {}; 23 }; 24 25 void Increment(int* count) { (*count)++; } 26 void IncrementBy(int* count, int n) { (*count) += n; } 27 void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {} 28 29 // Cancel(). 30 // - Callback can be run multiple times. 31 // - After Cancel(), Run() completes but has no effect. 32 TEST(CancelableCallbackTest, Cancel) { 33 int count = 0; 34 CancelableClosure cancelable( 35 base::Bind(&Increment, base::Unretained(&count))); 36 37 base::Closure callback = cancelable.callback(); 38 callback.Run(); 39 EXPECT_EQ(1, count); 40 41 callback.Run(); 42 EXPECT_EQ(2, count); 43 44 cancelable.Cancel(); 45 callback.Run(); 46 EXPECT_EQ(2, count); 47 } 48 49 // Cancel() called multiple times. 50 // - Cancel() cancels all copies of the wrapped callback. 51 // - Calling Cancel() more than once has no effect. 52 // - After Cancel(), callback() returns a null callback. 53 TEST(CancelableCallbackTest, MultipleCancel) { 54 int count = 0; 55 CancelableClosure cancelable( 56 base::Bind(&Increment, base::Unretained(&count))); 57 58 base::Closure callback1 = cancelable.callback(); 59 base::Closure callback2 = cancelable.callback(); 60 cancelable.Cancel(); 61 62 callback1.Run(); 63 EXPECT_EQ(0, count); 64 65 callback2.Run(); 66 EXPECT_EQ(0, count); 67 68 // Calling Cancel() again has no effect. 69 cancelable.Cancel(); 70 71 // callback() of a cancelled callback is null. 72 base::Closure callback3 = cancelable.callback(); 73 EXPECT_TRUE(callback3.is_null()); 74 } 75 76 // CancelableCallback destroyed before callback is run. 77 // - Destruction of CancelableCallback cancels outstanding callbacks. 78 TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) { 79 int count = 0; 80 base::Closure callback; 81 82 { 83 CancelableClosure cancelable( 84 base::Bind(&Increment, base::Unretained(&count))); 85 86 callback = cancelable.callback(); 87 callback.Run(); 88 EXPECT_EQ(1, count); 89 } 90 91 callback.Run(); 92 EXPECT_EQ(1, count); 93 } 94 95 // Cancel() called on bound closure with a RefCounted parameter. 96 // - Cancel drops wrapped callback (and, implicitly, its bound arguments). 97 TEST(CancelableCallbackTest, CancelDropsCallback) { 98 scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted; 99 EXPECT_TRUE(ref_counted->HasOneRef()); 100 101 CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted)); 102 EXPECT_FALSE(cancelable.IsCancelled()); 103 EXPECT_TRUE(ref_counted.get()); 104 EXPECT_FALSE(ref_counted->HasOneRef()); 105 106 // There is only one reference to |ref_counted| after the Cancel(). 107 cancelable.Cancel(); 108 EXPECT_TRUE(cancelable.IsCancelled()); 109 EXPECT_TRUE(ref_counted.get()); 110 EXPECT_TRUE(ref_counted->HasOneRef()); 111 } 112 113 // Reset(). 114 // - Reset() replaces the existing wrapped callback with a new callback. 115 // - Reset() deactivates outstanding callbacks. 116 TEST(CancelableCallbackTest, Reset) { 117 int count = 0; 118 CancelableClosure cancelable( 119 base::Bind(&Increment, base::Unretained(&count))); 120 121 base::Closure callback = cancelable.callback(); 122 callback.Run(); 123 EXPECT_EQ(1, count); 124 125 callback.Run(); 126 EXPECT_EQ(2, count); 127 128 cancelable.Reset( 129 base::Bind(&IncrementBy, base::Unretained(&count), 3)); 130 EXPECT_FALSE(cancelable.IsCancelled()); 131 132 // The stale copy of the cancelable callback is non-null. 133 ASSERT_FALSE(callback.is_null()); 134 135 // The stale copy of the cancelable callback is no longer active. 136 callback.Run(); 137 EXPECT_EQ(2, count); 138 139 base::Closure callback2 = cancelable.callback(); 140 ASSERT_FALSE(callback2.is_null()); 141 142 callback2.Run(); 143 EXPECT_EQ(5, count); 144 } 145 146 // IsCanceled(). 147 // - Cancel() transforms the CancelableCallback into a cancelled state. 148 TEST(CancelableCallbackTest, IsNull) { 149 CancelableClosure cancelable; 150 EXPECT_TRUE(cancelable.IsCancelled()); 151 152 int count = 0; 153 cancelable.Reset(base::Bind(&Increment, 154 base::Unretained(&count))); 155 EXPECT_FALSE(cancelable.IsCancelled()); 156 157 cancelable.Cancel(); 158 EXPECT_TRUE(cancelable.IsCancelled()); 159 } 160 161 // CancelableCallback posted to a MessageLoop with PostTask. 162 // - Callbacks posted to a MessageLoop can be cancelled. 163 TEST(CancelableCallbackTest, PostTask) { 164 MessageLoop loop; 165 166 int count = 0; 167 CancelableClosure cancelable(base::Bind(&Increment, 168 base::Unretained(&count))); 169 170 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback()); 171 RunLoop().RunUntilIdle(); 172 173 EXPECT_EQ(1, count); 174 175 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback()); 176 177 // Cancel before running the message loop. 178 cancelable.Cancel(); 179 RunLoop().RunUntilIdle(); 180 181 // Callback never ran due to cancellation; count is the same. 182 EXPECT_EQ(1, count); 183 } 184 185 } // namespace 186 } // namespace base 187