• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
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 "base/at_exit.h"
6 #include "base/file_util.h"
7 #include "base/memory/singleton.h"
8 #include "base/path_service.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace {
12 
13 COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
14 
15 typedef void (*CallbackFunc)();
16 
17 class IntSingleton {
18  public:
GetInstance()19   static IntSingleton* GetInstance() {
20     return Singleton<IntSingleton>::get();
21   }
22 
23   int value_;
24 };
25 
26 class Init5Singleton {
27  public:
28   struct Trait;
29 
GetInstance()30   static Init5Singleton* GetInstance() {
31     return Singleton<Init5Singleton, Trait>::get();
32   }
33 
34   int value_;
35 };
36 
37 struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
New__anon06230e660111::Init5Singleton::Trait38   static Init5Singleton* New() {
39     Init5Singleton* instance = new Init5Singleton();
40     instance->value_ = 5;
41     return instance;
42   }
43 };
44 
SingletonInt()45 int* SingletonInt() {
46   return &IntSingleton::GetInstance()->value_;
47 }
48 
SingletonInt5()49 int* SingletonInt5() {
50   return &Init5Singleton::GetInstance()->value_;
51 }
52 
53 template <typename Type>
54 struct CallbackTrait : public DefaultSingletonTraits<Type> {
Delete__anon06230e660111::CallbackTrait55   static void Delete(Type* instance) {
56     if (instance->callback_)
57       (instance->callback_)();
58     DefaultSingletonTraits<Type>::Delete(instance);
59   }
60 };
61 
62 class CallbackSingleton {
63  public:
CallbackSingleton()64   CallbackSingleton() : callback_(NULL) { }
65   CallbackFunc callback_;
66 };
67 
68 class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
69  public:
70   struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
71 
CallbackSingletonWithNoLeakTrait()72   CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
73 
GetInstance()74   static CallbackSingletonWithNoLeakTrait* GetInstance() {
75     return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
76   }
77 };
78 
79 class CallbackSingletonWithLeakTrait : public CallbackSingleton {
80  public:
81   struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
82     static const bool kRegisterAtExit = false;
83   };
84 
CallbackSingletonWithLeakTrait()85   CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
86 
GetInstance()87   static CallbackSingletonWithLeakTrait* GetInstance() {
88     return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
89   }
90 };
91 
92 class CallbackSingletonWithStaticTrait : public CallbackSingleton {
93  public:
94   struct Trait;
95 
CallbackSingletonWithStaticTrait()96   CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
97 
GetInstance()98   static CallbackSingletonWithStaticTrait* GetInstance() {
99     return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
100   }
101 };
102 
103 struct CallbackSingletonWithStaticTrait::Trait
104     : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
Delete__anon06230e660111::CallbackSingletonWithStaticTrait::Trait105   static void Delete(CallbackSingletonWithStaticTrait* instance) {
106     if (instance->callback_)
107       (instance->callback_)();
108     StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
109         instance);
110   }
111 };
112 
113 
SingletonNoLeak(CallbackFunc CallOnQuit)114 void SingletonNoLeak(CallbackFunc CallOnQuit) {
115   CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
116 }
117 
SingletonLeak(CallbackFunc CallOnQuit)118 void SingletonLeak(CallbackFunc CallOnQuit) {
119   CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
120 }
121 
GetLeakySingleton()122 CallbackFunc* GetLeakySingleton() {
123   return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
124 }
125 
DeleteLeakySingleton()126 void DeleteLeakySingleton() {
127   DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
128       CallbackSingletonWithLeakTrait::GetInstance());
129 }
130 
SingletonStatic(CallbackFunc CallOnQuit)131 void SingletonStatic(CallbackFunc CallOnQuit) {
132   CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
133 }
134 
GetStaticSingleton()135 CallbackFunc* GetStaticSingleton() {
136   return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
137 }
138 
ResurrectStaticSingleton()139 void ResurrectStaticSingleton() {
140 }
141 
142 }  // namespace
143 
144 class SingletonTest : public testing::Test {
145  public:
SingletonTest()146   SingletonTest() { }
147 
SetUp()148   virtual void SetUp() {
149     non_leak_called_ = false;
150     leaky_called_ = false;
151     static_called_ = false;
152   }
153 
154  protected:
VerifiesCallbacks()155   void VerifiesCallbacks() {
156     EXPECT_TRUE(non_leak_called_);
157     EXPECT_FALSE(leaky_called_);
158     EXPECT_TRUE(static_called_);
159     non_leak_called_ = false;
160     leaky_called_ = false;
161     static_called_ = false;
162   }
163 
VerifiesCallbacksNotCalled()164   void VerifiesCallbacksNotCalled() {
165     EXPECT_FALSE(non_leak_called_);
166     EXPECT_FALSE(leaky_called_);
167     EXPECT_FALSE(static_called_);
168     non_leak_called_ = false;
169     leaky_called_ = false;
170     static_called_ = false;
171   }
172 
CallbackNoLeak()173   static void CallbackNoLeak() {
174     non_leak_called_ = true;
175   }
176 
CallbackLeak()177   static void CallbackLeak() {
178     leaky_called_ = true;
179   }
180 
CallbackStatic()181   static void CallbackStatic() {
182     static_called_ = true;
183   }
184 
185  private:
186   static bool non_leak_called_;
187   static bool leaky_called_;
188   static bool static_called_;
189 };
190 
191 bool SingletonTest::non_leak_called_ = false;
192 bool SingletonTest::leaky_called_ = false;
193 bool SingletonTest::static_called_ = false;
194 
TEST_F(SingletonTest,Basic)195 TEST_F(SingletonTest, Basic) {
196   int* singleton_int;
197   int* singleton_int_5;
198   CallbackFunc* leaky_singleton;
199   CallbackFunc* static_singleton;
200 
201   {
202     base::ShadowingAtExitManager sem;
203     {
204       singleton_int = SingletonInt();
205     }
206     // Ensure POD type initialization.
207     EXPECT_EQ(*singleton_int, 0);
208     *singleton_int = 1;
209 
210     EXPECT_EQ(singleton_int, SingletonInt());
211     EXPECT_EQ(*singleton_int, 1);
212 
213     {
214       singleton_int_5 = SingletonInt5();
215     }
216     // Is default initialized to 5.
217     EXPECT_EQ(*singleton_int_5, 5);
218 
219     SingletonNoLeak(&CallbackNoLeak);
220     SingletonLeak(&CallbackLeak);
221     SingletonStatic(&CallbackStatic);
222     static_singleton = GetStaticSingleton();
223     leaky_singleton = GetLeakySingleton();
224     EXPECT_TRUE(leaky_singleton);
225   }
226 
227   // Verify that only the expected callback has been called.
228   VerifiesCallbacks();
229   // Delete the leaky singleton. It is interesting to note that Purify does
230   // *not* detect the leak when this call is commented out. :(
231   DeleteLeakySingleton();
232 
233   // The static singleton can't be acquired post-atexit.
234   EXPECT_EQ(NULL, GetStaticSingleton());
235 
236   {
237     base::ShadowingAtExitManager sem;
238     // Verifiy that the variables were reset.
239     {
240       singleton_int = SingletonInt();
241       EXPECT_EQ(*singleton_int, 0);
242     }
243     {
244       singleton_int_5 = SingletonInt5();
245       EXPECT_EQ(*singleton_int_5, 5);
246     }
247     {
248       // Resurrect the static singleton, and assert that it
249       // still points to the same (static) memory.
250       CallbackSingletonWithStaticTrait::Trait::Resurrect();
251       EXPECT_EQ(GetStaticSingleton(), static_singleton);
252     }
253   }
254   // The leaky singleton shouldn't leak since SingletonLeak has not been called.
255   VerifiesCallbacksNotCalled();
256 }
257