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/memory/scoped_ptr.h"
6#include "base/memory/weak_ptr.h"
7#include "testing/gtest/include/gtest/gtest.h"
8#include "base/message_loop.h"
9#include "base/threading/thread.h"
10
11namespace base {
12namespace {
13
14template <class T>
15class OffThreadObjectCreator {
16 public:
17  static T* NewObject() {
18    T* result;
19    {
20      Thread creator_thread("creator_thread");
21      creator_thread.Start();
22      creator_thread.message_loop()->PostTask(
23          FROM_HERE,
24          NewRunnableFunction(OffThreadObjectCreator::CreateObject, &result));
25    }
26    DCHECK(result);  // We synchronized on thread destruction above.
27    return result;
28  }
29 private:
30  static void CreateObject(T** result) {
31    *result = new T;
32  }
33};
34
35struct Base {};
36struct Derived : Base {};
37
38struct Producer : SupportsWeakPtr<Producer> {};
39struct Consumer { WeakPtr<Producer> producer; };
40
41}  // namespace
42
43TEST(WeakPtrTest, Basic) {
44  int data;
45  WeakPtrFactory<int> factory(&data);
46  WeakPtr<int> ptr = factory.GetWeakPtr();
47  EXPECT_EQ(&data, ptr.get());
48}
49
50TEST(WeakPtrTest, Comparison) {
51  int data;
52  WeakPtrFactory<int> factory(&data);
53  WeakPtr<int> ptr = factory.GetWeakPtr();
54  WeakPtr<int> ptr2 = ptr;
55  EXPECT_TRUE(ptr == ptr2);
56}
57
58TEST(WeakPtrTest, OutOfScope) {
59  WeakPtr<int> ptr;
60  EXPECT_TRUE(ptr.get() == NULL);
61  {
62    int data;
63    WeakPtrFactory<int> factory(&data);
64    ptr = factory.GetWeakPtr();
65  }
66  EXPECT_TRUE(ptr.get() == NULL);
67}
68
69TEST(WeakPtrTest, Multiple) {
70  WeakPtr<int> a, b;
71  {
72    int data;
73    WeakPtrFactory<int> factory(&data);
74    a = factory.GetWeakPtr();
75    b = factory.GetWeakPtr();
76    EXPECT_EQ(&data, a.get());
77    EXPECT_EQ(&data, b.get());
78  }
79  EXPECT_TRUE(a.get() == NULL);
80  EXPECT_TRUE(b.get() == NULL);
81}
82
83TEST(WeakPtrTest, UpCast) {
84  Derived data;
85  WeakPtrFactory<Derived> factory(&data);
86  WeakPtr<Base> ptr = factory.GetWeakPtr();
87  ptr = factory.GetWeakPtr();
88  EXPECT_EQ(ptr.get(), &data);
89}
90
91TEST(WeakPtrTest, SupportsWeakPtr) {
92  Producer f;
93  WeakPtr<Producer> ptr = f.AsWeakPtr();
94  EXPECT_EQ(&f, ptr.get());
95}
96
97TEST(WeakPtrTest, InvalidateWeakPtrs) {
98  int data;
99  WeakPtrFactory<int> factory(&data);
100  WeakPtr<int> ptr = factory.GetWeakPtr();
101  EXPECT_EQ(&data, ptr.get());
102  EXPECT_TRUE(factory.HasWeakPtrs());
103  factory.InvalidateWeakPtrs();
104  EXPECT_TRUE(ptr.get() == NULL);
105  EXPECT_FALSE(factory.HasWeakPtrs());
106}
107
108TEST(WeakPtrTest, HasWeakPtrs) {
109  int data;
110  WeakPtrFactory<int> factory(&data);
111  {
112    WeakPtr<int> ptr = factory.GetWeakPtr();
113    EXPECT_TRUE(factory.HasWeakPtrs());
114  }
115  EXPECT_FALSE(factory.HasWeakPtrs());
116}
117
118TEST(WeakPtrTest, SingleThreaded1) {
119  // Test that it is OK to create a class that supports weak references on one
120  // thread, but use it on another.  This tests that we do not trip runtime
121  // checks that ensure that a weak reference is not used by multiple threads.
122  scoped_ptr<Producer> producer(OffThreadObjectCreator<Producer>::NewObject());
123  WeakPtr<Producer> weak_producer = producer->AsWeakPtr();
124  EXPECT_EQ(producer.get(), weak_producer.get());
125}
126
127TEST(WeakPtrTest, SingleThreaded2) {
128  // Test that it is OK to create a class that has a WeakPtr member on one
129  // thread, but use it on another.  This tests that we do not trip runtime
130  // checks that ensure that a weak reference is not used by multiple threads.
131  scoped_ptr<Consumer> consumer(OffThreadObjectCreator<Consumer>::NewObject());
132  Producer producer;
133  consumer->producer = producer.AsWeakPtr();
134  EXPECT_EQ(&producer, consumer->producer.get());
135}
136
137}  // namespace base
138