Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 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/cancelable_callback.h"
      6 
      7 #include <memory>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/location.h"
     12 #include "base/memory/ptr_util.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/run_loop.h"
     15 #include "base/single_thread_task_runner.h"
     16 #include "base/threading/thread_task_runner_handle.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 namespace base {
     20 namespace {
     21 
     22 class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
     23  private:
     24   friend class RefCountedThreadSafe<TestRefCounted>;
     25   ~TestRefCounted() {};
     26 };
     27 
     28 void Increment(int* count) { (*count)++; }
     29 void IncrementBy(int* count, int n) { (*count) += n; }
     30 void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
     31 
     32 void OnMoveOnlyReceived(int* value, std::unique_ptr<int> result) {
     33   *value = *result;
     34 }
     35 
     36 // Cancel().
     37 //  - Callback can be run multiple times.
     38 //  - After Cancel(), Run() completes but has no effect.
     39 TEST(CancelableCallbackTest, Cancel) {
     40   int count = 0;
     41   CancelableClosure cancelable(
     42       base::Bind(&Increment, base::Unretained(&count)));
     43 
     44   base::Closure callback = cancelable.callback();
     45   callback.Run();
     46   EXPECT_EQ(1, count);
     47 
     48   callback.Run();
     49   EXPECT_EQ(2, count);
     50 
     51   cancelable.Cancel();
     52   callback.Run();
     53   EXPECT_EQ(2, count);
     54 }
     55 
     56 // Cancel() called multiple times.
     57 //  - Cancel() cancels all copies of the wrapped callback.
     58 //  - Calling Cancel() more than once has no effect.
     59 //  - After Cancel(), callback() returns a null callback.
     60 TEST(CancelableCallbackTest, MultipleCancel) {
     61   int count = 0;
     62   CancelableClosure cancelable(
     63       base::Bind(&Increment, base::Unretained(&count)));
     64 
     65   base::Closure callback1 = cancelable.callback();
     66   base::Closure callback2 = cancelable.callback();
     67   cancelable.Cancel();
     68 
     69   callback1.Run();
     70   EXPECT_EQ(0, count);
     71 
     72   callback2.Run();
     73   EXPECT_EQ(0, count);
     74 
     75   // Calling Cancel() again has no effect.
     76   cancelable.Cancel();
     77 
     78   // callback() of a cancelled callback is null.
     79   base::Closure callback3 = cancelable.callback();
     80   EXPECT_TRUE(callback3.is_null());
     81 }
     82 
     83 // CancelableCallback destroyed before callback is run.
     84 //  - Destruction of CancelableCallback cancels outstanding callbacks.
     85 TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
     86   int count = 0;
     87   base::Closure callback;
     88 
     89   {
     90     CancelableClosure cancelable(
     91         base::Bind(&Increment, base::Unretained(&count)));
     92 
     93     callback = cancelable.callback();
     94     callback.Run();
     95     EXPECT_EQ(1, count);
     96   }
     97 
     98   callback.Run();
     99   EXPECT_EQ(1, count);
    100 }
    101 
    102 // Cancel() called on bound closure with a RefCounted parameter.
    103 //  - Cancel drops wrapped callback (and, implicitly, its bound arguments).
    104 TEST(CancelableCallbackTest, CancelDropsCallback) {
    105   scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
    106   EXPECT_TRUE(ref_counted->HasOneRef());
    107 
    108   CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted));
    109   EXPECT_FALSE(cancelable.IsCancelled());
    110   EXPECT_TRUE(ref_counted.get());
    111   EXPECT_FALSE(ref_counted->HasOneRef());
    112 
    113   // There is only one reference to |ref_counted| after the Cancel().
    114   cancelable.Cancel();
    115   EXPECT_TRUE(cancelable.IsCancelled());
    116   EXPECT_TRUE(ref_counted.get());
    117   EXPECT_TRUE(ref_counted->HasOneRef());
    118 }
    119 
    120 // Reset().
    121 //  - Reset() replaces the existing wrapped callback with a new callback.
    122 //  - Reset() deactivates outstanding callbacks.
    123 TEST(CancelableCallbackTest, Reset) {
    124   int count = 0;
    125   CancelableClosure cancelable(
    126       base::Bind(&Increment, base::Unretained(&count)));
    127 
    128   base::Closure callback = cancelable.callback();
    129   callback.Run();
    130   EXPECT_EQ(1, count);
    131 
    132   callback.Run();
    133   EXPECT_EQ(2, count);
    134 
    135   cancelable.Reset(
    136       base::Bind(&IncrementBy, base::Unretained(&count), 3));
    137   EXPECT_FALSE(cancelable.IsCancelled());
    138 
    139   // The stale copy of the cancelable callback is non-null.
    140   ASSERT_FALSE(callback.is_null());
    141 
    142   // The stale copy of the cancelable callback is no longer active.
    143   callback.Run();
    144   EXPECT_EQ(2, count);
    145 
    146   base::Closure callback2 = cancelable.callback();
    147   ASSERT_FALSE(callback2.is_null());
    148 
    149   callback2.Run();
    150   EXPECT_EQ(5, count);
    151 }
    152 
    153 // IsCanceled().
    154 //  - Cancel() transforms the CancelableCallback into a cancelled state.
    155 TEST(CancelableCallbackTest, IsNull) {
    156   CancelableClosure cancelable;
    157   EXPECT_TRUE(cancelable.IsCancelled());
    158 
    159   int count = 0;
    160   cancelable.Reset(base::Bind(&Increment,
    161                               base::Unretained(&count)));
    162   EXPECT_FALSE(cancelable.IsCancelled());
    163 
    164   cancelable.Cancel();
    165   EXPECT_TRUE(cancelable.IsCancelled());
    166 }
    167 
    168 // CancelableCallback posted to a MessageLoop with PostTask.
    169 //  - Callbacks posted to a MessageLoop can be cancelled.
    170 TEST(CancelableCallbackTest, PostTask) {
    171   MessageLoop loop;
    172 
    173   int count = 0;
    174   CancelableClosure cancelable(base::Bind(&Increment,
    175                                            base::Unretained(&count)));
    176 
    177   ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
    178   RunLoop().RunUntilIdle();
    179 
    180   EXPECT_EQ(1, count);
    181 
    182   ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
    183 
    184   // Cancel before running the message loop.
    185   cancelable.Cancel();
    186   RunLoop().RunUntilIdle();
    187 
    188   // Callback never ran due to cancellation; count is the same.
    189   EXPECT_EQ(1, count);
    190 }
    191 
    192 // CancelableCallback can be used with move-only types.
    193 TEST(CancelableCallbackTest, MoveOnlyType) {
    194   const int kExpectedResult = 42;
    195 
    196   int result = 0;
    197   CancelableCallback<void(std::unique_ptr<int>)> cb(
    198       base::Bind(&OnMoveOnlyReceived, base::Unretained(&result)));
    199   cb.callback().Run(base::WrapUnique(new int(kExpectedResult)));
    200 
    201   EXPECT_EQ(kExpectedResult, result);
    202 }
    203 
    204 }  // namespace
    205 }  // namespace base
    206