Home | History | Annotate | Download | only in memory
      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 
     11 namespace {
     12 
     13 COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
     14 
     15 typedef void (*CallbackFunc)();
     16 
     17 class IntSingleton {
     18  public:
     19   static IntSingleton* GetInstance() {
     20     return Singleton<IntSingleton>::get();
     21   }
     22 
     23   int value_;
     24 };
     25 
     26 class Init5Singleton {
     27  public:
     28   struct Trait;
     29 
     30   static Init5Singleton* GetInstance() {
     31     return Singleton<Init5Singleton, Trait>::get();
     32   }
     33 
     34   int value_;
     35 };
     36 
     37 struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
     38   static Init5Singleton* New() {
     39     Init5Singleton* instance = new Init5Singleton();
     40     instance->value_ = 5;
     41     return instance;
     42   }
     43 };
     44 
     45 int* SingletonInt() {
     46   return &IntSingleton::GetInstance()->value_;
     47 }
     48 
     49 int* SingletonInt5() {
     50   return &Init5Singleton::GetInstance()->value_;
     51 }
     52 
     53 template <typename Type>
     54 struct 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 
     62 class CallbackSingleton {
     63  public:
     64   CallbackSingleton() : callback_(NULL) { }
     65   CallbackFunc callback_;
     66 };
     67 
     68 class 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 
     79 class 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 
     92 class 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 
    103 struct 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 
    114 void SingletonNoLeak(CallbackFunc CallOnQuit) {
    115   CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
    116 }
    117 
    118 void SingletonLeak(CallbackFunc CallOnQuit) {
    119   CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
    120 }
    121 
    122 CallbackFunc* GetLeakySingleton() {
    123   return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
    124 }
    125 
    126 void DeleteLeakySingleton() {
    127   DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
    128       CallbackSingletonWithLeakTrait::GetInstance());
    129 }
    130 
    131 void SingletonStatic(CallbackFunc CallOnQuit) {
    132   CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
    133 }
    134 
    135 CallbackFunc* GetStaticSingleton() {
    136   return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
    137 }
    138 
    139 void ResurrectStaticSingleton() {
    140 }
    141 
    142 }  // namespace
    143 
    144 class 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 
    191 bool SingletonTest::non_leak_called_ = false;
    192 bool SingletonTest::leaky_called_ = false;
    193 bool SingletonTest::static_called_ = false;
    194 
    195 TEST_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