blob: e1292151fab3659bf865b4aa42eea3c936f6d79a [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
brettw16289b3e2017-06-13 21:58:4019template <size_t alignment>
20class AlignedData {
21 public:
22 AlignedData() {}
23 ~AlignedData() {}
24 alignas(alignment) char data_[alignment];
25};
26
[email protected]625332e02010-12-14 07:48:4927class IntSingleton {
28 public:
29 static IntSingleton* GetInstance() {
30 return Singleton<IntSingleton>::get();
31 }
32
33 int value_;
34};
35
36class Init5Singleton {
37 public:
38 struct Trait;
39
40 static Init5Singleton* GetInstance() {
41 return Singleton<Init5Singleton, Trait>::get();
42 }
43
44 int value_;
45};
46
47struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
48 static Init5Singleton* New() {
49 Init5Singleton* instance = new Init5Singleton();
50 instance->value_ = 5;
51 return instance;
[email protected]5820d2f02010-12-11 10:23:3752 }
53};
[email protected]49ab5562010-12-11 09:13:5454
[email protected]625332e02010-12-14 07:48:4955int* SingletonInt() {
56 return &IntSingleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0657}
58
59int* SingletonInt5() {
[email protected]625332e02010-12-14 07:48:4960 return &Init5Singleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0661}
62
[email protected]625332e02010-12-14 07:48:4963template <typename Type>
64struct CallbackTrait : public DefaultSingletonTraits<Type> {
65 static void Delete(Type* instance) {
66 if (instance->callback_)
67 (instance->callback_)();
68 DefaultSingletonTraits<Type>::Delete(instance);
69 }
70};
71
72class CallbackSingleton {
73 public:
74 CallbackSingleton() : callback_(NULL) { }
75 CallbackFunc callback_;
76};
77
78class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
79 public:
80 struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
81
82 CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
83
84 static CallbackSingletonWithNoLeakTrait* GetInstance() {
85 return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
86 }
87};
88
89class CallbackSingletonWithLeakTrait : public CallbackSingleton {
90 public:
91 struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
92 static const bool kRegisterAtExit = false;
93 };
94
95 CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
96
97 static CallbackSingletonWithLeakTrait* GetInstance() {
98 return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
99 }
100};
101
102class CallbackSingletonWithStaticTrait : public CallbackSingleton {
103 public:
104 struct Trait;
105
106 CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
107
108 static CallbackSingletonWithStaticTrait* GetInstance() {
109 return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
110 }
111};
112
113struct CallbackSingletonWithStaticTrait::Trait
114 : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
115 static void Delete(CallbackSingletonWithStaticTrait* instance) {
116 if (instance->callback_)
117 (instance->callback_)();
118 StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
119 instance);
120 }
121};
122
[email protected]cd924d62012-02-23 17:52:20123template <class Type>
124class AlignedTestSingleton {
125 public:
126 AlignedTestSingleton() {}
127 ~AlignedTestSingleton() {}
128 static AlignedTestSingleton* GetInstance() {
129 return Singleton<AlignedTestSingleton,
olli.raula36aa8be2015-09-10 11:14:22130 StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
[email protected]cd924d62012-02-23 17:52:20131 }
132
133 Type type_;
134};
135
[email protected]625332e02010-12-14 07:48:49136
[email protected]4ac8f672008-08-11 14:02:06137void SingletonNoLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49138 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06139}
140
141void SingletonLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49142 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06143}
144
145CallbackFunc* GetLeakySingleton() {
[email protected]625332e02010-12-14 07:48:49146 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
147}
148
149void DeleteLeakySingleton() {
150 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
151 CallbackSingletonWithLeakTrait::GetInstance());
[email protected]4ac8f672008-08-11 14:02:06152}
153
[email protected]297d0e52010-05-07 15:24:49154void SingletonStatic(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49155 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]297d0e52010-05-07 15:24:49156}
157
158CallbackFunc* GetStaticSingleton() {
[email protected]625332e02010-12-14 07:48:49159 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
160}
161
initial.commitd7cae122008-07-26 21:49:38162
163class SingletonTest : public testing::Test {
164 public:
[email protected]44106182012-04-06 03:53:02165 SingletonTest() {}
initial.commitd7cae122008-07-26 21:49:38166
dcheng8aef37612014-12-23 02:56:47167 void SetUp() override {
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
initial.commitd7cae122008-07-26 21:49:38173 protected:
initial.commitd7cae122008-07-26 21:49:38174 void VerifiesCallbacks() {
175 EXPECT_TRUE(non_leak_called_);
176 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49177 EXPECT_TRUE(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
183 void VerifiesCallbacksNotCalled() {
184 EXPECT_FALSE(non_leak_called_);
185 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49186 EXPECT_FALSE(static_called_);
initial.commitd7cae122008-07-26 21:49:38187 non_leak_called_ = false;
188 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49189 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38190 }
191
[email protected]4ac8f672008-08-11 14:02:06192 static void CallbackNoLeak() {
initial.commitd7cae122008-07-26 21:49:38193 non_leak_called_ = true;
194 }
195
[email protected]4ac8f672008-08-11 14:02:06196 static void CallbackLeak() {
initial.commitd7cae122008-07-26 21:49:38197 leaky_called_ = true;
198 }
199
[email protected]297d0e52010-05-07 15:24:49200 static void CallbackStatic() {
201 static_called_ = true;
202 }
203
initial.commitd7cae122008-07-26 21:49:38204 private:
initial.commitd7cae122008-07-26 21:49:38205 static bool non_leak_called_;
206 static bool leaky_called_;
[email protected]297d0e52010-05-07 15:24:49207 static bool static_called_;
initial.commitd7cae122008-07-26 21:49:38208};
209
210bool SingletonTest::non_leak_called_ = false;
211bool SingletonTest::leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49212bool SingletonTest::static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38213
initial.commitd7cae122008-07-26 21:49:38214TEST_F(SingletonTest, Basic) {
[email protected]625332e02010-12-14 07:48:49215 int* singleton_int;
initial.commitd7cae122008-07-26 21:49:38216 int* singleton_int_5;
[email protected]4ac8f672008-08-11 14:02:06217 CallbackFunc* leaky_singleton;
[email protected]297d0e52010-05-07 15:24:49218 CallbackFunc* static_singleton;
initial.commitd7cae122008-07-26 21:49:38219
initial.commitd7cae122008-07-26 21:49:38220 {
olli.raula36aa8be2015-09-10 11:14:22221 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38222 {
[email protected]625332e02010-12-14 07:48:49223 singleton_int = SingletonInt();
initial.commitd7cae122008-07-26 21:49:38224 }
225 // Ensure POD type initialization.
[email protected]625332e02010-12-14 07:48:49226 EXPECT_EQ(*singleton_int, 0);
227 *singleton_int = 1;
initial.commitd7cae122008-07-26 21:49:38228
[email protected]625332e02010-12-14 07:48:49229 EXPECT_EQ(singleton_int, SingletonInt());
230 EXPECT_EQ(*singleton_int, 1);
initial.commitd7cae122008-07-26 21:49:38231
232 {
[email protected]4ac8f672008-08-11 14:02:06233 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38234 }
235 // Is default initialized to 5.
236 EXPECT_EQ(*singleton_int_5, 5);
initial.commitd7cae122008-07-26 21:49:38237
[email protected]4ac8f672008-08-11 14:02:06238 SingletonNoLeak(&CallbackNoLeak);
239 SingletonLeak(&CallbackLeak);
[email protected]297d0e52010-05-07 15:24:49240 SingletonStatic(&CallbackStatic);
241 static_singleton = GetStaticSingleton();
[email protected]4ac8f672008-08-11 14:02:06242 leaky_singleton = GetLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38243 EXPECT_TRUE(leaky_singleton);
244 }
initial.commitd7cae122008-07-26 21:49:38245
246 // Verify that only the expected callback has been called.
247 VerifiesCallbacks();
[email protected]64e95e12011-08-17 17:41:02248 // Delete the leaky singleton.
[email protected]625332e02010-12-14 07:48:49249 DeleteLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38250
[email protected]297d0e52010-05-07 15:24:49251 // The static singleton can't be acquired post-atexit.
252 EXPECT_EQ(NULL, GetStaticSingleton());
253
initial.commitd7cae122008-07-26 21:49:38254 {
olli.raula36aa8be2015-09-10 11:14:22255 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38256 // Verifiy that the variables were reset.
257 {
[email protected]625332e02010-12-14 07:48:49258 singleton_int = SingletonInt();
259 EXPECT_EQ(*singleton_int, 0);
initial.commitd7cae122008-07-26 21:49:38260 }
261 {
[email protected]4ac8f672008-08-11 14:02:06262 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38263 EXPECT_EQ(*singleton_int_5, 5);
264 }
[email protected]297d0e52010-05-07 15:24:49265 {
266 // Resurrect the static singleton, and assert that it
267 // still points to the same (static) memory.
[email protected]625332e02010-12-14 07:48:49268 CallbackSingletonWithStaticTrait::Trait::Resurrect();
[email protected]297d0e52010-05-07 15:24:49269 EXPECT_EQ(GetStaticSingleton(), static_singleton);
270 }
initial.commitd7cae122008-07-26 21:49:38271 }
272 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
initial.commitd7cae122008-07-26 21:49:38273 VerifiesCallbacksNotCalled();
274}
[email protected]cd924d62012-02-23 17:52:20275
276#define EXPECT_ALIGNED(ptr, align) \
277 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
278
279TEST_F(SingletonTest, Alignment) {
[email protected]cd924d62012-02-23 17:52:20280 // Create some static singletons with increasing sizes and alignment
281 // requirements. By ordering this way, the linker will need to do some work to
282 // ensure proper alignment of the static data.
avi9beac252015-12-24 08:44:47283 AlignedTestSingleton<int32_t>* align4 =
284 AlignedTestSingleton<int32_t>::GetInstance();
brettw16289b3e2017-06-13 21:58:40285 AlignedTestSingleton<AlignedData<32>>* align32 =
286 AlignedTestSingleton<AlignedData<32>>::GetInstance();
287 AlignedTestSingleton<AlignedData<128>>* align128 =
288 AlignedTestSingleton<AlignedData<128>>::GetInstance();
289 AlignedTestSingleton<AlignedData<4096>>* align4096 =
290 AlignedTestSingleton<AlignedData<4096>>::GetInstance();
[email protected]cd924d62012-02-23 17:52:20291
292 EXPECT_ALIGNED(align4, 4);
293 EXPECT_ALIGNED(align32, 32);
294 EXPECT_ALIGNED(align128, 128);
295 EXPECT_ALIGNED(align4096, 4096);
296}
olli.raula36aa8be2015-09-10 11:14:22297
298} // namespace
299} // namespace base