- add sources.
[platform/framework/web/crosswalk.git] / src / base / memory / singleton_unittest.cc
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 }