blob: 3d7e7e60d10d5f47e801d5b379aa9dd99be45ffc [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commitd7cae122008-07-26 21:49:384
[email protected]4ac8f672008-08-11 14:02:065#include "base/at_exit.h"
initial.commitd7cae122008-07-26 21:49:386#include "base/file_util.h"
7#include "base/path_service.h"
[email protected]4ac8f672008-08-11 14:02:068#include "base/singleton.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace {
12
[email protected]4ac8f672008-08-11 14:02:0613COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
14
[email protected]4ac8f672008-08-11 14:02:0615typedef void (*CallbackFunc)();
16
[email protected]625332e02010-12-14 07:48:4917class IntSingleton {
18 public:
19 static IntSingleton* GetInstance() {
20 return Singleton<IntSingleton>::get();
21 }
22
23 int value_;
24};
25
26class Init5Singleton {
27 public:
28 struct Trait;
29
30 static Init5Singleton* GetInstance() {
31 return Singleton<Init5Singleton, Trait>::get();
32 }
33
34 int value_;
35};
36
37struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
38 static Init5Singleton* New() {
39 Init5Singleton* instance = new Init5Singleton();
40 instance->value_ = 5;
41 return instance;
[email protected]5820d2f02010-12-11 10:23:3742 }
43};
[email protected]49ab5562010-12-11 09:13:5444
[email protected]625332e02010-12-14 07:48:4945int* SingletonInt() {
46 return &IntSingleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0647}
48
49int* SingletonInt5() {
[email protected]625332e02010-12-14 07:48:4950 return &Init5Singleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0651}
52
[email protected]625332e02010-12-14 07:48:4953template <typename Type>
54struct CallbackTrait : public DefaultSingletonTraits<Type> {
55 static void Delete(Type* instance) {
56 if (instance->callback_)
57 (instance->callback_)();
58 DefaultSingletonTraits<Type>::Delete(instance);
59 }
60};
61
62class CallbackSingleton {
63 public:
64 CallbackSingleton() : callback_(NULL) { }
65 CallbackFunc callback_;
66};
67
68class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
69 public:
70 struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
71
72 CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
73
74 static CallbackSingletonWithNoLeakTrait* GetInstance() {
75 return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
76 }
77};
78
79class CallbackSingletonWithLeakTrait : public CallbackSingleton {
80 public:
81 struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
82 static const bool kRegisterAtExit = false;
83 };
84
85 CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
86
87 static CallbackSingletonWithLeakTrait* GetInstance() {
88 return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
89 }
90};
91
92class CallbackSingletonWithStaticTrait : public CallbackSingleton {
93 public:
94 struct Trait;
95
96 CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
97
98 static CallbackSingletonWithStaticTrait* GetInstance() {
99 return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
100 }
101};
102
103struct CallbackSingletonWithStaticTrait::Trait
104 : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
105 static void Delete(CallbackSingletonWithStaticTrait* instance) {
106 if (instance->callback_)
107 (instance->callback_)();
108 StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
109 instance);
110 }
111};
112
113
[email protected]4ac8f672008-08-11 14:02:06114void SingletonNoLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49115 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06116}
117
118void SingletonLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49119 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06120}
121
122CallbackFunc* GetLeakySingleton() {
[email protected]625332e02010-12-14 07:48:49123 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
124}
125
126void DeleteLeakySingleton() {
127 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
128 CallbackSingletonWithLeakTrait::GetInstance());
[email protected]4ac8f672008-08-11 14:02:06129}
130
[email protected]297d0e52010-05-07 15:24:49131void SingletonStatic(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49132 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]297d0e52010-05-07 15:24:49133}
134
135CallbackFunc* GetStaticSingleton() {
[email protected]625332e02010-12-14 07:48:49136 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
137}
138
139void ResurrectStaticSingleton() {
[email protected]297d0e52010-05-07 15:24:49140}
141
[email protected]4ac8f672008-08-11 14:02:06142} // namespace
initial.commitd7cae122008-07-26 21:49:38143
144class SingletonTest : public testing::Test {
145 public:
[email protected]4ac8f672008-08-11 14:02:06146 SingletonTest() { }
initial.commitd7cae122008-07-26 21:49:38147
148 virtual void SetUp() {
initial.commitd7cae122008-07-26 21:49:38149 non_leak_called_ = false;
150 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49151 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38152 }
153
initial.commitd7cae122008-07-26 21:49:38154 protected:
initial.commitd7cae122008-07-26 21:49:38155 void VerifiesCallbacks() {
156 EXPECT_TRUE(non_leak_called_);
157 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49158 EXPECT_TRUE(static_called_);
initial.commitd7cae122008-07-26 21:49:38159 non_leak_called_ = false;
160 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49161 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38162 }
163
164 void VerifiesCallbacksNotCalled() {
165 EXPECT_FALSE(non_leak_called_);
166 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49167 EXPECT_FALSE(static_called_);
initial.commitd7cae122008-07-26 21:49:38168 non_leak_called_ = false;
169 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49170 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38171 }
172
[email protected]4ac8f672008-08-11 14:02:06173 static void CallbackNoLeak() {
initial.commitd7cae122008-07-26 21:49:38174 non_leak_called_ = true;
175 }
176
[email protected]4ac8f672008-08-11 14:02:06177 static void CallbackLeak() {
initial.commitd7cae122008-07-26 21:49:38178 leaky_called_ = true;
179 }
180
[email protected]297d0e52010-05-07 15:24:49181 static void CallbackStatic() {
182 static_called_ = true;
183 }
184
initial.commitd7cae122008-07-26 21:49:38185 private:
initial.commitd7cae122008-07-26 21:49:38186 static bool non_leak_called_;
187 static bool leaky_called_;
[email protected]297d0e52010-05-07 15:24:49188 static bool static_called_;
initial.commitd7cae122008-07-26 21:49:38189};
190
191bool SingletonTest::non_leak_called_ = false;
192bool SingletonTest::leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49193bool SingletonTest::static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38194
initial.commitd7cae122008-07-26 21:49:38195TEST_F(SingletonTest, Basic) {
[email protected]625332e02010-12-14 07:48:49196 int* singleton_int;
initial.commitd7cae122008-07-26 21:49:38197 int* singleton_int_5;
[email protected]4ac8f672008-08-11 14:02:06198 CallbackFunc* leaky_singleton;
[email protected]297d0e52010-05-07 15:24:49199 CallbackFunc* static_singleton;
initial.commitd7cae122008-07-26 21:49:38200
initial.commitd7cae122008-07-26 21:49:38201 {
[email protected]4ea927b2009-11-19 09:11:39202 base::ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38203 {
[email protected]625332e02010-12-14 07:48:49204 singleton_int = SingletonInt();
initial.commitd7cae122008-07-26 21:49:38205 }
206 // Ensure POD type initialization.
[email protected]625332e02010-12-14 07:48:49207 EXPECT_EQ(*singleton_int, 0);
208 *singleton_int = 1;
initial.commitd7cae122008-07-26 21:49:38209
[email protected]625332e02010-12-14 07:48:49210 EXPECT_EQ(singleton_int, SingletonInt());
211 EXPECT_EQ(*singleton_int, 1);
initial.commitd7cae122008-07-26 21:49:38212
213 {
[email protected]4ac8f672008-08-11 14:02:06214 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38215 }
216 // Is default initialized to 5.
217 EXPECT_EQ(*singleton_int_5, 5);
initial.commitd7cae122008-07-26 21:49:38218
[email protected]4ac8f672008-08-11 14:02:06219 SingletonNoLeak(&CallbackNoLeak);
220 SingletonLeak(&CallbackLeak);
[email protected]297d0e52010-05-07 15:24:49221 SingletonStatic(&CallbackStatic);
222 static_singleton = GetStaticSingleton();
[email protected]4ac8f672008-08-11 14:02:06223 leaky_singleton = GetLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38224 EXPECT_TRUE(leaky_singleton);
225 }
initial.commitd7cae122008-07-26 21:49:38226
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. :(
[email protected]625332e02010-12-14 07:48:49231 DeleteLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38232
[email protected]297d0e52010-05-07 15:24:49233 // The static singleton can't be acquired post-atexit.
234 EXPECT_EQ(NULL, GetStaticSingleton());
235
initial.commitd7cae122008-07-26 21:49:38236 {
[email protected]4ea927b2009-11-19 09:11:39237 base::ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38238 // Verifiy that the variables were reset.
239 {
[email protected]625332e02010-12-14 07:48:49240 singleton_int = SingletonInt();
241 EXPECT_EQ(*singleton_int, 0);
initial.commitd7cae122008-07-26 21:49:38242 }
243 {
[email protected]4ac8f672008-08-11 14:02:06244 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38245 EXPECT_EQ(*singleton_int_5, 5);
246 }
[email protected]297d0e52010-05-07 15:24:49247 {
248 // Resurrect the static singleton, and assert that it
249 // still points to the same (static) memory.
[email protected]625332e02010-12-14 07:48:49250 CallbackSingletonWithStaticTrait::Trait::Resurrect();
[email protected]297d0e52010-05-07 15:24:49251 EXPECT_EQ(GetStaticSingleton(), static_singleton);
252 }
initial.commitd7cae122008-07-26 21:49:38253 }
254 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
initial.commitd7cae122008-07-26 21:49:38255 VerifiesCallbacksNotCalled();
256}