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