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
|
||||
check_PROGRAMS += test/gmock-spec-builders_test
|
||||
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
|
||||
check_PROGRAMS += test/gmock_test
|
||||
|
@ -147,6 +147,11 @@ dist_check_SCRIPTS =
|
|||
# Python modules used by multiple Python tests below.
|
||||
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_
|
||||
test_gmock_output_test__SOURCES = test/gmock_output_test_.cc
|
||||
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.
|
||||
if HAVE_PYTHON
|
||||
TESTS += test/gmock_output_test.py
|
||||
TESTS += \
|
||||
test/gmock_leak_test.py \
|
||||
test/gmock_output_test.py
|
||||
endif
|
||||
|
||||
# Nonstandard package files for distribution.
|
||||
EXTRA_DIST += \
|
||||
CHANGES \
|
||||
CONTRIBUTORS \
|
||||
make/Makefile \
|
||||
src/gmock-all.cc
|
||||
CHANGES \
|
||||
CONTRIBUTORS \
|
||||
make/Makefile \
|
||||
src/gmock-all.cc
|
||||
|
||||
# Pump scripts for generating Google Mock headers.
|
||||
# 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_main.vcproj \
|
||||
msvc/gmock_output_test_.vcproj \
|
||||
msvc/gmock-spec-builders_test.vcproj \
|
||||
msvc/gmock_test.vcproj
|
||||
|
|
|
@ -246,6 +246,10 @@ class Mock {
|
|||
public:
|
||||
// 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.
|
||||
// If the expectations aren't satisfied, generates one or more
|
||||
// Google Test non-fatal failures and returns false.
|
||||
|
@ -311,6 +315,13 @@ class Mock {
|
|||
static void Register(const void* mock_obj,
|
||||
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
|
||||
// the registry when the last mock method associated with it has
|
||||
// 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;
|
||||
// returns a reference to the function mocker object. This is only
|
||||
// called by the ON_CALL() and EXPECT_CALL() macros.
|
||||
// L < g_gmock_mutex
|
||||
FunctionMocker<F>& RegisterOwner(const void* mock_obj) {
|
||||
{
|
||||
MutexLock l(&g_gmock_mutex);
|
||||
mock_obj_ = mock_obj;
|
||||
}
|
||||
Mock::Register(mock_obj, 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.
|
||||
// L < g_gmock_mutex
|
||||
DefaultActionSpec<F>& AddNewDefaultActionSpec(
|
||||
const char* file, int line,
|
||||
const ArgumentMatcherTuple& m) {
|
||||
Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
|
||||
default_actions_.push_back(DefaultActionSpec<F>(file, line, m));
|
||||
return default_actions_.back();
|
||||
}
|
||||
|
||||
// Adds and returns an expectation spec for this mock function.
|
||||
// L < g_gmock_mutex
|
||||
Expectation<F>& AddNewExpectation(
|
||||
const char* file, int line,
|
||||
const ArgumentMatcherTuple& m) {
|
||||
Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
|
||||
const linked_ptr<Expectation<F> > expectation(
|
||||
new Expectation<F>(this, file, line, m));
|
||||
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.
|
||||
|
||||
// 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.
|
||||
|
||||
// The current spec (either default action spec or expectation spec)
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
namespace testing {
|
||||
|
||||
// Declares Google Mock flags that we want a user to use programmatically.
|
||||
GMOCK_DECLARE_bool_(catch_leaked_mocks);
|
||||
GMOCK_DECLARE_string_(verbose);
|
||||
|
||||
// Initializes Google Mock. This must be called before running the
|
||||
|
|
|
@ -242,6 +242,21 @@ typedef ::wstring wstring;
|
|||
typedef ::std::wstring 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.
|
||||
//
|
||||
// GMOCK_CHECK_ is an all mode assert. It aborts the program if the condition
|
||||
|
@ -260,26 +275,13 @@ typedef ::std::wstring wstring;
|
|||
class GMockCheckProvider {
|
||||
public:
|
||||
GMockCheckProvider(const char* condition, const char* file, int line) {
|
||||
FormatFileLocation(file, line);
|
||||
FormatFileLocation(file, line, &::std::cerr);
|
||||
::std::cerr << " ERROR: Condition " << condition << " failed. ";
|
||||
}
|
||||
~GMockCheckProvider() {
|
||||
::std::cerr << ::std::endl;
|
||||
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; }
|
||||
};
|
||||
#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
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock_main", "gmock_main.vcproj", "{E4EF614B-30DF-4954-8C53-580A0BF6B589}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmock-spec-builders_test", "gmock-spec-builders_test.vcproj", "{46972604-5BE0-4493-BAE3-878DB825FDCB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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}.Release|Win32.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -172,8 +172,8 @@
|
|||
</Configurations>
|
||||
<References>
|
||||
<ProjectReference
|
||||
ReferencedProjectIdentifier="{E4EF614B-30DF-4954-8C53-580A0BF6B589}"
|
||||
RelativePathToProject=".\gmock_main.vcproj"
|
||||
ReferencedProjectIdentifier="{34681F0D-CE45-415D-B5F2-5C662DFE3BD5}"
|
||||
RelativePathToProject=".\gmock.vcproj"
|
||||
/>
|
||||
</References>
|
||||
<Files>
|
||||
|
|
|
@ -226,10 +226,6 @@
|
|||
RelativePath="..\test\gmock-printers_test.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\test\gmock-spec-builders_test.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\test\gmock_test.cc"
|
||||
>
|
||||
|
|
|
@ -36,9 +36,17 @@
|
|||
|
||||
#include <gmock/gmock-spec-builders.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <iostream> // NOLINT
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
|
||||
#include <unistd.h> // NOLINT
|
||||
#endif
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
|
@ -148,10 +156,77 @@ void ReportUninterestingCall(CallReaction reaction, const string& msg) {
|
|||
namespace {
|
||||
|
||||
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
|
||||
// by g_gmock_mutex.
|
||||
// The current state of a mock object. Such information is needed for
|
||||
// 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;
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
// 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
|
||||
// the expectations aren't satisfied, generates one or more Google
|
||||
// Test non-fatal failures and returns false.
|
||||
|
@ -233,7 +316,7 @@ bool Mock::VerifyAndClear(void* mock_obj) {
|
|||
// L >= g_gmock_mutex
|
||||
bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) {
|
||||
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.
|
||||
return true;
|
||||
}
|
||||
|
@ -241,7 +324,8 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) {
|
|||
// Verifies and clears the expectations on each mock method in the
|
||||
// given mock object.
|
||||
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();
|
||||
it != mockers.end(); ++it) {
|
||||
if (!(*it)->VerifyAndClearExpectationsLocked()) {
|
||||
|
@ -259,7 +343,21 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj) {
|
|||
void Mock::Register(const void* mock_obj,
|
||||
internal::UntypedFunctionMockerBase* mocker) {
|
||||
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
|
||||
|
@ -269,13 +367,14 @@ void Mock::Register(const void* mock_obj,
|
|||
// L >= g_gmock_mutex
|
||||
void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) {
|
||||
internal::g_gmock_mutex.AssertHeld();
|
||||
for (MockObjectRegistry::iterator it = g_mock_object_registry.begin();
|
||||
it != g_mock_object_registry.end(); ++it) {
|
||||
FunctionMockers& mockers = it->second;
|
||||
for (MockObjectRegistry::StateMap::iterator it =
|
||||
g_mock_object_registry.states().begin();
|
||||
it != g_mock_object_registry.states().end(); ++it) {
|
||||
FunctionMockers& mockers = it->second.function_mockers;
|
||||
if (mockers.erase(mocker) > 0) {
|
||||
// mocker was in mockers and has been just removed.
|
||||
if (mockers.empty()) {
|
||||
g_mock_object_registry.erase(it);
|
||||
g_mock_object_registry.states().erase(it);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -287,14 +386,15 @@ void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) {
|
|||
void Mock::ClearDefaultActionsLocked(void* mock_obj) {
|
||||
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.
|
||||
return;
|
||||
}
|
||||
|
||||
// Clears the default actions for each mock method in the given mock
|
||||
// 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();
|
||||
it != mockers.end(); ++it) {
|
||||
(*it)->ClearDefaultActionsLocked();
|
||||
|
|
31
src/gmock.cc
31
src/gmock.cc
|
@ -34,6 +34,15 @@
|
|||
|
||||
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,
|
||||
"Controls how verbose Google Mock's output is."
|
||||
" Valid values:\n"
|
||||
|
@ -76,6 +85,24 @@ static const char* ParseGoogleMockFlagValue(const char* str,
|
|||
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
|
||||
// "--gmock_flag=value".
|
||||
//
|
||||
|
@ -110,7 +137,9 @@ void InitGoogleMockImpl(int* argc, CharType** argv) {
|
|||
const char* const arg = arg_string.c_str();
|
||||
|
||||
// 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
|
||||
// that argv has (*argc + 1) elements, the last one always being
|
||||
// NULL. The following loop moves the trailing NULL element as
|
||||
|
|
|
@ -1612,6 +1612,43 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) {
|
|||
|
||||
#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
|
||||
// when none of its methods has expectations.
|
||||
|
@ -1916,3 +1953,14 @@ void Helper(MockC* c) {
|
|||
}
|
||||
|
||||
} // 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_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_PATH = os.path.join(gmock_test_utils.GetSourceDir(),
|
||||
GOLDEN_NAME)
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
using testing::_;
|
||||
using testing::AnyNumber;
|
||||
using testing::Ge;
|
||||
using testing::InSequence;
|
||||
using testing::Ref;
|
||||
|
@ -239,3 +240,31 @@ TEST_F(GMockOutputTest, ExplicitActionsRunOutWithDefaultAction) {
|
|||
foo_.Bar2(2, 2);
|
||||
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
|
||||
|
||||
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:#:
|
||||
Stack trace:
|
||||
[ OK ] GMockOutputTest.ExplicitActionsRunOutWithDefaultAction
|
||||
[ RUN ] GMockOutputTest.CatchesLeakedMocks
|
||||
[ OK ] GMockOutputTest.CatchesLeakedMocks
|
||||
[ FAILED ] GMockOutputTest.UnexpectedCall
|
||||
[ FAILED ] GMockOutputTest.UnexpectedCallToVoidFunction
|
||||
[ FAILED ] GMockOutputTest.ExcessiveCall
|
||||
|
@ -294,3 +295,7 @@ Stack trace:
|
|||
[ FAILED ] GMockOutputTest.UnexpectedCallWithDefaultAction
|
||||
[ 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");
|
||||
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