Implements --gmock_catch_leaked_mocks and Mock::AllowLeak.
This commit is contained in:
parent
1c8eb1c059
commit
df35a763b9
20
Makefile.am
20
Makefile.am
|
@ -128,7 +128,7 @@ test_gmock_printers_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la
|
||||||
TESTS += test/gmock-spec-builders_test
|
TESTS += test/gmock-spec-builders_test
|
||||||
check_PROGRAMS += test/gmock-spec-builders_test
|
check_PROGRAMS += test/gmock-spec-builders_test
|
||||||
test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc
|
test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc
|
||||||
test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la
|
test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la
|
||||||
|
|
||||||
TESTS += test/gmock_test
|
TESTS += test/gmock_test
|
||||||
check_PROGRAMS += test/gmock_test
|
check_PROGRAMS += test/gmock_test
|
||||||
|
@ -147,6 +147,11 @@ dist_check_SCRIPTS =
|
||||||
# Python modules used by multiple Python tests below.
|
# Python modules used by multiple Python tests below.
|
||||||
dist_check_SCRIPTS += test/gmock_test_utils.py
|
dist_check_SCRIPTS += test/gmock_test_utils.py
|
||||||
|
|
||||||
|
check_PROGRAMS += test/gmock_leak_test_
|
||||||
|
test_gmock_leak_test__SOURCES = test/gmock_leak_test_.cc
|
||||||
|
test_gmock_leak_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la
|
||||||
|
dist_check_SCRIPTS += test/gmock_leak_test.py
|
||||||
|
|
||||||
check_PROGRAMS += test/gmock_output_test_
|
check_PROGRAMS += test/gmock_output_test_
|
||||||
test_gmock_output_test__SOURCES = test/gmock_output_test_.cc
|
test_gmock_output_test__SOURCES = test/gmock_output_test_.cc
|
||||||
test_gmock_output_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la
|
test_gmock_output_test__LDADD = $(GTEST_LIBS) lib/libgmock_main.la
|
||||||
|
@ -155,15 +160,17 @@ EXTRA_DIST += test/gmock_output_test_golden.txt
|
||||||
|
|
||||||
# Enable all the python driven tests when we can run them.
|
# Enable all the python driven tests when we can run them.
|
||||||
if HAVE_PYTHON
|
if HAVE_PYTHON
|
||||||
TESTS += test/gmock_output_test.py
|
TESTS += \
|
||||||
|
test/gmock_leak_test.py \
|
||||||
|
test/gmock_output_test.py
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Nonstandard package files for distribution.
|
# Nonstandard package files for distribution.
|
||||||
EXTRA_DIST += \
|
EXTRA_DIST += \
|
||||||
CHANGES \
|
CHANGES \
|
||||||
CONTRIBUTORS \
|
CONTRIBUTORS \
|
||||||
make/Makefile \
|
make/Makefile \
|
||||||
src/gmock-all.cc
|
src/gmock-all.cc
|
||||||
|
|
||||||
# Pump scripts for generating Google Mock headers.
|
# Pump scripts for generating Google Mock headers.
|
||||||
# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump.
|
# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump.
|
||||||
|
@ -199,4 +206,5 @@ EXTRA_DIST += \
|
||||||
msvc/gmock_link_test.vcproj \
|
msvc/gmock_link_test.vcproj \
|
||||||
msvc/gmock_main.vcproj \
|
msvc/gmock_main.vcproj \
|
||||||
msvc/gmock_output_test_.vcproj \
|
msvc/gmock_output_test_.vcproj \
|
||||||
|
msvc/gmock-spec-builders_test.vcproj \
|
||||||
msvc/gmock_test.vcproj
|
msvc/gmock_test.vcproj
|
||||||
|
|
|
@ -246,6 +246,10 @@ class Mock {
|
||||||
public:
|
public:
|
||||||
// The following public methods can be called concurrently.
|
// The following public methods can be called concurrently.
|
||||||
|
|
||||||
|
// Tells Google Mock to ignore mock_obj when checking for leaked
|
||||||
|
// mock objects.
|
||||||
|
static void AllowLeak(const void* mock_obj);
|
||||||
|
|
||||||
// Verifies and clears all expectations on the given mock object.
|
// Verifies and clears all expectations on the given mock object.
|
||||||
// If the expectations aren't satisfied, generates one or more
|
// If the expectations aren't satisfied, generates one or more
|
||||||
// Google Test non-fatal failures and returns false.
|
// Google Test non-fatal failures and returns false.
|
||||||
|
@ -311,6 +315,13 @@ class Mock {
|
||||||
static void Register(const void* mock_obj,
|
static void Register(const void* mock_obj,
|
||||||
internal::UntypedFunctionMockerBase* mocker);
|
internal::UntypedFunctionMockerBase* mocker);
|
||||||
|
|
||||||
|
// Tells Google Mock where in the source code mock_obj is used in an
|
||||||
|
// ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this
|
||||||
|
// information helps the user identify which object it is.
|
||||||
|
// L < g_gmock_mutex
|
||||||
|
static void RegisterUseByOnCallOrExpectCall(
|
||||||
|
const void* mock_obj, const char* file, int line);
|
||||||
|
|
||||||
// Unregisters a mock method; removes the owning mock object from
|
// Unregisters a mock method; removes the owning mock object from
|
||||||
// the registry when the last mock method associated with it has
|
// the registry when the last mock method associated with it has
|
||||||
// been unregistered. This is called only in the destructor of
|
// been unregistered. This is called only in the destructor of
|
||||||
|
@ -1081,7 +1092,12 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
|
||||||
// Registers this function mocker and the mock object owning it;
|
// Registers this function mocker and the mock object owning it;
|
||||||
// returns a reference to the function mocker object. This is only
|
// returns a reference to the function mocker object. This is only
|
||||||
// called by the ON_CALL() and EXPECT_CALL() macros.
|
// called by the ON_CALL() and EXPECT_CALL() macros.
|
||||||
|
// L < g_gmock_mutex
|
||||||
FunctionMocker<F>& RegisterOwner(const void* mock_obj) {
|
FunctionMocker<F>& RegisterOwner(const void* mock_obj) {
|
||||||
|
{
|
||||||
|
MutexLock l(&g_gmock_mutex);
|
||||||
|
mock_obj_ = mock_obj;
|
||||||
|
}
|
||||||
Mock::Register(mock_obj, this);
|
Mock::Register(mock_obj, this);
|
||||||
return *::testing::internal::down_cast<FunctionMocker<F>*>(this);
|
return *::testing::internal::down_cast<FunctionMocker<F>*>(this);
|
||||||
}
|
}
|
||||||
|
@ -1155,17 +1171,21 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds and returns a default action spec for this mock function.
|
// Adds and returns a default action spec for this mock function.
|
||||||
|
// L < g_gmock_mutex
|
||||||
DefaultActionSpec<F>& AddNewDefaultActionSpec(
|
DefaultActionSpec<F>& AddNewDefaultActionSpec(
|
||||||
const char* file, int line,
|
const char* file, int line,
|
||||||
const ArgumentMatcherTuple& m) {
|
const ArgumentMatcherTuple& m) {
|
||||||
|
Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
|
||||||
default_actions_.push_back(DefaultActionSpec<F>(file, line, m));
|
default_actions_.push_back(DefaultActionSpec<F>(file, line, m));
|
||||||
return default_actions_.back();
|
return default_actions_.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds and returns an expectation spec for this mock function.
|
// Adds and returns an expectation spec for this mock function.
|
||||||
|
// L < g_gmock_mutex
|
||||||
Expectation<F>& AddNewExpectation(
|
Expectation<F>& AddNewExpectation(
|
||||||
const char* file, int line,
|
const char* file, int line,
|
||||||
const ArgumentMatcherTuple& m) {
|
const ArgumentMatcherTuple& m) {
|
||||||
|
Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
|
||||||
const linked_ptr<Expectation<F> > expectation(
|
const linked_ptr<Expectation<F> > expectation(
|
||||||
new Expectation<F>(this, file, line, m));
|
new Expectation<F>(this, file, line, m));
|
||||||
expectations_.push_back(expectation);
|
expectations_.push_back(expectation);
|
||||||
|
@ -1314,10 +1334,13 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address of the mock object this mock method belongs to.
|
// Address of the mock object this mock method belongs to. Only
|
||||||
|
// valid after this mock method has been called or
|
||||||
|
// ON_CALL/EXPECT_CALL has been invoked on it.
|
||||||
const void* mock_obj_; // Protected by g_gmock_mutex.
|
const void* mock_obj_; // Protected by g_gmock_mutex.
|
||||||
|
|
||||||
// Name of the function being mocked.
|
// Name of the function being mocked. Only valid after this mock
|
||||||
|
// method has been called.
|
||||||
const char* name_; // Protected by g_gmock_mutex.
|
const char* name_; // Protected by g_gmock_mutex.
|
||||||
|
|
||||||
// The current spec (either default action spec or expectation spec)
|
// The current spec (either default action spec or expectation spec)
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
// Declares Google Mock flags that we want a user to use programmatically.
|
// Declares Google Mock flags that we want a user to use programmatically.
|
||||||
|
GMOCK_DECLARE_bool_(catch_leaked_mocks);
|
||||||
GMOCK_DECLARE_string_(verbose);
|
GMOCK_DECLARE_string_(verbose);
|
||||||
|
|
||||||
// Initializes Google Mock. This must be called before running the
|
// Initializes Google Mock. This must be called before running the
|
||||||
|
|
|
@ -242,6 +242,21 @@ typedef ::wstring wstring;
|
||||||
typedef ::std::wstring wstring;
|
typedef ::std::wstring wstring;
|
||||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||||
|
|
||||||
|
// Prints the file location in the format native to the compiler.
|
||||||
|
inline void FormatFileLocation(const char* file, int line, ::std::ostream* os) {
|
||||||
|
if (file == NULL)
|
||||||
|
file = "unknown file";
|
||||||
|
if (line < 0) {
|
||||||
|
*os << file << ":";
|
||||||
|
} else {
|
||||||
|
#if _MSC_VER
|
||||||
|
*os << file << "(" << line << "):";
|
||||||
|
#else
|
||||||
|
*os << file << ":" << line << ":";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE.
|
||||||
//
|
//
|
||||||
// GMOCK_CHECK_ is an all mode assert. It aborts the program if the condition
|
// GMOCK_CHECK_ is an all mode assert. It aborts the program if the condition
|
||||||
|
@ -260,26 +275,13 @@ typedef ::std::wstring wstring;
|
||||||
class GMockCheckProvider {
|
class GMockCheckProvider {
|
||||||
public:
|
public:
|
||||||
GMockCheckProvider(const char* condition, const char* file, int line) {
|
GMockCheckProvider(const char* condition, const char* file, int line) {
|
||||||
FormatFileLocation(file, line);
|
FormatFileLocation(file, line, &::std::cerr);
|
||||||
::std::cerr << " ERROR: Condition " << condition << " failed. ";
|
::std::cerr << " ERROR: Condition " << condition << " failed. ";
|
||||||
}
|
}
|
||||||
~GMockCheckProvider() {
|
~GMockCheckProvider() {
|
||||||
::std::cerr << ::std::endl;
|
::std::cerr << ::std::endl;
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
void FormatFileLocation(const char* file, int line) {
|
|
||||||
if (file == NULL)
|
|
||||||
file = "unknown file";
|
|
||||||
if (line < 0) {
|
|
||||||
::std::cerr << file << ":";
|
|
||||||
} else {
|
|
||||||
#if _MSC_VER
|
|
||||||
::std::cerr << file << "(" << line << "):";
|
|
||||||
#else
|
|
||||||
::std::cerr << file << ":" << line << ":";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
::std::ostream& GetStream() { return ::std::cerr; }
|
::std::ostream& GetStream() { return ::std::cerr; }
|
||||||
};
|
};
|
||||||
#define GMOCK_CHECK_(condition) \
|
#define GMOCK_CHECK_(condition) \
|
||||||
|
|
205
msvc/gmock-spec-builders_test.vcproj
Executable file
205
msvc/gmock-spec-builders_test.vcproj
Executable file
|
@ -0,0 +1,205 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="8.00"
|
||||||
|
Name="gmock-spec-builders_test"
|
||||||
|
ProjectGUID="{46972604-5BE0-4493-BAE3-878DB825FDCB}"
|
||||||
|
RootNamespace="gmockspecbuilders_test"
|
||||||
|
Keyword="Win32Proj"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="1"
|
||||||
|
InheritedPropertySheets=".\gmock_config.vsprops"
|
||||||
|
CharacterSet="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../include"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="true"
|
||||||
|
DebugInformationFormat="4"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
LinkIncremental="2"
|
||||||
|
GenerateDebugInformation="true"
|
||||||
|
SubSystem="1"
|
||||||
|
TargetMachine="1"
|
||||||
|
/>
|
||||||
|
<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"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="1"
|
||||||
|
InheritedPropertySheets=".\gmock_config.vsprops"
|
||||||
|
CharacterSet="1"
|
||||||
|
WholeProgramOptimization="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
AdditionalIncludeDirectories="../include"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="true"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
LinkIncremental="1"
|
||||||
|
GenerateDebugInformation="true"
|
||||||
|
SubSystem="1"
|
||||||
|
OptimizeReferences="2"
|
||||||
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"
|
||||||
|
/>
|
||||||
|
<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>
|
||||||
|
<ProjectReference
|
||||||
|
ReferencedProjectIdentifier="{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}"
|
||||||
|
RelativePathToProject=".\gmock.vcproj"
|
||||||
|
/>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<Filter
|
||||||
|
Name="Source Files"
|
||||||
|
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||||
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\test\gmock-spec-builders_test.cc"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Header Files"
|
||||||
|
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||||
|
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||||
|
>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Resource Files"
|
||||||
|
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||||
|
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||||
|
>
|
||||||
|
</Filter>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -11,6 +11,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_output_test_", "gmock
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock-spec-builders_test", "gmock-spec-builders_test.vcproj", "{46972604-5BE0-4493-BAE3-878DB825FDCB}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
@ -37,6 +39,10 @@ Global
|
||||||
{E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32
|
{E4EF614B-30DF-4954-8C53-580A0BF6B589}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
{E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32
|
{E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32
|
{E4EF614B-30DF-4954-8C53-580A0BF6B589}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{46972604-5BE0-4493-BAE3-878DB825FDCB}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{46972604-5BE0-4493-BAE3-878DB825FDCB}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{46972604-5BE0-4493-BAE3-878DB825FDCB}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{46972604-5BE0-4493-BAE3-878DB825FDCB}.Release|Win32.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -172,8 +172,8 @@
|
||||||
</Configurations>
|
</Configurations>
|
||||||
<References>
|
<References>
|
||||||
<ProjectReference
|
<ProjectReference
|
||||||
ReferencedProjectIdentifier="{E4EF614B-30DF-4954-8C53-580A0BF6B589}"
|
ReferencedProjectIdentifier="{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}"
|
||||||
RelativePathToProject=".\gmock_main.vcproj"
|
RelativePathToProject=".\gmock.vcproj"
|
||||||
/>
|
/>
|
||||||
</References>
|
</References>
|
||||||
<Files>
|
<Files>
|
||||||
|
|
|
@ -226,10 +226,6 @@
|
||||||
RelativePath="..\test\gmock-printers_test.cc"
|
RelativePath="..\test\gmock-printers_test.cc"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\test\gmock-spec-builders_test.cc"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\test\gmock_test.cc"
|
RelativePath="..\test\gmock_test.cc"
|
||||||
>
|
>
|
||||||
|
|
|
@ -36,9 +36,17 @@
|
||||||
|
|
||||||
#include <gmock/gmock-spec-builders.h>
|
#include <gmock/gmock-spec-builders.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <iostream> // NOLINT
|
||||||
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
|
||||||
|
#include <unistd.h> // NOLINT
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
@ -148,10 +156,77 @@ void ReportUninterestingCall(CallReaction reaction, const string& msg) {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef std::set<internal::UntypedFunctionMockerBase*> FunctionMockers;
|
typedef std::set<internal::UntypedFunctionMockerBase*> FunctionMockers;
|
||||||
typedef std::map<const void*, FunctionMockers> MockObjectRegistry;
|
|
||||||
|
|
||||||
// Maps a mock object to the set of mock methods it owns. Protected
|
// The current state of a mock object. Such information is needed for
|
||||||
// by g_gmock_mutex.
|
// detecting leaked mock objects and explicitly verifying a mock's
|
||||||
|
// expectations.
|
||||||
|
struct MockObjectState {
|
||||||
|
MockObjectState()
|
||||||
|
: first_used_file(NULL), first_used_line(-1), leakable(false) {}
|
||||||
|
|
||||||
|
// Where in the source file an ON_CALL or EXPECT_CALL is first
|
||||||
|
// invoked on this mock object.
|
||||||
|
const char* first_used_file;
|
||||||
|
int first_used_line;
|
||||||
|
bool leakable; // true iff it's OK to leak the object.
|
||||||
|
FunctionMockers function_mockers; // All registered methods of the object.
|
||||||
|
};
|
||||||
|
|
||||||
|
// A global registry holding the state of all mock objects that are
|
||||||
|
// alive. A mock object is added to this registry the first time
|
||||||
|
// Mock::AllowLeak(), ON_CALL(), or EXPECT_CALL() is called on it. It
|
||||||
|
// is removed from the registry in the mock object's destructor.
|
||||||
|
class MockObjectRegistry {
|
||||||
|
public:
|
||||||
|
// Maps a mock object (identified by its address) to its state.
|
||||||
|
typedef std::map<const void*, MockObjectState> StateMap;
|
||||||
|
|
||||||
|
// This destructor will be called when a program exits, after all
|
||||||
|
// tests in it have been run. By then, there should be no mock
|
||||||
|
// object alive. Therefore we report any living object as test
|
||||||
|
// failure, unless the user explicitly asked us to ignore it.
|
||||||
|
~MockObjectRegistry() {
|
||||||
|
using ::std::cout;
|
||||||
|
|
||||||
|
if (!GMOCK_FLAG(catch_leaked_mocks))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int leaked_count = 0;
|
||||||
|
for (StateMap::const_iterator it = states_.begin(); it != states_.end();
|
||||||
|
++it) {
|
||||||
|
if (it->second.leakable) // The user said it's fine to leak this object.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// TODO(wan@google.com): Print the type of the leaked object.
|
||||||
|
// This can help the user identify the leaked object.
|
||||||
|
cout << "\n";
|
||||||
|
const MockObjectState& state = it->second;
|
||||||
|
internal::FormatFileLocation(
|
||||||
|
state.first_used_file, state.first_used_line, &cout);
|
||||||
|
cout << " ERROR: this mock object should be deleted but never is. "
|
||||||
|
<< "Its address is @" << it->first << ".";
|
||||||
|
leaked_count++;
|
||||||
|
}
|
||||||
|
if (leaked_count > 0) {
|
||||||
|
cout << "\nERROR: " << leaked_count
|
||||||
|
<< " leaked mock " << (leaked_count == 1 ? "object" : "objects")
|
||||||
|
<< " found at program exit.\n";
|
||||||
|
cout.flush();
|
||||||
|
::std::cerr.flush();
|
||||||
|
// RUN_ALL_TESTS() has already returned when this destructor is
|
||||||
|
// called. Therefore we cannot use the normal Google Test
|
||||||
|
// failure reporting mechanism.
|
||||||
|
_exit(1); // We cannot call exit() as it is not reentrant and
|
||||||
|
// may already have been called.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateMap& states() { return states_; }
|
||||||
|
private:
|
||||||
|
StateMap states_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Protected by g_gmock_mutex.
|
||||||
MockObjectRegistry g_mock_object_registry;
|
MockObjectRegistry g_mock_object_registry;
|
||||||
|
|
||||||
// Maps a mock object to the reaction Google Mock should have when an
|
// Maps a mock object to the reaction Google Mock should have when an
|
||||||
|
@ -208,6 +283,14 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls(
|
||||||
internal::WARN : g_uninteresting_call_reaction[mock_obj];
|
internal::WARN : g_uninteresting_call_reaction[mock_obj];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tells Google Mock to ignore mock_obj when checking for leaked mock
|
||||||
|
// objects.
|
||||||
|
// L < g_gmock_mutex
|
||||||
|
void Mock::AllowLeak(const void* mock_obj) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
g_mock_object_registry.states()[mock_obj].leakable = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Verifies and clears all expectations on the given mock object. If
|
// Verifies and clears all expectations on the given mock object. If
|
||||||
// the expectations aren't satisfied, generates one or more Google
|
// the expectations aren't satisfied, generates one or more Google
|
||||||
// Test non-fatal failures and returns false.
|
// Test non-fatal failures and returns false.
|
||||||
|
@ -233,7 +316,7 @@ bool Mock::VerifyAndClear(void* mock_obj) {
|
||||||
// L >= g_gmock_mutex
|
// L >= g_gmock_mutex
|
||||||
bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) {
|
bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) {
|
||||||
internal::g_gmock_mutex.AssertHeld();
|
internal::g_gmock_mutex.AssertHeld();
|
||||||
if (g_mock_object_registry.count(mock_obj) == 0) {
|
if (g_mock_object_registry.states().count(mock_obj) == 0) {
|
||||||
// No EXPECT_CALL() was set on the given mock object.
|
// No EXPECT_CALL() was set on the given mock object.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +324,8 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) {
|
||||||
// Verifies and clears the expectations on each mock method in the
|
// Verifies and clears the expectations on each mock method in the
|
||||||
// given mock object.
|
// given mock object.
|
||||||
bool expectations_met = true;
|
bool expectations_met = true;
|
||||||
FunctionMockers& mockers = g_mock_object_registry[mock_obj];
|
FunctionMockers& mockers =
|
||||||
|
g_mock_object_registry.states()[mock_obj].function_mockers;
|
||||||
for (FunctionMockers::const_iterator it = mockers.begin();
|
for (FunctionMockers::const_iterator it = mockers.begin();
|
||||||
it != mockers.end(); ++it) {
|
it != mockers.end(); ++it) {
|
||||||
if (!(*it)->VerifyAndClearExpectationsLocked()) {
|
if (!(*it)->VerifyAndClearExpectationsLocked()) {
|
||||||
|
@ -259,7 +343,21 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) {
|
||||||
void Mock::Register(const void* mock_obj,
|
void Mock::Register(const void* mock_obj,
|
||||||
internal::UntypedFunctionMockerBase* mocker) {
|
internal::UntypedFunctionMockerBase* mocker) {
|
||||||
internal::MutexLock l(&internal::g_gmock_mutex);
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
g_mock_object_registry[mock_obj].insert(mocker);
|
g_mock_object_registry.states()[mock_obj].function_mockers.insert(mocker);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tells Google Mock where in the source code mock_obj is used in an
|
||||||
|
// ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this
|
||||||
|
// information helps the user identify which object it is.
|
||||||
|
// L < g_gmock_mutex
|
||||||
|
void Mock::RegisterUseByOnCallOrExpectCall(
|
||||||
|
const void* mock_obj, const char* file, int line) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
MockObjectState& state = g_mock_object_registry.states()[mock_obj];
|
||||||
|
if (state.first_used_file == NULL) {
|
||||||
|
state.first_used_file = file;
|
||||||
|
state.first_used_line = line;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unregisters a mock method; removes the owning mock object from the
|
// Unregisters a mock method; removes the owning mock object from the
|
||||||
|
@ -269,13 +367,14 @@ void Mock::Register(const void* mock_obj,
|
||||||
// L >= g_gmock_mutex
|
// L >= g_gmock_mutex
|
||||||
void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) {
|
void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) {
|
||||||
internal::g_gmock_mutex.AssertHeld();
|
internal::g_gmock_mutex.AssertHeld();
|
||||||
for (MockObjectRegistry::iterator it = g_mock_object_registry.begin();
|
for (MockObjectRegistry::StateMap::iterator it =
|
||||||
it != g_mock_object_registry.end(); ++it) {
|
g_mock_object_registry.states().begin();
|
||||||
FunctionMockers& mockers = it->second;
|
it != g_mock_object_registry.states().end(); ++it) {
|
||||||
|
FunctionMockers& mockers = it->second.function_mockers;
|
||||||
if (mockers.erase(mocker) > 0) {
|
if (mockers.erase(mocker) > 0) {
|
||||||
// mocker was in mockers and has been just removed.
|
// mocker was in mockers and has been just removed.
|
||||||
if (mockers.empty()) {
|
if (mockers.empty()) {
|
||||||
g_mock_object_registry.erase(it);
|
g_mock_object_registry.states().erase(it);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -287,14 +386,15 @@ void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) {
|
||||||
void Mock::ClearDefaultActionsLocked(void* mock_obj) {
|
void Mock::ClearDefaultActionsLocked(void* mock_obj) {
|
||||||
internal::g_gmock_mutex.AssertHeld();
|
internal::g_gmock_mutex.AssertHeld();
|
||||||
|
|
||||||
if (g_mock_object_registry.count(mock_obj) == 0) {
|
if (g_mock_object_registry.states().count(mock_obj) == 0) {
|
||||||
// No ON_CALL() was set on the given mock object.
|
// No ON_CALL() was set on the given mock object.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears the default actions for each mock method in the given mock
|
// Clears the default actions for each mock method in the given mock
|
||||||
// object.
|
// object.
|
||||||
FunctionMockers& mockers = g_mock_object_registry[mock_obj];
|
FunctionMockers& mockers =
|
||||||
|
g_mock_object_registry.states()[mock_obj].function_mockers;
|
||||||
for (FunctionMockers::const_iterator it = mockers.begin();
|
for (FunctionMockers::const_iterator it = mockers.begin();
|
||||||
it != mockers.end(); ++it) {
|
it != mockers.end(); ++it) {
|
||||||
(*it)->ClearDefaultActionsLocked();
|
(*it)->ClearDefaultActionsLocked();
|
||||||
|
|
31
src/gmock.cc
31
src/gmock.cc
|
@ -34,6 +34,15 @@
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
|
// TODO(wan@google.com): support using environment variables to
|
||||||
|
// control the flag values, like what Google Test does.
|
||||||
|
|
||||||
|
// TODO(wan@google.com): change the default value to true after people
|
||||||
|
// have a chance to fix their leaked mocks.
|
||||||
|
GMOCK_DEFINE_bool_(catch_leaked_mocks, false,
|
||||||
|
"true iff Google Mock should report leaked mock objects "
|
||||||
|
"as failures.");
|
||||||
|
|
||||||
GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity,
|
GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity,
|
||||||
"Controls how verbose Google Mock's output is."
|
"Controls how verbose Google Mock's output is."
|
||||||
" Valid values:\n"
|
" Valid values:\n"
|
||||||
|
@ -76,6 +85,24 @@ static const char* ParseGoogleMockFlagValue(const char* str,
|
||||||
return flag_end + 1;
|
return flag_end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parses a string for a Google Mock bool flag, in the form of
|
||||||
|
// "--gmock_flag=value".
|
||||||
|
//
|
||||||
|
// On success, stores the value of the flag in *value, and returns
|
||||||
|
// true. On failure, returns false without changing *value.
|
||||||
|
static bool ParseGoogleMockBoolFlag(const char* str, const char* flag,
|
||||||
|
bool* value) {
|
||||||
|
// Gets the value of the flag as a string.
|
||||||
|
const char* const value_str = ParseGoogleMockFlagValue(str, flag, true);
|
||||||
|
|
||||||
|
// Aborts if the parsing failed.
|
||||||
|
if (value_str == NULL) return false;
|
||||||
|
|
||||||
|
// Converts the string value to a bool.
|
||||||
|
*value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Parses a string for a Google Mock string flag, in the form of
|
// Parses a string for a Google Mock string flag, in the form of
|
||||||
// "--gmock_flag=value".
|
// "--gmock_flag=value".
|
||||||
//
|
//
|
||||||
|
@ -110,7 +137,9 @@ void InitGoogleMockImpl(int* argc, CharType** argv) {
|
||||||
const char* const arg = arg_string.c_str();
|
const char* const arg = arg_string.c_str();
|
||||||
|
|
||||||
// Do we see a Google Mock flag?
|
// Do we see a Google Mock flag?
|
||||||
if (ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose))) {
|
if (ParseGoogleMockBoolFlag(arg, "catch_leaked_mocks",
|
||||||
|
&GMOCK_FLAG(catch_leaked_mocks)) ||
|
||||||
|
ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose))) {
|
||||||
// Yes. Shift the remainder of the argv list left by one. Note
|
// Yes. Shift the remainder of the argv list left by one. Note
|
||||||
// that argv has (*argc + 1) elements, the last one always being
|
// that argv has (*argc + 1) elements, the last one always being
|
||||||
// NULL. The following loop moves the trailing NULL element as
|
// NULL. The following loop moves the trailing NULL element as
|
||||||
|
|
|
@ -1612,6 +1612,43 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) {
|
||||||
|
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
|
TEST(AllowLeakTest, AllowsLeakingUnusedMockObject) {
|
||||||
|
MockA* a = new MockA;
|
||||||
|
Mock::AllowLeak(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AllowLeakTest, CanBeCalledBeforeOnCall) {
|
||||||
|
MockA* a = new MockA;
|
||||||
|
Mock::AllowLeak(a);
|
||||||
|
ON_CALL(*a, DoA(_)).WillByDefault(Return());
|
||||||
|
a->DoA(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AllowLeakTest, CanBeCalledAfterOnCall) {
|
||||||
|
MockA* a = new MockA;
|
||||||
|
ON_CALL(*a, DoA(_)).WillByDefault(Return());
|
||||||
|
Mock::AllowLeak(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AllowLeakTest, CanBeCalledBeforeExpectCall) {
|
||||||
|
MockA* a = new MockA;
|
||||||
|
Mock::AllowLeak(a);
|
||||||
|
EXPECT_CALL(*a, DoA(_));
|
||||||
|
a->DoA(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AllowLeakTest, CanBeCalledAfterExpectCall) {
|
||||||
|
MockA* a = new MockA;
|
||||||
|
EXPECT_CALL(*a, DoA(_)).Times(AnyNumber());
|
||||||
|
Mock::AllowLeak(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AllowLeakTest, WorksWhenBothOnCallAndExpectCallArePresent) {
|
||||||
|
MockA* a = new MockA;
|
||||||
|
ON_CALL(*a, DoA(_)).WillByDefault(Return());
|
||||||
|
EXPECT_CALL(*a, DoA(_)).Times(AnyNumber());
|
||||||
|
Mock::AllowLeak(a);
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that we can verify and clear a mock object's expectations
|
// Tests that we can verify and clear a mock object's expectations
|
||||||
// when none of its methods has expectations.
|
// when none of its methods has expectations.
|
||||||
|
@ -1916,3 +1953,14 @@ void Helper(MockC* c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
testing::InitGoogleMock(&argc, argv);
|
||||||
|
|
||||||
|
// Ensures that the tests pass no matter what value of
|
||||||
|
// --gmock_catch_leaked_mocks and --gmock_verbose the user specifies.
|
||||||
|
testing::GMOCK_FLAG(catch_leaked_mocks) = true;
|
||||||
|
testing::GMOCK_FLAG(verbose) = testing::internal::kWarningVerbosity;
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
84
test/gmock_leak_test.py
Executable file
84
test/gmock_leak_test.py
Executable file
|
@ -0,0 +1,84 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2009, 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.
|
||||||
|
|
||||||
|
"""Tests that leaked mock objects can be caught be Google Mock."""
|
||||||
|
|
||||||
|
__author__ = 'wan@google.com (Zhanyong Wan)'
|
||||||
|
|
||||||
|
import gmock_test_utils
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
IS_WINDOWS = os.name == 'nt'
|
||||||
|
|
||||||
|
if IS_WINDOWS:
|
||||||
|
# TODO(wan@google.com): test the opt build too. We should do it
|
||||||
|
# when Vlad Losev's work on Google Test's Python test driver is
|
||||||
|
# done, such that we can reuse the work.
|
||||||
|
PROGRAM = r'..\build.dbg\gmock_leak_test_.exe'
|
||||||
|
else:
|
||||||
|
PROGRAM = 'gmock_leak_test_'
|
||||||
|
|
||||||
|
PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM)
|
||||||
|
TEST_WITH_EXPECT_CALL = PROGRAM_PATH + ' --gtest_filter=*ExpectCall*'
|
||||||
|
TEST_WITH_ON_CALL = PROGRAM_PATH + ' --gtest_filter=*OnCall*'
|
||||||
|
TEST_MULTIPLE_LEAKS = PROGRAM_PATH + ' --gtest_filter=*MultipleLeaked*'
|
||||||
|
|
||||||
|
|
||||||
|
class GMockLeakTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def testDoesNotCatchLeakedMockByDefault(self):
|
||||||
|
self.assertEquals(0, os.system(TEST_WITH_EXPECT_CALL))
|
||||||
|
self.assertEquals(0, os.system(TEST_WITH_ON_CALL))
|
||||||
|
|
||||||
|
def testDoesNotCatchLeakedMockWhenDisabled(self):
|
||||||
|
self.assertEquals(
|
||||||
|
0, os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=0'))
|
||||||
|
self.assertEquals(
|
||||||
|
0, os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks=0'))
|
||||||
|
|
||||||
|
def testCatchesLeakedMockWhenEnabled(self):
|
||||||
|
self.assertNotEqual(
|
||||||
|
os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks'), 0)
|
||||||
|
self.assertNotEqual(
|
||||||
|
os.system(TEST_WITH_ON_CALL + ' --gmock_catch_leaked_mocks'), 0)
|
||||||
|
|
||||||
|
def testCatchesLeakedMockWhenEnabledWithExplictFlagValue(self):
|
||||||
|
self.assertNotEqual(
|
||||||
|
os.system(TEST_WITH_EXPECT_CALL + ' --gmock_catch_leaked_mocks=1'), 0)
|
||||||
|
|
||||||
|
def testCatchesMultipleLeakedMocks(self):
|
||||||
|
self.assertNotEqual(
|
||||||
|
os.system(TEST_MULTIPLE_LEAKS + ' --gmock_catch_leaked_mocks'), 0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
gmock_test_utils.Main()
|
95
test/gmock_leak_test_.cc
Normal file
95
test/gmock_leak_test_.cc
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// Copyright 2009, 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.
|
||||||
|
//
|
||||||
|
// Author: wan@google.com (Zhanyong Wan)
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This program is for verifying that a leaked mock object can be
|
||||||
|
// caught by Google Mock's leak detector.
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::testing::Return;
|
||||||
|
|
||||||
|
class FooInterface {
|
||||||
|
public:
|
||||||
|
virtual ~FooInterface() {}
|
||||||
|
virtual void DoThis() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockFoo : public FooInterface {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0(DoThis, void());
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(LeakTest, LeakedMockWithExpectCallCausesFailureWhenLeakCheckingIsEnabled) {
|
||||||
|
MockFoo* foo = new MockFoo;
|
||||||
|
|
||||||
|
EXPECT_CALL(*foo, DoThis());
|
||||||
|
foo->DoThis();
|
||||||
|
|
||||||
|
// In order to test the leak detector, we deliberately leak foo.
|
||||||
|
|
||||||
|
// Makes sure Google Mock's leak detector can change the exit code
|
||||||
|
// to 1 even when the code is already exiting with 0.
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LeakTest, LeakedMockWithOnCallCausesFailureWhenLeakCheckingIsEnabled) {
|
||||||
|
MockFoo* foo = new MockFoo;
|
||||||
|
|
||||||
|
ON_CALL(*foo, DoThis()).WillByDefault(Return());
|
||||||
|
|
||||||
|
// In order to test the leak detector, we deliberately leak foo.
|
||||||
|
|
||||||
|
// Makes sure Google Mock's leak detector can change the exit code
|
||||||
|
// to 1 even when the code is already exiting with 0.
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LeakTest, CatchesMultipleLeakedMockObjects) {
|
||||||
|
MockFoo* foo1 = new MockFoo;
|
||||||
|
MockFoo* foo2 = new MockFoo;
|
||||||
|
|
||||||
|
ON_CALL(*foo1, DoThis()).WillByDefault(Return());
|
||||||
|
EXPECT_CALL(*foo2, DoThis());
|
||||||
|
foo2->DoThis();
|
||||||
|
|
||||||
|
// In order to test the leak detector, we deliberately leak foo1 and
|
||||||
|
// foo2.
|
||||||
|
|
||||||
|
// Makes sure Google Mock's leak detector can change the exit code
|
||||||
|
// to 1 even when the code is already exiting with 0.
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
|
@ -59,7 +59,7 @@ else:
|
||||||
PROGRAM = 'gmock_output_test_'
|
PROGRAM = 'gmock_output_test_'
|
||||||
|
|
||||||
PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM)
|
PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM)
|
||||||
COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0'
|
COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0 --gtest_print_time=0'
|
||||||
GOLDEN_NAME = 'gmock_output_test_golden.txt'
|
GOLDEN_NAME = 'gmock_output_test_golden.txt'
|
||||||
GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(),
|
GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(),
|
||||||
GOLDEN_NAME)
|
GOLDEN_NAME)
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
using testing::_;
|
using testing::_;
|
||||||
|
using testing::AnyNumber;
|
||||||
using testing::Ge;
|
using testing::Ge;
|
||||||
using testing::InSequence;
|
using testing::InSequence;
|
||||||
using testing::Ref;
|
using testing::Ref;
|
||||||
|
@ -239,3 +240,31 @@ TEST_F(GMockOutputTest, ExplicitActionsRunOutWithDefaultAction) {
|
||||||
foo_.Bar2(2, 2);
|
foo_.Bar2(2, 2);
|
||||||
foo_.Bar2(1, 1); // Explicit actions in EXPECT_CALL run out.
|
foo_.Bar2(1, 1); // Explicit actions in EXPECT_CALL run out.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(GMockOutputTest, CatchesLeakedMocks) {
|
||||||
|
MockFoo* foo1 = new MockFoo;
|
||||||
|
MockFoo* foo2 = new MockFoo;
|
||||||
|
|
||||||
|
// Invokes ON_CALL on foo1.
|
||||||
|
ON_CALL(*foo1, Bar(_, _, _)).WillByDefault(Return('a'));
|
||||||
|
|
||||||
|
// Invokes EXPECT_CALL on foo2.
|
||||||
|
EXPECT_CALL(*foo2, Bar2(_, _));
|
||||||
|
EXPECT_CALL(*foo2, Bar2(1, _));
|
||||||
|
EXPECT_CALL(*foo2, Bar3(_, _)).Times(AnyNumber());
|
||||||
|
foo2->Bar2(2, 1);
|
||||||
|
foo2->Bar2(1, 1);
|
||||||
|
|
||||||
|
// Both foo1 and foo2 are deliberately leaked.
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
testing::InitGoogleMock(&argc, argv);
|
||||||
|
|
||||||
|
// Ensures that the tests pass no matter what value of
|
||||||
|
// --gmock_catch_leaked_mocks and --gmock_verbose the user specifies.
|
||||||
|
testing::GMOCK_FLAG(catch_leaked_mocks) = true;
|
||||||
|
testing::GMOCK_FLAG(verbose) = "warning";
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
Running main() from gmock_main.cc
|
|
||||||
[ RUN ] GMockOutputTest.ExpectedCall
|
[ RUN ] GMockOutputTest.ExpectedCall
|
||||||
|
|
||||||
FILE:#: EXPECT_CALL(foo_, Bar2(0, _)) invoked
|
FILE:#: EXPECT_CALL(foo_, Bar2(0, _)) invoked
|
||||||
|
@ -280,6 +279,8 @@ Called 2 times, but only 1 WillOnce() is specified - taking default action speci
|
||||||
FILE:#:
|
FILE:#:
|
||||||
Stack trace:
|
Stack trace:
|
||||||
[ OK ] GMockOutputTest.ExplicitActionsRunOutWithDefaultAction
|
[ OK ] GMockOutputTest.ExplicitActionsRunOutWithDefaultAction
|
||||||
|
[ RUN ] GMockOutputTest.CatchesLeakedMocks
|
||||||
|
[ OK ] GMockOutputTest.CatchesLeakedMocks
|
||||||
[ FAILED ] GMockOutputTest.UnexpectedCall
|
[ FAILED ] GMockOutputTest.UnexpectedCall
|
||||||
[ FAILED ] GMockOutputTest.UnexpectedCallToVoidFunction
|
[ FAILED ] GMockOutputTest.UnexpectedCallToVoidFunction
|
||||||
[ FAILED ] GMockOutputTest.ExcessiveCall
|
[ FAILED ] GMockOutputTest.ExcessiveCall
|
||||||
|
@ -294,3 +295,7 @@ Stack trace:
|
||||||
[ FAILED ] GMockOutputTest.UnexpectedCallWithDefaultAction
|
[ FAILED ] GMockOutputTest.UnexpectedCallWithDefaultAction
|
||||||
[ FAILED ] GMockOutputTest.ExcessiveCallWithDefaultAction
|
[ FAILED ] GMockOutputTest.ExcessiveCallWithDefaultAction
|
||||||
|
|
||||||
|
|
||||||
|
FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#.
|
||||||
|
FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#.
|
||||||
|
ERROR: 2 leaked mock objects found at program exit.
|
||||||
|
|
|
@ -246,3 +246,10 @@ TEST(WideInitGoogleMockTest, CallsInitGoogleTest) {
|
||||||
TestInitGoogleMock(argv, new_argv, "error");
|
TestInitGoogleMock(argv, new_argv, "error");
|
||||||
EXPECT_EQ(old_init_gtest_count + 1, g_init_gtest_count);
|
EXPECT_EQ(old_init_gtest_count + 1, g_init_gtest_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes sure Google Mock flags can be accessed in code.
|
||||||
|
TEST(FlagTest, IsAccessibleInCode) {
|
||||||
|
bool dummy = testing::GMOCK_FLAG(catch_leaked_mocks) &&
|
||||||
|
testing::GMOCK_FLAG(verbose) == "";
|
||||||
|
dummy = dummy; // Avoids the "unused local variable" warning.
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user