diff options
author | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-11 14:02:06 +0000 |
---|---|---|
committer | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-11 14:02:06 +0000 |
commit | 4ac8f670af190931c88542ae57295da97e2971ce (patch) | |
tree | c53779e5876223856392e291d340c20088ab339e | |
parent | 663fe3c5c9327b3b604fe7f2c7fd3f4d5cccc4e4 (diff) | |
download | chromium_src-4ac8f670af190931c88542ae57295da97e2971ce.zip chromium_src-4ac8f670af190931c88542ae57295da97e2971ce.tar.gz chromium_src-4ac8f670af190931c88542ae57295da97e2971ce.tar.bz2 |
Allow multiple AtExitManagers to be chained in a stack, this allows much easier testing for code that is expecting to be run via an AtExitManager. This actually cleaned up a lot of the at exit code.
Clean up singleton_dll_unittest. It is no longer windows specific DLL, and now is much simpler, and builds and runs cross platform.
BUG=1314043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@646 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/SConscript | 19 | ||||
-rw-r--r-- | base/at_exit.cc | 79 | ||||
-rw-r--r-- | base/at_exit.h | 8 | ||||
-rw-r--r-- | base/base.sln | 6 | ||||
-rw-r--r-- | base/build/singleton_dll_unittest.def | 9 | ||||
-rw-r--r-- | base/build/singleton_dll_unittest.vsprops | 15 | ||||
-rw-r--r-- | base/build/singleton_unittest.vcproj | 157 | ||||
-rw-r--r-- | base/singleton_dll_unittest.cc | 118 | ||||
-rw-r--r-- | base/singleton_dll_unittest.h | 83 | ||||
-rw-r--r-- | base/singleton_unittest.cc | 187 |
10 files changed, 146 insertions, 535 deletions
diff --git a/base/SConscript b/base/SConscript index 719e29b..b8d9da9 100644 --- a/base/SConscript +++ b/base/SConscript @@ -200,23 +200,6 @@ if env['PLATFORM'] == 'win32': ], ) - -env_tests_dll = env_tests.Clone() -env_tests_dll.Append( - CPPDEFINES = [ - '_WINDLL', - 'SINGLETON_UNITTEST_EXPORTS', - ], -) -dll = env_tests_dll.ChromeSharedLibrary(['singleton_dll_unittest.dll', - 'singleton_dll_unittest.lib', - 'singleton_dll_unittest.ilk', - 'singleton_dll_unittest.pdb'], - ['singleton_dll_unittest.cc', - 'build/singleton_dll_unittest.def']) -i = env.Install('$TARGET_ROOT', dll[0]) -env.Alias('base', i) - env_tests.ChromeTestProgram(['debug_message.exe', 'debug_message.ilk', 'debug_message.pdb'], @@ -269,8 +252,6 @@ test_files = [ 'win_util_unittest.cc', 'word_iterator_unittest.cc', 'wmi_util_unittest.cc', - - dll[1], ] if env['PLATFORM'] == 'win32': diff --git a/base/at_exit.cc b/base/at_exit.cc index 1f56057..734de74 100644 --- a/base/at_exit.cc +++ b/base/at_exit.cc @@ -30,58 +30,63 @@ #include "base/at_exit.h" #include "base/logging.h" -namespace { - -std::stack<base::AtExitCallbackType>* g_atexit_queue = NULL; -Lock* g_atexit_lock = NULL; - -void ProcessCallbacks() { - if (!g_atexit_queue) - return; - base::AtExitCallbackType func = NULL; - while(!g_atexit_queue->empty()) { - func = g_atexit_queue->top(); - g_atexit_queue->pop(); - if (func) - func(); - } -} - -} // namespace +// Keep a stack of registered AtExitManagers. We always operate on the most +// recent, and we should never have more than one outside of testing, when we +// use the shadow version of the constructor. We don't protect this for +// thread-safe access, since it will only be modified in testing. +static std::stack<base::AtExitManager*> g_managers; namespace base { AtExitManager::AtExitManager() { - DCHECK(NULL == g_atexit_queue); - DCHECK(NULL == g_atexit_lock); - g_atexit_lock = &lock_; - g_atexit_queue = &atexit_queue_; + DCHECK(g_managers.empty()); + g_managers.push(this); +} + +AtExitManager::AtExitManager(bool shadow) { + DCHECK(shadow || g_managers.empty()); + g_managers.push(this); } AtExitManager::~AtExitManager() { - AutoLock lock(lock_); - ProcessCallbacks(); - g_atexit_queue = NULL; - g_atexit_lock = NULL; + if (g_managers.empty()) { + NOTREACHED() << "Tried to ~AtExitManager without a AtExitManager"; + return; + } + DCHECK(g_managers.top() == this); + + ProcessCallbacksNow(); + g_managers.pop(); } +// static void AtExitManager::RegisterCallback(AtExitCallbackType func) { - DCHECK(NULL != g_atexit_queue); - DCHECK(NULL != g_atexit_lock); - if (!g_atexit_lock) + if (g_managers.empty()) { + NOTREACHED() << "Tried to RegisterCallback without a AtExitManager"; return; - AutoLock lock(*g_atexit_lock); - if (g_atexit_queue) - g_atexit_queue->push(func); + } + + AtExitManager* manager = g_managers.top(); + AutoLock lock(manager->lock_); + manager->stack_.push(func); } +// static void AtExitManager::ProcessCallbacksNow() { - DCHECK(NULL != g_atexit_lock); - if (!g_atexit_lock) + if (g_managers.empty()) { + NOTREACHED() << "Tried to RegisterCallback without a AtExitManager"; return; - AutoLock lock(*g_atexit_lock); - DCHECK(NULL != g_atexit_queue); - ProcessCallbacks(); + } + + AtExitManager* manager = g_managers.top(); + AutoLock lock(manager->lock_); + + while (!manager->stack_.empty()) { + base::AtExitCallbackType func = manager->stack_.top(); + manager->stack_.pop(); + if (func) + func(); + } } } // namespace base diff --git a/base/at_exit.h b/base/at_exit.h index 8b9f946..123935d 100644 --- a/base/at_exit.h +++ b/base/at_exit.h @@ -54,6 +54,12 @@ typedef void (*AtExitCallbackType)(); // callbacks and singleton destructors will be called. class AtExitManager { + protected: + // This constructor will allow this instance of AtExitManager to be created + // even if on already exists. This should only be used for testing! + // AtExitManagers are kept on a global stack, and it will be removed during + // destruction. This allows you to shadow another AtExitManager. + AtExitManager(bool shadow); public: AtExitManager(); @@ -71,7 +77,7 @@ class AtExitManager { private: Lock lock_; - std::stack<base::AtExitCallbackType> atexit_queue_; + std::stack<base::AtExitCallbackType> stack_; DISALLOW_EVIL_CONSTRUCTORS(AtExitManager); }; diff --git a/base/base.sln b/base/base.sln index c928064..94a02d3 100644 --- a/base/base.sln +++ b/base/base.sln @@ -36,12 +36,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "..\third_party\li EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\third_party\zlib\zlib.vcproj", "{8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "singleton_dll_unittest", "build\singleton_unittest.vcproj", "{E457F2FB-4708-4001-9B1C-275D7BD7F2A8}" - ProjectSection(ProjectDependencies) = postProject - {1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165} - {8C27D792-2648-4F5E-9ED0-374276327308} = {8C27D792-2648-4F5E-9ED0-374276327308} - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\testing\gtest.vcproj", "{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}" EndProject Global diff --git a/base/build/singleton_dll_unittest.def b/base/build/singleton_dll_unittest.def deleted file mode 100644 index 6ad4d90..0000000 --- a/base/build/singleton_dll_unittest.def +++ /dev/null @@ -1,9 +0,0 @@ -EXPORTS - SingletonInt1 - SingletonInt2 - SingletonInt3 - SingletonInt4 - SingletonInt5 - SingletonNoLeak - SingletonLeak - GetLeakySingleton diff --git a/base/build/singleton_dll_unittest.vsprops b/base/build/singleton_dll_unittest.vsprops deleted file mode 100644 index a3eb79b..0000000 --- a/base/build/singleton_dll_unittest.vsprops +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioPropertySheet - ProjectType="Visual C++" - Version="8.00" - Name="singleton_dll_unittest" - > - <Tool - Name="VCCLCompilerTool" - PreprocessorDefinitions="SINGLETON_UNITTEST_EXPORTS" - /> - <Tool - Name="VCLinkerTool" - ModuleDefinitionFile="singleton_dll_unittest.def" - /> -</VisualStudioPropertySheet> diff --git a/base/build/singleton_unittest.vcproj b/base/build/singleton_unittest.vcproj deleted file mode 100644 index 6fcb715..0000000 --- a/base/build/singleton_unittest.vcproj +++ /dev/null @@ -1,157 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="singleton_dll_unittest" - ProjectGUID="{E457F2FB-4708-4001-9B1C-275D7BD7F2A8}" - RootNamespace="singleton_unittest" - Keyword="Win32Proj" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - ConfigurationType="2" - InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;.\singleton_dll_unittest.vsprops" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - ConfigurationType="2" - InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;.\singleton_dll_unittest.vsprops" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <File - RelativePath="..\singleton_dll_unittest.cc" - > - </File> - <File - RelativePath=".\singleton_dll_unittest.def" - > - </File> - <File - RelativePath="..\singleton_dll_unittest.h" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/base/singleton_dll_unittest.cc b/base/singleton_dll_unittest.cc deleted file mode 100644 index 6892965..0000000 --- a/base/singleton_dll_unittest.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "base/singleton_dll_unittest.h" -#include "base/at_exit.h" -#include "base/logging.h" - -namespace { - -base::AtExitManager g_exit_manager; - -} // namespace - -BOOL APIENTRY DllMain(HMODULE module, DWORD reason_for_call, LPVOID reserved) { - switch (reason_for_call) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(module); - break; - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - -COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a); - -template<typename Type> -struct LockTrait : public DefaultSingletonTraits<Type> { -}; - -struct Init5Trait : public DefaultSingletonTraits<int> { - static int* New() { - return new int(5); - } -}; - -struct CallbackTrait : public CustomAllocTrait<CallBackFunc> { - static void Delete(CallBackFunc* p) { - if (*p) - (*p)(); - CHECK(CustomAllocTrait<CallBackFunc>::Delete(p)); - } -}; - -struct NoLeakTrait : public CallbackTrait { -}; - -struct LeakTrait : public CallbackTrait { - static const bool kRegisterAtExit = false; -}; - -SINGLETON_UNITTEST_API int* WINAPI SingletonInt1() { - return Singleton<int>::get(); -} - -SINGLETON_UNITTEST_API int* WINAPI SingletonInt2() { - // Force to use a different singleton than SingletonInt1. - return Singleton<int, DefaultSingletonTraits<int> >::get(); -} - -class DummyDifferentiatingClass { -}; - -SINGLETON_UNITTEST_API int* WINAPI SingletonInt3() { - // Force to use a different singleton than SingletonInt1 and SingletonInt2. - // Note that any type can be used; int, float, std::wstring... - return Singleton<int, DefaultSingletonTraits<int>, - DummyDifferentiatingClass>::get(); -} - -SINGLETON_UNITTEST_API int* WINAPI SingletonInt4() { - return Singleton<int, LockTrait<int> >::get(); -} - -SINGLETON_UNITTEST_API int* WINAPI SingletonInt5() { - return Singleton<int, Init5Trait>::get(); -} - -SINGLETON_UNITTEST_API void WINAPI SingletonNoLeak(CallBackFunc CallOnQuit) { - *Singleton<CallBackFunc, NoLeakTrait>::get() = CallOnQuit; -} - -SINGLETON_UNITTEST_API void WINAPI SingletonLeak(CallBackFunc CallOnQuit) { - *Singleton<CallBackFunc, LeakTrait>::get() = CallOnQuit; -} - -SINGLETON_UNITTEST_API CallBackFunc* WINAPI GetLeakySingleton() { - return Singleton<CallBackFunc, LeakTrait>::get(); -} diff --git a/base/singleton_dll_unittest.h b/base/singleton_dll_unittest.h deleted file mode 100644 index d161722..0000000 --- a/base/singleton_dll_unittest.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef BASE_SINGLETON_DLL_UNITTEST_H__ -#define BASE_SINGLETON_DLL_UNITTEST_H__ - -#include "base/singleton.h" - -#ifdef SINGLETON_UNITTEST_EXPORTS -#define SINGLETON_UNITTEST_API __declspec(dllexport) -#else -#define SINGLETON_UNITTEST_API __declspec(dllimport) -#endif - -// Function pointer for singleton getters. -typedef int* (WINAPI* SingletonIntFunc)(); - -// Callback function to be called on library unload. -typedef void (WINAPI* CallBackFunc)(); - -// Leaky/nonleak singleton initialization. -typedef void (WINAPI* LeakySingletonFunc)(CallBackFunc); - -// Retrieve the leaky singleton for later disposal. -typedef CallBackFunc* (WINAPI* GetLeakySingletonFunc)(); - -// When using new/delete, the heap is destroyed on library unload. So use -// VirtualAlloc/VirtualFree to bypass this behavior. -template<typename Type> -struct CustomAllocTrait : public DefaultSingletonTraits<Type> { - static Type* New() { - return static_cast<Type*>(VirtualAlloc(NULL, sizeof(Type), MEM_COMMIT, - PAGE_READWRITE)); - } - - static bool Delete(Type* p) { - return 0!=VirtualFree(p, 0, MEM_RELEASE); - } -}; - -// 1 and 2 share the same instance. -// 3 simply use a different key. -// 4 sets kMustCallNewExactlyOnce to true. -// 5 default initialize to 5. -extern "C" SINGLETON_UNITTEST_API int* WINAPI SingletonInt1(); -extern "C" SINGLETON_UNITTEST_API int* WINAPI SingletonInt2(); -extern "C" SINGLETON_UNITTEST_API int* WINAPI SingletonInt3(); -extern "C" SINGLETON_UNITTEST_API int* WINAPI SingletonInt4(); -extern "C" SINGLETON_UNITTEST_API int* WINAPI SingletonInt5(); - -extern "C" SINGLETON_UNITTEST_API void WINAPI SingletonNoLeak( - CallBackFunc CallOnQuit); -extern "C" SINGLETON_UNITTEST_API void WINAPI SingletonLeak( - CallBackFunc CallOnQuit); -extern "C" SINGLETON_UNITTEST_API CallBackFunc* WINAPI GetLeakySingleton(); - -#endif // BASE_SINGLETON_DLL_UNITTEST_H__ diff --git a/base/singleton_unittest.cc b/base/singleton_unittest.cc index 5d21593..167fa78 100644 --- a/base/singleton_unittest.cc +++ b/base/singleton_unittest.cc @@ -27,54 +27,99 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "testing/gtest/include/gtest/gtest.h" -#include "base/singleton_dll_unittest.h" +#include "base/at_exit.h" #include "base/file_util.h" #include "base/path_service.h" +#include "base/singleton.h" +#include "testing/gtest/include/gtest/gtest.h" -class SingletonTest : public testing::Test { +namespace { + +class ShadowingAtExitManager : public base::AtExitManager { public: - SingletonTest() { - } + ShadowingAtExitManager() : AtExitManager(true) { } +}; - virtual void SetUp() { - module_ = NULL; - non_leak_called_ = false; - leaky_called_ = false; - } +COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a); - virtual void TearDown() { - ASSERT_FALSE(module_); - } +template<typename Type> +struct LockTrait : public DefaultSingletonTraits<Type> { +}; - static bool IsTestCaseDisabled() { - // Check if the dll exists beside the executable. - std::wstring path; - PathService::Get(base::DIR_EXE, &path); - file_util::AppendToPath(&path, kLibrary); - return !file_util::PathExists(path); +struct Init5Trait : public DefaultSingletonTraits<int> { + static int* New() { + return new int(5); } +}; - protected: - void LoadLibrary() { - ASSERT_FALSE(module_); - module_ = ::LoadLibrary(kLibrary); - ASSERT_TRUE(module_ != NULL); - } +typedef void (*CallbackFunc)(); - void FreeLibrary() { - ASSERT_TRUE(module_ != NULL); - ASSERT_TRUE(::FreeLibrary(module_)); - module_ = NULL; +struct CallbackTrait : public DefaultSingletonTraits<CallbackFunc> { + static void Delete(CallbackFunc* p) { + if (*p) + (*p)(); + DefaultSingletonTraits<CallbackFunc>::Delete(p); } +}; + +struct NoLeakTrait : public CallbackTrait { +}; + +struct LeakTrait : public CallbackTrait { + static const bool kRegisterAtExit = false; +}; + +int* SingletonInt1() { + return Singleton<int>::get(); +} + +int* SingletonInt2() { + // Force to use a different singleton than SingletonInt1. + return Singleton<int, DefaultSingletonTraits<int> >::get(); +} + +class DummyDifferentiatingClass { +}; + +int* SingletonInt3() { + // Force to use a different singleton than SingletonInt1 and SingletonInt2. + // Note that any type can be used; int, float, std::wstring... + return Singleton<int, DefaultSingletonTraits<int>, + DummyDifferentiatingClass>::get(); +} + +int* SingletonInt4() { + return Singleton<int, LockTrait<int> >::get(); +} + +int* SingletonInt5() { + return Singleton<int, Init5Trait>::get(); +} + +void SingletonNoLeak(CallbackFunc CallOnQuit) { + *Singleton<CallbackFunc, NoLeakTrait>::get() = CallOnQuit; +} + +void SingletonLeak(CallbackFunc CallOnQuit) { + *Singleton<CallbackFunc, LeakTrait>::get() = CallOnQuit; +} + +CallbackFunc* GetLeakySingleton() { + return Singleton<CallbackFunc, LeakTrait>::get(); +} - template<typename T> - void GetProc(const char* function_name, T* function) { - ASSERT_TRUE(module_ != NULL); - *function = reinterpret_cast<T>(GetProcAddress(module_, function_name)); - ASSERT_TRUE(*function); +} // namespace + +class SingletonTest : public testing::Test { + public: + SingletonTest() { } + + virtual void SetUp() { + non_leak_called_ = false; + leaky_called_ = false; } + protected: void VerifiesCallbacks() { EXPECT_TRUE(non_leak_called_); EXPECT_FALSE(leaky_called_); @@ -89,17 +134,15 @@ class SingletonTest : public testing::Test { leaky_called_ = false; } - static void WINAPI CallbackNoLeak() { + static void CallbackNoLeak() { non_leak_called_ = true; } - static void WINAPI CallbackLeak() { + static void CallbackLeak() { leaky_called_ = true; } private: - static const wchar_t* const kLibrary; - HMODULE module_; static bool non_leak_called_; static bool leaky_called_; }; @@ -107,48 +150,35 @@ class SingletonTest : public testing::Test { bool SingletonTest::non_leak_called_ = false; bool SingletonTest::leaky_called_ = false; -const wchar_t* const SingletonTest::kLibrary = L"singleton_dll_unittest.dll"; - TEST_F(SingletonTest, Basic) { - if (IsTestCaseDisabled()) - return; - int* singleton_int_1; int* singleton_int_2; int* singleton_int_3; int* singleton_int_4; int* singleton_int_5; - CallBackFunc* leaky_singleton; + CallbackFunc* leaky_singleton; - LoadLibrary(); { - SingletonIntFunc sut1; - SingletonIntFunc sut2; - SingletonIntFunc sut3; - SingletonIntFunc sut4; - SingletonIntFunc sut5; + ShadowingAtExitManager sem; { - GetProc("SingletonInt1", &sut1); - singleton_int_1 = sut1(); + singleton_int_1 = SingletonInt1(); } // Ensure POD type initialization. EXPECT_EQ(*singleton_int_1, 0); *singleton_int_1 = 1; - EXPECT_EQ(singleton_int_1, sut1()); + EXPECT_EQ(singleton_int_1, SingletonInt1()); EXPECT_EQ(*singleton_int_1, 1); { - GetProc("SingletonInt2", &sut2); - singleton_int_2 = sut2(); + singleton_int_2 = SingletonInt2(); } // Same instance that 1. EXPECT_EQ(*singleton_int_2, 1); EXPECT_EQ(singleton_int_1, singleton_int_2); { - GetProc("SingletonInt3", &sut3); - singleton_int_3 = sut3(); + singleton_int_3 = SingletonInt3(); } // Different instance than 1 and 2. EXPECT_EQ(*singleton_int_3, 0); @@ -158,8 +188,7 @@ TEST_F(SingletonTest, Basic) { EXPECT_EQ(*singleton_int_2, 1); { - GetProc("SingletonInt4", &sut4); - singleton_int_4 = sut4(); + singleton_int_4 = SingletonInt4(); } // Use a lock for creation. Not really tested at length. EXPECT_EQ(*singleton_int_4, 0); @@ -168,60 +197,38 @@ TEST_F(SingletonTest, Basic) { EXPECT_NE(singleton_int_3, singleton_int_4); { - GetProc("SingletonInt5", &sut5); - singleton_int_5 = sut5(); + singleton_int_5 = SingletonInt5(); } // Is default initialized to 5. EXPECT_EQ(*singleton_int_5, 5); EXPECT_NE(singleton_int_1, singleton_int_5); EXPECT_NE(singleton_int_3, singleton_int_5); EXPECT_NE(singleton_int_4, singleton_int_5); -#ifdef _DEBUG - // In release, the optimizer may make both exports use exactly the same - // code. - EXPECT_NE(sut1, sut2); -#endif - EXPECT_NE(sut2, sut3); - EXPECT_NE(sut3, sut4); - EXPECT_NE(sut4, sut5); - - LeakySingletonFunc noleak; - GetProc("SingletonNoLeak", &noleak); - noleak(&CallbackNoLeak); - LeakySingletonFunc leak; - GetProc("SingletonLeak", &leak); - leak(&CallbackLeak); - GetLeakySingletonFunc get_leaky; - GetProc("GetLeakySingleton", &get_leaky); - leaky_singleton = get_leaky(); + + SingletonNoLeak(&CallbackNoLeak); + SingletonLeak(&CallbackLeak); + leaky_singleton = GetLeakySingleton(); EXPECT_TRUE(leaky_singleton); } - FreeLibrary(); // Verify that only the expected callback has been called. VerifiesCallbacks(); // Delete the leaky singleton. It is interesting to note that Purify does // *not* detect the leak when this call is commented out. :( - EXPECT_TRUE(CustomAllocTrait<CallBackFunc>::Delete(leaky_singleton)); + DefaultSingletonTraits<CallbackFunc>::Delete(leaky_singleton); - LoadLibrary(); { + ShadowingAtExitManager sem; // Verifiy that the variables were reset. { - SingletonIntFunc sut1; - GetProc("SingletonInt1", &sut1); - singleton_int_1 = sut1(); + singleton_int_1 = SingletonInt1(); EXPECT_EQ(*singleton_int_1, 0); } { - SingletonIntFunc sut5; - GetProc("SingletonInt5", &sut5); - singleton_int_5 = sut5(); + singleton_int_5 = SingletonInt5(); EXPECT_EQ(*singleton_int_5, 5); } } // The leaky singleton shouldn't leak since SingletonLeak has not been called. - FreeLibrary(); - VerifiesCallbacksNotCalled(); } |