diff --git a/Makefile.am b/Makefile.am index eba27760..e56fadf4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index d6673d1a..90c36a53 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -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& test_properties() const { + const internal::Vector& 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 > test_part_results_; // The vector of TestProperties - internal::scoped_ptr > - test_properties_; + internal::scoped_ptr > 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& 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. diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h index 76945551..be37726a 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -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 class Vector; // A generic vector. @@ -747,9 +746,6 @@ class TypeParameterizedTestCase { // 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(); diff --git a/run_tests.py b/run_tests.py index e558c155..727ecca5 100755 --- a/run_tests.py +++ b/run_tests.py @@ -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: - /scons/build/win-dbg8/scons/ - /scons/build/win-opt8/scons/ - /scons/build/win-dbg/scons/ - /scons/build/win-opt/scons/ + /scons/build/win-dbg8/gtest/scons/ + /scons/build/win-opt8/gtest/scons/ + /scons/build/win-dbg/gtest/scons/ + /scons/build/win-opt/gtest/scons/ On Mac: - /scons/build/mac-dbg/scons/ - /scons/build/mac-opt/scons/ + /scons/build/mac-dbg/gtest/scons/ + /scons/build/mac-opt/gtest/scons/ On other platforms: - /scons/build/dbg/scons/ - /scons/build/opt/scons/ + /scons/build/dbg/gtest/scons/ + /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). diff --git a/scons/SConscript b/scons/SConscript index 2faf8645..21c3e6d9 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -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') diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 92975dd0..5bb981d2 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -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& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + } // namespace internal } // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc index bc970173..69d2517f 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -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), - test_properties_(new Vector), + : test_part_results_(new internal::Vector), + test_properties_(new internal::Vector), 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, " 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 { diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index 8b2173bf..e9317e17 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -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) { diff --git a/test/gtest-unittest-api_test.cc b/test/gtest-unittest-api_test.cc new file mode 100644 index 00000000..658e2985 --- /dev/null +++ b/test/gtest-unittest-api_test.cc @@ -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 + +#include // For strcmp. +#include + +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 +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()); + 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()); + 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 class TestCaseWithCommentTest : public Test {}; +TYPED_TEST_CASE(TestCaseWithCommentTest, Types); +TYPED_TEST(TestCaseWithCommentTest, Dummy) {} + +const int kTypedTestCases = 1; +const int kTypedTests = 1; + +String GetExpectedTestCaseComment() { + Message comment; + comment << "TypeParam = " << GetTypeName().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(); +} diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 7cdfa172..4eb098e7 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -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& 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(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 diff --git a/test/run_tests_test.py b/test/run_tests_test.py index d8bbc362..2582262e 100755 --- a/test/run_tests_test.py +++ b/test/run_tests_test.py @@ -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)