1 // Copyright (c) 2012 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/callback.h" 6 7 #include <memory> 8 9 #include "base/bind.h" 10 #include "base/callback_helpers.h" 11 #include "base/callback_internal.h" 12 #include "base/memory/ref_counted.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace base { 16 17 void NopInvokeFunc() {} 18 19 // White-box testpoints to inject into a Callback<> object for checking 20 // comparators and emptiness APIs. Use a BindState that is specialized 21 // based on a type we declared in the anonymous namespace above to remove any 22 // chance of colliding with another instantiation and breaking the 23 // one-definition-rule. 24 struct FakeBindState : internal::BindStateBase { 25 FakeBindState() : BindStateBase(&NopInvokeFunc, &Destroy, &IsCancelled) {} 26 27 private: 28 ~FakeBindState() {} 29 static void Destroy(const internal::BindStateBase* self) { 30 delete static_cast<const FakeBindState*>(self); 31 } 32 static bool IsCancelled(const internal::BindStateBase*) { 33 return false; 34 } 35 }; 36 37 namespace { 38 39 class CallbackTest : public ::testing::Test { 40 public: 41 CallbackTest() 42 : callback_a_(new FakeBindState()), callback_b_(new FakeBindState()) {} 43 44 ~CallbackTest() override {} 45 46 protected: 47 Callback<void()> callback_a_; 48 const Callback<void()> callback_b_; // Ensure APIs work with const. 49 Callback<void()> null_callback_; 50 }; 51 52 // Ensure we can create unbound callbacks. We need this to be able to store 53 // them in class members that can be initialized later. 54 TEST_F(CallbackTest, DefaultConstruction) { 55 Callback<void()> c0; 56 Callback<void(int)> c1; 57 Callback<void(int,int)> c2; 58 Callback<void(int,int,int)> c3; 59 Callback<void(int,int,int,int)> c4; 60 Callback<void(int,int,int,int,int)> c5; 61 Callback<void(int,int,int,int,int,int)> c6; 62 63 EXPECT_TRUE(c0.is_null()); 64 EXPECT_TRUE(c1.is_null()); 65 EXPECT_TRUE(c2.is_null()); 66 EXPECT_TRUE(c3.is_null()); 67 EXPECT_TRUE(c4.is_null()); 68 EXPECT_TRUE(c5.is_null()); 69 EXPECT_TRUE(c6.is_null()); 70 } 71 72 TEST_F(CallbackTest, IsNull) { 73 EXPECT_TRUE(null_callback_.is_null()); 74 EXPECT_FALSE(callback_a_.is_null()); 75 EXPECT_FALSE(callback_b_.is_null()); 76 } 77 78 TEST_F(CallbackTest, Equals) { 79 EXPECT_TRUE(callback_a_.Equals(callback_a_)); 80 EXPECT_FALSE(callback_a_.Equals(callback_b_)); 81 EXPECT_FALSE(callback_b_.Equals(callback_a_)); 82 83 // We should compare based on instance, not type. 84 Callback<void()> callback_c(new FakeBindState()); 85 Callback<void()> callback_a2 = callback_a_; 86 EXPECT_TRUE(callback_a_.Equals(callback_a2)); 87 EXPECT_FALSE(callback_a_.Equals(callback_c)); 88 89 // Empty, however, is always equal to empty. 90 Callback<void()> empty2; 91 EXPECT_TRUE(null_callback_.Equals(empty2)); 92 } 93 94 TEST_F(CallbackTest, Reset) { 95 // Resetting should bring us back to empty. 96 ASSERT_FALSE(callback_a_.is_null()); 97 ASSERT_FALSE(callback_a_.Equals(null_callback_)); 98 99 callback_a_.Reset(); 100 101 EXPECT_TRUE(callback_a_.is_null()); 102 EXPECT_TRUE(callback_a_.Equals(null_callback_)); 103 } 104 105 TEST_F(CallbackTest, Move) { 106 // Moving should reset the callback. 107 ASSERT_FALSE(callback_a_.is_null()); 108 ASSERT_FALSE(callback_a_.Equals(null_callback_)); 109 110 auto tmp = std::move(callback_a_); 111 112 EXPECT_TRUE(callback_a_.is_null()); 113 EXPECT_TRUE(callback_a_.Equals(null_callback_)); 114 } 115 116 struct TestForReentrancy { 117 TestForReentrancy() 118 : cb_already_run(false), 119 cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) { 120 } 121 void AssertCBIsNull() { 122 ASSERT_TRUE(cb.is_null()); 123 cb_already_run = true; 124 } 125 bool cb_already_run; 126 Closure cb; 127 }; 128 129 TEST_F(CallbackTest, ResetAndReturn) { 130 TestForReentrancy tfr; 131 ASSERT_FALSE(tfr.cb.is_null()); 132 ASSERT_FALSE(tfr.cb_already_run); 133 ResetAndReturn(&tfr.cb).Run(); 134 ASSERT_TRUE(tfr.cb.is_null()); 135 ASSERT_TRUE(tfr.cb_already_run); 136 } 137 138 TEST_F(CallbackTest, NullAfterMoveRun) { 139 Closure cb = Bind([] {}); 140 ASSERT_TRUE(cb); 141 std::move(cb).Run(); 142 ASSERT_FALSE(cb); 143 144 const Closure cb2 = Bind([] {}); 145 ASSERT_TRUE(cb2); 146 std::move(cb2).Run(); 147 ASSERT_TRUE(cb2); 148 149 OnceClosure cb3 = BindOnce([] {}); 150 ASSERT_TRUE(cb3); 151 std::move(cb3).Run(); 152 ASSERT_FALSE(cb3); 153 } 154 155 class CallbackOwner : public base::RefCounted<CallbackOwner> { 156 public: 157 explicit CallbackOwner(bool* deleted) { 158 callback_ = Bind(&CallbackOwner::Unused, this); 159 deleted_ = deleted; 160 } 161 void Reset() { 162 callback_.Reset(); 163 // We are deleted here if no-one else had a ref to us. 164 } 165 166 private: 167 friend class base::RefCounted<CallbackOwner>; 168 virtual ~CallbackOwner() { 169 *deleted_ = true; 170 } 171 void Unused() { 172 FAIL() << "Should never be called"; 173 } 174 175 Closure callback_; 176 bool* deleted_; 177 }; 178 179 TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) { 180 bool deleted = false; 181 CallbackOwner* owner = new CallbackOwner(&deleted); 182 owner->Reset(); 183 ASSERT_TRUE(deleted); 184 } 185 186 } // namespace 187 } // namespace base 188