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: 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 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; 42 } 43 }; 44 45 int* SingletonInt() { 46 return &IntSingleton::GetInstance()->value_; 47 } 48 49 int* SingletonInt5() { 50 return &Init5Singleton::GetInstance()->value_; 51 } 52 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); 59 } 60 }; 61 62 class CallbackSingleton { 63 public: 64 CallbackSingleton() : callback_(NULL) { } 65 CallbackFunc callback_; 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); 110 } 111 }; 112 113 114 void SingletonNoLeak(CallbackFunc CallOnQuit) { 115 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit; 116 } 117 118 void SingletonLeak(CallbackFunc CallOnQuit) { 119 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit; 120 } 121 122 CallbackFunc* GetLeakySingleton() { 123 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_; 124 } 125 126 void DeleteLeakySingleton() { 127 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete( 128 CallbackSingletonWithLeakTrait::GetInstance()); 129 } 130 131 void SingletonStatic(CallbackFunc CallOnQuit) { 132 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit; 133 } 134 135 CallbackFunc* GetStaticSingleton() { 136 return &CallbackSingletonWithStaticTrait::GetInstance()->callback_; 137 } 138 139 void ResurrectStaticSingleton() { 140 } 141 142 } // namespace 143 144 class 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 191 bool SingletonTest::non_leak_called_ = false; 192 bool SingletonTest::leaky_called_ = false; 193 bool SingletonTest::static_called_ = false; 194 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