This source file includes following definitions.
- NewObject
- CreateObject
- CreateArrowFromTarget
- CreateArrowFromArrow
- DeleteTarget
- CopyAndAssignArrow
- CopyAndAssignArrowBase
- DeleteArrow
- DeRef
- DoCreateArrowFromArrow
- DoCreateArrowFromTarget
- DoDeRef
- DoDeleteTarget
- DoCopyAndAssignArrow
- DoCopyAndAssignArrowBase
- DoDeleteArrow
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
#include "base/memory/weak_ptr.h"
#include <string>
#include "base/bind.h"
#include "base/debug/leak_annotations.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
template <class T>
class OffThreadObjectCreator {
public:
static T* NewObject() {
T* result;
{
Thread creator_thread("creator_thread");
creator_thread.Start();
creator_thread.message_loop()->PostTask(
FROM_HERE,
base::Bind(OffThreadObjectCreator::CreateObject, &result));
}
DCHECK(result);
return result;
}
private:
static void CreateObject(T** result) {
*result = new T;
}
};
struct Base {
std::string member;
};
struct Derived : public Base {};
struct TargetBase {};
struct Target : public TargetBase, public SupportsWeakPtr<Target> {
virtual ~Target() {}
};
struct DerivedTarget : public Target {};
struct Arrow {
WeakPtr<Target> target;
};
struct TargetWithFactory : public Target {
TargetWithFactory() : factory(this) {}
WeakPtrFactory<Target> factory;
};
class BackgroundThread : public Thread {
public:
BackgroundThread() : Thread("owner_thread") {}
virtual ~BackgroundThread() {
Stop();
}
void CreateArrowFromTarget(Arrow** arrow, Target* target) {
WaitableEvent completion(true, false);
message_loop()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoCreateArrowFromTarget,
arrow, target, &completion));
completion.Wait();
}
void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
WaitableEvent completion(true, false);
message_loop()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoCreateArrowFromArrow,
arrow, other, &completion));
completion.Wait();
}
void DeleteTarget(Target* object) {
WaitableEvent completion(true, false);
message_loop()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
completion.Wait();
}
void CopyAndAssignArrow(Arrow* object) {
WaitableEvent completion(true, false);
message_loop()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoCopyAndAssignArrow,
object, &completion));
completion.Wait();
}
void CopyAndAssignArrowBase(Arrow* object) {
WaitableEvent completion(true, false);
message_loop()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
object, &completion));
completion.Wait();
}
void DeleteArrow(Arrow* object) {
WaitableEvent completion(true, false);
message_loop()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
completion.Wait();
}
Target* DeRef(const Arrow* arrow) {
WaitableEvent completion(true, false);
Target* result = NULL;
message_loop()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion));
completion.Wait();
return result;
}
protected:
static void DoCreateArrowFromArrow(Arrow** arrow,
const Arrow* other,
WaitableEvent* completion) {
*arrow = new Arrow;
**arrow = *other;
completion->Signal();
}
static void DoCreateArrowFromTarget(Arrow** arrow,
Target* target,
WaitableEvent* completion) {
*arrow = new Arrow;
(*arrow)->target = target->AsWeakPtr();
completion->Signal();
}
static void DoDeRef(const Arrow* arrow,
Target** result,
WaitableEvent* completion) {
*result = arrow->target.get();
completion->Signal();
}
static void DoDeleteTarget(Target* object, WaitableEvent* completion) {
delete object;
completion->Signal();
}
static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) {
Arrow a = *object;
*object = a;
completion->Signal();
}
static void DoCopyAndAssignArrowBase(
Arrow* object,
WaitableEvent* completion) {
WeakPtr<TargetBase> b = object->target;
WeakPtr<TargetBase> c;
c = object->target;
completion->Signal();
}
static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) {
delete object;
completion->Signal();
}
};
}
TEST(WeakPtrFactoryTest, Basic) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr.get());
}
TEST(WeakPtrFactoryTest, Comparison) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr = factory.GetWeakPtr();
WeakPtr<int> ptr2 = ptr;
EXPECT_EQ(ptr.get(), ptr2.get());
}
TEST(WeakPtrFactoryTest, OutOfScope) {
WeakPtr<int> ptr;
EXPECT_EQ(NULL, ptr.get());
{
int data;
WeakPtrFactory<int> factory(&data);
ptr = factory.GetWeakPtr();
}
EXPECT_EQ(NULL, ptr.get());
}
TEST(WeakPtrFactoryTest, Multiple) {
WeakPtr<int> a, b;
{
int data;
WeakPtrFactory<int> factory(&data);
a = factory.GetWeakPtr();
b = factory.GetWeakPtr();
EXPECT_EQ(&data, a.get());
EXPECT_EQ(&data, b.get());
}
EXPECT_EQ(NULL, a.get());
EXPECT_EQ(NULL, b.get());
}
TEST(WeakPtrFactoryTest, MultipleStaged) {
WeakPtr<int> a;
{
int data;
WeakPtrFactory<int> factory(&data);
a = factory.GetWeakPtr();
{
WeakPtr<int> b = factory.GetWeakPtr();
}
EXPECT_TRUE(NULL != a.get());
}
EXPECT_EQ(NULL, a.get());
}
TEST(WeakPtrFactoryTest, Dereference) {
Base data;
data.member = "123456";
WeakPtrFactory<Base> factory(&data);
WeakPtr<Base> ptr = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr.get());
EXPECT_EQ(data.member, (*ptr).member);
EXPECT_EQ(data.member, ptr->member);
}
TEST(WeakPtrFactoryTest, UpCast) {
Derived data;
WeakPtrFactory<Derived> factory(&data);
WeakPtr<Base> ptr = factory.GetWeakPtr();
ptr = factory.GetWeakPtr();
EXPECT_EQ(ptr.get(), &data);
}
TEST(WeakPtrTest, SupportsWeakPtr) {
Target target;
WeakPtr<Target> ptr = target.AsWeakPtr();
EXPECT_EQ(&target, ptr.get());
}
TEST(WeakPtrTest, DerivedTarget) {
DerivedTarget target;
WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target);
EXPECT_EQ(&target, ptr.get());
}
TEST(WeakPtrTest, InvalidateWeakPtrs) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr.get());
EXPECT_TRUE(factory.HasWeakPtrs());
factory.InvalidateWeakPtrs();
EXPECT_EQ(NULL, ptr.get());
EXPECT_FALSE(factory.HasWeakPtrs());
}
TEST(WeakPtrTest, HasWeakPtrs) {
int data;
WeakPtrFactory<int> factory(&data);
{
WeakPtr<int> ptr = factory.GetWeakPtr();
EXPECT_TRUE(factory.HasWeakPtrs());
}
EXPECT_FALSE(factory.HasWeakPtrs());
}
TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject());
WeakPtr<Target> weak_ptr = target->AsWeakPtr();
EXPECT_EQ(target.get(), weak_ptr.get());
}
TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject());
Target target;
arrow->target = target.AsWeakPtr();
EXPECT_EQ(&target, arrow->target.get());
}
TEST(WeakPtrTest, MoveOwnershipImplicitly) {
BackgroundThread background;
background.Start();
Target* target = new Target();
{
WeakPtr<Target> weak_ptr = target->AsWeakPtr();
}
Arrow* arrow;
background.CreateArrowFromTarget(&arrow, target);
EXPECT_EQ(background.DeRef(arrow), target);
{
Arrow arrow;
arrow.target = target->AsWeakPtr();
EXPECT_EQ(target, background.DeRef(&arrow));
}
background.DeleteTarget(target);
background.DeleteArrow(arrow);
}
TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) {
BackgroundThread background;
background.Start();
Arrow* arrow;
{
Target target;
background.CreateArrowFromTarget(&arrow, &target);
EXPECT_EQ(&target, background.DeRef(arrow));
arrow->target.reset();
arrow->target = target.AsWeakPtr();
EXPECT_EQ(&target, arrow->target.get());
}
delete arrow;
}
TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) {
BackgroundThread background;
background.Start();
Arrow arrow;
scoped_ptr<TargetWithFactory> target(new TargetWithFactory);
arrow.target = target->factory.GetWeakPtr();
EXPECT_EQ(target.get(), arrow.target.get());
target->factory.InvalidateWeakPtrs();
EXPECT_EQ(NULL, arrow.target.get());
arrow.target = target->factory.GetWeakPtr();
EXPECT_EQ(target.get(), background.DeRef(&arrow));
background.DeleteTarget(target.release());
}
TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) {
BackgroundThread background;
background.Start();
Target target;
Arrow arrow;
arrow.target = target.AsWeakPtr();
Arrow* arrow_copy;
background.CreateArrowFromArrow(&arrow_copy, &arrow);
EXPECT_EQ(arrow_copy->target.get(), &target);
background.DeleteArrow(arrow_copy);
}
TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) {
BackgroundThread background;
background.Start();
Target target;
Arrow* arrow_copy;
{
Arrow arrow;
arrow.target = target.AsWeakPtr();
background.CreateArrowFromArrow(&arrow_copy, &arrow);
}
EXPECT_EQ(arrow_copy->target.get(), &target);
background.DeleteArrow(arrow_copy);
}
TEST(WeakPtrTest, OwnerThreadDeletesObject) {
BackgroundThread background;
background.Start();
Arrow* arrow_copy;
{
Target target;
Arrow arrow;
arrow.target = target.AsWeakPtr();
background.CreateArrowFromArrow(&arrow_copy, &arrow);
}
EXPECT_EQ(NULL, arrow_copy->target.get());
background.DeleteArrow(arrow_copy);
}
TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) {
Target target;
Arrow *arrow = new Arrow();
arrow->target = target.AsWeakPtr();
BackgroundThread background;
background.Start();
background.CopyAndAssignArrow(arrow);
background.DeleteArrow(arrow);
}
TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) {
Target target;
Arrow *arrow = new Arrow();
arrow->target = target.AsWeakPtr();
BackgroundThread background;
background.Start();
background.CopyAndAssignArrowBase(arrow);
background.DeleteArrow(arrow);
}
TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) {
Target target;
Arrow* arrow = new Arrow();
arrow->target = target.AsWeakPtr();
BackgroundThread background;
background.Start();
background.DeleteArrow(arrow);
}
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
BackgroundThread background;
background.Start();
Target target;
Arrow arrow;
arrow.target = target.AsWeakPtr();
Arrow* arrow_copy;
background.CreateArrowFromArrow(&arrow_copy, &arrow);
EXPECT_EQ(arrow.target.get(), arrow_copy->target.get());
ASSERT_DEATH(background.DeRef(arrow_copy), "");
background.DeleteArrow(arrow_copy);
}
TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
Target target;
Arrow arrow;
arrow.target = target.AsWeakPtr();
arrow.target.get();
BackgroundThread background;
background.Start();
ASSERT_DEATH(background.DeRef(&arrow), "");
}
TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
scoped_ptr<Target> target(new Target());
Arrow arrow;
arrow.target = target->AsWeakPtr();
BackgroundThread background;
background.Start();
background.DeRef(&arrow);
ASSERT_DEATH(target.reset(), "");
background.DeleteTarget(target.release());
}
TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
scoped_ptr<Target> target(new Target());
Arrow arrow;
arrow.target = target->AsWeakPtr();
arrow.target.get();
BackgroundThread background;
background.Start();
ASSERT_DEATH(background.DeleteTarget(target.release()), "");
}
TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
scoped_ptr<Target> target(new Target());
Arrow arrow;
arrow.target = target->AsWeakPtr();
BackgroundThread background;
background.Start();
background.DeleteTarget(target.release());
ASSERT_DEATH(arrow.target.get(), "");
}
#endif
}