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/at_exit.h"
6 #include "base/file_util.h"
7 #include "base/memory/singleton.h"
8 #include "base/path_service.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 namespace {
12
13 COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
14
15 typedef void (*CallbackFunc)();
16
17 class IntSingleton {
18 public:
GetInstance()19 static IntSingleton* GetInstance() {
20 return Singleton<IntSingleton>::get();
21 }
22
23 int value_;
24 };
25
26 class Init5Singleton {
27 public:
28 struct Trait;
29
GetInstance()30 static Init5Singleton* GetInstance() {
31 return Singleton<Init5Singleton, Trait>::get();
32 }
33
34 int value_;
35 };
36
37 struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
New__anon06230e660111::Init5Singleton::Trait38 static Init5Singleton* New() {
39 Init5Singleton* instance = new Init5Singleton();
40 instance->value_ = 5;
41 return instance;
42 }
43 };
44
SingletonInt()45 int* SingletonInt() {
46 return &IntSingleton::GetInstance()->value_;
47 }
48
SingletonInt5()49 int* SingletonInt5() {
50 return &Init5Singleton::GetInstance()->value_;
51 }
52
53 template <typename Type>
54 struct CallbackTrait : public DefaultSingletonTraits<Type> {
Delete__anon06230e660111::CallbackTrait55 static void Delete(Type* instance) {
56 if (instance->callback_)
57 (instance->callback_)();
58 DefaultSingletonTraits<Type>::Delete(instance);
59 }
60 };
61
62 class CallbackSingleton {
63 public:
CallbackSingleton()64 CallbackSingleton() : callback_(NULL) { }
65 CallbackFunc callback_;
66 };
67
68 class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
69 public:
70 struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
71
CallbackSingletonWithNoLeakTrait()72 CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
73
GetInstance()74 static CallbackSingletonWithNoLeakTrait* GetInstance() {
75 return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
76 }
77 };
78
79 class CallbackSingletonWithLeakTrait : public CallbackSingleton {
80 public:
81 struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
82 static const bool kRegisterAtExit = false;
83 };
84
CallbackSingletonWithLeakTrait()85 CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
86
GetInstance()87 static CallbackSingletonWithLeakTrait* GetInstance() {
88 return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
89 }
90 };
91
92 class CallbackSingletonWithStaticTrait : public CallbackSingleton {
93 public:
94 struct Trait;
95
CallbackSingletonWithStaticTrait()96 CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
97
GetInstance()98 static CallbackSingletonWithStaticTrait* GetInstance() {
99 return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
100 }
101 };
102
103 struct CallbackSingletonWithStaticTrait::Trait
104 : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
Delete__anon06230e660111::CallbackSingletonWithStaticTrait::Trait105 static void Delete(CallbackSingletonWithStaticTrait* instance) {
106 if (instance->callback_)
107 (instance->callback_)();
108 StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
109 instance);
110 }
111 };
112
113
SingletonNoLeak(CallbackFunc CallOnQuit)114 void SingletonNoLeak(CallbackFunc CallOnQuit) {
115 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
116 }
117
SingletonLeak(CallbackFunc CallOnQuit)118 void SingletonLeak(CallbackFunc CallOnQuit) {
119 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
120 }
121
GetLeakySingleton()122 CallbackFunc* GetLeakySingleton() {
123 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
124 }
125
DeleteLeakySingleton()126 void DeleteLeakySingleton() {
127 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
128 CallbackSingletonWithLeakTrait::GetInstance());
129 }
130
SingletonStatic(CallbackFunc CallOnQuit)131 void SingletonStatic(CallbackFunc CallOnQuit) {
132 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
133 }
134
GetStaticSingleton()135 CallbackFunc* GetStaticSingleton() {
136 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
137 }
138
ResurrectStaticSingleton()139 void ResurrectStaticSingleton() {
140 }
141
142 } // namespace
143
144 class SingletonTest : public testing::Test {
145 public:
SingletonTest()146 SingletonTest() { }
147
SetUp()148 virtual void SetUp() {
149 non_leak_called_ = false;
150 leaky_called_ = false;
151 static_called_ = false;
152 }
153
154 protected:
VerifiesCallbacks()155 void VerifiesCallbacks() {
156 EXPECT_TRUE(non_leak_called_);
157 EXPECT_FALSE(leaky_called_);
158 EXPECT_TRUE(static_called_);
159 non_leak_called_ = false;
160 leaky_called_ = false;
161 static_called_ = false;
162 }
163
VerifiesCallbacksNotCalled()164 void VerifiesCallbacksNotCalled() {
165 EXPECT_FALSE(non_leak_called_);
166 EXPECT_FALSE(leaky_called_);
167 EXPECT_FALSE(static_called_);
168 non_leak_called_ = false;
169 leaky_called_ = false;
170 static_called_ = false;
171 }
172
CallbackNoLeak()173 static void CallbackNoLeak() {
174 non_leak_called_ = true;
175 }
176
CallbackLeak()177 static void CallbackLeak() {
178 leaky_called_ = true;
179 }
180
CallbackStatic()181 static void CallbackStatic() {
182 static_called_ = true;
183 }
184
185 private:
186 static bool non_leak_called_;
187 static bool leaky_called_;
188 static bool static_called_;
189 };
190
191 bool SingletonTest::non_leak_called_ = false;
192 bool SingletonTest::leaky_called_ = false;
193 bool SingletonTest::static_called_ = false;
194
TEST_F(SingletonTest,Basic)195 TEST_F(SingletonTest, Basic) {
196 int* singleton_int;
197 int* singleton_int_5;
198 CallbackFunc* leaky_singleton;
199 CallbackFunc* static_singleton;
200
201 {
202 base::ShadowingAtExitManager sem;
203 {
204 singleton_int = SingletonInt();
205 }
206 // Ensure POD type initialization.
207 EXPECT_EQ(*singleton_int, 0);
208 *singleton_int = 1;
209
210 EXPECT_EQ(singleton_int, SingletonInt());
211 EXPECT_EQ(*singleton_int, 1);
212
213 {
214 singleton_int_5 = SingletonInt5();
215 }
216 // Is default initialized to 5.
217 EXPECT_EQ(*singleton_int_5, 5);
218
219 SingletonNoLeak(&CallbackNoLeak);
220 SingletonLeak(&CallbackLeak);
221 SingletonStatic(&CallbackStatic);
222 static_singleton = GetStaticSingleton();
223 leaky_singleton = GetLeakySingleton();
224 EXPECT_TRUE(leaky_singleton);
225 }
226
227 // Verify that only the expected callback has been called.
228 VerifiesCallbacks();
229 // Delete the leaky singleton. It is interesting to note that Purify does
230 // *not* detect the leak when this call is commented out. :(
231 DeleteLeakySingleton();
232
233 // The static singleton can't be acquired post-atexit.
234 EXPECT_EQ(NULL, GetStaticSingleton());
235
236 {
237 base::ShadowingAtExitManager sem;
238 // Verifiy that the variables were reset.
239 {
240 singleton_int = SingletonInt();
241 EXPECT_EQ(*singleton_int, 0);
242 }
243 {
244 singleton_int_5 = SingletonInt5();
245 EXPECT_EQ(*singleton_int_5, 5);
246 }
247 {
248 // Resurrect the static singleton, and assert that it
249 // still points to the same (static) memory.
250 CallbackSingletonWithStaticTrait::Trait::Resurrect();
251 EXPECT_EQ(GetStaticSingleton(), static_singleton);
252 }
253 }
254 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
255 VerifiesCallbacksNotCalled();
256 }
257