singleton_unittest.cc 7.4 KB

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