diff options
author | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-17 01:07:19 +0000 |
---|---|---|
committer | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-17 01:07:19 +0000 |
commit | 406203d804cfd1c0ff1b74bced465700df5a531b (patch) | |
tree | dbb0c78215287dd9215eb69411493bff8ae4d3f4 /sync/internal_api/public/util/weak_handle_unittest.cc | |
parent | a263538270e30269c67e914fa67542e5d6da2be2 (diff) | |
download | chromium_src-406203d804cfd1c0ff1b74bced465700df5a531b.zip chromium_src-406203d804cfd1c0ff1b74bced465700df5a531b.tar.gz chromium_src-406203d804cfd1c0ff1b74bced465700df5a531b.tar.bz2 |
sync: move internal_api components used by chrome/browser into internal_api/public
TBR=jhawkins@chromium.org
BUG=131130
TEST=
Review URL: https://chromiumcodereview.appspot.com/10534080
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142626 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/internal_api/public/util/weak_handle_unittest.cc')
-rw-r--r-- | sync/internal_api/public/util/weak_handle_unittest.cc | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/sync/internal_api/public/util/weak_handle_unittest.cc b/sync/internal_api/public/util/weak_handle_unittest.cc new file mode 100644 index 0000000..af919ad --- /dev/null +++ b/sync/internal_api/public/util/weak_handle_unittest.cc @@ -0,0 +1,326 @@ +// Copyright (c) 2012 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 "sync/internal_api/public/util/weak_handle.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/location.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop.h" +#include "base/threading/thread.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace browser_sync { + +using ::testing::_; +using ::testing::SaveArg; +using ::testing::StrictMock; + +class Base { + public: + Base() : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} + + WeakHandle<Base> AsWeakHandle() { + return MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()); + } + + void Kill() { + weak_ptr_factory_.InvalidateWeakPtrs(); + } + + MOCK_METHOD0(Test, void()); + MOCK_METHOD1(Test1, void(const int&)); + MOCK_METHOD2(Test2, void(const int&, Base*)); + MOCK_METHOD3(Test3, void(const int&, Base*, float)); + MOCK_METHOD4(Test4, void(const int&, Base*, float, const char*)); + + MOCK_METHOD1(TestWithSelf, void(const WeakHandle<Base>&)); + + private: + base::WeakPtrFactory<Base> weak_ptr_factory_; +}; + +class Derived : public Base, public base::SupportsWeakPtr<Derived> {}; + +class WeakHandleTest : public ::testing::Test { + protected: + virtual void TearDown() { + // Process any last-minute posted tasks. + PumpLoop(); + } + + void PumpLoop() { + message_loop_.RunAllPending(); + } + + static void CallTestFromOtherThread(tracked_objects::Location from_here, + const WeakHandle<Base>& h) { + base::Thread t("Test thread"); + ASSERT_TRUE(t.Start()); + t.message_loop()->PostTask( + from_here, base::Bind(&WeakHandleTest::CallTest, from_here, h)); + } + + private: + static void CallTest(tracked_objects::Location from_here, + const WeakHandle<Base>& h) { + h.Call(from_here, &Base::Test); + } + + MessageLoop message_loop_; +}; + +TEST_F(WeakHandleTest, Uninitialized) { + // Default. + WeakHandle<int> h; + EXPECT_FALSE(h.IsInitialized()); + // Copy. + { + WeakHandle<int> h2(h); + EXPECT_FALSE(h2.IsInitialized()); + } + // Assign. + { + WeakHandle<int> h2; + h2 = h; + EXPECT_FALSE(h.IsInitialized()); + } +} + +TEST_F(WeakHandleTest, InitializedAfterDestroy) { + WeakHandle<Base> h; + { + StrictMock<Base> b; + h = b.AsWeakHandle(); + } + EXPECT_TRUE(h.IsInitialized()); + EXPECT_FALSE(h.Get()); +} + +TEST_F(WeakHandleTest, InitializedAfterInvalidate) { + StrictMock<Base> b; + WeakHandle<Base> h = b.AsWeakHandle(); + b.Kill(); + EXPECT_TRUE(h.IsInitialized()); + EXPECT_FALSE(h.Get()); +} + +TEST_F(WeakHandleTest, Call) { + StrictMock<Base> b; + const char test_str[] = "test"; + EXPECT_CALL(b, Test()); + EXPECT_CALL(b, Test1(5)); + EXPECT_CALL(b, Test2(5, &b)); + EXPECT_CALL(b, Test3(5, &b, 5)); + EXPECT_CALL(b, Test4(5, &b, 5, test_str)); + + WeakHandle<Base> h = b.AsWeakHandle(); + EXPECT_TRUE(h.IsInitialized()); + + // Should run. + h.Call(FROM_HERE, &Base::Test); + h.Call(FROM_HERE, &Base::Test1, 5); + h.Call(FROM_HERE, &Base::Test2, 5, &b); + h.Call(FROM_HERE, &Base::Test3, 5, &b, 5); + h.Call(FROM_HERE, &Base::Test4, 5, &b, 5, test_str); + PumpLoop(); +} + +TEST_F(WeakHandleTest, CallAfterDestroy) { + { + StrictMock<Base> b; + EXPECT_CALL(b, Test()).Times(0); + + WeakHandle<Base> h = b.AsWeakHandle(); + EXPECT_TRUE(h.IsInitialized()); + + // Should not run. + h.Call(FROM_HERE, &Base::Test); + } + PumpLoop(); +} + +TEST_F(WeakHandleTest, CallAfterInvalidate) { + StrictMock<Base> b; + EXPECT_CALL(b, Test()).Times(0); + + WeakHandle<Base> h = b.AsWeakHandle(); + EXPECT_TRUE(h.IsInitialized()); + + // Should not run. + h.Call(FROM_HERE, &Base::Test); + + b.Kill(); + PumpLoop(); +} + +TEST_F(WeakHandleTest, CallThreaded) { + StrictMock<Base> b; + EXPECT_CALL(b, Test()); + + WeakHandle<Base> h = b.AsWeakHandle(); + // Should run. + CallTestFromOtherThread(FROM_HERE, h); + PumpLoop(); +} + +TEST_F(WeakHandleTest, CallAfterDestroyThreaded) { + WeakHandle<Base> h; + { + StrictMock<Base> b; + EXPECT_CALL(b, Test()).Times(0); + h = b.AsWeakHandle(); + } + + // Should not run. + CallTestFromOtherThread(FROM_HERE, h); + PumpLoop(); +} + +TEST_F(WeakHandleTest, CallAfterInvalidateThreaded) { + StrictMock<Base> b; + EXPECT_CALL(b, Test()).Times(0); + + WeakHandle<Base> h = b.AsWeakHandle(); + b.Kill(); + // Should not run. + CallTestFromOtherThread(FROM_HERE, h); + PumpLoop(); +} + +TEST_F(WeakHandleTest, DeleteOnOtherThread) { + StrictMock<Base> b; + EXPECT_CALL(b, Test()).Times(0); + + WeakHandle<Base>* h = new WeakHandle<Base>(b.AsWeakHandle()); + + { + base::Thread t("Test thread"); + ASSERT_TRUE(t.Start()); + t.message_loop()->DeleteSoon(FROM_HERE, h); + } + + PumpLoop(); +} + +void CallTestWithSelf(const WeakHandle<Base>& b1) { + StrictMock<Base> b2; + b1.Call(FROM_HERE, &Base::TestWithSelf, b2.AsWeakHandle()); +} + +TEST_F(WeakHandleTest, WithDestroyedThread) { + StrictMock<Base> b1; + WeakHandle<Base> b2; + EXPECT_CALL(b1, TestWithSelf(_)).WillOnce(SaveArg<0>(&b2)); + + { + base::Thread t("Test thread"); + ASSERT_TRUE(t.Start()); + t.message_loop()->PostTask(FROM_HERE, + base::Bind(&CallTestWithSelf, + b1.AsWeakHandle())); + } + + // Calls b1.TestWithSelf(). + PumpLoop(); + + // Shouldn't do anything, since the thread is gone. + b2.Call(FROM_HERE, &Base::Test); + + // |b2| shouldn't leak when it's destroyed, even if the original + // thread is gone. +} + +TEST_F(WeakHandleTest, InitializedAcrossCopyAssign) { + StrictMock<Base> b; + EXPECT_CALL(b, Test()).Times(3); + + EXPECT_TRUE(b.AsWeakHandle().IsInitialized()); + b.AsWeakHandle().Call(FROM_HERE, &Base::Test); + + { + WeakHandle<Base> h(b.AsWeakHandle()); + EXPECT_TRUE(h.IsInitialized()); + h.Call(FROM_HERE, &Base::Test); + h.Reset(); + EXPECT_FALSE(h.IsInitialized()); + } + + { + WeakHandle<Base> h; + h = b.AsWeakHandle(); + EXPECT_TRUE(h.IsInitialized()); + h.Call(FROM_HERE, &Base::Test); + h.Reset(); + EXPECT_FALSE(h.IsInitialized()); + } + + PumpLoop(); +} + +TEST_F(WeakHandleTest, TypeConversionConstructor) { + StrictMock<Derived> d; + EXPECT_CALL(d, Test()).Times(2); + + const WeakHandle<Derived> weak_handle = MakeWeakHandle(d.AsWeakPtr()); + + // Should trigger type conversion constructor. + const WeakHandle<Base> base_weak_handle(weak_handle); + // Should trigger regular copy constructor. + const WeakHandle<Derived> derived_weak_handle(weak_handle); + + EXPECT_TRUE(base_weak_handle.IsInitialized()); + base_weak_handle.Call(FROM_HERE, &Base::Test); + + EXPECT_TRUE(derived_weak_handle.IsInitialized()); + // Copy constructor shouldn't construct a new |core_|. + EXPECT_EQ(weak_handle.core_.get(), derived_weak_handle.core_.get()); + derived_weak_handle.Call(FROM_HERE, &Base::Test); + + PumpLoop(); +} + +TEST_F(WeakHandleTest, TypeConversionConstructorMakeWeakHandle) { + const base::WeakPtr<Derived> weak_ptr; + + // Should trigger type conversion constructor after MakeWeakHandle. + WeakHandle<Base> base_weak_handle(MakeWeakHandle(weak_ptr)); + // Should trigger regular copy constructor after MakeWeakHandle. + const WeakHandle<Derived> derived_weak_handle(MakeWeakHandle(weak_ptr)); + + EXPECT_TRUE(base_weak_handle.IsInitialized()); + EXPECT_TRUE(derived_weak_handle.IsInitialized()); +} + +TEST_F(WeakHandleTest, TypeConversionConstructorAssignment) { + const WeakHandle<Derived> weak_handle = + MakeWeakHandle(Derived().AsWeakPtr()); + + // Should trigger type conversion constructor before the assignment. + WeakHandle<Base> base_weak_handle; + base_weak_handle = weak_handle; + // Should trigger regular copy constructor before the assignment. + WeakHandle<Derived> derived_weak_handle; + derived_weak_handle = weak_handle; + + EXPECT_TRUE(base_weak_handle.IsInitialized()); + EXPECT_TRUE(derived_weak_handle.IsInitialized()); + // Copy constructor shouldn't construct a new |core_|. + EXPECT_EQ(weak_handle.core_.get(), derived_weak_handle.core_.get()); +} + +TEST_F(WeakHandleTest, TypeConversionConstructorUninitialized) { + const WeakHandle<Base> base_weak_handle = WeakHandle<Derived>(); + EXPECT_FALSE(base_weak_handle.IsInitialized()); +} + +TEST_F(WeakHandleTest, TypeConversionConstructorUninitializedAssignment) { + WeakHandle<Base> base_weak_handle; + base_weak_handle = WeakHandle<Derived>(); + EXPECT_FALSE(base_weak_handle.IsInitialized()); +} + +} // namespace browser_sync |