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 10namespace { 11 12COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a); 13 14typedef void (*CallbackFunc)(); 15 16class IntSingleton { 17 public: 18 static IntSingleton* GetInstance() { 19 return Singleton<IntSingleton>::get(); 20 } 21 22 int value_; 23}; 24 25class Init5Singleton { 26 public: 27 struct Trait; 28 29 static Init5Singleton* GetInstance() { 30 return Singleton<Init5Singleton, Trait>::get(); 31 } 32 33 int value_; 34}; 35 36struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> { 37 static Init5Singleton* New() { 38 Init5Singleton* instance = new Init5Singleton(); 39 instance->value_ = 5; 40 return instance; 41 } 42}; 43 44int* SingletonInt() { 45 return &IntSingleton::GetInstance()->value_; 46} 47 48int* SingletonInt5() { 49 return &Init5Singleton::GetInstance()->value_; 50} 51 52template <typename Type> 53struct 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 61class CallbackSingleton { 62 public: 63 CallbackSingleton() : callback_(NULL) { } 64 CallbackFunc callback_; 65}; 66 67class 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 78class 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 91class 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 102struct 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 112template <class Type> 113class 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 126void SingletonNoLeak(CallbackFunc CallOnQuit) { 127 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit; 128} 129 130void SingletonLeak(CallbackFunc CallOnQuit) { 131 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit; 132} 133 134CallbackFunc* GetLeakySingleton() { 135 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_; 136} 137 138void DeleteLeakySingleton() { 139 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete( 140 CallbackSingletonWithLeakTrait::GetInstance()); 141} 142 143void SingletonStatic(CallbackFunc CallOnQuit) { 144 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit; 145} 146 147CallbackFunc* GetStaticSingleton() { 148 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_; 149} 150 151} // namespace 152 153class 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 200bool SingletonTest::non_leak_called_ = false; 201bool SingletonTest::leaky_called_ = false; 202bool SingletonTest::static_called_ = false; 203 204TEST_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 269TEST_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