blob: 33928a760eb3ec60709b09999311e726f67d354a [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// 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"
[email protected]3b63f8f42011-03-28 01:54:157#include "base/memory/singleton.h"
initial.commitd7cae122008-07-26 21:49:388#include "base/path_service.h"
[email protected]4ac8f672008-08-11 14:02:069#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
[email protected]cd924d62012-02-23 17:52:20113template <class Type>
114class AlignedTestSingleton {
115 public:
116 AlignedTestSingleton() {}
117 ~AlignedTestSingleton() {}
118 static AlignedTestSingleton* GetInstance() {
119 return Singleton<AlignedTestSingleton,
120 StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
121 }
122
123 Type type_;
124};
125
[email protected]625332e02010-12-14 07:48:49126
[email protected]4ac8f672008-08-11 14:02:06127void SingletonNoLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49128 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06129}
130
131void SingletonLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49132 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06133}
134
135CallbackFunc* GetLeakySingleton() {
[email protected]625332e02010-12-14 07:48:49136 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
137}
138
139void DeleteLeakySingleton() {
140 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
141 CallbackSingletonWithLeakTrait::GetInstance());
[email protected]4ac8f672008-08-11 14:02:06142}
143
[email protected]297d0e52010-05-07 15:24:49144void SingletonStatic(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49145 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]297d0e52010-05-07 15:24:49146}
147
148CallbackFunc* GetStaticSingleton() {
[email protected]625332e02010-12-14 07:48:49149 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
150}
151
[email protected]4ac8f672008-08-11 14:02:06152} // namespace
initial.commitd7cae122008-07-26 21:49:38153
154class SingletonTest : public testing::Test {
155 public:
[email protected]4ac8f672008-08-11 14:02:06156 SingletonTest() { }
initial.commitd7cae122008-07-26 21:49:38157
158 virtual void SetUp() {
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
initial.commitd7cae122008-07-26 21:49:38164 protected:
initial.commitd7cae122008-07-26 21:49:38165 void VerifiesCallbacks() {
166 EXPECT_TRUE(non_leak_called_);
167 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49168 EXPECT_TRUE(static_called_);
initial.commitd7cae122008-07-26 21:49:38169 non_leak_called_ = false;
170 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49171 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38172 }
173
174 void VerifiesCallbacksNotCalled() {
175 EXPECT_FALSE(non_leak_called_);
176 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49177 EXPECT_FALSE(static_called_);
initial.commitd7cae122008-07-26 21:49:38178 non_leak_called_ = false;
179 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49180 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38181 }
182
[email protected]4ac8f672008-08-11 14:02:06183 static void CallbackNoLeak() {
initial.commitd7cae122008-07-26 21:49:38184 non_leak_called_ = true;
185 }
186
[email protected]4ac8f672008-08-11 14:02:06187 static void CallbackLeak() {
initial.commitd7cae122008-07-26 21:49:38188 leaky_called_ = true;
189 }
190
[email protected]297d0e52010-05-07 15:24:49191 static void CallbackStatic() {
192 static_called_ = true;
193 }
194
initial.commitd7cae122008-07-26 21:49:38195 private:
initial.commitd7cae122008-07-26 21:49:38196 static bool non_leak_called_;
197 static bool leaky_called_;
[email protected]297d0e52010-05-07 15:24:49198 static bool static_called_;
initial.commitd7cae122008-07-26 21:49:38199};
200
201bool SingletonTest::non_leak_called_ = false;
202bool SingletonTest::leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49203bool SingletonTest::static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38204
initial.commitd7cae122008-07-26 21:49:38205TEST_F(SingletonTest, Basic) {
[email protected]625332e02010-12-14 07:48:49206 int* singleton_int;
initial.commitd7cae122008-07-26 21:49:38207 int* singleton_int_5;
[email protected]4ac8f672008-08-11 14:02:06208 CallbackFunc* leaky_singleton;
[email protected]297d0e52010-05-07 15:24:49209 CallbackFunc* static_singleton;
initial.commitd7cae122008-07-26 21:49:38210
initial.commitd7cae122008-07-26 21:49:38211 {
[email protected]4ea927b2009-11-19 09:11:39212 base::ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38213 {
[email protected]625332e02010-12-14 07:48:49214 singleton_int = SingletonInt();
initial.commitd7cae122008-07-26 21:49:38215 }
216 // Ensure POD type initialization.
[email protected]625332e02010-12-14 07:48:49217 EXPECT_EQ(*singleton_int, 0);
218 *singleton_int = 1;
initial.commitd7cae122008-07-26 21:49:38219
[email protected]625332e02010-12-14 07:48:49220 EXPECT_EQ(singleton_int, SingletonInt());
221 EXPECT_EQ(*singleton_int, 1);
initial.commitd7cae122008-07-26 21:49:38222
223 {
[email protected]4ac8f672008-08-11 14:02:06224 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38225 }
226 // Is default initialized to 5.
227 EXPECT_EQ(*singleton_int_5, 5);
initial.commitd7cae122008-07-26 21:49:38228
[email protected]4ac8f672008-08-11 14:02:06229 SingletonNoLeak(&CallbackNoLeak);
230 SingletonLeak(&CallbackLeak);
[email protected]297d0e52010-05-07 15:24:49231 SingletonStatic(&CallbackStatic);
232 static_singleton = GetStaticSingleton();
[email protected]4ac8f672008-08-11 14:02:06233 leaky_singleton = GetLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38234 EXPECT_TRUE(leaky_singleton);
235 }
initial.commitd7cae122008-07-26 21:49:38236
237 // Verify that only the expected callback has been called.
238 VerifiesCallbacks();
[email protected]64e95e12011-08-17 17:41:02239 // Delete the leaky singleton.
[email protected]625332e02010-12-14 07:48:49240 DeleteLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38241
[email protected]297d0e52010-05-07 15:24:49242 // The static singleton can't be acquired post-atexit.
243 EXPECT_EQ(NULL, GetStaticSingleton());
244
initial.commitd7cae122008-07-26 21:49:38245 {
[email protected]4ea927b2009-11-19 09:11:39246 base::ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38247 // Verifiy that the variables were reset.
248 {
[email protected]625332e02010-12-14 07:48:49249 singleton_int = SingletonInt();
250 EXPECT_EQ(*singleton_int, 0);
initial.commitd7cae122008-07-26 21:49:38251 }
252 {
[email protected]4ac8f672008-08-11 14:02:06253 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38254 EXPECT_EQ(*singleton_int_5, 5);
255 }
[email protected]297d0e52010-05-07 15:24:49256 {
257 // Resurrect the static singleton, and assert that it
258 // still points to the same (static) memory.
[email protected]625332e02010-12-14 07:48:49259 CallbackSingletonWithStaticTrait::Trait::Resurrect();
[email protected]297d0e52010-05-07 15:24:49260 EXPECT_EQ(GetStaticSingleton(), static_singleton);
261 }
initial.commitd7cae122008-07-26 21:49:38262 }
263 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
initial.commitd7cae122008-07-26 21:49:38264 VerifiesCallbacksNotCalled();
265}
[email protected]cd924d62012-02-23 17:52:20266
267#define EXPECT_ALIGNED(ptr, align) \
268 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
269
270TEST_F(SingletonTest, Alignment) {
271 using base::AlignedMemory;
272
273 // Create some static singletons with increasing sizes and alignment
274 // requirements. By ordering this way, the linker will need to do some work to
275 // ensure proper alignment of the static data.
276 AlignedTestSingleton<int32>* align4 =
277 AlignedTestSingleton<int32>::GetInstance();
278 AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
279 AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
280 AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
281 AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
282 AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
283 AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
284
285 EXPECT_ALIGNED(align4, 4);
286 EXPECT_ALIGNED(align32, 32);
287 EXPECT_ALIGNED(align128, 128);
288 EXPECT_ALIGNED(align4096, 4096);
289}