Home | History | Annotate | Download | only in base
      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> {
     20   static int* New() {
     21     return new int(5);
     22   }
     23 };
     24 
     25 typedef void (*CallbackFunc)();
     26 
     27 struct CallbackTrait : public DefaultSingletonTraits<CallbackFunc> {
     28   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 
     42 int* SingletonInt1() {
     43   return Singleton<int>::get();
     44 }
     45 
     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 
     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 
     61 int* SingletonInt4() {
     62   return Singleton<int, LockTrait<int> >::get();
     63 }
     64 
     65 int* SingletonInt5() {
     66   return Singleton<int, Init5Trait>::get();
     67 }
     68 
     69 void SingletonNoLeak(CallbackFunc CallOnQuit) {
     70   *Singleton<CallbackFunc, NoLeakTrait>::get() = CallOnQuit;
     71 }
     72 
     73 void SingletonLeak(CallbackFunc CallOnQuit) {
     74   *Singleton<CallbackFunc, LeakTrait>::get() = CallOnQuit;
     75 }
     76 
     77 CallbackFunc* GetLeakySingleton() {
     78   return Singleton<CallbackFunc, LeakTrait>::get();
     79 }
     80 
     81 }  // namespace
     82 
     83 class SingletonTest : public testing::Test {
     84  public:
     85   SingletonTest() { }
     86 
     87   virtual void SetUp() {
     88     non_leak_called_ = false;
     89     leaky_called_ = false;
     90   }
     91 
     92  protected:
     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 
    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 
    107   static void CallbackNoLeak() {
    108     non_leak_called_ = true;
    109   }
    110 
    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 
    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