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