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