More refactoring for the event listener API, by Vlad Losev.

This commit is contained in:
zhanyong.wan 2009-07-16 00:36:55 +00:00
parent 3a47ddf8ea
commit c214ebc830
11 changed files with 729 additions and 324 deletions

View File

@ -292,6 +292,11 @@ check_PROGRAMS += test/gtest_unittest
test_gtest_unittest_SOURCES = test/gtest_unittest.cc
test_gtest_unittest_LDADD = lib/libgtest_main.la
TESTS += test/gtest-unittest-api_test
check_PROGRAMS += test/gtest-unittest-api_test
test_gtest_unittest_api_test_SOURCES = test/gtest-unittest-api_test.cc
test_gtest_unittest_api_test_LDADD = lib/libgtest_main.la
# Verifies that Google Test works when RTTI is disabled.
TESTS += test/gtest_no_rtti_test
check_PROGRAMS += test/gtest_no_rtti_test

View File

@ -150,9 +150,13 @@ namespace internal {
class AssertHelper;
class DefaultGlobalTestPartResultReporter;
class ExecDeathTest;
class FinalSuccessChecker;
class GTestFlagSaver;
class TestCase; // A collection of related tests.
class TestCase;
class TestInfoImpl;
class TestResultAccessor;
class UnitTestAccessor;
class WindowsDeathTest;
class UnitTestImpl* GetUnitTestImpl();
void ReportFailureInUnknownLocation(TestPartResultType result_type,
const String& message);
@ -360,6 +364,8 @@ class Test {
GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
};
typedef internal::TimeInMillis TimeInMillis;
namespace internal {
// A copyable object representing a user specified test property which can be
@ -392,9 +398,9 @@ class TestProperty {
private:
// The key supplied by the user.
String key_;
internal::String key_;
// The value supplied by the user.
String value_;
internal::String value_;
};
// The result of a single Test. This includes a list of
@ -411,12 +417,6 @@ class TestResult {
// D'tor. Do not inherit from TestResult.
~TestResult();
// Gets the number of successful test parts.
int successful_part_count() const;
// Gets the number of failed test parts.
int failed_part_count() const;
// Gets the number of all test parts. This is the sum of the number
// of successful test parts and the number of failed test parts.
int total_part_count() const;
@ -428,7 +428,7 @@ class TestResult {
bool Passed() const { return !Failed(); }
// Returns true iff the test failed.
bool Failed() const { return failed_part_count() > 0; }
bool Failed() const;
// Returns true iff the test fatally failed.
bool HasFatalFailure() const;
@ -450,12 +450,12 @@ class TestResult {
const TestProperty& GetTestProperty(int i) const;
private:
friend class DefaultGlobalTestPartResultReporter;
friend class ExecDeathTest;
friend class TestInfoImpl;
friend class TestResultAccessor;
friend class UnitTestImpl;
friend class WindowsDeathTest;
friend class internal::DefaultGlobalTestPartResultReporter;
friend class internal::ExecDeathTest;
friend class internal::TestInfoImpl;
friend class internal::TestResultAccessor;
friend class internal::UnitTestImpl;
friend class internal::WindowsDeathTest;
friend class testing::TestInfo;
friend class testing::UnitTest;
@ -465,7 +465,7 @@ class TestResult {
}
// Gets the vector of TestProperties.
const internal::Vector<internal::TestProperty>& test_properties() const {
const internal::Vector<TestProperty>& test_properties() const {
return *test_properties_;
}
@ -477,12 +477,12 @@ class TestResult {
// key names). If a property is already recorded for the same key, the
// value will be updated, rather than storing multiple values for the same
// key.
void RecordProperty(const internal::TestProperty& test_property);
void RecordProperty(const TestProperty& test_property);
// Adds a failure if the key is a reserved attribute of Google Test
// testcase tags. Returns true if the property is valid.
// TODO(russr): Validate attribute names are legal and human readable.
static bool ValidateTestProperty(const internal::TestProperty& test_property);
static bool ValidateTestProperty(const TestProperty& test_property);
// Adds a test part result to the list.
void AddTestPartResult(const TestPartResult& test_part_result);
@ -506,8 +506,7 @@ class TestResult {
// The vector of TestPartResults
internal::scoped_ptr<internal::Vector<TestPartResult> > test_part_results_;
// The vector of TestProperties
internal::scoped_ptr<internal::Vector<internal::TestProperty> >
test_properties_;
internal::scoped_ptr<internal::Vector<TestProperty> > test_properties_;
// Running count of death tests.
int death_test_count_;
// The elapsed time, in milliseconds.
@ -664,7 +663,7 @@ class TestCase {
bool Failed() const { return failed_test_count() > 0; }
// Returns the elapsed time, in milliseconds.
internal::TimeInMillis elapsed_time() const { return elapsed_time_; }
TimeInMillis elapsed_time() const { return elapsed_time_; }
// Returns the i-th test among all the tests. i can range from 0 to
// total_test_count() - 1. If i is not in that range, returns NULL.
@ -672,7 +671,7 @@ class TestCase {
private:
friend class testing::Test;
friend class UnitTestImpl;
friend class internal::UnitTestImpl;
// Gets the (mutable) vector of TestInfos in this TestCase.
internal::Vector<TestInfo*>& test_info_list() { return *test_info_list_; }
@ -728,7 +727,7 @@ class TestCase {
// True iff any test in this test case should run.
bool should_run_;
// Elapsed time, in milliseconds.
internal::TimeInMillis elapsed_time_;
TimeInMillis elapsed_time_;
// We disallow copying TestCases.
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
@ -874,7 +873,7 @@ class UnitTest {
int test_to_run_count() const;
// Gets the elapsed time, in milliseconds.
internal::TimeInMillis elapsed_time() const;
TimeInMillis elapsed_time() const;
// Returns true iff the unit test passed (i.e. all test cases passed).
bool Passed() const;
@ -902,6 +901,11 @@ class UnitTest {
// TODO(vladl@google.com): Remove these when publishing the new accessors.
friend class PrettyUnitTestResultPrinter;
friend class XmlUnitTestResultPrinter;
friend class internal::UnitTestAccessor;
friend class FinalSuccessChecker;
FRIEND_TEST(ApiTest, UnitTestImmutableAccessorsWork);
FRIEND_TEST(ApiTest, TestCaseImmutableAccessorsWork);
FRIEND_TEST(ApiTest, DisabledTestCaseAccessorsWork);
// Creates an empty UnitTest.

View File

@ -101,20 +101,19 @@ namespace testing {
// Forward declaration of classes.
class AssertionResult; // Result of an assertion.
class Message; // Represents a failure message.
class Test; // Represents a test.
class TestPartResult; // Result of a test part.
class TestInfo; // Information about a test.
class TestPartResult; // Result of a test part.
class UnitTest; // A collection of test cases.
class UnitTestEventListenerInterface; // Listens to Google Test events.
class AssertionResult; // Result of an assertion.
namespace internal {
struct TraceInfo; // Information about a trace point.
class ScopedTrace; // Implements scoped trace.
class TestInfoImpl; // Opaque implementation of TestInfo
class TestResult; // Result of a single Test.
class UnitTestImpl; // Opaque implementation of UnitTest
template <typename E> class Vector; // A generic vector.
@ -747,9 +746,6 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> {
// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count);
// Returns the number of failed test parts in the given test result object.
int GetFailedPartCount(const TestResult* result);
// A helper for suppressing warnings on unreachable code in some macros.
bool AlwaysTrue();

View File

@ -98,16 +98,16 @@ KNOWN BUILD DIRECTORIES
defines them as follows (the default build directory is the first one
listed in each group):
On Windows:
<gtest root>/scons/build/win-dbg8/scons/
<gtest root>/scons/build/win-opt8/scons/
<gtest root>/scons/build/win-dbg/scons/
<gtest root>/scons/build/win-opt/scons/
<gtest root>/scons/build/win-dbg8/gtest/scons/
<gtest root>/scons/build/win-opt8/gtest/scons/
<gtest root>/scons/build/win-dbg/gtest/scons/
<gtest root>/scons/build/win-opt/gtest/scons/
On Mac:
<gtest root>/scons/build/mac-dbg/scons/
<gtest root>/scons/build/mac-opt/scons/
<gtest root>/scons/build/mac-dbg/gtest/scons/
<gtest root>/scons/build/mac-opt/gtest/scons/
On other platforms:
<gtest root>/scons/build/dbg/scons/
<gtest root>/scons/build/opt/scons/
<gtest root>/scons/build/dbg/gtest/scons/
<gtest root>/scons/build/opt/gtest/scons/
AUTHOR
Written by Zhanyong Wan (wan@google.com)
@ -177,7 +177,8 @@ class TestRunner(object):
"""Returns the build directory for a given configuration."""
return self.os.path.normpath(
self.os.path.join(self.script_dir, 'scons/build/%s/scons' % config))
self.os.path.join(self.script_dir,
'scons/build/%s/gtest/scons' % config))
def Run(self, args):
"""Runs the executable with given args (args[0] is the executable name).

View File

@ -29,10 +29,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Builds the Google Test (gtest) lib; this is for Windows projects
using SCons and can probably be easily extended for cross-platform
SCons builds. The compilation settings from your project will be used,
with some specific flags required for gtest added.
"""Builds the Google Test (gtest) lib. This has been tested on Windows,
Linux, Mac OS X, and Cygwin. The compilation settings from your project
will be used, with some specific flags required for gtest added.
You should be able to call this file from more or less any SConscript
file.
@ -97,19 +96,35 @@ import os
############################################################
# Environments for building the targets, sorted by name.
def NewEnvironment(env, type):
"""Copies environment and gives it suffix for names of targets built in it."""
if type:
suffix = '_' + type
else:
suffix = ''
new_env = env.Clone()
new_env['OBJ_SUFFIX'] = suffix
return new_env;
Import('env')
env = env.Clone()
env = NewEnvironment(env, '')
# Note: The relative paths in SConscript files are relative to the location of
# the SConscript file itself. To make a path relative to the location of the
# main SConstruct file, prepend the path with the # sign.
# Include paths to gtest headers are relative to either the gtest
# directory or the 'include' subdirectory of it, and this SConscript
# file is one directory deeper than the gtest directory.
env.Prepend(CPPPATH = ['#/..',
'#/../include'])
env.Prepend(CPPPATH = ['..', '../include'])
env_use_own_tuple = env.Clone()
env_use_own_tuple = NewEnvironment(env, 'use_own_tuple')
env_use_own_tuple.Append(CPPDEFINES = 'GTEST_USE_OWN_TR1_TUPLE=1')
env_with_exceptions = env.Clone()
env_with_exceptions = NewEnvironment(env, 'ex')
if env_with_exceptions['PLATFORM'] == 'win32':
env_with_exceptions.Append(CCFLAGS=['/EHsc'])
env_with_exceptions.Append(CPPDEFINES='_HAS_EXCEPTIONS=1')
@ -129,9 +144,9 @@ else:
# We need to disable some optimization flags for some tests on
# Windows; otherwise the redirection of stdout does not work
# (apparently because of a compiler bug).
env_with_less_optimization = env.Clone()
if env_with_less_optimization['PLATFORM'] == 'win32':
linker_flags = env_with_less_optimization['LINKFLAGS']
env_less_optimized = NewEnvironment(env, 'less_optimized')
if env_less_optimized['PLATFORM'] == 'win32':
linker_flags = env_less_optimized['LINKFLAGS']
for flag in ['/O1', '/Os', '/Og', '/Oy']:
if flag in linker_flags:
linker_flags.remove(flag)
@ -139,12 +154,12 @@ if env_with_less_optimization['PLATFORM'] == 'win32':
# Assuming POSIX-like environment with GCC.
# TODO(vladl@google.com): sniff presence of pthread_atfork instead of
# selecting on a platform.
env_with_threads = env.Clone()
env_with_threads = NewEnvironment(env, 'with_threads')
if env_with_threads['PLATFORM'] != 'win32':
env_with_threads.Append(CCFLAGS=['-pthread'])
env_with_threads.Append(LINKFLAGS=['-pthread'])
env_without_rtti = env.Clone()
env_without_rtti = NewEnvironment(env, 'no_rtti')
if env_without_rtti['PLATFORM'] == 'win32':
env_without_rtti.Append(CCFLAGS=['/GR-'])
else:
@ -154,121 +169,106 @@ else:
############################################################
# Helpers for creating build targets.
def GtestObject(build_env, source, obj_suffix=None):
"""Returns a target to build an object file from the given .cc source file.
When obj_suffix is provided, appends it to the end of the object
file base name.
"""
if obj_suffix:
obj_suffix = '_' + obj_suffix
else:
obj_suffix = ''
def GtestObject(build_env, source):
"""Returns a target to build an object file from the given .cc source file."""
return build_env.Object(
target=os.path.basename(source).rstrip('.cc') + obj_suffix,
target=os.path.basename(source).rstrip('.cc') + build_env['OBJ_SUFFIX'],
source=source)
def GtestStaticLibrary(build_env, lib_target, sources, obj_suffix=None):
"""Returns a target to build the given static library from sources."""
if obj_suffix:
srcs = [GtestObject(build_env, src, obj_suffix) for src in sources]
else:
srcs = sources
return build_env.StaticLibrary(target=lib_target, source=srcs)
def GtestStaticLibraries(build_env):
"""Builds static libraries for gtest and gtest_main in build_env.
Args:
build_env: An environment in which to build libraries.
Returns:
A pair (gtest library, gtest_main library) built in the given environment.
"""
gtest_object = GtestObject(build_env, '../src/gtest-all.cc')
gtest_main_object = GtestObject(build_env, '../src/gtest_main.cc')
return (build_env.StaticLibrary(target='gtest' + build_env['OBJ_SUFFIX'],
source=[gtest_object]),
build_env.StaticLibrary(target='gtest_main' + build_env['OBJ_SUFFIX'],
source=[gtest_object, gtest_main_object]))
def GtestBinary(build_env, target, gtest_lib, sources, obj_suffix=None):
def GtestBinary(build_env, target, gtest_libs, sources):
"""Creates a target to build a binary (either test or sample).
Args:
build_env: The SCons construction environment to use to build.
target: The basename of the target's main source file, also used as the
target name.
gtest_lib: The gtest library to use.
gtest_libs: The gtest library or the list of libraries to link.
sources: A list of source files in the target.
obj_suffix: A suffix to append to all object file's basenames.
"""
if obj_suffix:
if build_env['OBJ_SUFFIX']:
srcs = [] # The object targets corresponding to sources.
for src in sources:
if type(src) is str:
srcs.append(GtestObject(build_env, src, obj_suffix))
srcs.append(GtestObject(build_env, src))
else:
srcs.append(src)
else:
srcs = sources
if gtest_lib:
gtest_libs=[gtest_lib]
else:
gtest_libs=[]
if type(gtest_libs) != type(list()):
gtest_libs = [gtest_libs]
binary = build_env.Program(target=target, source=srcs, LIBS=gtest_libs)
if 'EXE_OUTPUT' in build_env.Dictionary():
build_env.Install('$EXE_OUTPUT', source=[binary])
def GtestTest(build_env, target, gtest_lib, additional_sources=None):
def GtestTest(build_env, target, gtest_libs, additional_sources=None):
"""Creates a target to build the given test.
Args:
build_env: The SCons construction environment to use to build.
target: The basename of the target test .cc file.
gtest_lib: The gtest lib to use.
gtest_libs: The gtest library or the list of libraries to use.
additional_sources: A list of additional source files in the target.
"""
GtestBinary(build_env, target, gtest_lib,
GtestBinary(build_env, target, gtest_libs,
['../test/%s.cc' % target] + (additional_sources or []))
def GtestSample(build_env, target, gtest_lib, additional_sources=None):
def GtestSample(build_env, target, additional_sources=None):
"""Creates a target to build the given sample.
Args:
build_env: The SCons construction environment to use to build.
target: The basename of the target sample .cc file.
gtest_lib: The gtest lib to use.
gtest_libs: The gtest library or the list of libraries to use.
additional_sources: A list of additional source files in the target.
"""
GtestBinary(build_env, target, gtest_lib,
['../samples/%s.cc' % target] + (additional_sources or []))
GtestBinary(build_env, target, gtest_main,
['../samples/%s.cc' % target] + (additional_sources or []))
############################################################
# Object and library targets.
# Sources used by base library and library that includes main.
gtest_source = '../src/gtest-all.cc'
gtest_main_source = '../src/gtest_main.cc'
gtest_main_obj = GtestObject(env, gtest_main_source)
gtest_unittest_obj = GtestObject(env, '../test/gtest_unittest.cc')
# gtest.lib to be used by most apps (if you have your own main
# function).
gtest = env.StaticLibrary(target='gtest',
source=[gtest_source])
# gtest_main.lib can be used if you just want a basic main function;
# it is also used by some tests for Google Test itself.
gtest_main = env.StaticLibrary(target='gtest_main',
source=[gtest_source, gtest_main_obj])
gtest_ex = GtestStaticLibrary(
env_with_exceptions, 'gtest_ex', [gtest_source], obj_suffix='ex')
gtest_ex_main = GtestStaticLibrary(
env_with_exceptions, 'gtest_ex_main', [gtest_source, gtest_main_source],
obj_suffix='ex')
gtest_use_own_tuple_main = GtestStaticLibrary(
env_use_own_tuple, 'gtest_use_own_tuple_main',
[gtest_source, gtest_main_source],
obj_suffix='use_own_tuple')
# gtest.lib to be used by most apps (if you have your own main function).
# gtest_main.lib can be used if you just want a basic main function; it is also
# used by some tests for Google Test itself.
gtest, gtest_main = GtestStaticLibraries(env)
gtest_ex, gtest_main_ex = GtestStaticLibraries(env_with_exceptions)
gtest_no_rtti, gtest_main_no_rtti = GtestStaticLibraries(env_without_rtti)
gtest_use_own_tuple, gtest_use_own_tuple_main = GtestStaticLibraries(
env_use_own_tuple)
# Install the libraries if needed.
if 'LIB_OUTPUT' in env.Dictionary():
env.Install('$LIB_OUTPUT', source=[gtest, gtest_main, gtest_ex_main])
env.Install('$LIB_OUTPUT', source=[gtest, gtest_main,
gtest_ex, gtest_main_ex,
gtest_no_rtti, gtest_main_no_rtti,
gtest_use_own_tuple,
gtest_use_own_tuple_main])
############################################################
# Test targets using the standard environment.
@ -300,8 +300,8 @@ GtestTest(env, 'gtest_throw_on_failure_test_', gtest)
GtestTest(env, 'gtest_xml_outfile1_test_', gtest_main)
GtestTest(env, 'gtest_xml_outfile2_test_', gtest_main)
GtestTest(env, 'gtest_xml_output_unittest_', gtest_main)
GtestBinary(env, 'gtest_unittest', gtest_main, [gtest_unittest_obj])
GtestTest(env, 'gtest-unittest-api_test', gtest)
GtestTest(env, 'gtest_unittest', gtest_main)
############################################################
# Tests targets using custom environments.
@ -309,22 +309,18 @@ GtestBinary(env, 'gtest_unittest', gtest_main, [gtest_unittest_obj])
GtestTest(env_with_exceptions, 'gtest_output_test_', gtest_ex)
GtestTest(env_with_exceptions, 'gtest_throw_on_failure_ex_test', gtest_ex)
GtestTest(env_with_threads, 'gtest-death-test_test', gtest_main)
GtestTest(env_with_less_optimization, 'gtest_env_var_test_', gtest)
GtestTest(env_with_less_optimization, 'gtest_uninitialized_test_', gtest)
GtestBinary(env_use_own_tuple, 'gtest-tuple_test', gtest_use_own_tuple_main,
['../test/gtest-tuple_test.cc'],
obj_suffix='use_own_tuple')
GtestBinary(env_use_own_tuple, 'gtest_use_own_tuple_test',
GtestTest(env_less_optimized, 'gtest_env_var_test_', gtest)
GtestTest(env_less_optimized, 'gtest_uninitialized_test_', gtest)
GtestTest(env_use_own_tuple, 'gtest-tuple_test', gtest_use_own_tuple_main)
GtestBinary(env_use_own_tuple,
'gtest_use_own_tuple_test',
gtest_use_own_tuple_main,
['../test/gtest-param-test_test.cc',
'../test/gtest-param-test2_test.cc'],
obj_suffix='use_own_tuple')
GtestBinary(env_with_exceptions, 'gtest_ex_unittest', gtest_ex_main,
['../test/gtest_unittest.cc'], obj_suffix='ex')
GtestBinary(env_without_rtti, 'gtest_no_rtti_test', None,
['../test/gtest_unittest.cc', gtest_source, gtest_main_source],
obj_suffix='no_rtti')
'../test/gtest-param-test2_test.cc'])
GtestBinary(env_with_exceptions, 'gtest_ex_unittest', gtest_main_ex,
['../test/gtest_unittest.cc'])
GtestBinary(env_without_rtti, 'gtest_no_rtti_test', gtest_main_no_rtti,
['../test/gtest_unittest.cc'])
############################################################
# Sample targets.
@ -337,15 +333,25 @@ GtestBinary(env_without_rtti, 'gtest_no_rtti_test', None,
# Then, in the command line use GTEST_BUILD_SAMPLES=true to enable them.
if env.get('GTEST_BUILD_SAMPLES', False):
sample1_obj = env.Object('../samples/sample1.cc')
GtestSample(env, 'sample1_unittest', gtest_main,
additional_sources=[sample1_obj])
GtestSample(env, 'sample2_unittest', gtest_main,
GtestSample(env, 'sample1_unittest', additional_sources=[sample1_obj])
GtestSample(env, 'sample2_unittest',
additional_sources=['../samples/sample2.cc'])
GtestSample(env, 'sample3_unittest', gtest_main)
GtestSample(env, 'sample4_unittest', gtest_main,
GtestSample(env, 'sample3_unittest')
GtestSample(env, 'sample4_unittest',
additional_sources=['../samples/sample4.cc'])
GtestSample(env, 'sample5_unittest', gtest_main,
additional_sources=[sample1_obj])
GtestSample(env, 'sample6_unittest', gtest_main)
GtestSample(env, 'sample7_unittest', gtest_main)
GtestSample(env, 'sample8_unittest', gtest_main)
GtestSample(env, 'sample5_unittest', additional_sources=[sample1_obj])
GtestSample(env, 'sample6_unittest')
GtestSample(env, 'sample7_unittest')
GtestSample(env, 'sample8_unittest')
# These exports are used by Google Mock.
gtest_exports = {'gtest': gtest,
'gtest_ex': gtest_ex,
'gtest_no_rtti': gtest_no_rtti,
'gtest_use_own_tuple': gtest_use_own_tuple,
'NewEnvironment': NewEnvironment,
'GtestObject': GtestObject,
'GtestBinary': GtestBinary,
'GtestTest': GtestTest}
# Makes the gtest_exports dictionary available to the invoking SConstruct.
Return('gtest_exports')

View File

@ -483,8 +483,8 @@ class TestInfoImpl {
TypeId fixture_class_id() const { return fixture_class_id_; }
// Returns the test result.
internal::TestResult* result() { return &result_; }
const internal::TestResult* result() const { return &result_; }
TestResult* result() { return &result_; }
const TestResult* result() const { return &result_; }
// Creates the test object, runs it, records its result, and then
// deletes it.
@ -520,7 +520,7 @@ class TestInfoImpl {
// This field is mutable and needs to be reset before running the
// test for the second time.
internal::TestResult result_;
TestResult result_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl);
};
@ -742,19 +742,17 @@ class UnitTestImpl {
// Returns the TestResult for the test that's currently running, or
// the TestResult for the ad hoc test if no test is running.
internal::TestResult* current_test_result();
TestResult* current_test_result();
// Returns the TestResult for the ad hoc test.
const internal::TestResult* ad_hoc_test_result() const {
return &ad_hoc_test_result_;
}
const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
// Sets the unit test result printer.
//
// Does nothing if the input and the current printer object are the
// same; otherwise, deletes the old printer object and makes the
// input the current printer.
void set_result_printer(UnitTestEventListenerInterface * result_printer);
void set_result_printer(UnitTestEventListenerInterface* result_printer);
// Returns the current unit test result printer if it is not NULL;
// otherwise, creates an appropriate result printer, makes it the
@ -991,7 +989,7 @@ class UnitTestImpl {
// If an assertion is encountered when no TEST or TEST_F is running,
// Google Test attributes the assertion result to an imaginary "ad hoc"
// test, and records the result in ad_hoc_test_result_.
internal::TestResult ad_hoc_test_result_;
TestResult ad_hoc_test_result_;
// The unit test result printer. Will be deleted when the UnitTest
// object is destructed. By default, a plain text printer is used,
@ -1122,6 +1120,28 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
}
#endif // GTEST_HAS_DEATH_TEST
// TestResult contains some private methods that should be hidden from
// Google Test user but are required for testing. This class allow our tests
// to access them.
class TestResultAccessor {
public:
static void RecordProperty(TestResult* test_result,
const TestProperty& property) {
test_result->RecordProperty(property);
}
static bool Passed(const TestResult& result) { return result.Passed(); }
static void ClearTestPartResults(TestResult* test_result) {
test_result->ClearTestPartResults();
}
static const Vector<testing::TestPartResult>& test_part_results(
const TestResult& test_result) {
return test_result.test_part_results();
}
};
} // namespace internal
} // namespace testing

View File

@ -130,6 +130,8 @@
namespace testing {
using internal::TestCase;
using internal::TestProperty;
using internal::TestResult;
// Constants.
@ -1831,8 +1833,8 @@ String AppendUserMessage(const String& gtest_msg,
// Creates an empty TestResult.
TestResult::TestResult()
: test_part_results_(new Vector<TestPartResult>),
test_properties_(new Vector<TestProperty>),
: test_part_results_(new internal::Vector<TestPartResult>),
test_properties_(new internal::Vector<TestProperty>),
death_test_count_(0),
elapsed_time_(0) {
}
@ -1872,9 +1874,10 @@ void TestResult::RecordProperty(const TestProperty& test_property) {
if (!ValidateTestProperty(test_property)) {
return;
}
MutexLock lock(&test_properites_mutex_);
internal::MutexLock lock(&test_properites_mutex_);
TestProperty* const property_with_matching_key =
test_properties_->FindIf(TestPropertyKeyIs(test_property.key()));
test_properties_->FindIf(
internal::TestPropertyKeyIs(test_property.key()));
if (property_with_matching_key == NULL) {
test_properties_->PushBack(test_property);
return;
@ -1885,7 +1888,7 @@ void TestResult::RecordProperty(const TestProperty& test_property) {
// Adds a failure if the key is a reserved attribute of Google Test
// testcase tags. Returns true if the property is valid.
bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
String key(test_property.key());
internal::String key(test_property.key());
if (key == "name" || key == "status" || key == "time" || key == "classname") {
ADD_FAILURE()
<< "Reserved key used in RecordProperty(): "
@ -1905,24 +1908,13 @@ void TestResult::Clear() {
elapsed_time_ = 0;
}
// Returns true iff the test part passed.
static bool TestPartPassed(const TestPartResult & result) {
return result.passed();
}
// Gets the number of successful test parts.
int TestResult::successful_part_count() const {
return test_part_results_->CountIf(TestPartPassed);
}
// Returns true iff the test part failed.
static bool TestPartFailed(const TestPartResult & result) {
return result.failed();
}
// Gets the number of failed test parts.
int TestResult::failed_part_count() const {
return test_part_results_->CountIf(TestPartFailed);
// Returns true iff the test failed.
bool TestResult::Failed() const {
for (int i = 0; i < total_part_count(); ++i) {
if (GetTestPartResult(i).failed())
return true;
}
return false;
}
// Returns true iff the test part fatally failed.
@ -2264,7 +2256,7 @@ bool TestInfo::should_run() const { return impl_->should_run(); }
bool TestInfo::matches_filter() const { return impl_->matches_filter(); }
// Returns the result of the test.
const internal::TestResult* TestInfo::result() const { return impl_->result(); }
const TestResult* TestInfo::result() const { return impl_->result(); }
// Increments the number of death tests encountered in this test so
// far.
@ -3021,7 +3013,7 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
// When the String is not empty, it includes a space at the beginning,
// to delimit this attribute from prior attributes.
static internal::String TestPropertiesAsXmlAttributes(
const internal::TestResult& result);
const TestResult& result);
// The output file.
const internal::String output_file_;
@ -3160,7 +3152,7 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) {
void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
const char* test_case_name,
const TestInfo& test_info) {
const internal::TestResult& result = *test_info.result();
const TestResult& result = *test_info.result();
fprintf(out,
" <testcase name=\"%s\" status=\"%s\" time=\"%s\" "
"classname=\"%s\"%s",
@ -3233,8 +3225,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
// Produces a string representing the test properties in a result as space
// delimited XML attributes based on the property key="value" pairs.
internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
const internal::TestResult& result) {
using internal::TestProperty;
const TestResult& result) {
Message attributes;
for (int i = 0; i < result.test_property_count(); ++i) {
const TestProperty& property = result.GetTestProperty(i);
@ -3481,7 +3472,7 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type,
// the supplied value already exists, updates its value instead.
void UnitTest::RecordPropertyForCurrentTest(const char* key,
const char* value) {
const internal::TestProperty test_property(key, value);
const TestProperty test_property(key, value);
impl_->current_test_result()->RecordProperty(test_property);
}
@ -4089,7 +4080,7 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
// Returns the TestResult for the test that's currently running, or
// the TestResult for the ad hoc test if no test is running.
internal::TestResult* UnitTestImpl::current_test_result() {
TestResult* UnitTestImpl::current_test_result() {
return current_test_info_ ?
current_test_info_->impl()->result() : &ad_hoc_test_result_;
}
@ -4136,11 +4127,6 @@ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) {
return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
}
// Returns the number of failed test parts in the given test result object.
int GetFailedPartCount(const TestResult* result) {
return result->failed_part_count();
}
// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable
// code warnings.
namespace {

View File

@ -957,16 +957,11 @@ TEST_F(MacroLogicDeathTest, ChildDoesNotDie) {
EXPECT_TRUE(factory_->TestDeleted());
}
// Returns the number of successful parts in the current test.
static size_t GetSuccessfulTestPartCount() {
return GetUnitTestImpl()->current_test_result()->successful_part_count();
}
// Tests that a successful death test does not register a successful
// test part.
TEST(SuccessRegistrationDeathTest, NoSuccessPart) {
EXPECT_DEATH(_exit(1), "");
EXPECT_EQ(0u, GetSuccessfulTestPartCount());
EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
}
TEST(StreamingAssertionsDeathTest, DeathTest) {

View File

@ -0,0 +1,363 @@
// 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: vladl@google.com (Vlad Losev)
//
// The Google C++ Testing Framework (Google Test)
//
// This file contains tests verifying correctness of data provided via
// UnitTest's public methods.
#include <gtest/gtest.h>
#include <string.h> // For strcmp.
#include <algorithm>
using ::testing::AddGlobalTestEnvironment;
using ::testing::Environment;
using ::testing::InitGoogleTest;
using ::testing::Test;
using ::testing::TestInfo;
using ::testing::TestPartResult;
using ::testing::UnitTest;
using ::testing::internal::TestCase;
using ::testing::internal::TestProperty;
#if GTEST_HAS_TYPED_TEST
using ::testing::Types;
using ::testing::internal::GetTypeName;
using ::testing::internal::String;
#endif // GTEST_HAS_TYPED_TEST
namespace testing {
namespace internal {
template <typename T>
struct LessByName {
bool operator()(const T* a, const T* b) {
return strcmp(a->name(), b->name()) < 0;
}
};
class UnitTestAccessor {
public:
// Returns the array of pointers to all test cases sorted by the test case
// name. The caller is responsible for deleting the array.
static TestCase const** const GetSortedTestCases() {
UnitTest* unit_test = UnitTest::GetInstance();
TestCase const** const test_cases =
new const TestCase*[unit_test->total_test_case_count()];
for (int i = 0; i < unit_test->total_test_case_count(); ++i)
test_cases[i] = unit_test->GetTestCase(i);
std::sort(test_cases,
test_cases + unit_test->total_test_case_count(),
LessByName<TestCase>());
return test_cases;
}
// Returns the test case by its name. The caller doesn't own the returned
// pointer.
static const TestCase* FindTestCase(const char* name) {
UnitTest* unit_test = UnitTest::GetInstance();
for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
const TestCase* test_case = unit_test->GetTestCase(i);
if (0 == strcmp(test_case->name(), name))
return test_case;
}
return NULL;
}
// Returns the array of pointers to all tests in a particular test case
// sorted by the test name. The caller is responsible for deleting the
// array.
static TestInfo const** const GetSortedTests(const TestCase* test_case) {
TestInfo const** const tests =
new const TestInfo*[test_case->total_test_count()];
for (int i = 0; i < test_case->total_test_count(); ++i)
tests[i] = test_case->GetTestInfo(i);
std::sort(tests,
tests + test_case->total_test_count(),
LessByName<TestInfo>());
return tests;
}
};
// TODO(vladl@google.com): Put tests into the internal namespace after
// UnitTest methods are published.
} // namespace internal
using internal::UnitTestAccessor;
#if GTEST_HAS_TYPED_TEST
template <typename T> class TestCaseWithCommentTest : public Test {};
TYPED_TEST_CASE(TestCaseWithCommentTest, Types<int>);
TYPED_TEST(TestCaseWithCommentTest, Dummy) {}
const int kTypedTestCases = 1;
const int kTypedTests = 1;
String GetExpectedTestCaseComment() {
Message comment;
comment << "TypeParam = " << GetTypeName<int>().c_str();
return comment.GetString();
}
#else
const int kTypedTestCases = 0;
const int kTypedTests = 0;
#endif // GTEST_HAS_TYPED_TEST
// We can only test the accessors that do not change value while tests run.
// Since tests can be run in any order, the values the accessors that track
// test execution (such as failed_test_count) can not be predicted.
TEST(ApiTest, UnitTestImmutableAccessorsWork) {
UnitTest* unit_test = UnitTest::GetInstance();
ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count());
EXPECT_EQ(1 + kTypedTestCases, unit_test->test_case_to_run_count());
EXPECT_EQ(2, unit_test->disabled_test_count());
EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count());
EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count());
const TestCase** const test_cases = UnitTestAccessor::GetSortedTestCases();
EXPECT_STREQ("ApiTest", test_cases[0]->name());
EXPECT_STREQ("DISABLED_Test", test_cases[1]->name());
#if GTEST_HAS_TYPED_TEST
EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name());
#endif // GTEST_HAS_TYPED_TEST
delete[] test_cases;
// The following lines initiate actions to verify certain methods in
// FinalSuccessChecker::TearDown.
// Records a test property to verify TestResult::GetTestProperty().
RecordProperty("key", "value");
}
TEST(ApiTest, TestCaseImmutableAccessorsWork) {
const TestCase* test_case = UnitTestAccessor::FindTestCase("ApiTest");
ASSERT_TRUE(test_case != NULL);
EXPECT_STREQ("ApiTest", test_case->name());
EXPECT_STREQ("", test_case->comment());
EXPECT_TRUE(test_case->should_run());
EXPECT_EQ(1, test_case->disabled_test_count());
EXPECT_EQ(3, test_case->test_to_run_count());
ASSERT_EQ(4, test_case->total_test_count());
const TestInfo** tests = UnitTestAccessor::GetSortedTests(test_case);
EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name());
EXPECT_STREQ("ApiTest", tests[0]->test_case_name());
EXPECT_STREQ("", tests[0]->comment());
EXPECT_STREQ("", tests[0]->test_case_comment());
EXPECT_FALSE(tests[0]->should_run());
EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name());
EXPECT_STREQ("ApiTest", tests[1]->test_case_name());
EXPECT_STREQ("", tests[1]->comment());
EXPECT_STREQ("", tests[1]->test_case_comment());
EXPECT_TRUE(tests[1]->should_run());
EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name());
EXPECT_STREQ("ApiTest", tests[2]->test_case_name());
EXPECT_STREQ("", tests[2]->comment());
EXPECT_STREQ("", tests[2]->test_case_comment());
EXPECT_TRUE(tests[2]->should_run());
EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name());
EXPECT_STREQ("ApiTest", tests[3]->test_case_name());
EXPECT_STREQ("", tests[3]->comment());
EXPECT_STREQ("", tests[3]->test_case_comment());
EXPECT_TRUE(tests[3]->should_run());
delete[] tests;
tests = NULL;
#if GTEST_HAS_TYPED_TEST
test_case = UnitTestAccessor::FindTestCase("TestCaseWithCommentTest/0");
ASSERT_TRUE(test_case != NULL);
EXPECT_STREQ("TestCaseWithCommentTest/0", test_case->name());
EXPECT_STREQ(GetExpectedTestCaseComment().c_str(), test_case->comment());
EXPECT_TRUE(test_case->should_run());
EXPECT_EQ(0, test_case->disabled_test_count());
EXPECT_EQ(1, test_case->test_to_run_count());
ASSERT_EQ(1, test_case->total_test_count());
tests = UnitTestAccessor::GetSortedTests(test_case);
EXPECT_STREQ("Dummy", tests[0]->name());
EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name());
EXPECT_STREQ("", tests[0]->comment());
EXPECT_STREQ(GetExpectedTestCaseComment().c_str(),
tests[0]->test_case_comment());
EXPECT_TRUE(tests[0]->should_run());
delete[] tests;
#endif // GTEST_HAS_TYPED_TEST
}
TEST(ApiTest, TestCaseDisabledAccessorsWork) {
const TestCase* test_case = UnitTestAccessor::FindTestCase("DISABLED_Test");
ASSERT_TRUE(test_case != NULL);
EXPECT_STREQ("DISABLED_Test", test_case->name());
EXPECT_STREQ("", test_case->comment());
EXPECT_FALSE(test_case->should_run());
EXPECT_EQ(1, test_case->disabled_test_count());
EXPECT_EQ(0, test_case->test_to_run_count());
ASSERT_EQ(1, test_case->total_test_count());
const TestInfo* const test_info = test_case->GetTestInfo(0);
EXPECT_STREQ("Dummy2", test_info->name());
EXPECT_STREQ("DISABLED_Test", test_info->test_case_name());
EXPECT_STREQ("", test_info->comment());
EXPECT_STREQ("", test_info->test_case_comment());
EXPECT_FALSE(test_info->should_run());
}
// These two tests are here to provide support for testing
// test_case_to_run_count, disabled_test_count, and test_to_run_count.
TEST(ApiTest, DISABLED_Dummy1) {}
TEST(DISABLED_Test, Dummy2) {}
class FinalSuccessChecker : public Environment {
protected:
virtual void TearDown() {
UnitTest* unit_test = UnitTest::GetInstance();
EXPECT_EQ(1 + kTypedTestCases, unit_test->successful_test_case_count());
EXPECT_EQ(3 + kTypedTests, unit_test->successful_test_count());
EXPECT_EQ(0, unit_test->failed_test_case_count());
EXPECT_EQ(0, unit_test->failed_test_count());
EXPECT_TRUE(unit_test->Passed());
EXPECT_FALSE(unit_test->Failed());
ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count());
const TestCase** const test_cases = UnitTestAccessor::GetSortedTestCases();
EXPECT_STREQ("ApiTest", test_cases[0]->name());
EXPECT_STREQ("", test_cases[0]->comment());
EXPECT_TRUE(test_cases[0]->should_run());
EXPECT_EQ(1, test_cases[0]->disabled_test_count());
ASSERT_EQ(4, test_cases[0]->total_test_count());
EXPECT_EQ(3, test_cases[0]->successful_test_count());
EXPECT_EQ(0, test_cases[0]->failed_test_count());
EXPECT_TRUE(test_cases[0]->Passed());
EXPECT_FALSE(test_cases[0]->Failed());
EXPECT_STREQ("DISABLED_Test", test_cases[1]->name());
EXPECT_STREQ("", test_cases[1]->comment());
EXPECT_FALSE(test_cases[1]->should_run());
EXPECT_EQ(1, test_cases[1]->disabled_test_count());
ASSERT_EQ(1, test_cases[1]->total_test_count());
EXPECT_EQ(0, test_cases[1]->successful_test_count());
EXPECT_EQ(0, test_cases[1]->failed_test_count());
#if GTEST_HAS_TYPED_TEST
EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name());
EXPECT_STREQ(GetExpectedTestCaseComment().c_str(),
test_cases[2]->comment());
EXPECT_TRUE(test_cases[2]->should_run());
EXPECT_EQ(0, test_cases[2]->disabled_test_count());
ASSERT_EQ(1, test_cases[2]->total_test_count());
EXPECT_EQ(1, test_cases[2]->successful_test_count());
EXPECT_EQ(0, test_cases[2]->failed_test_count());
EXPECT_TRUE(test_cases[2]->Passed());
EXPECT_FALSE(test_cases[2]->Failed());
#endif // GTEST_HAS_TYPED_TEST
const TestCase* test_case = UnitTestAccessor::FindTestCase("ApiTest");
const TestInfo** tests = UnitTestAccessor::GetSortedTests(test_case);
EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name());
EXPECT_STREQ("ApiTest", tests[0]->test_case_name());
EXPECT_FALSE(tests[0]->should_run());
EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name());
EXPECT_STREQ("ApiTest", tests[1]->test_case_name());
EXPECT_STREQ("", tests[1]->comment());
EXPECT_STREQ("", tests[1]->test_case_comment());
EXPECT_TRUE(tests[1]->should_run());
EXPECT_TRUE(tests[1]->result()->Passed());
EXPECT_EQ(0, tests[1]->result()->test_property_count());
EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name());
EXPECT_STREQ("ApiTest", tests[2]->test_case_name());
EXPECT_STREQ("", tests[2]->comment());
EXPECT_STREQ("", tests[2]->test_case_comment());
EXPECT_TRUE(tests[2]->should_run());
EXPECT_TRUE(tests[2]->result()->Passed());
EXPECT_EQ(0, tests[2]->result()->test_property_count());
EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name());
EXPECT_STREQ("ApiTest", tests[3]->test_case_name());
EXPECT_STREQ("", tests[3]->comment());
EXPECT_STREQ("", tests[3]->test_case_comment());
EXPECT_TRUE(tests[3]->should_run());
EXPECT_TRUE(tests[3]->result()->Passed());
EXPECT_EQ(1, tests[3]->result()->test_property_count());
const TestProperty& property = tests[3]->result()->GetTestProperty(0);
EXPECT_STREQ("key", property.key());
EXPECT_STREQ("value", property.value());
delete[] tests;
#if GTEST_HAS_TYPED_TEST
test_case = UnitTestAccessor::FindTestCase("TestCaseWithCommentTest/0");
tests = UnitTestAccessor::GetSortedTests(test_case);
EXPECT_STREQ("Dummy", tests[0]->name());
EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name());
EXPECT_STREQ("", tests[0]->comment());
EXPECT_STREQ(GetExpectedTestCaseComment().c_str(),
tests[0]->test_case_comment());
EXPECT_TRUE(tests[0]->should_run());
EXPECT_TRUE(tests[0]->result()->Passed());
EXPECT_EQ(0, tests[0]->result()->test_property_count());
delete[] tests;
#endif // GTEST_HAS_TYPED_TEST
delete[] test_cases;
}
};
} // namespace testing
int main(int argc, char **argv) {
InitGoogleTest(&argc, argv);
AddGlobalTestEnvironment(new testing::FinalSuccessChecker());
return RUN_ALL_TESTS();
}

View File

@ -94,26 +94,6 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms);
bool ParseInt32Flag(const char* str, const char* flag, Int32* value);
// TestResult contains some private methods that should be hidden from
// Google Test user but are required for testing. This class allow our tests
// to access them.
class TestResultAccessor {
public:
static void RecordProperty(TestResult* test_result,
const TestProperty& property) {
test_result->RecordProperty(property);
}
static void ClearTestPartResults(TestResult* test_result) {
test_result->ClearTestPartResults();
}
static const Vector<testing::TestPartResult>& test_part_results(
const TestResult& test_result) {
return test_result.test_part_results();
}
};
} // namespace internal
} // namespace testing
@ -138,8 +118,8 @@ using testing::FloatLE;
using testing::GTEST_FLAG(also_run_disabled_tests);
using testing::GTEST_FLAG(break_on_failure);
using testing::GTEST_FLAG(catch_exceptions);
using testing::GTEST_FLAG(death_test_use_fork);
using testing::GTEST_FLAG(color);
using testing::GTEST_FLAG(death_test_use_fork);
using testing::GTEST_FLAG(filter);
using testing::GTEST_FLAG(list_tests);
using testing::GTEST_FLAG(output);
@ -155,12 +135,12 @@ using testing::IsSubstring;
using testing::Message;
using testing::ScopedFakeTestPartResultReporter;
using testing::StaticAssertTypeEq;
using testing::Test;
using testing::TestPartResult;
using testing::TestPartResultArray;
using testing::TPRT_FATAL_FAILURE;
using testing::TPRT_NONFATAL_FAILURE;
using testing::TPRT_SUCCESS;
using testing::Test;
using testing::TestPartResult;
using testing::TestPartResultArray;
using testing::UnitTest;
using testing::internal::kMaxRandomSeed;
using testing::internal::kTestTypeIdInGoogleTest;
@ -168,14 +148,13 @@ using testing::internal::AppendUserMessage;
using testing::internal::CodePointToUtf8;
using testing::internal::EqFailure;
using testing::internal::FloatingPoint;
using testing::internal::GTestFlagSaver;
using testing::internal::GetCurrentOsStackTraceExceptTop;
using testing::internal::GetFailedPartCount;
using testing::internal::GetNextRandomSeed;
using testing::internal::GetRandomSeedFromFlag;
using testing::internal::GetTestTypeId;
using testing::internal::GetTypeId;
using testing::internal::GetUnitTestImpl;
using testing::internal::GTestFlagSaver;
using testing::internal::Int32;
using testing::internal::Int32FromEnvOrDie;
using testing::internal::ShouldRunTestOnShard;
@ -190,6 +169,7 @@ using testing::internal::TestResultAccessor;
using testing::internal::ThreadLocal;
using testing::internal::Vector;
using testing::internal::WideStringToUtf8;
using testing::internal::kTestTypeIdInGoogleTest;
// This line tests that we can define tests in an unnamed namespace.
namespace {
@ -1227,6 +1207,68 @@ TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) {
#endif // GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD
// Tests the TestProperty class.
TEST(TestPropertyTest, ConstructorWorks) {
const TestProperty property("key", "value");
EXPECT_STREQ("key", property.key());
EXPECT_STREQ("value", property.value());
}
TEST(TestPropertyTest, SetValue) {
TestProperty property("key", "value_1");
EXPECT_STREQ("key", property.key());
property.SetValue("value_2");
EXPECT_STREQ("key", property.key());
EXPECT_STREQ("value_2", property.value());
}
// Tests the TestPartResult class.
TEST(TestPartResultTest, ConstructorWorks) {
Message message;
message << "something is terribly wrong";
message << static_cast<const char*>(testing::internal::kStackTraceMarker);
message << "some unimportant stack trace";
const TestPartResult result(TPRT_NONFATAL_FAILURE,
"some_file.cc",
42,
message.GetString().c_str());
EXPECT_EQ(TPRT_NONFATAL_FAILURE, result.type());
EXPECT_STREQ("some_file.cc", result.file_name());
EXPECT_EQ(42, result.line_number());
EXPECT_STREQ(message.GetString().c_str(), result.message());
EXPECT_STREQ("something is terribly wrong", result.summary());
}
TEST(TestPartResultTest, ResultAccessorsWork) {
const TestPartResult success(TPRT_SUCCESS, "file.cc", 42, "message");
EXPECT_TRUE(success.passed());
EXPECT_FALSE(success.failed());
EXPECT_FALSE(success.nonfatally_failed());
EXPECT_FALSE(success.fatally_failed());
const TestPartResult nonfatal_failure(TPRT_NONFATAL_FAILURE,
"file.cc",
42,
"message");
EXPECT_FALSE(nonfatal_failure.passed());
EXPECT_TRUE(nonfatal_failure.failed());
EXPECT_TRUE(nonfatal_failure.nonfatally_failed());
EXPECT_FALSE(nonfatal_failure.fatally_failed());
const TestPartResult fatal_failure(TPRT_FATAL_FAILURE,
"file.cc",
42,
"message");
EXPECT_FALSE(fatal_failure.passed());
EXPECT_TRUE(fatal_failure.failed());
EXPECT_FALSE(fatal_failure.nonfatally_failed());
EXPECT_TRUE(fatal_failure.fatally_failed());
}
// Tests the TestResult class
// The test fixture for testing TestResult.
@ -1298,34 +1340,6 @@ class TestResultTest : public Test {
}
};
// Tests TestResult::total_part_count().
TEST_F(TestResultTest, test_part_results) {
ASSERT_EQ(0, r0->total_part_count());
ASSERT_EQ(1, r1->total_part_count());
ASSERT_EQ(2, r2->total_part_count());
}
// Tests TestResult::successful_part_count().
TEST_F(TestResultTest, successful_part_count) {
ASSERT_EQ(0, r0->successful_part_count());
ASSERT_EQ(1, r1->successful_part_count());
ASSERT_EQ(1, r2->successful_part_count());
}
// Tests TestResult::failed_part_count().
TEST_F(TestResultTest, failed_part_count) {
ASSERT_EQ(0, r0->failed_part_count());
ASSERT_EQ(0, r1->failed_part_count());
ASSERT_EQ(1, r2->failed_part_count());
}
// Tests testing::internal::GetFailedPartCount().
TEST_F(TestResultTest, GetFailedPartCount) {
ASSERT_EQ(0, GetFailedPartCount(r0));
ASSERT_EQ(0, GetFailedPartCount(r1));
ASSERT_EQ(1, GetFailedPartCount(r2));
}
// Tests TestResult::total_part_count().
TEST_F(TestResultTest, total_part_count) {
ASSERT_EQ(0, r0->total_part_count());
@ -3778,42 +3792,37 @@ TEST(AssertionSyntaxTest, WorksWithConst) {
} // namespace
// Returns the number of successful parts in the current test.
static size_t GetSuccessfulPartCount() {
return GetUnitTestImpl()->current_test_result()->successful_part_count();
}
namespace testing {
// Tests that Google Test tracks SUCCEED*.
TEST(SuccessfulAssertionTest, SUCCEED) {
SUCCEED();
SUCCEED() << "OK";
EXPECT_EQ(2, GetSuccessfulPartCount());
EXPECT_EQ(2, GetUnitTestImpl()->current_test_result()->total_part_count());
}
// Tests that Google Test doesn't track successful EXPECT_*.
TEST(SuccessfulAssertionTest, EXPECT) {
EXPECT_TRUE(true);
EXPECT_EQ(0, GetSuccessfulPartCount());
EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
}
// Tests that Google Test doesn't track successful EXPECT_STR*.
TEST(SuccessfulAssertionTest, EXPECT_STR) {
EXPECT_STREQ("", "");
EXPECT_EQ(0, GetSuccessfulPartCount());
EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
}
// Tests that Google Test doesn't track successful ASSERT_*.
TEST(SuccessfulAssertionTest, ASSERT) {
ASSERT_TRUE(true);
EXPECT_EQ(0, GetSuccessfulPartCount());
EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
}
// Tests that Google Test doesn't track successful ASSERT_STR*.
TEST(SuccessfulAssertionTest, ASSERT_STR) {
ASSERT_STREQ("", "");
EXPECT_EQ(0, GetSuccessfulPartCount());
EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
}
} // namespace testing

View File

@ -182,9 +182,10 @@ class GetTestsToRunTest(unittest.TestCase):
def setUp(self):
self.fake_os = FakeOs(FakePath(
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
known_paths=[AddExeExtension('scons/build/dbg/scons/gtest_unittest'),
AddExeExtension('scons/build/opt/scons/gtest_unittest'),
'test/gtest_color_test.py']))
known_paths=[
AddExeExtension('scons/build/dbg/gtest/scons/gtest_unittest'),
AddExeExtension('scons/build/opt/gtest/scons/gtest_unittest'),
'test/gtest_color_test.py']))
self.fake_configurations = ['dbg', 'opt']
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
injected_subprocess=None,
@ -201,17 +202,19 @@ class GetTestsToRunTest(unittest.TestCase):
False,
available_configurations=self.fake_configurations),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]))
# An explicitly specified directory.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'gtest_unittest'],
['scons/build/dbg/gtest/scons', 'gtest_unittest'],
'',
False,
available_configurations=self.fake_configurations),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]))
# A particular configuration.
self.AssertResultsEqual(
@ -221,8 +224,8 @@ class GetTestsToRunTest(unittest.TestCase):
False,
available_configurations=self.fake_configurations),
([],
[('scons/build/other/scons',
'scons/build/other/scons/gtest_unittest')]))
[('scons/build/other/gtest/scons',
'scons/build/other/gtest/scons/gtest_unittest')]))
# All available configurations
self.AssertResultsEqual(
@ -232,8 +235,10 @@ class GetTestsToRunTest(unittest.TestCase):
False,
available_configurations=self.fake_configurations),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest'),
('scons/build/opt/scons', 'scons/build/opt/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest'),
('scons/build/opt/gtest/scons',
'scons/build/opt/gtest/scons/gtest_unittest')]))
# All built configurations (unbuilt don't cause failure).
self.AssertResultsEqual(
@ -243,40 +248,47 @@ class GetTestsToRunTest(unittest.TestCase):
True,
available_configurations=self.fake_configurations + ['unbuilt']),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest'),
('scons/build/opt/scons', 'scons/build/opt/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest'),
('scons/build/opt/gtest/scons',
'scons/build/opt/gtest/scons/gtest_unittest')]))
# A combination of an explicit directory and a configuration.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'gtest_unittest'],
['scons/build/dbg/gtest/scons', 'gtest_unittest'],
'opt',
False,
available_configurations=self.fake_configurations),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest'),
('scons/build/opt/scons', 'scons/build/opt/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest'),
('scons/build/opt/gtest/scons',
'scons/build/opt/gtest/scons/gtest_unittest')]))
# Same test specified in an explicit directory and via a configuration.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'gtest_unittest'],
['scons/build/dbg/gtest/scons', 'gtest_unittest'],
'dbg',
False,
available_configurations=self.fake_configurations),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]))
# All built configurations + explicit directory + explicit configuration.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'gtest_unittest'],
['scons/build/dbg/gtest/scons', 'gtest_unittest'],
'opt',
True,
available_configurations=self.fake_configurations),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest'),
('scons/build/opt/scons', 'scons/build/opt/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest'),
('scons/build/opt/gtest/scons',
'scons/build/opt/gtest/scons/gtest_unittest')]))
def testPythonTestsOnly(self):
"""Exercises GetTestsToRun with parameters designating Python tests only."""
@ -288,17 +300,17 @@ class GetTestsToRunTest(unittest.TestCase):
'',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[]))
# An explicitly specified directory.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'test/gtest_color_test.py'],
['scons/build/dbg/gtest/scons', 'test/gtest_color_test.py'],
'',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[]))
# A particular configuration.
@ -308,7 +320,7 @@ class GetTestsToRunTest(unittest.TestCase):
'other',
False,
available_configurations=self.fake_configurations),
([('scons/build/other/scons', 'test/gtest_color_test.py')],
([('scons/build/other/gtest/scons', 'test/gtest_color_test.py')],
[]))
# All available configurations
@ -318,8 +330,8 @@ class GetTestsToRunTest(unittest.TestCase):
'all',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py'),
('scons/build/opt/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py'),
('scons/build/opt/gtest/scons', 'test/gtest_color_test.py')],
[]))
# All built configurations (unbuilt don't cause failure).
@ -329,40 +341,40 @@ class GetTestsToRunTest(unittest.TestCase):
'',
True,
available_configurations=self.fake_configurations + ['unbuilt']),
([('scons/build/dbg/scons', 'test/gtest_color_test.py'),
('scons/build/opt/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py'),
('scons/build/opt/gtest/scons', 'test/gtest_color_test.py')],
[]))
# A combination of an explicit directory and a configuration.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'gtest_color_test.py'],
['scons/build/dbg/gtest/scons', 'gtest_color_test.py'],
'opt',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py'),
('scons/build/opt/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py'),
('scons/build/opt/gtest/scons', 'test/gtest_color_test.py')],
[]))
# Same test specified in an explicit directory and via a configuration.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'gtest_color_test.py'],
['scons/build/dbg/gtest/scons', 'gtest_color_test.py'],
'dbg',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[]))
# All built configurations + explicit directory + explicit configuration.
self.AssertResultsEqual(
self.test_runner.GetTestsToRun(
['scons/build/dbg/scons', 'gtest_color_test.py'],
['scons/build/dbg/gtest/scons', 'gtest_color_test.py'],
'opt',
True,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py'),
('scons/build/opt/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py'),
('scons/build/opt/gtest/scons', 'test/gtest_color_test.py')],
[]))
def testCombinationOfBinaryAndPythonTests(self):
@ -377,8 +389,9 @@ class GetTestsToRunTest(unittest.TestCase):
'',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py')],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')]))
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]))
# Specifying both binary and Python tests.
self.AssertResultsEqual(
@ -387,8 +400,9 @@ class GetTestsToRunTest(unittest.TestCase):
'',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py')],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')]))
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]))
# Specifying binary tests suppresses Python tests.
self.AssertResultsEqual(
@ -398,7 +412,8 @@ class GetTestsToRunTest(unittest.TestCase):
False,
available_configurations=self.fake_configurations),
([],
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')]))
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]))
# Specifying Python tests suppresses binary tests.
self.AssertResultsEqual(
@ -407,7 +422,7 @@ class GetTestsToRunTest(unittest.TestCase):
'',
False,
available_configurations=self.fake_configurations),
([('scons/build/dbg/scons', 'test/gtest_color_test.py')],
([('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[]))
def testIgnoresNonTestFiles(self):
@ -415,8 +430,9 @@ class GetTestsToRunTest(unittest.TestCase):
self.fake_os = FakeOs(FakePath(
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
known_paths=[AddExeExtension('scons/build/dbg/scons/gtest_nontest'),
'test/']))
known_paths=[
AddExeExtension('scons/build/dbg/gtest/scons/gtest_nontest'),
'test/']))
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
injected_subprocess=None,
injected_script_dir='.')
@ -435,10 +451,11 @@ class GetTestsToRunTest(unittest.TestCase):
# directory /a/b/c/.
self.fake_os = FakeOs(FakePath(
current_dir=os.path.abspath('/a/b/c'),
known_paths=['/a/b/c/',
AddExeExtension('/d/scons/build/dbg/scons/gtest_unittest'),
AddExeExtension('/d/scons/build/opt/scons/gtest_unittest'),
'/d/test/gtest_color_test.py']))
known_paths=[
'/a/b/c/',
AddExeExtension('/d/scons/build/dbg/gtest/scons/gtest_unittest'),
AddExeExtension('/d/scons/build/opt/gtest/scons/gtest_unittest'),
'/d/test/gtest_color_test.py']))
self.fake_configurations = ['dbg', 'opt']
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
injected_subprocess=None,
@ -451,8 +468,8 @@ class GetTestsToRunTest(unittest.TestCase):
False,
available_configurations=self.fake_configurations),
([],
[('/d/scons/build/dbg/scons',
'/d/scons/build/dbg/scons/gtest_unittest')]))
[('/d/scons/build/dbg/gtest/scons',
'/d/scons/build/dbg/gtest/scons/gtest_unittest')]))
# A Python test.
self.AssertResultsEqual(
@ -461,7 +478,7 @@ class GetTestsToRunTest(unittest.TestCase):
'',
False,
available_configurations=self.fake_configurations),
([('/d/scons/build/dbg/scons', '/d/test/gtest_color_test.py')],
([('/d/scons/build/dbg/gtest/scons', '/d/test/gtest_color_test.py')],
[]))
@ -491,7 +508,7 @@ class GetTestsToRunTest(unittest.TestCase):
self.fake_os = FakeOs(FakePath(
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
known_paths=['scons/build/dbg/scons/gtest_test', 'test/']))
known_paths=['scons/build/dbg/gtest/scons/gtest_test', 'test/']))
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
injected_subprocess=None,
injected_script_dir='.')
@ -522,9 +539,10 @@ class RunTestsTest(unittest.TestCase):
def setUp(self):
self.fake_os = FakeOs(FakePath(
current_dir=os.path.abspath(os.path.dirname(run_tests.__file__)),
known_paths=[AddExeExtension('scons/build/dbg/scons/gtest_unittest'),
AddExeExtension('scons/build/opt/scons/gtest_unittest'),
'test/gtest_color_test.py']))
known_paths=[
AddExeExtension('scons/build/dbg/gtest/scons/gtest_unittest'),
AddExeExtension('scons/build/opt/gtest/scons/gtest_unittest'),
'test/gtest_color_test.py']))
self.fake_configurations = ['dbg', 'opt']
self.test_runner = run_tests.TestRunner(injected_os=self.fake_os,
injected_subprocess=None)
@ -536,7 +554,7 @@ class RunTestsTest(unittest.TestCase):
self.fake_os.spawn_impl = self.SpawnSuccess
self.assertEqual(
self.test_runner.RunTests(
[('scons/build/dbg/scons', 'test/gtest_color_test.py')],
[('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[]),
0)
self.assertEqual(self.num_spawn_calls, 1)
@ -548,8 +566,8 @@ class RunTestsTest(unittest.TestCase):
self.assertEqual(
self.test_runner.RunTests(
[],
[('scons/build/dbg/scons',
'scons/build/dbg/scons/gtest_unittest')]),
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]),
0)
self.assertEqual(self.num_spawn_calls, 1)
@ -559,7 +577,7 @@ class RunTestsTest(unittest.TestCase):
self.fake_os.spawn_impl = self.SpawnFailure
self.assertEqual(
self.test_runner.RunTests(
[('scons/build/dbg/scons', 'test/gtest_color_test.py')],
[('scons/build/dbg/gtest/scons', 'test/gtest_color_test.py')],
[]),
1)
self.assertEqual(self.num_spawn_calls, 1)
@ -571,8 +589,8 @@ class RunTestsTest(unittest.TestCase):
self.assertEqual(
self.test_runner.RunTests(
[],
[('scons/build/dbg/scons',
'scons/build/dbg/scons/gtest_unittest')]),
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]),
1)
self.assertEqual(self.num_spawn_calls, 1)
@ -582,9 +600,10 @@ class RunTestsTest(unittest.TestCase):
self.fake_os.spawn_impl = self.SpawnSuccess
self.assertEqual(
self.test_runner.RunTests(
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')],
[('scons/build/dbg/scons',
'scons/build/dbg/scons/gtest_unittest')]),
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')],
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]),
0)
self.assertEqual(self.num_spawn_calls, 2)
@ -602,9 +621,10 @@ class RunTestsTest(unittest.TestCase):
self.fake_os.spawn_impl = SpawnImpl
self.assertEqual(
self.test_runner.RunTests(
[('scons/build/dbg/scons', 'scons/build/dbg/scons/gtest_unittest')],
[('scons/build/dbg/scons',
'scons/build/dbg/scons/gtest_unittest')]),
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')],
[('scons/build/dbg/gtest/scons',
'scons/build/dbg/gtest/scons/gtest_unittest')]),
0)
self.assertEqual(self.num_spawn_calls, 2)