• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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.
4 
5 #include "base/at_exit.h"
6 #include "base/file_util.h"
7 #include "base/path_service.h"
8 #include "base/singleton.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace {
12 
13 COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
14 
15 template<typename Type>
16 struct LockTrait : public DefaultSingletonTraits<Type> {
17 };
18 
19 struct Init5Trait : public DefaultSingletonTraits<int> {
New__anon80d48fbe0111::Init5Trait20   static int* New() {
21     return new int(5);
22   }
23 };
24 
25 typedef void (*CallbackFunc)();
26 
27 struct CallbackTrait : public DefaultSingletonTraits<CallbackFunc> {
Delete__anon80d48fbe0111::CallbackTrait28   static void Delete(CallbackFunc* p) {
29     if (*p)
30       (*p)();
31     DefaultSingletonTraits<CallbackFunc>::Delete(p);
32   }
33 };
34 
35 struct NoLeakTrait : public CallbackTrait {
36 };
37 
38 struct LeakTrait : public CallbackTrait {
39   static const bool kRegisterAtExit = false;
40 };
41 
SingletonInt1()42 int* SingletonInt1() {
43   return Singleton<int>::get();
44 }
45 
SingletonInt2()46 int* SingletonInt2() {
47   // Force to use a different singleton than SingletonInt1.
48   return Singleton<int, DefaultSingletonTraits<int> >::get();
49 }
50 
51 class DummyDifferentiatingClass {
52 };
53 
SingletonInt3()54 int* SingletonInt3() {
55   // Force to use a different singleton than SingletonInt1 and SingletonInt2.
56   // Note that any type can be used; int, float, std::wstring...
57   return Singleton<int, DefaultSingletonTraits<int>,
58                    DummyDifferentiatingClass>::get();
59 }
60 
SingletonInt4()61 int* SingletonInt4() {
62   return Singleton<int, LockTrait<int> >::get();
63 }
64 
SingletonInt5()65 int* SingletonInt5() {
66   return Singleton<int, Init5Trait>::get();
67 }
68 
SingletonNoLeak(CallbackFunc CallOnQuit)69 void SingletonNoLeak(CallbackFunc CallOnQuit) {
70   *Singleton<CallbackFunc, NoLeakTrait>::get() = CallOnQuit;
71 }
72 
SingletonLeak(CallbackFunc CallOnQuit)73 void SingletonLeak(CallbackFunc CallOnQuit) {
74   *Singleton<CallbackFunc, LeakTrait>::get() = CallOnQuit;
75 }
76 
GetLeakySingleton()77 CallbackFunc* GetLeakySingleton() {
78   return Singleton<CallbackFunc, LeakTrait>::get();
79 }
80 
81 }  // namespace
82 
83 class SingletonTest : public testing::Test {
84  public:
SingletonTest()85   SingletonTest() { }
86 
SetUp()87   virtual void SetUp() {
88     non_leak_called_ = false;
89     leaky_called_ = false;
90   }
91 
92  protected:
VerifiesCallbacks()93   void VerifiesCallbacks() {
94     EXPECT_TRUE(non_leak_called_);
95     EXPECT_FALSE(leaky_called_);
96     non_leak_called_ = false;
97     leaky_called_ = false;
98   }
99 
VerifiesCallbacksNotCalled()100   void VerifiesCallbacksNotCalled() {
101     EXPECT_FALSE(non_leak_called_);
102     EXPECT_FALSE(leaky_called_);
103     non_leak_called_ = false;
104     leaky_called_ = false;
105   }
106 
CallbackNoLeak()107   static void CallbackNoLeak() {
108     non_leak_called_ = true;
109   }
110 
CallbackLeak()111   static void CallbackLeak() {
112     leaky_called_ = true;
113   }
114 
115  private:
116   static bool non_leak_called_;
117   static bool leaky_called_;
118 };
119 
120 bool SingletonTest::non_leak_called_ = false;
121 bool SingletonTest::leaky_called_ = false;
122 
TEST_F(SingletonTest,Basic)123 TEST_F(SingletonTest, Basic) {
124   int* singleton_int_1;
125   int* singleton_int_2;
126   int* singleton_int_3;
127   int* singleton_int_4;
128   int* singleton_int_5;
129   CallbackFunc* leaky_singleton;
130 
131   {
132     base::ShadowingAtExitManager sem;
133     {
134       singleton_int_1 = SingletonInt1();
135     }
136     // Ensure POD type initialization.
137     EXPECT_EQ(*singleton_int_1, 0);
138     *singleton_int_1 = 1;
139 
140     EXPECT_EQ(singleton_int_1, SingletonInt1());
141     EXPECT_EQ(*singleton_int_1, 1);
142 
143     {
144       singleton_int_2 = SingletonInt2();
145     }
146     // Same instance that 1.
147     EXPECT_EQ(*singleton_int_2, 1);
148     EXPECT_EQ(singleton_int_1, singleton_int_2);
149 
150     {
151       singleton_int_3 = SingletonInt3();
152     }
153     // Different instance than 1 and 2.
154     EXPECT_EQ(*singleton_int_3, 0);
155     EXPECT_NE(singleton_int_1, singleton_int_3);
156     *singleton_int_3 = 3;
157     EXPECT_EQ(*singleton_int_1, 1);
158     EXPECT_EQ(*singleton_int_2, 1);
159 
160     {
161       singleton_int_4 = SingletonInt4();
162     }
163     // Use a lock for creation. Not really tested at length.
164     EXPECT_EQ(*singleton_int_4, 0);
165     *singleton_int_4 = 4;
166     EXPECT_NE(singleton_int_1, singleton_int_4);
167     EXPECT_NE(singleton_int_3, singleton_int_4);
168 
169     {
170       singleton_int_5 = SingletonInt5();
171     }
172     // Is default initialized to 5.
173     EXPECT_EQ(*singleton_int_5, 5);
174     EXPECT_NE(singleton_int_1, singleton_int_5);
175     EXPECT_NE(singleton_int_3, singleton_int_5);
176     EXPECT_NE(singleton_int_4, singleton_int_5);
177 
178     SingletonNoLeak(&CallbackNoLeak);
179     SingletonLeak(&CallbackLeak);
180     leaky_singleton = GetLeakySingleton();
181     EXPECT_TRUE(leaky_singleton);
182   }
183 
184   // Verify that only the expected callback has been called.
185   VerifiesCallbacks();
186   // Delete the leaky singleton. It is interesting to note that Purify does
187   // *not* detect the leak when this call is commented out. :(
188   DefaultSingletonTraits<CallbackFunc>::Delete(leaky_singleton);
189 
190   {
191     base::ShadowingAtExitManager sem;
192     // Verifiy that the variables were reset.
193     {
194       singleton_int_1 = SingletonInt1();
195       EXPECT_EQ(*singleton_int_1, 0);
196     }
197     {
198       singleton_int_5 = SingletonInt5();
199       EXPECT_EQ(*singleton_int_5, 5);
200     }
201   }
202   // The leaky singleton shouldn't leak since SingletonLeak has not been called.
203   VerifiesCallbacksNotCalled();
204 }
205