blob: 815d6f2b404c88a16a599b6e71ed83eb3e3817db [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:
Chris Watkinsbb7211c2017-11-29 07:16:3822 AlignedData() = default;
23 ~AlignedData() = default;
brettw16289b3e2017-06-13 21:58:4024 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:
Ivan Kotenkova16212a52017-11-08 12:37:3374 CallbackSingleton() : callback_(nullptr) {}
[email protected]625332e02010-12-14 07:48:4975 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:
Chris Watkinsbb7211c2017-11-29 07:16:38126 AlignedTestSingleton() = default;
127 ~AlignedTestSingleton() = default;
[email protected]cd924d62012-02-23 17:52:20128 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() {
Sergei Datsenkoca37cc62020-06-08 18:59:59159 CallbackSingletonWithStaticTrait* instance =
160 CallbackSingletonWithStaticTrait::GetInstance();
161 if (instance == nullptr) {
162 return nullptr;
163 } else {
164 return &instance->callback_;
165 }
[email protected]625332e02010-12-14 07:48:49166}
167
initial.commitd7cae122008-07-26 21:49:38168class SingletonTest : public testing::Test {
169 public:
Chris Watkinsbb7211c2017-11-29 07:16:38170 SingletonTest() = default;
initial.commitd7cae122008-07-26 21:49:38171
dcheng8aef37612014-12-23 02:56:47172 void SetUp() override {
initial.commitd7cae122008-07-26 21:49:38173 non_leak_called_ = false;
174 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49175 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38176 }
177
initial.commitd7cae122008-07-26 21:49:38178 protected:
initial.commitd7cae122008-07-26 21:49:38179 void VerifiesCallbacks() {
180 EXPECT_TRUE(non_leak_called_);
181 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49182 EXPECT_TRUE(static_called_);
initial.commitd7cae122008-07-26 21:49:38183 non_leak_called_ = false;
184 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49185 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38186 }
187
188 void VerifiesCallbacksNotCalled() {
189 EXPECT_FALSE(non_leak_called_);
190 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49191 EXPECT_FALSE(static_called_);
initial.commitd7cae122008-07-26 21:49:38192 non_leak_called_ = false;
193 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49194 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38195 }
196
[email protected]4ac8f672008-08-11 14:02:06197 static void CallbackNoLeak() {
initial.commitd7cae122008-07-26 21:49:38198 non_leak_called_ = true;
199 }
200
[email protected]4ac8f672008-08-11 14:02:06201 static void CallbackLeak() {
initial.commitd7cae122008-07-26 21:49:38202 leaky_called_ = true;
203 }
204
[email protected]297d0e52010-05-07 15:24:49205 static void CallbackStatic() {
206 static_called_ = true;
207 }
208
initial.commitd7cae122008-07-26 21:49:38209 private:
initial.commitd7cae122008-07-26 21:49:38210 static bool non_leak_called_;
211 static bool leaky_called_;
[email protected]297d0e52010-05-07 15:24:49212 static bool static_called_;
initial.commitd7cae122008-07-26 21:49:38213};
214
215bool SingletonTest::non_leak_called_ = false;
216bool SingletonTest::leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49217bool SingletonTest::static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38218
initial.commitd7cae122008-07-26 21:49:38219TEST_F(SingletonTest, Basic) {
[email protected]625332e02010-12-14 07:48:49220 int* singleton_int;
initial.commitd7cae122008-07-26 21:49:38221 int* singleton_int_5;
[email protected]4ac8f672008-08-11 14:02:06222 CallbackFunc* leaky_singleton;
[email protected]297d0e52010-05-07 15:24:49223 CallbackFunc* static_singleton;
initial.commitd7cae122008-07-26 21:49:38224
initial.commitd7cae122008-07-26 21:49:38225 {
olli.raula36aa8be2015-09-10 11:14:22226 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38227 {
[email protected]625332e02010-12-14 07:48:49228 singleton_int = SingletonInt();
initial.commitd7cae122008-07-26 21:49:38229 }
230 // Ensure POD type initialization.
[email protected]625332e02010-12-14 07:48:49231 EXPECT_EQ(*singleton_int, 0);
232 *singleton_int = 1;
initial.commitd7cae122008-07-26 21:49:38233
[email protected]625332e02010-12-14 07:48:49234 EXPECT_EQ(singleton_int, SingletonInt());
235 EXPECT_EQ(*singleton_int, 1);
initial.commitd7cae122008-07-26 21:49:38236
237 {
[email protected]4ac8f672008-08-11 14:02:06238 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38239 }
240 // Is default initialized to 5.
241 EXPECT_EQ(*singleton_int_5, 5);
initial.commitd7cae122008-07-26 21:49:38242
[email protected]4ac8f672008-08-11 14:02:06243 SingletonNoLeak(&CallbackNoLeak);
244 SingletonLeak(&CallbackLeak);
[email protected]297d0e52010-05-07 15:24:49245 SingletonStatic(&CallbackStatic);
246 static_singleton = GetStaticSingleton();
[email protected]4ac8f672008-08-11 14:02:06247 leaky_singleton = GetLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38248 EXPECT_TRUE(leaky_singleton);
249 }
initial.commitd7cae122008-07-26 21:49:38250
251 // Verify that only the expected callback has been called.
252 VerifiesCallbacks();
[email protected]64e95e12011-08-17 17:41:02253 // Delete the leaky singleton.
[email protected]625332e02010-12-14 07:48:49254 DeleteLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38255
[email protected]297d0e52010-05-07 15:24:49256 // The static singleton can't be acquired post-atexit.
Ivan Kotenkova16212a52017-11-08 12:37:33257 EXPECT_EQ(nullptr, GetStaticSingleton());
[email protected]297d0e52010-05-07 15:24:49258
initial.commitd7cae122008-07-26 21:49:38259 {
olli.raula36aa8be2015-09-10 11:14:22260 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38261 // Verifiy that the variables were reset.
262 {
[email protected]625332e02010-12-14 07:48:49263 singleton_int = SingletonInt();
264 EXPECT_EQ(*singleton_int, 0);
initial.commitd7cae122008-07-26 21:49:38265 }
266 {
[email protected]4ac8f672008-08-11 14:02:06267 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38268 EXPECT_EQ(*singleton_int_5, 5);
269 }
[email protected]297d0e52010-05-07 15:24:49270 {
271 // Resurrect the static singleton, and assert that it
272 // still points to the same (static) memory.
Gabriel Charettef297f012018-01-17 20:59:07273 CallbackSingletonWithStaticTrait::Trait::ResurrectForTesting();
[email protected]297d0e52010-05-07 15:24:49274 EXPECT_EQ(GetStaticSingleton(), static_singleton);
275 }
initial.commitd7cae122008-07-26 21:49:38276 }
277 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
initial.commitd7cae122008-07-26 21:49:38278 VerifiesCallbacksNotCalled();
279}
[email protected]cd924d62012-02-23 17:52:20280
281#define EXPECT_ALIGNED(ptr, align) \
282 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
283
284TEST_F(SingletonTest, Alignment) {
[email protected]cd924d62012-02-23 17:52:20285 // Create some static singletons with increasing sizes and alignment
286 // requirements. By ordering this way, the linker will need to do some work to
287 // ensure proper alignment of the static data.
avi9beac252015-12-24 08:44:47288 AlignedTestSingleton<int32_t>* align4 =
289 AlignedTestSingleton<int32_t>::GetInstance();
brettw16289b3e2017-06-13 21:58:40290 AlignedTestSingleton<AlignedData<32>>* align32 =
291 AlignedTestSingleton<AlignedData<32>>::GetInstance();
292 AlignedTestSingleton<AlignedData<128>>* align128 =
293 AlignedTestSingleton<AlignedData<128>>::GetInstance();
294 AlignedTestSingleton<AlignedData<4096>>* align4096 =
295 AlignedTestSingleton<AlignedData<4096>>::GetInstance();
[email protected]cd924d62012-02-23 17:52:20296
297 EXPECT_ALIGNED(align4, 4);
298 EXPECT_ALIGNED(align32, 32);
299 EXPECT_ALIGNED(align128, 128);
300 EXPECT_ALIGNED(align4096, 4096);
301}
olli.raula36aa8be2015-09-10 11:14:22302
303} // namespace
304} // namespace base