Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
yangql
googletest
Commits
df35a763
Commit
df35a763
authored
Apr 22, 2009
by
zhanyong.wan
Browse files
Implements --gmock_catch_leaked_mocks and Mock::AllowLeak.
parent
1c8eb1c0
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
681 additions
and
43 deletions
+681
-43
Makefile.am
Makefile.am
+14
-6
include/gmock/gmock-spec-builders.h
include/gmock/gmock-spec-builders.h
+25
-2
include/gmock/gmock.h
include/gmock/gmock.h
+1
-0
include/gmock/internal/gmock-port.h
include/gmock/internal/gmock-port.h
+16
-14
msvc/gmock-spec-builders_test.vcproj
msvc/gmock-spec-builders_test.vcproj
+205
-0
msvc/gmock.sln
msvc/gmock.sln
+6
-0
msvc/gmock_output_test_.vcproj
msvc/gmock_output_test_.vcproj
+2
-2
msvc/gmock_test.vcproj
msvc/gmock_test.vcproj
+0
-4
src/gmock-spec-builders.cc
src/gmock-spec-builders.cc
+112
-12
src/gmock.cc
src/gmock.cc
+30
-1
test/gmock-spec-builders_test.cc
test/gmock-spec-builders_test.cc
+48
-0
test/gmock_leak_test.py
test/gmock_leak_test.py
+84
-0
test/gmock_leak_test_.cc
test/gmock_leak_test_.cc
+95
-0
test/gmock_output_test.py
test/gmock_output_test.py
+1
-1
test/gmock_output_test_.cc
test/gmock_output_test_.cc
+29
-0
test/gmock_output_test_golden.txt
test/gmock_output_test_golden.txt
+6
-1
test/gmock_test.cc
test/gmock_test.cc
+7
-0
No files found.
Makefile.am
View file @
df35a763
...
...
@@ -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,7 +160,9 @@ 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.
...
...
@@ -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
include/gmock/gmock-spec-builders.h
View file @
df35a763
...
...
@@ -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)
...
...
include/gmock/gmock.h
View file @
df35a763
...
...
@@ -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
...
...
include/gmock/internal/gmock-port.h
View file @
df35a763
...
...
@@ -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) \
...
...
msvc/gmock-spec-builders_test.vcproj
0 → 100755
View file @
df35a763
<?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>
msvc/gmock.sln
View file @
df35a763
...
...
@@ -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
...
...
msvc/gmock_output_test_.vcproj
View file @
df35a763
...
...
@@ -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>
...
...
msvc/gmock_test.vcproj
View file @
df35a763
...
...
@@ -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"
>
...
...
src/gmock-spec-builders.cc
View file @
df35a763
...
...
@@ -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
<<
"
\n
ERROR: "
<<
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
();
...
...
src/gmock.cc
View file @
df35a763
...
...
@@ -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
...
...
test/gmock-spec-builders_test.cc
View file @
df35a763
...
...
@@ -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
();
}
test/gmock_leak_test.py
0 → 100755
View file @
df35a763
#!/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
()
test/gmock_leak_test_.cc
0 → 100644
View file @
df35a763
// 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
test/gmock_output_test.py
View file @
df35a763
...
...
@@ -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
)
...
...
test/gmock_output_test_.cc
View file @
df35a763
...
...
@@ -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
();
}
test/gmock_output_test_golden.txt
View file @
df35a763
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.
test/gmock_test.cc
View file @
df35a763
...
...
@@ -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.
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment