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