blob: 8fd8b930a73bda93cbf7bc06e0f59ca848029cab [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
deanm@google.com4c68cc62008-08-11 23:02:06 +09005#include "base/at_exit.h"
initial.commit3f4a7322008-07-27 06:49:38 +09006#include "base/file_util.h"
7#include "base/path_service.h"
deanm@google.com4c68cc62008-08-11 23:02:06 +09008#include "base/singleton.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace {
12
13class ShadowingAtExitManager : public base::AtExitManager {
14 public:
15 ShadowingAtExitManager() : AtExitManager(true) { }
16};
17
18COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
19
20template<typename Type>
21struct LockTrait : public DefaultSingletonTraits<Type> {
22};
23
24struct Init5Trait : public DefaultSingletonTraits<int> {
25 static int* New() {
26 return new int(5);
27 }
28};
29
30typedef void (*CallbackFunc)();
31
32struct CallbackTrait : public DefaultSingletonTraits<CallbackFunc> {
33 static void Delete(CallbackFunc* p) {
34 if (*p)
35 (*p)();
36 DefaultSingletonTraits<CallbackFunc>::Delete(p);
37 }
38};
39
40struct NoLeakTrait : public CallbackTrait {
41};
42
43struct LeakTrait : public CallbackTrait {
44 static const bool kRegisterAtExit = false;
45};
46
47int* SingletonInt1() {
48 return Singleton<int>::get();
49}
50
51int* SingletonInt2() {
52 // Force to use a different singleton than SingletonInt1.
53 return Singleton<int, DefaultSingletonTraits<int> >::get();
54}
55
56class DummyDifferentiatingClass {
57};
58
59int* SingletonInt3() {
60 // Force to use a different singleton than SingletonInt1 and SingletonInt2.
61 // Note that any type can be used; int, float, std::wstring...
62 return Singleton<int, DefaultSingletonTraits<int>,
63 DummyDifferentiatingClass>::get();
64}
65
66int* SingletonInt4() {
67 return Singleton<int, LockTrait<int> >::get();
68}
69
70int* SingletonInt5() {
71 return Singleton<int, Init5Trait>::get();
72}
73
74void SingletonNoLeak(CallbackFunc CallOnQuit) {
75 *Singleton<CallbackFunc, NoLeakTrait>::get() = CallOnQuit;
76}
77
78void SingletonLeak(CallbackFunc CallOnQuit) {
79 *Singleton<CallbackFunc, LeakTrait>::get() = CallOnQuit;
80}
81
82CallbackFunc* GetLeakySingleton() {
83 return Singleton<CallbackFunc, LeakTrait>::get();
84}
85
86} // namespace
initial.commit3f4a7322008-07-27 06:49:38 +090087
88class SingletonTest : public testing::Test {
89 public:
deanm@google.com4c68cc62008-08-11 23:02:06 +090090 SingletonTest() { }
initial.commit3f4a7322008-07-27 06:49:38 +090091
92 virtual void SetUp() {
initial.commit3f4a7322008-07-27 06:49:38 +090093 non_leak_called_ = false;
94 leaky_called_ = false;
95 }
96
initial.commit3f4a7322008-07-27 06:49:38 +090097 protected:
initial.commit3f4a7322008-07-27 06:49:38 +090098 void VerifiesCallbacks() {
99 EXPECT_TRUE(non_leak_called_);
100 EXPECT_FALSE(leaky_called_);
101 non_leak_called_ = false;
102 leaky_called_ = false;
103 }
104
105 void VerifiesCallbacksNotCalled() {
106 EXPECT_FALSE(non_leak_called_);
107 EXPECT_FALSE(leaky_called_);
108 non_leak_called_ = false;
109 leaky_called_ = false;
110 }
111
deanm@google.com4c68cc62008-08-11 23:02:06 +0900112 static void CallbackNoLeak() {
initial.commit3f4a7322008-07-27 06:49:38 +0900113 non_leak_called_ = true;
114 }
115
deanm@google.com4c68cc62008-08-11 23:02:06 +0900116 static void CallbackLeak() {
initial.commit3f4a7322008-07-27 06:49:38 +0900117 leaky_called_ = true;
118 }
119
120 private:
initial.commit3f4a7322008-07-27 06:49:38 +0900121 static bool non_leak_called_;
122 static bool leaky_called_;
123};
124
125bool SingletonTest::non_leak_called_ = false;
126bool SingletonTest::leaky_called_ = false;
127
initial.commit3f4a7322008-07-27 06:49:38 +0900128TEST_F(SingletonTest, Basic) {
initial.commit3f4a7322008-07-27 06:49:38 +0900129 int* singleton_int_1;
130 int* singleton_int_2;
131 int* singleton_int_3;
132 int* singleton_int_4;
133 int* singleton_int_5;
deanm@google.com4c68cc62008-08-11 23:02:06 +0900134 CallbackFunc* leaky_singleton;
initial.commit3f4a7322008-07-27 06:49:38 +0900135
initial.commit3f4a7322008-07-27 06:49:38 +0900136 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900137 ShadowingAtExitManager sem;
initial.commit3f4a7322008-07-27 06:49:38 +0900138 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900139 singleton_int_1 = SingletonInt1();
initial.commit3f4a7322008-07-27 06:49:38 +0900140 }
141 // Ensure POD type initialization.
142 EXPECT_EQ(*singleton_int_1, 0);
143 *singleton_int_1 = 1;
144
deanm@google.com4c68cc62008-08-11 23:02:06 +0900145 EXPECT_EQ(singleton_int_1, SingletonInt1());
initial.commit3f4a7322008-07-27 06:49:38 +0900146 EXPECT_EQ(*singleton_int_1, 1);
147
148 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900149 singleton_int_2 = SingletonInt2();
initial.commit3f4a7322008-07-27 06:49:38 +0900150 }
151 // Same instance that 1.
152 EXPECT_EQ(*singleton_int_2, 1);
153 EXPECT_EQ(singleton_int_1, singleton_int_2);
154
155 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900156 singleton_int_3 = SingletonInt3();
initial.commit3f4a7322008-07-27 06:49:38 +0900157 }
158 // Different instance than 1 and 2.
159 EXPECT_EQ(*singleton_int_3, 0);
160 EXPECT_NE(singleton_int_1, singleton_int_3);
161 *singleton_int_3 = 3;
162 EXPECT_EQ(*singleton_int_1, 1);
163 EXPECT_EQ(*singleton_int_2, 1);
164
165 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900166 singleton_int_4 = SingletonInt4();
initial.commit3f4a7322008-07-27 06:49:38 +0900167 }
168 // Use a lock for creation. Not really tested at length.
169 EXPECT_EQ(*singleton_int_4, 0);
170 *singleton_int_4 = 4;
171 EXPECT_NE(singleton_int_1, singleton_int_4);
172 EXPECT_NE(singleton_int_3, singleton_int_4);
173
174 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900175 singleton_int_5 = SingletonInt5();
initial.commit3f4a7322008-07-27 06:49:38 +0900176 }
177 // Is default initialized to 5.
178 EXPECT_EQ(*singleton_int_5, 5);
179 EXPECT_NE(singleton_int_1, singleton_int_5);
180 EXPECT_NE(singleton_int_3, singleton_int_5);
181 EXPECT_NE(singleton_int_4, singleton_int_5);
initial.commit3f4a7322008-07-27 06:49:38 +0900182
deanm@google.com4c68cc62008-08-11 23:02:06 +0900183 SingletonNoLeak(&CallbackNoLeak);
184 SingletonLeak(&CallbackLeak);
185 leaky_singleton = GetLeakySingleton();
initial.commit3f4a7322008-07-27 06:49:38 +0900186 EXPECT_TRUE(leaky_singleton);
187 }
initial.commit3f4a7322008-07-27 06:49:38 +0900188
189 // Verify that only the expected callback has been called.
190 VerifiesCallbacks();
191 // Delete the leaky singleton. It is interesting to note that Purify does
192 // *not* detect the leak when this call is commented out. :(
deanm@google.com4c68cc62008-08-11 23:02:06 +0900193 DefaultSingletonTraits<CallbackFunc>::Delete(leaky_singleton);
initial.commit3f4a7322008-07-27 06:49:38 +0900194
initial.commit3f4a7322008-07-27 06:49:38 +0900195 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900196 ShadowingAtExitManager sem;
initial.commit3f4a7322008-07-27 06:49:38 +0900197 // Verifiy that the variables were reset.
198 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900199 singleton_int_1 = SingletonInt1();
initial.commit3f4a7322008-07-27 06:49:38 +0900200 EXPECT_EQ(*singleton_int_1, 0);
201 }
202 {
deanm@google.com4c68cc62008-08-11 23:02:06 +0900203 singleton_int_5 = SingletonInt5();
initial.commit3f4a7322008-07-27 06:49:38 +0900204 EXPECT_EQ(*singleton_int_5, 5);
205 }
206 }
207 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
initial.commit3f4a7322008-07-27 06:49:38 +0900208 VerifiesCallbacksNotCalled();
209}
license.botf003cfe2008-08-24 09:55:55 +0900210