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