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 15namespace base { 16 17void NopInvokeFunc(internal::BindStateBase*) {} 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. 24struct FakeBindState1 : internal::BindStateBase { 25 FakeBindState1() : BindStateBase(&Destroy) {} 26 private: 27 ~FakeBindState1() {} 28 static void Destroy(internal::BindStateBase* self) { 29 delete static_cast<FakeBindState1*>(self); 30 } 31}; 32 33struct FakeBindState2 : internal::BindStateBase { 34 FakeBindState2() : BindStateBase(&Destroy) {} 35 private: 36 ~FakeBindState2() {} 37 static void Destroy(internal::BindStateBase* self) { 38 delete static_cast<FakeBindState2*>(self); 39 } 40}; 41 42namespace { 43 44class CallbackTest : public ::testing::Test { 45 public: 46 CallbackTest() 47 : callback_a_(new FakeBindState1(), &NopInvokeFunc), 48 callback_b_(new FakeBindState2(), &NopInvokeFunc) { 49 } 50 51 ~CallbackTest() override {} 52 53 protected: 54 Callback<void()> callback_a_; 55 const Callback<void()> callback_b_; // Ensure APIs work with const. 56 Callback<void()> null_callback_; 57}; 58 59// Ensure we can create unbound callbacks. We need this to be able to store 60// them in class members that can be initialized later. 61TEST_F(CallbackTest, DefaultConstruction) { 62 Callback<void()> c0; 63 Callback<void(int)> c1; 64 Callback<void(int,int)> c2; 65 Callback<void(int,int,int)> c3; 66 Callback<void(int,int,int,int)> c4; 67 Callback<void(int,int,int,int,int)> c5; 68 Callback<void(int,int,int,int,int,int)> c6; 69 70 EXPECT_TRUE(c0.is_null()); 71 EXPECT_TRUE(c1.is_null()); 72 EXPECT_TRUE(c2.is_null()); 73 EXPECT_TRUE(c3.is_null()); 74 EXPECT_TRUE(c4.is_null()); 75 EXPECT_TRUE(c5.is_null()); 76 EXPECT_TRUE(c6.is_null()); 77} 78 79TEST_F(CallbackTest, IsNull) { 80 EXPECT_TRUE(null_callback_.is_null()); 81 EXPECT_FALSE(callback_a_.is_null()); 82 EXPECT_FALSE(callback_b_.is_null()); 83} 84 85TEST_F(CallbackTest, Equals) { 86 EXPECT_TRUE(callback_a_.Equals(callback_a_)); 87 EXPECT_FALSE(callback_a_.Equals(callback_b_)); 88 EXPECT_FALSE(callback_b_.Equals(callback_a_)); 89 90 // We should compare based on instance, not type. 91 Callback<void()> callback_c(new FakeBindState1(), &NopInvokeFunc); 92 Callback<void()> callback_a2 = callback_a_; 93 EXPECT_TRUE(callback_a_.Equals(callback_a2)); 94 EXPECT_FALSE(callback_a_.Equals(callback_c)); 95 96 // Empty, however, is always equal to empty. 97 Callback<void()> empty2; 98 EXPECT_TRUE(null_callback_.Equals(empty2)); 99} 100 101TEST_F(CallbackTest, Reset) { 102 // Resetting should bring us back to empty. 103 ASSERT_FALSE(callback_a_.is_null()); 104 ASSERT_FALSE(callback_a_.Equals(null_callback_)); 105 106 callback_a_.Reset(); 107 108 EXPECT_TRUE(callback_a_.is_null()); 109 EXPECT_TRUE(callback_a_.Equals(null_callback_)); 110} 111 112struct TestForReentrancy { 113 TestForReentrancy() 114 : cb_already_run(false), 115 cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) { 116 } 117 void AssertCBIsNull() { 118 ASSERT_TRUE(cb.is_null()); 119 cb_already_run = true; 120 } 121 bool cb_already_run; 122 Closure cb; 123}; 124 125TEST_F(CallbackTest, ResetAndReturn) { 126 TestForReentrancy tfr; 127 ASSERT_FALSE(tfr.cb.is_null()); 128 ASSERT_FALSE(tfr.cb_already_run); 129 ResetAndReturn(&tfr.cb).Run(); 130 ASSERT_TRUE(tfr.cb.is_null()); 131 ASSERT_TRUE(tfr.cb_already_run); 132} 133 134class CallbackOwner : public base::RefCounted<CallbackOwner> { 135 public: 136 explicit CallbackOwner(bool* deleted) { 137 callback_ = Bind(&CallbackOwner::Unused, this); 138 deleted_ = deleted; 139 } 140 void Reset() { 141 callback_.Reset(); 142 // We are deleted here if no-one else had a ref to us. 143 } 144 145 private: 146 friend class base::RefCounted<CallbackOwner>; 147 virtual ~CallbackOwner() { 148 *deleted_ = true; 149 } 150 void Unused() { 151 FAIL() << "Should never be called"; 152 } 153 154 Closure callback_; 155 bool* deleted_; 156}; 157 158TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) { 159 bool deleted = false; 160 CallbackOwner* owner = new CallbackOwner(&deleted); 161 owner->Reset(); 162 ASSERT_TRUE(deleted); 163} 164 165} // namespace 166} // namespace base 167