Home | History | Annotate | Download | only in memory
      1 // Copyright (c) 2012 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/memory/singleton.h"
      7 #include "base/path_service.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 
     10 namespace {
     11 
     12 COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
     13 
     14 typedef void (*CallbackFunc)();
     15 
     16 class IntSingleton {
     17  public:
     18   static IntSingleton* GetInstance() {
     19     return Singleton<IntSingleton>::get();
     20   }
     21 
     22   int value_;
     23 };
     24 
     25 class Init5Singleton {
     26  public:
     27   struct Trait;
     28 
     29   static Init5Singleton* GetInstance() {
     30     return Singleton<Init5Singleton, Trait>::get();
     31   }
     32 
     33   int value_;
     34 };
     35 
     36 struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
     37   static Init5Singleton* New() {
     38     Init5Singleton* instance = new Init5Singleton();
     39     instance->value_ = 5;
     40     return instance;
     41   }
     42 };
     43 
     44 int* SingletonInt() {
     45   return &IntSingleton::GetInstance()->value_;
     46 }
     47 
     48 int* SingletonInt5() {
     49   return &Init5Singleton::GetInstance()->value_;
     50 }
     51 
     52 template <typename Type>
     53 struct CallbackTrait : public DefaultSingletonTraits<Type> {
     54   static void Delete(Type* instance) {
     55     if (instance->callback_)
     56       (instance->callback_)();
     57     DefaultSingletonTraits<Type>::Delete(instance);
     58   }
     59 };
     60 
     61 class CallbackSingleton {
     62  public:
     63   CallbackSingleton() : callback_(NULL) { }
     64   CallbackFunc callback_;
     65 };
     66 
     67 class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
     68  public:
     69   struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
     70 
     71   CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
     72 
     73   static CallbackSingletonWithNoLeakTrait* GetInstance() {
     74     return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
     75   }
     76 };
     77 
     78 class CallbackSingletonWithLeakTrait : public CallbackSingleton {
     79  public:
     80   struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
     81     static const bool kRegisterAtExit = false;
     82   };
     83 
     84   CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
     85 
     86   static CallbackSingletonWithLeakTrait* GetInstance() {
     87     return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
     88   }
     89 };
     90 
     91 class CallbackSingletonWithStaticTrait : public CallbackSingleton {
     92  public:
     93   struct Trait;
     94 
     95   CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
     96 
     97   static CallbackSingletonWithStaticTrait* GetInstance() {
     98     return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
     99   }
    100 };
    101 
    102 struct CallbackSingletonWithStaticTrait::Trait
    103     : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
    104   static void Delete(CallbackSingletonWithStaticTrait* instance) {
    105     if (instance->callback_)
    106       (instance->callback_)();
    107     StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
    108         instance);
    109   }
    110 };
    111 
    112 template <class Type>
    113 class AlignedTestSingleton {
    114  public:
    115   AlignedTestSingleton() {}
    116   ~AlignedTestSingleton() {}
    117   static AlignedTestSingleton* GetInstance() {
    118     return Singleton<AlignedTestSingleton,
    119         StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
    120   }
    121 
    122   Type type_;
    123 };
    124 
    125 
    126 void SingletonNoLeak(CallbackFunc CallOnQuit) {
    127   CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
    128 }
    129 
    130 void SingletonLeak(CallbackFunc CallOnQuit) {
    131   CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
    132 }
    133 
    134 CallbackFunc* GetLeakySingleton() {
    135   return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
    136 }
    137 
    138 void DeleteLeakySingleton() {
    139   DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
    140       CallbackSingletonWithLeakTrait::GetInstance());
    141 }
    142 
    143 void SingletonStatic(CallbackFunc CallOnQuit) {
    144   CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
    145 }
    146 
    147 CallbackFunc* GetStaticSingleton() {
    148   return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
    149 }
    150 
    151 }  // namespace
    152 
    153 class SingletonTest : public testing::Test {
    154  public:
    155   SingletonTest() {}
    156 
    157   virtual void SetUp() OVERRIDE {
    158     non_leak_called_ = false;
    159     leaky_called_ = false;
    160     static_called_ = false;
    161   }
    162 
    163  protected:
    164   void VerifiesCallbacks() {
    165     EXPECT_TRUE(non_leak_called_);
    166     EXPECT_FALSE(leaky_called_);
    167     EXPECT_TRUE(static_called_);
    168     non_leak_called_ = false;
    169     leaky_called_ = false;
    170     static_called_ = false;
    171   }
    172 
    173   void VerifiesCallbacksNotCalled() {
    174     EXPECT_FALSE(non_leak_called_);
    175     EXPECT_FALSE(leaky_called_);
    176     EXPECT_FALSE(static_called_);
    177     non_leak_called_ = false;
    178     leaky_called_ = false;
    179     static_called_ = false;
    180   }
    181 
    182   static void CallbackNoLeak() {
    183     non_leak_called_ = true;
    184   }
    185 
    186   static void CallbackLeak() {
    187     leaky_called_ = true;
    188   }
    189 
    190   static void CallbackStatic() {
    191     static_called_ = true;
    192   }
    193 
    194  private:
    195   static bool non_leak_called_;
    196   static bool leaky_called_;
    197   static bool static_called_;
    198 };
    199 
    200 bool SingletonTest::non_leak_called_ = false;
    201 bool SingletonTest::leaky_called_ = false;
    202 bool SingletonTest::static_called_ = false;
    203 
    204 TEST_F(SingletonTest, Basic) {
    205   int* singleton_int;
    206   int* singleton_int_5;
    207   CallbackFunc* leaky_singleton;
    208   CallbackFunc* static_singleton;
    209 
    210   {
    211     base::ShadowingAtExitManager sem;
    212     {
    213       singleton_int = SingletonInt();
    214     }
    215     // Ensure POD type initialization.
    216     EXPECT_EQ(*singleton_int, 0);
    217     *singleton_int = 1;
    218 
    219     EXPECT_EQ(singleton_int, SingletonInt());
    220     EXPECT_EQ(*singleton_int, 1);
    221 
    222     {
    223       singleton_int_5 = SingletonInt5();
    224     }
    225     // Is default initialized to 5.
    226     EXPECT_EQ(*singleton_int_5, 5);
    227 
    228     SingletonNoLeak(&CallbackNoLeak);
    229     SingletonLeak(&CallbackLeak);
    230     SingletonStatic(&CallbackStatic);
    231     static_singleton = GetStaticSingleton();
    232     leaky_singleton = GetLeakySingleton();
    233     EXPECT_TRUE(leaky_singleton);
    234   }
    235 
    236   // Verify that only the expected callback has been called.
    237   VerifiesCallbacks();
    238   // Delete the leaky singleton.
    239   DeleteLeakySingleton();
    240 
    241   // The static singleton can't be acquired post-atexit.
    242   EXPECT_EQ(NULL, GetStaticSingleton());
    243 
    244   {
    245     base::ShadowingAtExitManager sem;
    246     // Verifiy that the variables were reset.
    247     {
    248       singleton_int = SingletonInt();
    249       EXPECT_EQ(*singleton_int, 0);
    250     }
    251     {
    252       singleton_int_5 = SingletonInt5();
    253       EXPECT_EQ(*singleton_int_5, 5);
    254     }
    255     {
    256       // Resurrect the static singleton, and assert that it
    257       // still points to the same (static) memory.
    258       CallbackSingletonWithStaticTrait::Trait::Resurrect();
    259       EXPECT_EQ(GetStaticSingleton(), static_singleton);
    260     }
    261   }
    262   // The leaky singleton shouldn't leak since SingletonLeak has not been called.
    263   VerifiesCallbacksNotCalled();
    264 }
    265 
    266 #define EXPECT_ALIGNED(ptr, align) \
    267     EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
    268 
    269 TEST_F(SingletonTest, Alignment) {
    270   using base::AlignedMemory;
    271 
    272   // Create some static singletons with increasing sizes and alignment
    273   // requirements. By ordering this way, the linker will need to do some work to
    274   // ensure proper alignment of the static data.
    275   AlignedTestSingleton<int32>* align4 =
    276       AlignedTestSingleton<int32>::GetInstance();
    277   AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
    278       AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
    279   AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
    280       AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
    281   AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
    282       AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
    283 
    284   EXPECT_ALIGNED(align4, 4);
    285   EXPECT_ALIGNED(align32, 32);
    286   EXPECT_ALIGNED(align128, 128);
    287   EXPECT_ALIGNED(align4096, 4096);
    288 }
    289