xref: /aosp_15_r20/external/cronet/base/memory/singleton_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdint.h>
6 
7 #include "base/at_exit.h"
8 #include "base/memory/aligned_memory.h"
9 #include "base/memory/singleton.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace base {
13 namespace {
14 
15 static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
16               "object must be deleted on process exit");
17 
18 typedef void (*CallbackFunc)();
19 
20 template <size_t alignment>
21 class AlignedData {
22  public:
23   AlignedData() = default;
24   ~AlignedData() = default;
25   alignas(alignment) char data_[alignment];
26 };
27 
28 class IntSingleton {
29  public:
GetInstance()30   static IntSingleton* GetInstance() {
31     return Singleton<IntSingleton>::get();
32   }
33 
34   int value_;
35 };
36 
37 class Init5Singleton {
38  public:
39   struct Trait;
40 
GetInstance()41   static Init5Singleton* GetInstance() {
42     return Singleton<Init5Singleton, Trait>::get();
43   }
44 
45   int value_;
46 };
47 
48 struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
Newbase::__anon2f1763790111::Init5Singleton::Trait49   static Init5Singleton* New() {
50     Init5Singleton* instance = new Init5Singleton();
51     instance->value_ = 5;
52     return instance;
53   }
54 };
55 
SingletonInt()56 int* SingletonInt() {
57   return &IntSingleton::GetInstance()->value_;
58 }
59 
SingletonInt5()60 int* SingletonInt5() {
61   return &Init5Singleton::GetInstance()->value_;
62 }
63 
64 template <typename Type>
65 struct CallbackTrait : public DefaultSingletonTraits<Type> {
Deletebase::__anon2f1763790111::CallbackTrait66   static void Delete(Type* instance) {
67     if (instance->callback_)
68       (instance->callback_)();
69     DefaultSingletonTraits<Type>::Delete(instance);
70   }
71 };
72 
73 class CallbackSingleton {
74  public:
CallbackSingleton()75   CallbackSingleton() : callback_(nullptr) {}
76   CallbackFunc callback_;
77 };
78 
79 class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
80  public:
81   struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
82 
CallbackSingletonWithNoLeakTrait()83   CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
84 
GetInstance()85   static CallbackSingletonWithNoLeakTrait* GetInstance() {
86     return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
87   }
88 };
89 
90 class CallbackSingletonWithLeakTrait : public CallbackSingleton {
91  public:
92   struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
93     static const bool kRegisterAtExit = false;
94   };
95 
CallbackSingletonWithLeakTrait()96   CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
97 
GetInstance()98   static CallbackSingletonWithLeakTrait* GetInstance() {
99     return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
100   }
101 };
102 
103 class CallbackSingletonWithStaticTrait : public CallbackSingleton {
104  public:
105   struct Trait;
106 
CallbackSingletonWithStaticTrait()107   CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
108 
GetInstance()109   static CallbackSingletonWithStaticTrait* GetInstance() {
110     return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
111   }
112 };
113 
114 struct CallbackSingletonWithStaticTrait::Trait
115     : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
Deletebase::__anon2f1763790111::CallbackSingletonWithStaticTrait::Trait116   static void Delete(CallbackSingletonWithStaticTrait* instance) {
117     if (instance->callback_)
118       (instance->callback_)();
119     StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
120         instance);
121   }
122 };
123 
124 template <class Type>
125 class AlignedTestSingleton {
126  public:
127   AlignedTestSingleton() = default;
128   ~AlignedTestSingleton() = default;
GetInstance()129   static AlignedTestSingleton* GetInstance() {
130     return Singleton<AlignedTestSingleton,
131                      StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
132   }
133 
134   Type type_;
135 };
136 
137 
SingletonNoLeak(CallbackFunc CallOnQuit)138 void SingletonNoLeak(CallbackFunc CallOnQuit) {
139   CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
140 }
141 
SingletonLeak(CallbackFunc CallOnQuit)142 void SingletonLeak(CallbackFunc CallOnQuit) {
143   CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
144 }
145 
GetLeakySingleton()146 CallbackFunc* GetLeakySingleton() {
147   return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
148 }
149 
DeleteLeakySingleton()150 void DeleteLeakySingleton() {
151   DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
152       CallbackSingletonWithLeakTrait::GetInstance());
153 }
154 
SingletonStatic(CallbackFunc CallOnQuit)155 void SingletonStatic(CallbackFunc CallOnQuit) {
156   CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
157 }
158 
GetStaticSingleton()159 CallbackFunc* GetStaticSingleton() {
160   CallbackSingletonWithStaticTrait* instance =
161       CallbackSingletonWithStaticTrait::GetInstance();
162   if (instance == nullptr) {
163     return nullptr;
164   } else {
165     return &instance->callback_;
166   }
167 }
168 
169 class SingletonTest : public testing::Test {
170  public:
171   SingletonTest() = default;
172 
SetUp()173   void SetUp() override {
174     non_leak_called_ = false;
175     leaky_called_ = false;
176     static_called_ = false;
177   }
178 
179  protected:
VerifiesCallbacks()180   void VerifiesCallbacks() {
181     EXPECT_TRUE(non_leak_called_);
182     EXPECT_FALSE(leaky_called_);
183     EXPECT_TRUE(static_called_);
184     non_leak_called_ = false;
185     leaky_called_ = false;
186     static_called_ = false;
187   }
188 
VerifiesCallbacksNotCalled()189   void VerifiesCallbacksNotCalled() {
190     EXPECT_FALSE(non_leak_called_);
191     EXPECT_FALSE(leaky_called_);
192     EXPECT_FALSE(static_called_);
193     non_leak_called_ = false;
194     leaky_called_ = false;
195     static_called_ = false;
196   }
197 
CallbackNoLeak()198   static void CallbackNoLeak() {
199     non_leak_called_ = true;
200   }
201 
CallbackLeak()202   static void CallbackLeak() {
203     leaky_called_ = true;
204   }
205 
CallbackStatic()206   static void CallbackStatic() {
207     static_called_ = true;
208   }
209 
210  private:
211   static bool non_leak_called_;
212   static bool leaky_called_;
213   static bool static_called_;
214 };
215 
216 bool SingletonTest::non_leak_called_ = false;
217 bool SingletonTest::leaky_called_ = false;
218 bool SingletonTest::static_called_ = false;
219 
TEST_F(SingletonTest,Basic)220 TEST_F(SingletonTest, Basic) {
221   int* singleton_int;
222   int* singleton_int_5;
223   CallbackFunc* leaky_singleton;
224   CallbackFunc* static_singleton;
225 
226   {
227     ShadowingAtExitManager sem;
228     {
229       singleton_int = SingletonInt();
230     }
231     // Ensure POD type initialization.
232     EXPECT_EQ(*singleton_int, 0);
233     *singleton_int = 1;
234 
235     EXPECT_EQ(singleton_int, SingletonInt());
236     EXPECT_EQ(*singleton_int, 1);
237 
238     {
239       singleton_int_5 = SingletonInt5();
240     }
241     // Is default initialized to 5.
242     EXPECT_EQ(*singleton_int_5, 5);
243 
244     SingletonNoLeak(&CallbackNoLeak);
245     SingletonLeak(&CallbackLeak);
246     SingletonStatic(&CallbackStatic);
247     static_singleton = GetStaticSingleton();
248     leaky_singleton = GetLeakySingleton();
249     EXPECT_TRUE(leaky_singleton);
250   }
251 
252   // Verify that only the expected callback has been called.
253   VerifiesCallbacks();
254   // Delete the leaky singleton.
255   DeleteLeakySingleton();
256 
257   // The static singleton can't be acquired post-atexit.
258   EXPECT_EQ(nullptr, GetStaticSingleton());
259 
260   {
261     ShadowingAtExitManager sem;
262     // Verifiy that the variables were reset.
263     {
264       singleton_int = SingletonInt();
265       EXPECT_EQ(*singleton_int, 0);
266     }
267     {
268       singleton_int_5 = SingletonInt5();
269       EXPECT_EQ(*singleton_int_5, 5);
270     }
271     {
272       // Resurrect the static singleton, and assert that it
273       // still points to the same (static) memory.
274       CallbackSingletonWithStaticTrait::Trait::ResurrectForTesting();
275       EXPECT_EQ(GetStaticSingleton(), static_singleton);
276     }
277   }
278   // The leaky singleton shouldn't leak since SingletonLeak has not been called.
279   VerifiesCallbacksNotCalled();
280 }
281 
TEST_F(SingletonTest,Alignment)282 TEST_F(SingletonTest, Alignment) {
283   // Create some static singletons with increasing sizes and alignment
284   // requirements. By ordering this way, the linker will need to do some work to
285   // ensure proper alignment of the static data.
286   AlignedTestSingleton<int32_t>* align4 =
287       AlignedTestSingleton<int32_t>::GetInstance();
288   AlignedTestSingleton<AlignedData<32>>* align32 =
289       AlignedTestSingleton<AlignedData<32>>::GetInstance();
290   AlignedTestSingleton<AlignedData<128>>* align128 =
291       AlignedTestSingleton<AlignedData<128>>::GetInstance();
292   AlignedTestSingleton<AlignedData<4096>>* align4096 =
293       AlignedTestSingleton<AlignedData<4096>>::GetInstance();
294 
295   EXPECT_TRUE(IsAligned(align4, 4));
296   EXPECT_TRUE(IsAligned(align32, 32));
297   EXPECT_TRUE(IsAligned(align128, 128));
298   EXPECT_TRUE(IsAligned(align4096, 4096));
299 }
300 
301 }  // namespace
302 }  // namespace base
303