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