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