blob: a15145c8747145cb3f6e6774890307cc0fa46794 [file] [log] [blame]
[email protected]44106182012-04-06 03:53:021// Copyright (c) 2012 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
avi9beac252015-12-24 08:44:475#include <stdint.h>
6
[email protected]4ac8f672008-08-11 14:02:067#include "base/at_exit.h"
[email protected]3b63f8f42011-03-28 01:54:158#include "base/memory/singleton.h"
[email protected]4ac8f672008-08-11 14:02:069#include "testing/gtest/include/gtest/gtest.h"
10
olli.raula36aa8be2015-09-10 11:14:2211namespace base {
[email protected]4ac8f672008-08-11 14:02:0612namespace {
13
avi4ec0dff2015-11-24 14:26:2414static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
15 "object must be deleted on process exit");
[email protected]4ac8f672008-08-11 14:02:0616
[email protected]4ac8f672008-08-11 14:02:0617typedef void (*CallbackFunc)();
18
[email protected]625332e02010-12-14 07:48:4919class IntSingleton {
20 public:
21 static IntSingleton* GetInstance() {
22 return Singleton<IntSingleton>::get();
23 }
24
25 int value_;
26};
27
28class Init5Singleton {
29 public:
30 struct Trait;
31
32 static Init5Singleton* GetInstance() {
33 return Singleton<Init5Singleton, Trait>::get();
34 }
35
36 int value_;
37};
38
39struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
40 static Init5Singleton* New() {
41 Init5Singleton* instance = new Init5Singleton();
42 instance->value_ = 5;
43 return instance;
[email protected]5820d2f02010-12-11 10:23:3744 }
45};
[email protected]49ab5562010-12-11 09:13:5446
[email protected]625332e02010-12-14 07:48:4947int* SingletonInt() {
48 return &IntSingleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0649}
50
51int* SingletonInt5() {
[email protected]625332e02010-12-14 07:48:4952 return &Init5Singleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0653}
54
[email protected]625332e02010-12-14 07:48:4955template <typename Type>
56struct CallbackTrait : public DefaultSingletonTraits<Type> {
57 static void Delete(Type* instance) {
58 if (instance->callback_)
59 (instance->callback_)();
60 DefaultSingletonTraits<Type>::Delete(instance);
61 }
62};
63
64class CallbackSingleton {
65 public:
66 CallbackSingleton() : callback_(NULL) { }
67 CallbackFunc callback_;
68};
69
70class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
71 public:
72 struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
73
74 CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
75
76 static CallbackSingletonWithNoLeakTrait* GetInstance() {
77 return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
78 }
79};
80
81class CallbackSingletonWithLeakTrait : public CallbackSingleton {
82 public:
83 struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
84 static const bool kRegisterAtExit = false;
85 };
86
87 CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
88
89 static CallbackSingletonWithLeakTrait* GetInstance() {
90 return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
91 }
92};
93
94class CallbackSingletonWithStaticTrait : public CallbackSingleton {
95 public:
96 struct Trait;
97
98 CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
99
100 static CallbackSingletonWithStaticTrait* GetInstance() {
101 return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
102 }
103};
104
105struct CallbackSingletonWithStaticTrait::Trait
106 : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
107 static void Delete(CallbackSingletonWithStaticTrait* instance) {
108 if (instance->callback_)
109 (instance->callback_)();
110 StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
111 instance);
112 }
113};
114
[email protected]cd924d62012-02-23 17:52:20115template <class Type>
116class AlignedTestSingleton {
117 public:
118 AlignedTestSingleton() {}
119 ~AlignedTestSingleton() {}
120 static AlignedTestSingleton* GetInstance() {
121 return Singleton<AlignedTestSingleton,
olli.raula36aa8be2015-09-10 11:14:22122 StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
[email protected]cd924d62012-02-23 17:52:20123 }
124
125 Type type_;
126};
127
[email protected]625332e02010-12-14 07:48:49128
[email protected]4ac8f672008-08-11 14:02:06129void SingletonNoLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49130 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06131}
132
133void SingletonLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49134 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06135}
136
137CallbackFunc* GetLeakySingleton() {
[email protected]625332e02010-12-14 07:48:49138 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
139}
140
141void DeleteLeakySingleton() {
142 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
143 CallbackSingletonWithLeakTrait::GetInstance());
[email protected]4ac8f672008-08-11 14:02:06144}
145
[email protected]297d0e52010-05-07 15:24:49146void SingletonStatic(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49147 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]297d0e52010-05-07 15:24:49148}
149
150CallbackFunc* GetStaticSingleton() {
[email protected]625332e02010-12-14 07:48:49151 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
152}
153
initial.commitd7cae122008-07-26 21:49:38154
155class SingletonTest : public testing::Test {
156 public:
[email protected]44106182012-04-06 03:53:02157 SingletonTest() {}
initial.commitd7cae122008-07-26 21:49:38158
dcheng8aef37612014-12-23 02:56:47159 void SetUp() override {
initial.commitd7cae122008-07-26 21:49:38160 non_leak_called_ = false;
161 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49162 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38163 }
164
initial.commitd7cae122008-07-26 21:49:38165 protected:
initial.commitd7cae122008-07-26 21:49:38166 void VerifiesCallbacks() {
167 EXPECT_TRUE(non_leak_called_);
168 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49169 EXPECT_TRUE(static_called_);
initial.commitd7cae122008-07-26 21:49:38170 non_leak_called_ = false;
171 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49172 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38173 }
174
175 void VerifiesCallbacksNotCalled() {
176 EXPECT_FALSE(non_leak_called_);
177 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49178 EXPECT_FALSE(static_called_);
initial.commitd7cae122008-07-26 21:49:38179 non_leak_called_ = false;
180 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49181 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38182 }
183
[email protected]4ac8f672008-08-11 14:02:06184 static void CallbackNoLeak() {
initial.commitd7cae122008-07-26 21:49:38185 non_leak_called_ = true;
186 }
187
[email protected]4ac8f672008-08-11 14:02:06188 static void CallbackLeak() {
initial.commitd7cae122008-07-26 21:49:38189 leaky_called_ = true;
190 }
191
[email protected]297d0e52010-05-07 15:24:49192 static void CallbackStatic() {
193 static_called_ = true;
194 }
195
initial.commitd7cae122008-07-26 21:49:38196 private:
initial.commitd7cae122008-07-26 21:49:38197 static bool non_leak_called_;
198 static bool leaky_called_;
[email protected]297d0e52010-05-07 15:24:49199 static bool static_called_;
initial.commitd7cae122008-07-26 21:49:38200};
201
202bool SingletonTest::non_leak_called_ = false;
203bool SingletonTest::leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49204bool SingletonTest::static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38205
initial.commitd7cae122008-07-26 21:49:38206TEST_F(SingletonTest, Basic) {
[email protected]625332e02010-12-14 07:48:49207 int* singleton_int;
initial.commitd7cae122008-07-26 21:49:38208 int* singleton_int_5;
[email protected]4ac8f672008-08-11 14:02:06209 CallbackFunc* leaky_singleton;
[email protected]297d0e52010-05-07 15:24:49210 CallbackFunc* static_singleton;
initial.commitd7cae122008-07-26 21:49:38211
initial.commitd7cae122008-07-26 21:49:38212 {
olli.raula36aa8be2015-09-10 11:14:22213 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38214 {
[email protected]625332e02010-12-14 07:48:49215 singleton_int = SingletonInt();
initial.commitd7cae122008-07-26 21:49:38216 }
217 // Ensure POD type initialization.
[email protected]625332e02010-12-14 07:48:49218 EXPECT_EQ(*singleton_int, 0);
219 *singleton_int = 1;
initial.commitd7cae122008-07-26 21:49:38220
[email protected]625332e02010-12-14 07:48:49221 EXPECT_EQ(singleton_int, SingletonInt());
222 EXPECT_EQ(*singleton_int, 1);
initial.commitd7cae122008-07-26 21:49:38223
224 {
[email protected]4ac8f672008-08-11 14:02:06225 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38226 }
227 // Is default initialized to 5.
228 EXPECT_EQ(*singleton_int_5, 5);
initial.commitd7cae122008-07-26 21:49:38229
[email protected]4ac8f672008-08-11 14:02:06230 SingletonNoLeak(&CallbackNoLeak);
231 SingletonLeak(&CallbackLeak);
[email protected]297d0e52010-05-07 15:24:49232 SingletonStatic(&CallbackStatic);
233 static_singleton = GetStaticSingleton();
[email protected]4ac8f672008-08-11 14:02:06234 leaky_singleton = GetLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38235 EXPECT_TRUE(leaky_singleton);
236 }
initial.commitd7cae122008-07-26 21:49:38237
238 // Verify that only the expected callback has been called.
239 VerifiesCallbacks();
[email protected]64e95e12011-08-17 17:41:02240 // Delete the leaky singleton.
[email protected]625332e02010-12-14 07:48:49241 DeleteLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38242
[email protected]297d0e52010-05-07 15:24:49243 // The static singleton can't be acquired post-atexit.
244 EXPECT_EQ(NULL, GetStaticSingleton());
245
initial.commitd7cae122008-07-26 21:49:38246 {
olli.raula36aa8be2015-09-10 11:14:22247 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38248 // Verifiy that the variables were reset.
249 {
[email protected]625332e02010-12-14 07:48:49250 singleton_int = SingletonInt();
251 EXPECT_EQ(*singleton_int, 0);
initial.commitd7cae122008-07-26 21:49:38252 }
253 {
[email protected]4ac8f672008-08-11 14:02:06254 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38255 EXPECT_EQ(*singleton_int_5, 5);
256 }
[email protected]297d0e52010-05-07 15:24:49257 {
258 // Resurrect the static singleton, and assert that it
259 // still points to the same (static) memory.
[email protected]625332e02010-12-14 07:48:49260 CallbackSingletonWithStaticTrait::Trait::Resurrect();
[email protected]297d0e52010-05-07 15:24:49261 EXPECT_EQ(GetStaticSingleton(), static_singleton);
262 }
initial.commitd7cae122008-07-26 21:49:38263 }
264 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
initial.commitd7cae122008-07-26 21:49:38265 VerifiesCallbacksNotCalled();
266}
[email protected]cd924d62012-02-23 17:52:20267
268#define EXPECT_ALIGNED(ptr, align) \
269 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
270
271TEST_F(SingletonTest, Alignment) {
272 using base::AlignedMemory;
273
274 // Create some static singletons with increasing sizes and alignment
275 // requirements. By ordering this way, the linker will need to do some work to
276 // ensure proper alignment of the static data.
avi9beac252015-12-24 08:44:47277 AlignedTestSingleton<int32_t>* align4 =
278 AlignedTestSingleton<int32_t>::GetInstance();
[email protected]cd924d62012-02-23 17:52:20279 AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
280 AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
281 AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
282 AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
283 AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
284 AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
285
286 EXPECT_ALIGNED(align4, 4);
287 EXPECT_ALIGNED(align32, 32);
288 EXPECT_ALIGNED(align128, 128);
289 EXPECT_ALIGNED(align4096, 4096);
290}
olli.raula36aa8be2015-09-10 11:14:22291
292} // namespace
293} // namespace base