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