summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authordeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-11 14:02:06 +0000
committerdeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-11 14:02:06 +0000
commit4ac8f670af190931c88542ae57295da97e2971ce (patch)
treec53779e5876223856392e291d340c20088ab339e /base
parent663fe3c5c9327b3b604fe7f2c7fd3f4d5cccc4e4 (diff)
downloadchromium_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
Diffstat (limited to 'base')
-rw-r--r--base/SConscript19
-rw-r--r--base/at_exit.cc79
-rw-r--r--base/at_exit.h8
-rw-r--r--base/base.sln6
-rw-r--r--base/build/singleton_dll_unittest.def9
-rw-r--r--base/build/singleton_dll_unittest.vsprops15
-rw-r--r--base/build/singleton_unittest.vcproj157
-rw-r--r--base/singleton_dll_unittest.cc118
-rw-r--r--base/singleton_dll_unittest.h83
-rw-r--r--base/singleton_unittest.cc187
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();
}