diff options
author | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-24 04:12:04 +0000 |
---|---|---|
committer | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-24 04:12:04 +0000 |
commit | b77576f54910cfb2e64ef91f3b3bb197136553b0 (patch) | |
tree | f1a78f1e6983ff1a44e0afb8fdca3b32785263c1 /base/cancelable_callback_unittest.cc | |
parent | a8135bc3dc27230e8107ebf44f99826a05989365 (diff) | |
download | chromium_src-b77576f54910cfb2e64ef91f3b3bb197136553b0.zip chromium_src-b77576f54910cfb2e64ef91f3b3bb197136553b0.tar.gz chromium_src-b77576f54910cfb2e64ef91f3b3bb197136553b0.tar.bz2 |
base::Bind: Implement CancelableCallback to replace CancelableTask.
Designed by groby,binji,csilv,jhawkins.
BUG=96749
TEST=CancelableCallbackTest.*
R=ajwong@chromium.org,darin@chromium.org
Review URL: http://codereview.chromium.org/8673008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111493 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/cancelable_callback_unittest.cc')
-rw-r--r-- | base/cancelable_callback_unittest.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc new file mode 100644 index 0000000..980359b --- /dev/null +++ b/base/cancelable_callback_unittest.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/cancelable_callback.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace { + +class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> { + private: + friend class RefCountedThreadSafe<TestRefCounted>; + ~TestRefCounted() {}; +}; + +void Increment(int* count) { (*count)++; } +void IncrementBy(int* count, int n) { (*count) += n; } +void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {} + +// Cancel(). +// - Callback can be run multiple times. +// - After Cancel(), Run() completes but has no effect. +TEST(CancelableCallbackTest, Cancel) { + int count = 0; + CancelableCallback cancelable( + base::Bind(&Increment, base::Unretained(&count))); + + base::Closure callback = cancelable.callback(); + callback.Run(); + EXPECT_EQ(1, count); + + callback.Run(); + EXPECT_EQ(2, count); + + cancelable.Cancel(); + callback.Run(); + EXPECT_EQ(2, count); +} + +// Cancel() called multiple times. +// - Cancel() cancels all copies of the wrapped callback. +TEST(CancelableCallbackTest, MultipleCancel) { + int count = 0; + CancelableCallback cancelable( + base::Bind(&Increment, base::Unretained(&count))); + + base::Closure callback1 = cancelable.callback(); + cancelable.Cancel(); + + callback1.Run(); + EXPECT_EQ(0, count); + + base::Closure callback2 = cancelable.callback(); + callback2.Run(); + EXPECT_EQ(0, count); + + // Cancel() should have no effect, but callback() is still runnable. + base::Closure callback3 = cancelable.callback(); + cancelable.Cancel(); + callback3.Run(); + EXPECT_EQ(0, count); +} + +// CancelableCallback destroyed before callback is run. +// - Destruction of CancelableCallback cancels outstanding callbacks. +TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) { + int count = 0; + base::Closure callback; + + { + CancelableCallback cancelable( + base::Bind(&Increment, base::Unretained(&count))); + + callback = cancelable.callback(); + callback.Run(); + EXPECT_EQ(1, count); + } + + callback.Run(); + EXPECT_EQ(1, count); +} + +// Cancel() called on bound closure with a RefCounted parameter. +// - Cancel drops wrapped callback (and, implicitly, its bound arguments). +TEST(CancelableCallbackTest, CancelDropsCallback) { + scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted; + EXPECT_TRUE(ref_counted->HasOneRef()); + + CancelableCallback cancelable(base::Bind(RefCountedParam, ref_counted)); + EXPECT_FALSE(cancelable.IsCancelled()); + EXPECT_TRUE(ref_counted.get()); + EXPECT_FALSE(ref_counted->HasOneRef()); + + // There is only one reference to |ref_counted| after the Cancel(). + cancelable.Cancel(); + EXPECT_TRUE(cancelable.IsCancelled()); + EXPECT_TRUE(ref_counted.get()); + EXPECT_TRUE(ref_counted->HasOneRef()); +} + +// Reset(). +// - Reset() replaces the existing wrapped callback with a new callback. +// - Reset() deactivates outstanding callbacks. +TEST(CancelableCallbackTest, Reset) { + int count = 0; + CancelableCallback cancelable( + base::Bind(&Increment, base::Unretained(&count))); + + base::Closure callback = cancelable.callback(); + callback.Run(); + EXPECT_EQ(1, count); + + callback.Run(); + EXPECT_EQ(2, count); + + cancelable.Reset( + base::Bind(&IncrementBy, base::Unretained(&count), 3)); + EXPECT_FALSE(cancelable.IsCancelled()); + + // The stale copy of the cancelable callback is non-null. + ASSERT_FALSE(callback.is_null()); + + // The stale copy of the cancelable callback is no longer active. + callback.Run(); + EXPECT_EQ(2, count); + + base::Closure callback2 = cancelable.callback(); + ASSERT_FALSE(callback2.is_null()); + + callback2.Run(); + EXPECT_EQ(5, count); +} + +// IsCanceled(). +// - Cancel() transforms the CancelableCallback into a cancelled state. +TEST(CancelableCallbackTest, IsNull) { + CancelableCallback cancelable; + EXPECT_TRUE(cancelable.IsCancelled()); + + int count = 0; + cancelable.Reset(base::Bind(&Increment, + base::Unretained(&count))); + EXPECT_FALSE(cancelable.IsCancelled()); + + cancelable.Cancel(); + EXPECT_TRUE(cancelable.IsCancelled()); +} + +// CancelableCallback posted to a MessageLoop with PostTask. +// - Callbacks posted to a MessageLoop can be cancelled. +TEST(CancelableCallbackTest, PostTask) { + MessageLoop loop(MessageLoop::TYPE_DEFAULT); + + int count = 0; + CancelableCallback cancelable(base::Bind(&Increment, + base::Unretained(&count))); + + MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback()); + MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + MessageLoop::current()->Run(); + + EXPECT_EQ(1, count); + + MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback()); + MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + + // Cancel before running the message loop. + cancelable.Cancel(); + MessageLoop::current()->Run(); + + // Callback never ran due to cancellation; count is the same. + EXPECT_EQ(1, count); +} + +} // namespace +} // namespace base |