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() {} 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 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 37namespace { 38 39class 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. 54TEST_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 72TEST_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 78TEST_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 94TEST_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 105TEST_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 116struct 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 129TEST_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 138TEST_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 155class 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 179TEST_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