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