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 11namespace { 12 13COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a); 14 15typedef void (*CallbackFunc)(); 16 17class IntSingleton { 18 public: 19 static IntSingleton* GetInstance() { 20 return Singleton<IntSingleton>::get(); 21 } 22 23 int value_; 24}; 25 26class Init5Singleton { 27 public: 28 struct Trait; 29 30 static Init5Singleton* GetInstance() { 31 return Singleton<Init5Singleton, Trait>::get(); 32 } 33 34 int value_; 35}; 36 37struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> { 38 static Init5Singleton* New() { 39 Init5Singleton* instance = new Init5Singleton(); 40 instance->value_ = 5; 41 return instance; 42 } 43}; 44 45int* SingletonInt() { 46 return &IntSingleton::GetInstance()->value_; 47} 48 49int* SingletonInt5() { 50 return &Init5Singleton::GetInstance()->value_; 51} 52 53template <typename Type> 54struct CallbackTrait : public DefaultSingletonTraits<Type> { 55 static void Delete(Type* instance) { 56 if (instance->callback_) 57 (instance->callback_)(); 58 DefaultSingletonTraits<Type>::Delete(instance); 59 } 60}; 61 62class CallbackSingleton { 63 public: 64 CallbackSingleton() : callback_(NULL) { } 65 CallbackFunc callback_; 66}; 67 68class 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 79class 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 92class 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 103struct 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); 110 } 111}; 112 113 114void SingletonNoLeak(CallbackFunc CallOnQuit) { 115 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit; 116} 117 118void SingletonLeak(CallbackFunc CallOnQuit) { 119 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit; 120} 121 122CallbackFunc* GetLeakySingleton() { 123 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_; 124} 125 126void DeleteLeakySingleton() { 127 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete( 128 CallbackSingletonWithLeakTrait::GetInstance()); 129} 130 131void SingletonStatic(CallbackFunc CallOnQuit) { 132 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit; 133} 134 135CallbackFunc* GetStaticSingleton() { 136 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_; 137} 138 139void ResurrectStaticSingleton() { 140} 141 142} // namespace 143 144class SingletonTest : public testing::Test { 145 public: 146 SingletonTest() { } 147 148 virtual void SetUp() { 149 non_leak_called_ = false; 150 leaky_called_ = false; 151 static_called_ = false; 152 } 153 154 protected: 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 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 173 static void CallbackNoLeak() { 174 non_leak_called_ = true; 175 } 176 177 static void CallbackLeak() { 178 leaky_called_ = true; 179 } 180 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 191bool SingletonTest::non_leak_called_ = false; 192bool SingletonTest::leaky_called_ = false; 193bool SingletonTest::static_called_ = false; 194 195TEST_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