From f39160b423e8f90902066cf6774e4180667dcbee Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 4 Sep 2009 18:30:25 +0000 Subject: More implementation of the event listener interface (by Vlad Losev); Reduces the stack space usage of assertions by moving AssertHelper's fields to the heap (by Jorg Brown); Makes String faster, smaller, and simpler (by Zhanyong Wan); Fixes a bug in String::Format() (by Chandler); Adds the /MD version of VC projects to the distribution (by Vlad Losev). git-svn-id: http://googletest.googlecode.com/svn/trunk@301 861a406c-534a-0410-8894-cb66d6ee9925 --- CHANGES | 19 +- Makefile.am | 17 +- README | 21 +- include/gtest/gtest-test-part.h | 3 + include/gtest/gtest.h | 215 ++++++++++++++- include/gtest/internal/gtest-internal.h | 1 - include/gtest/internal/gtest-string.h | 54 ++-- scons/SConscript | 3 +- src/gtest-death-test.cc | 6 +- src/gtest-internal-inl.h | 43 +-- src/gtest.cc | 451 +++++++++++++++++--------------- test/gtest-listener_test.cc | 230 ++++++++++++++++ test/gtest_env_var_test.py | 2 +- test/gtest_unittest.cc | 339 +++++++++++++++++++++++- test/gtest_xml_output_unittest.py | 33 ++- test/gtest_xml_output_unittest_.cc | 28 ++ 16 files changed, 1173 insertions(+), 292 deletions(-) create mode 100644 test/gtest-listener_test.cc diff --git a/CHANGES b/CHANGES index 3565588..bad7c3c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,20 @@ +Changes for 1.4.0 (up to r300): + + * New feature: the XML report format is closer to junitreport and can + be parsed by Hudson now. + * New feature: when a test runs under Visual Studio, its failures are + integrated in the IDE. + * New feature: /MD(d) versions of VC++ projects. + * New feature: elapsed time for the tests is printed by default. + * New feature: comes with a TR1 tuple implementation such that Boost + is no longer needed for Combine(). + * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends. + * New feature: the Xcode project can now produce static gtest + libraries in addition to a framework. + * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile, + Symbian, gcc, and C++Builder. + * Bug fixes and implementation clean-ups. + Changes for 1.3.0: * New feature: death tests on Windows, Cygwin, and Mac. @@ -11,7 +28,7 @@ Changes for 1.3.0: .cc file for easy deployment. * New feature: support for distributing test functions to multiple machines (requires support from the test runner). - * Bug fixes and implementation clean-up. + * Bug fixes and implementation clean-ups. Changes for 1.2.1: diff --git a/Makefile.am b/Makefile.am index 2f7e911..19d64ea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,6 +12,8 @@ EXTRA_DIST = \ include/gtest/internal/gtest-param-util-generated.h.pump \ make/Makefile \ scons/SConscript \ + scons/SConstruct \ + scons/SConstruct.common \ scripts/fuse_gtest_files.py \ scripts/gen_gtest_pred_impl.py \ scripts/test/Makefile \ @@ -24,10 +26,15 @@ EXTRA_DIST += \ msvc/gtest_color_test_.vcproj \ msvc/gtest_env_var_test_.vcproj \ msvc/gtest_environment_test.vcproj \ + msvc/gtest_main-md.vcproj \ msvc/gtest_main.vcproj \ + msvc/gtest-md.sln \ + msvc/gtest-md.vcproj \ msvc/gtest_output_test_.vcproj \ + msvc/gtest_prod_test-md.vcproj \ msvc/gtest_prod_test.vcproj \ msvc/gtest_uninitialized_test_.vcproj \ + msvc/gtest_unittest-md.vcproj \ msvc/gtest_unittest.vcproj # xcode project files @@ -36,9 +43,8 @@ EXTRA_DIST += \ xcode/Config/FrameworkTarget.xcconfig \ xcode/Config/General.xcconfig \ xcode/Config/ReleaseProject.xcconfig \ + xcode/Config/StaticLibraryTarget.xcconfig \ xcode/Config/TestTarget.xcconfig \ - xcode/Config/InternalTestTarget.xcconfig \ - xcode/Config/InternalPythonTestTarget.xcconfig \ xcode/Resources/Info.plist \ xcode/Scripts/versiongenerate.py \ xcode/Scripts/runtests.sh \ @@ -299,6 +305,11 @@ 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 +TESTS += test/gtest-listener_test +check_PROGRAMS += test/gtest-listener_test +test_gtest_listener_test_SOURCES = test/gtest-listener_test.cc +test_gtest_listener_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 @@ -407,7 +418,7 @@ TESTS += test/gtest_xml_outfiles_test.py check_PROGRAMS += test/gtest_xml_output_unittest_ test_gtest_xml_output_unittest__SOURCES = test/gtest_xml_output_unittest_.cc -test_gtest_xml_output_unittest__LDADD = lib/libgtest_main.la +test_gtest_xml_output_unittest__LDADD = lib/libgtest.la check_SCRIPTS += test/gtest_xml_output_unittest.py TESTS += test/gtest_xml_output_unittest.py diff --git a/README b/README index d746401..a9172c5 100644 --- a/README +++ b/README @@ -190,9 +190,16 @@ see 'gtest-config --help' for more detailed information. g++ $(../../my_gtest_build/scripts/gtest-config ...) ... ### Windows ### -Open the gtest.sln file in the msvc/ folder using Visual Studio, and -you are ready to build Google Test the same way you build any Visual -Studio project. +The msvc\ folder contains two solutions with Visual C++ projects. Open the +gtest.sln or gtest-md.sln file using Visual Studio, and you are ready to +build Google Test the same way you build any Visual Studio project. Files +that have names ending with -md use DLL versions of Microsoft runtime +libraries (the /MD or the /MDd compiler option). Files without that suffix +use static versions of the runtime libraries (the /MT or the /MTd option). +Please note that one must use the same option to compile both gtest and his +test code. If you use Visual Studio 2005 or above, we recommend the -md +version as /MD is the default for new projects in these versions of Visual +Studio. ### Mac OS X (universal-binary framework) ### Open the gtest.xcodeproj in the xcode/ folder using Xcode. Build the "gtest" @@ -201,7 +208,7 @@ directory (selected in the Xcode "Preferences..." -> "Building" pane and defaults to xcode/build). Alternatively, at the command line, enter: xcodebuild - + This will build the "Release" configuration of gtest.framework in your default build location. See the "xcodebuild" man page for more information about building different configurations and building in different locations. @@ -213,7 +220,7 @@ ones) as errors. However, you should see a "Build succeeded" message at the end of the build log. To run all of the tests from the command line, enter: xcodebuild -target Check - + Installation with xcodebuild requires specifying an installation desitination directory, known as the DSTROOT. Three items will be installed when using xcodebuild: @@ -221,12 +228,12 @@ xcodebuild: $DSTROOT/Library/Frameworks/gtest.framework $DSTROOT/usr/local/lib/libgtest.a $DSTROOT/usr/local/lib/libgtest_main.a - + You specify the installation directory on the command line with the other xcodebuild options. Here's how you would install in a user-visible location: xcodebuild install DSTROOT=~ - + To perform a system-wide inistall, escalate to an administrator and specify the file system root as the DSTROOT: diff --git a/include/gtest/gtest-test-part.h b/include/gtest/gtest-test-part.h index d5b2713..14d8e7b 100644 --- a/include/gtest/gtest-test-part.h +++ b/include/gtest/gtest-test-part.h @@ -41,6 +41,9 @@ namespace testing { // The possible outcomes of a test part (i.e. an assertion or an // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). +// TODO(vladl@google.com): Rename the enum values to kSuccess, +// kNonFatalFailure, and kFatalFailure before publishing the event listener +// API (see issue http://code.google.com/p/googletest/issues/detail?id=165). enum TestPartResultType { TPRT_SUCCESS, // Succeeded. TPRT_NONFATAL_FAILURE, // Failed but the test can continue. diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index 90c36a5..0727adb 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -149,17 +149,23 @@ namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; +class EventListenersAccessor; class ExecDeathTest; +class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class TestCase; class TestInfoImpl; class TestResultAccessor; class UnitTestAccessor; +// TODO(vladl@google.com): Rename to TestEventRepeater. +class UnitTestEventsRepeater; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResultType result_type, const String& message); +class PrettyUnitTestResultPrinter; +class XmlUnitTestResultPrinter; // Converts a streamable value to a String. A NULL pointer is // converted to "(null)". When the input value is a ::string, @@ -766,6 +772,178 @@ class Environment { virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; +namespace internal { + +// TODO(vladl@google.com): Order the methods the way they are invoked by +// Google Test. +// The interface for tracing execution of tests. +class UnitTestEventListenerInterface { + public: + virtual ~UnitTestEventListenerInterface() {} + + // TODO(vladl@google.com): Add events for test program start and test program + // end: OnTestIterationStart(const UnitTest&); // Start of one iteration. + // Add tests, too. + // TODO(vladl@google.com): Rename OnUnitTestStart() and OnUnitTestEnd() to + // OnTestProgramStart() and OnTestProgramEnd(). + // Called before any test activity starts. + virtual void OnUnitTestStart(const UnitTest& unit_test) = 0; + + // Called after all test activities have ended. + virtual void OnUnitTestEnd(const UnitTest& unit_test) = 0; + + // Called before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Called after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // TODO(vladl@google.com): Rename OnGlobalSetUpStart to + // OnEnvironmentsSetUpStart. Make similar changes for the rest of + // environment-related events. + // Called before the global set-up starts. + virtual void OnGlobalSetUpStart(const UnitTest& unit_test) = 0; + + // Called after the global set-up ends. + virtual void OnGlobalSetUpEnd(const UnitTest& unit_test) = 0; + + // Called before the global tear-down starts. + virtual void OnGlobalTearDownStart(const UnitTest& unit_test) = 0; + + // Called after the global tear-down ends. + virtual void OnGlobalTearDownEnd(const UnitTest& unit_test) = 0; + + // Called before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Called after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Called after a failed assertion or a SUCCESS(). + virtual void OnNewTestPartResult(const TestPartResult& test_part_result) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. +class EmptyTestEventListener : public UnitTestEventListenerInterface { + public: + // Called before the unit test starts. + virtual void OnUnitTestStart(const UnitTest& /*unit_test*/) {} + + // Called after the unit test ends. + virtual void OnUnitTestEnd(const UnitTest& /*unit_test*/) {} + + // Called before the test case starts. + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + + // Called after the test case ends. + virtual void OnTestCaseEnd(const TestCase& /*test_case&*/) {} + + // Called before the global set-up starts. + virtual void OnGlobalSetUpStart(const UnitTest& /*unit_test*/) {} + + // Called after the global set-up ends. + virtual void OnGlobalSetUpEnd(const UnitTest& /*unit_test*/) {} + + // Called before the global tear-down starts. + virtual void OnGlobalTearDownStart(const UnitTest& /*unit_test*/) {} + + // Called after the global tear-down ends. + virtual void OnGlobalTearDownEnd(const UnitTest& /*unit_test*/) {} + + // Called before the test starts. + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + + // Called after the test ends. + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + + // Called after a failed assertion or a SUCCESS(). + virtual void OnNewTestPartResult(const TestPartResult& /*test_part_result*/) { + } +}; + +// EventListeners lets users add listeners to track events in Google Test. +class EventListeners { + public: + EventListeners(); + ~EventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(UnitTestEventListenerInterface* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + UnitTestEventListenerInterface* Release( + UnitTestEventListenerInterface* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + UnitTestEventListenerInterface* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + UnitTestEventListenerInterface* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::EventListenersAccessor; + friend class internal::NoExecDeathTest; + friend class internal::TestCase; + friend class internal::TestInfoImpl; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the UnitTestEventListenerInterface + // events to all subscribers. + UnitTestEventListenerInterface* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(UnitTestEventListenerInterface* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(UnitTestEventListenerInterface* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::UnitTestEventsRepeater* repeater_; + // Listener responsible for the standard result output. + UnitTestEventListenerInterface* default_result_printer_; + // Listener responsible for the creation of the XML output file. + UnitTestEventListenerInterface* default_xml_generator_; + + // We disallow copying EventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(EventListeners); +}; + +} // namespace internal + // A UnitTest consists of a vector of TestCases. // // This is a singleton class. The only instance of UnitTest is @@ -886,6 +1064,10 @@ class UnitTest { // total_test_case_count() - 1. If i is not in that range, returns NULL. const internal::TestCase* GetTestCase(int i) const; + // Returns the list of event listeners that can be used to track events + // inside Google Test. + internal::EventListeners& listeners(); + // ScopedTrace is a friend as it needs to modify the per-thread // trace stack, which is a private member of UnitTest. // TODO(vladl@google.com): Order all declarations according to the style @@ -899,9 +1081,12 @@ class UnitTest { TestPartResultType result_type, const internal::String& message); // TODO(vladl@google.com): Remove these when publishing the new accessors. - friend class PrettyUnitTestResultPrinter; - friend class XmlUnitTestResultPrinter; + friend class internal::PrettyUnitTestResultPrinter; + friend class internal::TestCase; + friend class internal::TestInfoImpl; friend class internal::UnitTestAccessor; + friend class internal::UnitTestImpl; + friend class internal::XmlUnitTestResultPrinter; friend class FinalSuccessChecker; FRIEND_TEST(ApiTest, UnitTestImmutableAccessorsWork); FRIEND_TEST(ApiTest, TestCaseImmutableAccessorsWork); @@ -1299,14 +1484,32 @@ class AssertHelper { // Constructor. AssertHelper(TestPartResultType type, const char* file, int line, const char* message); + ~AssertHelper(); + // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; + private: - TestPartResultType const type_; - const char* const file_; - int const line_; - String const message_; + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResultType t, const char* srcfile, int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResultType const type; + const char* const file; + int const line; + String const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h index be37726..f0a7966 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -107,7 +107,6 @@ class Test; // Represents a test. 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. namespace internal { diff --git a/include/gtest/internal/gtest-string.h b/include/gtest/internal/gtest-string.h index d36146a..39982d1 100644 --- a/include/gtest/internal/gtest-string.h +++ b/include/gtest/internal/gtest-string.h @@ -51,22 +51,6 @@ namespace testing { namespace internal { -// Holds data in a String object. We need this class in order to put -// String's data members on the heap instead of on the stack. -// Otherwise tests using many assertions (and thus Strings) in one -// function may need too much stack frame space to compile. -class StringData { - StringData() : c_str_(NULL), length_(0) {} - ~StringData() { delete[] c_str_; } - - private: - friend class String; - - const char* c_str_; - size_t length_; // Length of the string (excluding the terminating - // '\0' character). -}; - // String - a UTF-8 string class. // // We cannot use std::string as Microsoft's STL implementation in @@ -202,14 +186,14 @@ class String { // C'tors - // The default c'tor constructs a NULL string, which is represented - // by data_ being NULL. - String() : data_(NULL) {} + // The default c'tor constructs a NULL string. + String() : c_str_(NULL), length_(0) {} // Constructs a String by cloning a 0-terminated C string. String(const char* c_str) { // NOLINT if (c_str == NULL) { - data_ = NULL; + c_str_ = NULL; + length_ = 0; } else { ConstructNonNull(c_str, strlen(c_str)); } @@ -225,13 +209,11 @@ class String { // The copy c'tor creates a new copy of the string. The two // String objects do not share content. - String(const String& str) : data_(NULL) { *this = str; } + String(const String& str) : c_str_(NULL), length_(0) { *this = str; } // D'tor. String is intended to be a final class, so the d'tor // doesn't need to be virtual. - ~String() { - delete data_; - } + ~String() { delete[] c_str_; } // Allows a String to be implicitly converted to an ::std::string or // ::string, and vice versa. Converting a String containing a NULL @@ -285,12 +267,12 @@ class String { // Returns the length of the encapsulated string, or 0 if the // string is NULL. - size_t length() const { return (data_ == NULL) ? 0 : data_->length_; } + size_t length() const { return length_; } // Gets the 0-terminated C string this String object represents. // The String object still owns the string. Therefore the caller // should NOT delete the return value. - const char* c_str() const { return (data_ == NULL) ? NULL : data_->c_str_; } + const char* c_str() const { return c_str_; } // Assigns a C string to this object. Self-assignment works. const String& operator=(const char* c_str) { return *this = String(c_str); } @@ -298,10 +280,12 @@ class String { // Assigns a String object to this object. Self-assignment works. const String& operator=(const String& rhs) { if (this != &rhs) { - delete data_; - data_ = NULL; - if (rhs.data_ != NULL) { - ConstructNonNull(rhs.data_->c_str_, rhs.data_->length_); + delete[] c_str_; + if (rhs.c_str() == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(rhs.c_str(), rhs.length()); } } @@ -314,17 +298,15 @@ class String { // ConstructNonNull(NULL, 0) results in an empty string (""). // ConstructNonNull(NULL, non_zero) is undefined behavior. void ConstructNonNull(const char* buffer, size_t length) { - data_ = new StringData; char* const str = new char[length + 1]; memcpy(str, buffer, length); str[length] = '\0'; - data_->c_str_ = str; - data_->length_ = length; + c_str_ = str; + length_ = length; } - // Points to the representation of the String. A NULL String is - // represented by data_ == NULL. - StringData* data_; + const char* c_str_; + size_t length_; }; // class String // Streams a String to an ostream. Each '\0' character in the String diff --git a/scons/SConscript b/scons/SConscript index 8fbd5f5..e881828 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -318,8 +318,9 @@ GtestTest(env, 'gtest_list_tests_unittest_', gtest) 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) +GtestTest(env, 'gtest_xml_output_unittest_', gtest) GtestTest(env, 'gtest-unittest-api_test', gtest) +GtestTest(env, 'gtest-listener_test', gtest) ############################################################ # Tests targets using custom environments. diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 02ce48d..d975af7 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -469,7 +469,8 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { - if (RE::PartialMatch(error_message.c_str(), *regex())) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" @@ -767,6 +768,9 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 8431971..93217f4 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -741,6 +741,9 @@ class UnitTestImpl { return test_cases_.GetElementOr(i, NULL); } + // Provides access to the event listener list. + EventListeners* listeners() { return &listeners_; } + // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); @@ -748,18 +751,6 @@ class UnitTestImpl { // Returns the TestResult for the ad hoc test. 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); - - // Returns the current unit test result printer if it is not NULL; - // otherwise, creates an appropriate result printer, makes it the - // current printer, and returns it. - UnitTestEventListenerInterface* result_printer(); - // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter @@ -907,9 +898,13 @@ class UnitTestImpl { } #if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } @@ -919,9 +914,22 @@ class UnitTestImpl { return death_test_factory_.get(); } + void SuppressTestEventsIfInSubprocess(); + friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. + void PostFlagParsingInit(); + // Gets the random seed used at the start of the current test run. int random_seed() const { return random_seed_; } @@ -992,11 +1000,9 @@ class UnitTestImpl { // test, and records the result in 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, - // but the user can set this field to use a custom printer if that - // is desired. - UnitTestEventListenerInterface* result_printer_; + // The list of event listeners that can be used to track events inside + // Google Test. + EventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, @@ -1004,6 +1010,9 @@ class UnitTestImpl { // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + // The random number seed used at the beginning of the test run. int random_seed_; diff --git a/src/gtest.cc b/src/gtest.cc index 5cfabf8..1b602f5 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -129,9 +129,12 @@ namespace testing { +using internal::EventListeners; +using internal::EmptyTestEventListener; using internal::TestCase; using internal::TestProperty; using internal::TestResult; +using internal::UnitTestEventListenerInterface; // Constants. @@ -303,14 +306,18 @@ static bool ShouldRunTestCase(const TestCase* test_case) { // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResultType type, const char* file, int line, const char* message) - : type_(type), file_(file), line_(line), message_(message) { + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> - AddTestPartResult(type_, file_, line_, - AppendUserMessage(message_, message), + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. @@ -476,86 +483,6 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { } // namespace internal -// The interface for printing the result of a UnitTest -class UnitTestEventListenerInterface { - public: - // The d'tor is pure virtual as this is an abstract class. - virtual ~UnitTestEventListenerInterface() {} - - // Called before the unit test starts. - virtual void OnUnitTestStart(const UnitTest& unit_test) = 0; - - // Called after the unit test ends. - virtual void OnUnitTestEnd(const UnitTest& unit_test) = 0; - - // Called before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; - - // Called after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; - - // Called before the global set-up starts. - virtual void OnGlobalSetUpStart(const UnitTest& unit_test) = 0; - - // Called after the global set-up ends. - virtual void OnGlobalSetUpEnd(const UnitTest& unit_test) = 0; - - // Called before the global tear-down starts. - virtual void OnGlobalTearDownStart(const UnitTest& unit_test) = 0; - - // Called after the global tear-down ends. - virtual void OnGlobalTearDownEnd(const UnitTest& unit_test) = 0; - - // Called before the test starts. - virtual void OnTestStart(const TestInfo& test_info) = 0; - - // Called after the test ends. - virtual void OnTestEnd(const TestInfo& test_info) = 0; - - // Called after an assertion. - virtual void OnNewTestPartResult(const TestPartResult& test_part_result) = 0; -}; - -// The convenience class for users who need to override just one or two -// methods and are not concerned that a possible change to a signature of -// the methods they override will not be caught during the build. -class EmptyTestEventListener : public UnitTestEventListenerInterface { - public: - // Called before the unit test starts. - virtual void OnUnitTestStart(const UnitTest& /*unit_test*/) {} - - // Called after the unit test ends. - virtual void OnUnitTestEnd(const UnitTest& /*unit_test*/) {} - - // Called before the test case starts. - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - - // Called after the test case ends. - virtual void OnTestCaseEnd(const TestCase& /*test_case&*/) {} - - // Called before the global set-up starts. - virtual void OnGlobalSetUpStart(const UnitTest& /*unit_test*/) {} - - // Called after the global set-up ends. - virtual void OnGlobalSetUpEnd(const UnitTest& /*unit_test*/) {} - - // Called before the global tear-down starts. - virtual void OnGlobalTearDownStart(const UnitTest& /*unit_test*/) {} - - // Called after the global tear-down ends. - virtual void OnGlobalTearDownEnd(const UnitTest& /*unit_test*/) {} - - // Called before the test starts. - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - - // Called after the test ends. - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - - // Called after an assertion. - virtual void OnNewTestPartResult(const TestPartResult& /*test_part_result*/) { - } -}; - // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. @@ -690,7 +617,7 @@ DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->result_printer()->OnNewTestPartResult(result); + unit_test_->listeners()->repeater()->OnNewTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( @@ -1738,28 +1665,38 @@ bool String::EndsWithCaseInsensitive(const char* suffix) const { // available. // // The result is limited to 4096 characters (including the tailing 0). -// If 4096 characters are not enough to format the input, -// "" is returned. +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. String String::Format(const char * format, ...) { va_list args; va_start(args, format); char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. #ifdef _MSC_VER // We are using MSVC. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. - const int size = - vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); + const int size = vsnprintf(buffer, kBufferSize, format, args); #pragma warning(pop) // Restores the warning state. #else // We are not using MSVC. - const int size = - vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args); + const int size = vsnprintf(buffer, kBufferSize, format, args); #endif // _MSC_VER va_end(args); - return (size >= 0) ? String(buffer, size) : String(""); + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } } // Converts the buffer in a StrStream to a String, converting NUL @@ -2297,11 +2234,11 @@ void TestInfoImpl::Run() { UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(parent_); - // Notifies the unit test event listener that a test is about to - // start. - UnitTestEventListenerInterface* const result_printer = - impl->result_printer(); - result_printer->OnTestStart(*parent_); + UnitTestEventListenerInterface* repeater = + UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*parent_); const TimeInMillis start = GetTimeInMillis(); @@ -2344,7 +2281,7 @@ void TestInfoImpl::Run() { result_.set_elapsed_time(GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. - result_printer->OnTestEnd(*parent_); + repeater->OnTestEnd(*parent_); // Tells UnitTest to stop associating assertion results to this // test. @@ -2425,10 +2362,10 @@ void TestCase::Run() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); - UnitTestEventListenerInterface * const result_printer = - impl->result_printer(); + UnitTestEventListenerInterface* repeater = + UnitTest::GetInstance()->listeners().repeater(); - result_printer->OnTestCaseStart(*this); + repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); set_up_tc_(); @@ -2438,7 +2375,7 @@ void TestCase::Run() { impl->os_stack_trace_getter()->UponLeavingGTest(); tear_down_tc_(); - result_printer->OnTestCaseEnd(*this); + repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } @@ -2471,10 +2408,6 @@ bool TestCase::ShouldRunTest(const TestInfo *test_info) { } // namespace internal -// A result printer that never prints anything. Used in the child process -// of an exec-style death test to avoid needless output clutter. -class NullUnitTestResultPrinter : public EmptyTestEventListener {}; - // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // @@ -2663,14 +2596,6 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } -} // namespace internal - -using internal::ColoredPrintf; -using internal::COLOR_DEFAULT; -using internal::COLOR_RED; -using internal::COLOR_GREEN; -using internal::COLOR_YELLOW; - // This class implements the UnitTestEventListenerInterface interface. // // Class PrettyUnitTestResultPrinter is copyable. @@ -2888,10 +2813,16 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { // This class forwards events to other event listeners. class UnitTestEventsRepeater : public UnitTestEventListenerInterface { public: - typedef internal::Vector Listeners; - UnitTestEventsRepeater() {} + UnitTestEventsRepeater() : forwarding_enabled_(true) {} virtual ~UnitTestEventsRepeater(); - void AddListener(UnitTestEventListenerInterface *listener); + void Append(UnitTestEventListenerInterface *listener); + UnitTestEventListenerInterface* Release( + UnitTestEventListenerInterface* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnUnitTestStart(const UnitTest& unit_test); virtual void OnUnitTestEnd(const UnitTest& unit_test); @@ -2906,7 +2837,11 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { virtual void OnNewTestPartResult(const TestPartResult& result); private: - Listeners listeners_; + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + Vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestEventsRepeater); }; @@ -2917,17 +2852,31 @@ UnitTestEventsRepeater::~UnitTestEventsRepeater() { } } -void UnitTestEventsRepeater::AddListener( - UnitTestEventListenerInterface *listener) { +void UnitTestEventsRepeater::Append(UnitTestEventListenerInterface *listener) { listeners_.PushBack(listener); } +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +UnitTestEventListenerInterface* UnitTestEventsRepeater::Release( + UnitTestEventListenerInterface *listener) { + for (int i = 0; i < listeners_.size(); ++i) { + if (listeners_.GetElement(i) == listener) { + listeners_.Erase(i); + return listener; + } + } + + return NULL; +} + // Since the methods are identical, use a macro to reduce boilerplate. // This defines a member that repeats the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void UnitTestEventsRepeater::Name(const Type& parameter) { \ - for (int i = 0; i < listeners_.size(); i++) { \ - listeners_.GetElement(i)->Name(parameter); \ + if (forwarding_enabled_) { \ + for (int i = 0; i < listeners_.size(); i++) { \ + listeners_.GetElement(i)->Name(parameter); \ + } \ } \ } @@ -2945,7 +2894,7 @@ GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult) #undef GTEST_REPEATER_METHOD_ -// End PrettyUnitTestResultPrinter +// End UnitTestEventsRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { @@ -2970,18 +2919,15 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. - static internal::String EscapeXml(const char* str, - bool is_attribute); + static String EscapeXml(const char* str, bool is_attribute); // Convenience wrapper around EscapeXml when str is an attribute value. - static internal::String EscapeXmlAttribute(const char* str) { + static String EscapeXmlAttribute(const char* str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. - static internal::String EscapeXmlText(const char* str) { - return EscapeXml(str, false); - } + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Prints an XML representation of a TestInfo object. static void PrintXmlTestInfo(FILE* out, @@ -2998,11 +2944,10 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // delimited XML attributes based on the property key="value" pairs. // 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 TestResult& result); + static String TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. - const internal::String output_file_; + const String output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; @@ -3020,11 +2965,11 @@ XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) // Called after the unit test ends. void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { FILE* xmlout = NULL; - internal::FilePath output_file(output_file_); - internal::FilePath output_dir(output_file.RemoveFileName()); + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { - xmlout = internal::posix::FOpen(output_file_.c_str(), "w"); + xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. @@ -3059,8 +3004,7 @@ void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. -internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, - bool is_attribute) { +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { Message m; if (str != NULL) { @@ -3090,7 +3034,7 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, default: if (IsValidXmlCharacter(*src)) { if (is_attribute && IsNormalizableWhitespace(*src)) - m << internal::String::Format("&#x%02X;", unsigned(*src)); + m << String::Format("&#x%02X;", unsigned(*src)); else m << *src; } @@ -3102,7 +3046,6 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, return m.GetString(); } - // The following routines generate an XML representation of a UnitTest // object. // @@ -3119,8 +3062,6 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, // // -namespace internal { - // Formats the given time in milliseconds as seconds. The returned // C-string is owned by this function and cannot be released by the // caller. Calling the function again invalidates the previous @@ -3131,8 +3072,6 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { return str.c_str(); } -} // namespace internal - // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, @@ -3144,7 +3083,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, "classname=\"%s\"%s", EscapeXmlAttribute(test_info.name()).c_str(), test_info.should_run() ? "run" : "notrun", - internal::FormatTimeInMillisAsSeconds(result.elapsed_time()), + FormatTimeInMillisAsSeconds(result.elapsed_time()), EscapeXmlAttribute(test_case_name).c_str(), TestPropertiesAsXmlAttributes(result).c_str()); @@ -3152,9 +3091,8 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, for (int i = 0; i < result.total_part_count(); ++i) { const TestPartResult& part = result.GetTestPartResult(i); if (part.failed()) { - const internal::String message = - internal::String::Format("%s:%d\n%s", part.file_name(), - part.line_number(), part.message()); + const String message = String::Format("%s:%d\n%s", part.file_name(), + part.line_number(), part.message()); if (++failures == 1) fprintf(out, ">\n"); fprintf(out, @@ -3182,7 +3120,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, test_case.disabled_test_count()); fprintf(out, "errors=\"0\" time=\"%s\">\n", - internal::FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); for (int i = 0; i < test_case.total_test_count(); ++i) PrintXmlTestInfo(out, test_case.name(), *test_case.GetTestInfo(i)); fprintf(out, " \n"); @@ -3198,7 +3136,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, unit_test.total_test_count(), unit_test.failed_test_count(), unit_test.disabled_test_count(), - internal::FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed()); } @@ -3210,7 +3148,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( +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { @@ -3223,8 +3161,6 @@ internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( // End XmlUnitTestResultPrinter -namespace internal { - // Class ScopedTrace // Pushes the given source file location and message onto a per-thread @@ -3271,6 +3207,84 @@ OsStackTraceGetter::kElidedFramesMarker = } // namespace internal +// class EventListeners + +EventListeners::EventListeners() + : repeater_(new internal::UnitTestEventsRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +EventListeners::~EventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void EventListeners::Append(UnitTestEventListenerInterface* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +UnitTestEventListenerInterface* EventListeners::Release( + UnitTestEventListenerInterface* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the UnitTestEventListenerInterface +// events to all subscribers. +UnitTestEventListenerInterface* EventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void EventListeners::SetDefaultResultPrinter( + UnitTestEventListenerInterface* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void EventListeners::SetDefaultXmlGenerator( + UnitTestEventListenerInterface* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool EventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void EventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + // class UnitTest // Gets the singleton UnitTest object. The first time this method is @@ -3359,6 +3373,12 @@ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } +// Returns the list of event listeners that can be used to track events +// inside Google Test. +EventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have @@ -3614,8 +3634,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), - result_printer_(NULL), os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), random_seed_(0), #if GTEST_HAS_DEATH_TEST elapsed_time_(0), @@ -3624,6 +3644,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) #else elapsed_time_(0) { #endif // GTEST_HAS_DEATH_TEST + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { @@ -3633,12 +3654,58 @@ UnitTestImpl::~UnitTestImpl() { // Deletes every Environment. environments_.ForEach(internal::Delete); - // Deletes the current test result printer. - delete result_printer_; - delete os_stack_trace_getter_; } +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + } +} + // A predicate that checks the name of a TestCase against a known // value. // @@ -3726,7 +3793,8 @@ int UnitTestImpl::RunAllTests() { if (g_help_flag) return 0; - RegisterParameterizedTests(); + // TODO(vladl@google.com): Add a call to PostFlagParsingInit() here when + // merging into the main branch. // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding @@ -3738,12 +3806,9 @@ int UnitTestImpl::RunAllTests() { bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST - internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST - UnitTestEventListenerInterface * const printer = result_printer(); - const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); @@ -3766,6 +3831,8 @@ int UnitTestImpl::RunAllTests() { // True iff at least one test has failed. bool failed = false; + UnitTestEventListenerInterface* repeater = listeners()->repeater(); + // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); @@ -3773,21 +3840,24 @@ int UnitTestImpl::RunAllTests() { const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { if (repeat != 1) { + // TODO(vladl@google.com): Move this output to + // PrettyUnitTestResultPrinter. Add the iteration number parameter to + // OnUnitTestStart. printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1); } - // Tells the unit test event listener that the tests are about to - // start. - printer->OnUnitTestStart(*parent_); + // Tells the unit test event listeners that the tests are about to start. + repeater->OnUnitTestStart(*parent_); + // TODO(vladl@google.com): Move to before the OnUnitTestStart notification? const TimeInMillis start = GetTimeInMillis(); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. - printer->OnGlobalSetUpStart(*parent_); + repeater->OnGlobalSetUpStart(*parent_); environments_.ForEach(SetUpEnvironment); - printer->OnGlobalSetUpEnd(*parent_); + repeater->OnGlobalSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. @@ -3796,16 +3866,15 @@ int UnitTestImpl::RunAllTests() { } // Tears down all environments in reverse order afterwards. - printer->OnGlobalTearDownStart(*parent_); + repeater->OnGlobalTearDownStart(*parent_); environments_in_reverse_order_.ForEach(TearDownEnvironment); - printer->OnGlobalTearDownEnd(*parent_); + repeater->OnGlobalTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; - // Tells the unit test event listener that the tests have just - // finished. - printer->OnUnitTestEnd(*parent_); + // Tells the unit test event listener that the tests have just finished. + repeater->OnUnitTestEnd(*parent_); // Gets the result and clears it. if (!Passed()) { @@ -3997,49 +4066,6 @@ void UnitTestImpl::ListTestsMatchingFilter() { fflush(stdout); } -// 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 UnitTestImpl::set_result_printer( - UnitTestEventListenerInterface* result_printer) { - if (result_printer_ != result_printer) { - delete result_printer_; - result_printer_ = result_printer; - } -} - -// Returns the current unit test result printer if it is not NULL; -// otherwise, creates an appropriate result printer, makes it the -// current printer, and returns it. -UnitTestEventListenerInterface* UnitTestImpl::result_printer() { - if (result_printer_ != NULL) { - return result_printer_; - } - -#if GTEST_HAS_DEATH_TEST - if (internal_run_death_test_flag_.get() != NULL) { - result_printer_ = new NullUnitTestResultPrinter; - return result_printer_; - } -#endif // GTEST_HAS_DEATH_TEST - - UnitTestEventsRepeater *repeater = new UnitTestEventsRepeater; - const String& output_format = internal::UnitTestOptions::GetOutputFormat(); - if (output_format == "xml") { - repeater->AddListener(new XmlUnitTestResultPrinter( - internal::UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); - } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); - } - repeater->AddListener(new PrettyUnitTestResultPrinter); - result_printer_ = repeater; - return result_printer_; -} - // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are @@ -4420,6 +4446,7 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal diff --git a/test/gtest-listener_test.cc b/test/gtest-listener_test.cc new file mode 100644 index 0000000..fb6fcf4 --- /dev/null +++ b/test/gtest-listener_test.cc @@ -0,0 +1,230 @@ +// 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 verifies Google Test event listeners receive events at the +// right times. + +#include + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" // For Vector. +#undef GTEST_IMPLEMENTATION_ + +using ::testing::AddGlobalTestEnvironment; +using ::testing::Environment; +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; +using ::testing::internal::String; +using ::testing::internal::TestCase; +using ::testing::internal::UnitTestEventListenerInterface; +using ::testing::internal::Vector; + +// Used by tests to register their events. +Vector* g_events = NULL; + +namespace testing { +namespace internal { + +// TODO(vladl@google.com): Remove this and use UnitTest::listeners() +// directly after it is published. +class UnitTestAccessor { + public: + static EventListeners& GetEventListeners() { + return UnitTest::GetInstance()->listeners(); + } + static bool UnitTestFailed() { return UnitTest::GetInstance()->Failed(); } +}; + +class EventRecordingListener : public UnitTestEventListenerInterface { + protected: + virtual void OnUnitTestStart(const UnitTest& unit_test) { + g_events->PushBack(String("TestEventListener::OnUnitTestStart")); + } + + virtual void OnGlobalSetUpStart(const UnitTest& unit_test) { + g_events->PushBack(String("TestEventListener::OnGlobalSetUpStart")); + } + + virtual void OnGlobalSetUpEnd(const UnitTest& unit_test) { + g_events->PushBack(String("TestEventListener::OnGlobalSetUpEnd")); + } + + virtual void OnTestCaseStart(const TestCase& test_case) { + g_events->PushBack(String("TestEventListener::OnTestCaseStart")); + } + + virtual void OnTestStart(const TestInfo& test_info) { + g_events->PushBack(String("TestEventListener::OnTestStart")); + } + + virtual void OnNewTestPartResult(const TestPartResult& test_part_result) { + g_events->PushBack(String("TestEventListener::OnNewTestPartResult")); + } + + virtual void OnTestEnd(const TestInfo& test_info) { + g_events->PushBack(String("TestEventListener::OnTestEnd")); + } + + virtual void OnTestCaseEnd(const TestCase& test_case) { + g_events->PushBack(String("TestEventListener::OnTestCaseEnd")); + } + + virtual void OnGlobalTearDownStart(const UnitTest& unit_test) { + g_events->PushBack(String("TestEventListener::OnGlobalTearDownStart")); + } + + virtual void OnGlobalTearDownEnd(const UnitTest& unit_test) { + g_events->PushBack(String("TestEventListener::OnGlobalTearDownEnd")); + } + + virtual void OnUnitTestEnd(const UnitTest& unit_test) { + g_events->PushBack(String("TestEventListener::OnUnitTestEnd")); + } +}; + +class EnvironmentInvocationCatcher : public Environment { + protected: + virtual void SetUp() { + g_events->PushBack(String("Environment::SetUp")); + } + + virtual void TearDown() { + g_events->PushBack(String("Environment::TearDown")); + } +}; + +class ListenerTest : public Test { + protected: + static void SetUpTestCase() { + g_events->PushBack(String("ListenerTest::SetUpTestCase")); + } + + static void TearDownTestCase() { + g_events->PushBack(String("ListenerTest::TearDownTestCase")); + } + + virtual void SetUp() { + g_events->PushBack(String("ListenerTest::SetUp")); + } + + virtual void TearDown() { + g_events->PushBack(String("ListenerTest::TearDown")); + } +}; + +TEST_F(ListenerTest, DoesFoo) { + // Test execution order within a test case is not guaranteed so we are not + // recording the test name. + g_events->PushBack(String("ListenerTest::* Test Body")); + SUCCEED(); // Triggers OnTestPartResult. +} + +TEST_F(ListenerTest, DoesBar) { + g_events->PushBack(String("ListenerTest::* Test Body")); + SUCCEED(); // Triggers OnTestPartResult. +} + +} // namespace internal + +} // namespace testing + +using ::testing::internal::EnvironmentInvocationCatcher; +using ::testing::internal::EventRecordingListener; +using ::testing::internal::UnitTestAccessor; + +int main(int argc, char **argv) { + Vector events; + g_events = &events; + InitGoogleTest(&argc, argv); + + UnitTestEventListenerInterface* listener = new EventRecordingListener; + UnitTestAccessor::GetEventListeners().Append(listener); + + AddGlobalTestEnvironment(new EnvironmentInvocationCatcher); + + GTEST_CHECK_(events.size() == 0) + << "AddGlobalTestEnvironment should not generate any events itself."; + + int ret_val = RUN_ALL_TESTS(); + + const char* const expected_events[] = { + "TestEventListener::OnUnitTestStart", + "TestEventListener::OnGlobalSetUpStart", + "Environment::SetUp", + "TestEventListener::OnGlobalSetUpEnd", + "TestEventListener::OnTestCaseStart", + "ListenerTest::SetUpTestCase", + "TestEventListener::OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "TestEventListener::OnNewTestPartResult", + "ListenerTest::TearDown", + "TestEventListener::OnTestEnd", + "TestEventListener::OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "TestEventListener::OnNewTestPartResult", + "ListenerTest::TearDown", + "TestEventListener::OnTestEnd", + "ListenerTest::TearDownTestCase", + "TestEventListener::OnTestCaseEnd", + "TestEventListener::OnGlobalTearDownStart", + "Environment::TearDown", + "TestEventListener::OnGlobalTearDownEnd", + "TestEventListener::OnUnitTestEnd" + }; + const int kExpectedEventsSize = + sizeof(expected_events)/sizeof(expected_events[0]); + + // Cannot use ASSERT_EQ() here because it requires the scoping function to + // return void. + GTEST_CHECK_(events.size() == kExpectedEventsSize); + + for (int i = 0; i < events.size(); ++i) + GTEST_CHECK_(String(events.GetElement(i)) == expected_events[i]) + << "At position " << i; + + // We need to check manually for ad hoc test failures that happen after + // RUN_ALL_TESTS finishes. + if (UnitTestAccessor::UnitTestFailed()) + ret_val = 1; + + return ret_val; +} diff --git a/test/gtest_env_var_test.py b/test/gtest_env_var_test.py index 19fd810..f8250d4 100755 --- a/test/gtest_env_var_test.py +++ b/test/gtest_env_var_test.py @@ -85,7 +85,7 @@ class GTestEnvVarTest(gtest_test_utils.TestCase): TestFlag('break_on_failure', '1', '0') TestFlag('color', 'yes', 'auto') TestFlag('filter', 'FooTest.Bar', '*') - TestFlag('output', 'tmp/foo.xml', '') + TestFlag('output', 'xml:tmp/foo.xml', '') TestFlag('print_time', '0', '1') TestFlag('repeat', '999', '1') TestFlag('throw_on_failure', '1', '0') diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 90d29e5..dcec9da 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -84,11 +84,38 @@ const char* FormatTimeInMillisAsSeconds(TimeInMillis ms); bool ParseInt32Flag(const char* str, const char* flag, Int32* value); +// Provides access to otherwise private parts of the EventListeners class +// that are needed to test it. +class EventListenersAccessor { + public: + static UnitTestEventListenerInterface* GetRepeater( + EventListeners* listeners) { return listeners->repeater(); } + + static void SetDefaultResultPrinter( + EventListeners* listeners, + UnitTestEventListenerInterface* listener) { + listeners->SetDefaultResultPrinter(listener); + } + static void SetDefaultXmlGenerator(EventListeners* listeners, + UnitTestEventListenerInterface* listener) { + listeners->SetDefaultXmlGenerator(listener); + } + + static bool EventForwardingEnabled(const EventListeners& listeners) { + return listeners.EventForwardingEnabled(); + } + + static void SuppressEventForwarding(EventListeners* listeners) { + listeners->SuppressEventForwarding(); + } +}; + } // namespace internal } // namespace testing using testing::internal::FormatTimeInMillisAsSeconds; using testing::internal::ParseInt32Flag; +using testing::internal::EventListenersAccessor; namespace testing { @@ -136,7 +163,9 @@ using testing::internal::kMaxRandomSeed; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::AppendUserMessage; using testing::internal::CodePointToUtf8; +using testing::internal::EmptyTestEventListener; using testing::internal::EqFailure; +using testing::internal::EventListeners; using testing::internal::FloatingPoint; using testing::internal::GTestFlagSaver; using testing::internal::GetCurrentOsStackTraceExceptTop; @@ -160,6 +189,7 @@ using testing::internal::ThreadLocal; using testing::internal::Vector; using testing::internal::WideStringToUtf8; using testing::internal::kTestTypeIdInGoogleTest; +using testing::internal::scoped_ptr; // This line tests that we can define tests in an unnamed namespace. namespace { @@ -695,14 +725,16 @@ TEST(ListDeathTest, GetElement) { "Invalid Vector index -1: must be in range \\[0, 2\\]\\."); } -// Tests the String class. +// Tests the size of the AssertHelper class. -TEST(StringTest, SizeIsSmall) { +TEST(AssertHelperTest, AssertHelperIsSmall) { // To avoid breaking clients that use lots of assertions in one - // function, we cannot grow the size of String. - EXPECT_LE(sizeof(String), sizeof(void*)); + // function, we cannot grow the size of AssertHelper. + EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*)); } +// Tests the String class. + // Tests String's constructors. TEST(StringTest, Constructors) { // Default ctor. @@ -1037,6 +1069,33 @@ TEST(StringTest, Streams) { EXPECT_EQ(StreamableToString(String("a\0b", 3)), "a\\0b"); } +// Tests that String::Format() works. +TEST(StringTest, FormatWorks) { + // Normal case: the format spec is valid, the arguments match the + // spec, and the result is < 4095 characters. + EXPECT_STREQ("Hello, 42", String::Format("%s, %d", "Hello", 42).c_str()); + + // Edge case: the result is 4095 characters. + char buffer[4096]; + const size_t kSize = sizeof(buffer); + memset(buffer, 'a', kSize - 1); + buffer[kSize - 1] = '\0'; + EXPECT_STREQ(buffer, String::Format("%s", buffer).c_str()); + + // The result needs to be 4096 characters, exceeding Format()'s limit. + EXPECT_STREQ("", + String::Format("x%s", buffer).c_str()); + +#if GTEST_OS_LINUX + // On Linux, invalid format spec should lead to an error message. + // In other environment (e.g. MSVC on Windows), String::Format() may + // simply ignore a bad format spec, so this assertion is run on + // Linux only. + EXPECT_STREQ("", + String::Format("%").c_str()); +#endif +} + #if GTEST_OS_WINDOWS // Tests String::ShowWideCString(). @@ -6142,3 +6201,275 @@ TEST(HasFailureTest, WorksOutsideOfTestBody2) { ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } + +class TestListener : public EmptyTestEventListener { + public: + TestListener() : on_start_counter_(NULL), is_destroyed_(NULL) {} + TestListener(int* on_start_counter, bool* is_destroyed) + : on_start_counter_(on_start_counter), + is_destroyed_(is_destroyed) {} + + virtual ~TestListener() { + if (is_destroyed_) + *is_destroyed_ = true; + } + + protected: + virtual void OnUnitTestStart(const UnitTest& /*unit_test*/) { + if (on_start_counter_ != NULL) + (*on_start_counter_)++; + } + + private: + int* on_start_counter_; + bool* is_destroyed_; +}; + +// Tests the constructor. +TEST(EventListenersTest, ConstructionWorks) { + EventListeners listeners; + + EXPECT_TRUE(EventListenersAccessor::GetRepeater(&listeners) != NULL); + EXPECT_TRUE(listeners.default_result_printer() == NULL); + EXPECT_TRUE(listeners.default_xml_generator() == NULL); +} + +// Tests that the EventListeners destructor deletes all the listeners it +// owns. +TEST(EventListenersTest, DestructionWorks) { + bool default_result_printer_is_destroyed = false; + bool default_xml_printer_is_destroyed = false; + bool extra_listener_is_destroyed = false; + TestListener* default_result_printer = new TestListener( + NULL, &default_result_printer_is_destroyed); + TestListener* default_xml_printer = new TestListener( + NULL, &default_xml_printer_is_destroyed); + TestListener* extra_listener = new TestListener( + NULL, &extra_listener_is_destroyed); + + { + EventListeners listeners; + EventListenersAccessor::SetDefaultResultPrinter(&listeners, + default_result_printer); + EventListenersAccessor::SetDefaultXmlGenerator(&listeners, + default_xml_printer); + listeners.Append(extra_listener); + } + EXPECT_TRUE(default_result_printer_is_destroyed); + EXPECT_TRUE(default_xml_printer_is_destroyed); + EXPECT_TRUE(extra_listener_is_destroyed); +} + +// Tests that a listener Append'ed to an EventListeners list starts +// receiving events. +TEST(EventListenersTest, Append) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + EventListeners listeners; + listeners.Append(listener); + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); + } + EXPECT_TRUE(is_destroyed); +} + +// Tests that listeners receive requests in the order they were appended to +// the list. +class SequenceTestingListener : public EmptyTestEventListener { + public: + SequenceTestingListener(Vector* vector, const char* signature) + : vector_(vector), signature_(signature) {} + + protected: + virtual void OnUnitTestStart(const UnitTest& /*unit_test*/) { + if (vector_ != NULL) + vector_->PushBack(signature_); + } + + private: + Vector* vector_; + const char* const signature_; +}; + +TEST(EventListenerTest, AppendKeepsOrder) { + Vector vec; + EventListeners listeners; + listeners.Append(new SequenceTestingListener(&vec, "0")); + listeners.Append(new SequenceTestingListener(&vec, "1")); + listeners.Append(new SequenceTestingListener(&vec, "2")); + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + ASSERT_EQ(3, vec.size()); + ASSERT_STREQ("0", vec.GetElement(0)); + ASSERT_STREQ("1", vec.GetElement(1)); + ASSERT_STREQ("2", vec.GetElement(2)); +} + +// Tests that a listener removed from an EventListeners list stops receiving +// events and is not deleted when the list is destroyed. +TEST(EventListenersTest, Release) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + EventListeners listeners; + listeners.Append(listener); + EXPECT_EQ(listener, listeners.Release(listener)); + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + EXPECT_TRUE(listeners.Release(listener) == NULL); + } + EXPECT_EQ(0, on_start_counter); + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Tests that no events are forwarded when event forwarding is disabled. +TEST(EventListenerTest, SuppressEventForwarding) { + int on_start_counter = 0; + TestListener* listener = new TestListener(&on_start_counter, NULL); + + EventListeners listeners; + listeners.Append(listener); + ASSERT_TRUE(EventListenersAccessor::EventForwardingEnabled(listeners)); + EventListenersAccessor::SuppressEventForwarding(&listeners); + ASSERT_FALSE(EventListenersAccessor::EventForwardingEnabled(listeners)); + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); +} + +#if GTEST_HAS_DEATH_TEST +// Tests that events generated by Google Test are not forwarded in +// death test subprocesses. +TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses) { + EXPECT_DEATH({ // NOLINT + GTEST_CHECK_(EventListenersAccessor::EventForwardingEnabled( + *GetUnitTestImpl()->listeners())) << "expected failure";}, + "expected failure"); +} +#endif // GTEST_HAS_DEATH_TEST + +// Tests that a listener installed via SetDefaultResultPrinter() starts +// receiving events and is returned via default_result_printer() and that +// the previous default_result_printer is removed from the list and deleted. +TEST(EventListenerTest, default_result_printer) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + + EventListeners listeners; + EventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_result_printer()); + + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_result_printer with something else should remove it + // from the list and destroy it. + EventListenersAccessor::SetDefaultResultPrinter(&listeners, NULL); + + EXPECT_TRUE(listeners.default_result_printer() == NULL); + EXPECT_TRUE(is_destroyed); + + // After broadcasting an event the counter is still the same, indicating + // the listener is not in the list anymore. + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); +} + +// Tests that the default_result_printer listener stops receiving events +// when removed via Release and that is not owned by the list anymore. +TEST(EventListenerTest, RemovingDefaultResultPrinterWorks) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + EventListeners listeners; + EventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); + + EXPECT_EQ(listener, listeners.Release(listener)); + EXPECT_TRUE(listeners.default_result_printer() == NULL); + EXPECT_FALSE(is_destroyed); + + // Broadcasting events now should not affect default_result_printer. + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); + } + // Destroying the list should not affect the listener now, too. + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Tests that a listener installed via SetDefaultXmlGenerator() starts +// receiving events and is returned via default_xml_generator() and that +// the previous default_xml_generator is removed from the list and deleted. +TEST(EventListenerTest, default_xml_generator) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + + EventListeners listeners; + EventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_xml_generator()); + + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_xml_generator with something else should remove it + // from the list and destroy it. + EventListenersAccessor::SetDefaultXmlGenerator(&listeners, NULL); + + EXPECT_TRUE(listeners.default_xml_generator() == NULL); + EXPECT_TRUE(is_destroyed); + + // After broadcasting an event the counter is still the same, indicating + // the listener is not in the list anymore. + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); +} + +// Tests that the default_xml_generator listener stops receiving events +// when removed via Release and that is not owned by the list anymore. +TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + EventListeners listeners; + EventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); + + EXPECT_EQ(listener, listeners.Release(listener)); + EXPECT_TRUE(listeners.default_xml_generator() == NULL); + EXPECT_FALSE(is_destroyed); + + // Broadcasting events now should not affect default_xml_generator. + EventListenersAccessor::GetRepeater(&listeners)->OnUnitTestStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); + } + // Destroying the list should not affect the listener now, too. + EXPECT_FALSE(is_destroyed); + delete listener; +} diff --git a/test/gtest_xml_output_unittest.py b/test/gtest_xml_output_unittest.py index a0cd4d0..3ee6846 100755 --- a/test/gtest_xml_output_unittest.py +++ b/test/gtest_xml_output_unittest.py @@ -44,6 +44,7 @@ import gtest_xml_test_utils GTEST_OUTPUT_FLAG = "--gtest_output" GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" +GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_" SUPPORTS_STACK_TRACES = False @@ -108,8 +109,7 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): Runs a test program that generates a non-empty XML output, and tests that the XML output is expected. """ - self._TestXmlOutput("gtest_xml_output_unittest_", - EXPECTED_NON_EMPTY_XML, 1) + self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1) def testEmptyXmlOutput(self): """ @@ -142,6 +142,35 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): self.assertEquals(0, p.exit_code) self.assert_(os.path.isfile(output_file)) + def testSuppressedXmlOutput(self): + """ + Tests that no XML file is generated if the default XML listener is + shut down before RUN_ALL_TESTS is invoked. + """ + + xml_path = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_PROGRAM_NAME + "out.xml") + if os.path.isfile(xml_path): + os.remove(xml_path) + + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) + + command = [gtest_prog_path, + "%s=xml:%s" % (GTEST_OUTPUT_FLAG, xml_path), + "--shut_down_xml"] + p = gtest_test_utils.Subprocess(command) + if p.terminated_by_signal: + self.assert_(False, + "%s was killed by signal %d" % (gtest_prog_name, p.signal)) + else: + self.assert_(p.exited) + self.assertEquals(1, p.exit_code, + "'%s' exited with code %s, which doesn't match " + "the expected exit code %s." + % (command, p.exit_code, 1)) + + self.assert_(not os.path.isfile(xml_path)) + def _TestXmlOutput(self, gtest_prog_name, expected_xml, expected_exit_code): """ diff --git a/test/gtest_xml_output_unittest_.cc b/test/gtest_xml_output_unittest_.cc index d7ce2c6..bfeda3d 100644 --- a/test/gtest_xml_output_unittest_.cc +++ b/test/gtest_xml_output_unittest_.cc @@ -40,6 +40,20 @@ #include +// TODO(vladl@google.com): Remove this include when the event listener API is +// published and GetUnitTestImpl is no longer needed. +// +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +using ::testing::InitGoogleTest; + class SuccessfulTest : public testing::Test { }; @@ -118,3 +132,17 @@ TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) { TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); } + +int main(int argc, char** argv) { + InitGoogleTest(&argc, argv); + + if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) { + // TODO(vladl@google.com): Replace GetUnitTestImpl()->listeners() with + // UnitTest::GetInstance()->listeners() when the event listener API is + // published. + ::testing::internal::EventListeners& listeners = + *::testing::internal::GetUnitTestImpl()->listeners(); + delete listeners.Release(listeners.default_xml_generator()); + } + return RUN_ALL_TESTS(); +} -- cgit v1.2.1