Commit 16e9dd6e by zhanyong.wan

More implementation of the event listener interface (by Vlad Losev); Reduces the…

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).
parent 56a2e686
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: Changes for 1.3.0:
* New feature: death tests on Windows, Cygwin, and Mac. * New feature: death tests on Windows, Cygwin, and Mac.
...@@ -11,7 +28,7 @@ Changes for 1.3.0: ...@@ -11,7 +28,7 @@ Changes for 1.3.0:
.cc file for easy deployment. .cc file for easy deployment.
* New feature: support for distributing test functions to multiple * New feature: support for distributing test functions to multiple
machines (requires support from the test runner). machines (requires support from the test runner).
* Bug fixes and implementation clean-up. * Bug fixes and implementation clean-ups.
Changes for 1.2.1: Changes for 1.2.1:
......
...@@ -12,6 +12,8 @@ EXTRA_DIST = \ ...@@ -12,6 +12,8 @@ EXTRA_DIST = \
include/gtest/internal/gtest-param-util-generated.h.pump \ include/gtest/internal/gtest-param-util-generated.h.pump \
make/Makefile \ make/Makefile \
scons/SConscript \ scons/SConscript \
scons/SConstruct \
scons/SConstruct.common \
scripts/fuse_gtest_files.py \ scripts/fuse_gtest_files.py \
scripts/gen_gtest_pred_impl.py \ scripts/gen_gtest_pred_impl.py \
scripts/test/Makefile \ scripts/test/Makefile \
...@@ -24,10 +26,15 @@ EXTRA_DIST += \ ...@@ -24,10 +26,15 @@ EXTRA_DIST += \
msvc/gtest_color_test_.vcproj \ msvc/gtest_color_test_.vcproj \
msvc/gtest_env_var_test_.vcproj \ msvc/gtest_env_var_test_.vcproj \
msvc/gtest_environment_test.vcproj \ msvc/gtest_environment_test.vcproj \
msvc/gtest_main-md.vcproj \
msvc/gtest_main.vcproj \ msvc/gtest_main.vcproj \
msvc/gtest-md.sln \
msvc/gtest-md.vcproj \
msvc/gtest_output_test_.vcproj \ msvc/gtest_output_test_.vcproj \
msvc/gtest_prod_test-md.vcproj \
msvc/gtest_prod_test.vcproj \ msvc/gtest_prod_test.vcproj \
msvc/gtest_uninitialized_test_.vcproj \ msvc/gtest_uninitialized_test_.vcproj \
msvc/gtest_unittest-md.vcproj \
msvc/gtest_unittest.vcproj msvc/gtest_unittest.vcproj
# xcode project files # xcode project files
...@@ -36,9 +43,8 @@ EXTRA_DIST += \ ...@@ -36,9 +43,8 @@ EXTRA_DIST += \
xcode/Config/FrameworkTarget.xcconfig \ xcode/Config/FrameworkTarget.xcconfig \
xcode/Config/General.xcconfig \ xcode/Config/General.xcconfig \
xcode/Config/ReleaseProject.xcconfig \ xcode/Config/ReleaseProject.xcconfig \
xcode/Config/StaticLibraryTarget.xcconfig \
xcode/Config/TestTarget.xcconfig \ xcode/Config/TestTarget.xcconfig \
xcode/Config/InternalTestTarget.xcconfig \
xcode/Config/InternalPythonTestTarget.xcconfig \
xcode/Resources/Info.plist \ xcode/Resources/Info.plist \
xcode/Scripts/versiongenerate.py \ xcode/Scripts/versiongenerate.py \
xcode/Scripts/runtests.sh \ xcode/Scripts/runtests.sh \
...@@ -299,6 +305,11 @@ check_PROGRAMS += test/gtest-unittest-api_test ...@@ -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_SOURCES = test/gtest-unittest-api_test.cc
test_gtest_unittest_api_test_LDADD = lib/libgtest_main.la 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. # Verifies that Google Test works when RTTI is disabled.
TESTS += test/gtest_no_rtti_test TESTS += test/gtest_no_rtti_test
check_PROGRAMS += test/gtest_no_rtti_test check_PROGRAMS += test/gtest_no_rtti_test
...@@ -407,7 +418,7 @@ TESTS += test/gtest_xml_outfiles_test.py ...@@ -407,7 +418,7 @@ TESTS += test/gtest_xml_outfiles_test.py
check_PROGRAMS += test/gtest_xml_output_unittest_ check_PROGRAMS += test/gtest_xml_output_unittest_
test_gtest_xml_output_unittest__SOURCES = test/gtest_xml_output_unittest_.cc 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 check_SCRIPTS += test/gtest_xml_output_unittest.py
TESTS += test/gtest_xml_output_unittest.py TESTS += test/gtest_xml_output_unittest.py
......
...@@ -190,9 +190,16 @@ see 'gtest-config --help' for more detailed information. ...@@ -190,9 +190,16 @@ see 'gtest-config --help' for more detailed information.
g++ $(../../my_gtest_build/scripts/gtest-config ...) ... g++ $(../../my_gtest_build/scripts/gtest-config ...) ...
### Windows ### ### Windows ###
Open the gtest.sln file in the msvc/ folder using Visual Studio, and The msvc\ folder contains two solutions with Visual C++ projects. Open the
you are ready to build Google Test the same way you build any Visual gtest.sln or gtest-md.sln file using Visual Studio, and you are ready to
Studio project. 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) ### ### Mac OS X (universal-binary framework) ###
Open the gtest.xcodeproj in the xcode/ folder using Xcode. Build the "gtest" 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 ...@@ -201,7 +208,7 @@ directory (selected in the Xcode "Preferences..." -> "Building" pane and
defaults to xcode/build). Alternatively, at the command line, enter: defaults to xcode/build). Alternatively, at the command line, enter:
xcodebuild xcodebuild
This will build the "Release" configuration of gtest.framework in your This will build the "Release" configuration of gtest.framework in your
default build location. See the "xcodebuild" man page for more information about default build location. See the "xcodebuild" man page for more information about
building different configurations and building in different locations. 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 ...@@ -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: of the build log. To run all of the tests from the command line, enter:
xcodebuild -target Check xcodebuild -target Check
Installation with xcodebuild requires specifying an installation desitination Installation with xcodebuild requires specifying an installation desitination
directory, known as the DSTROOT. Three items will be installed when using directory, known as the DSTROOT. Three items will be installed when using
xcodebuild: xcodebuild:
...@@ -221,12 +228,12 @@ xcodebuild: ...@@ -221,12 +228,12 @@ xcodebuild:
$DSTROOT/Library/Frameworks/gtest.framework $DSTROOT/Library/Frameworks/gtest.framework
$DSTROOT/usr/local/lib/libgtest.a $DSTROOT/usr/local/lib/libgtest.a
$DSTROOT/usr/local/lib/libgtest_main.a $DSTROOT/usr/local/lib/libgtest_main.a
You specify the installation directory on the command line with the other 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 options. Here's how you would install in a user-visible location:
xcodebuild install DSTROOT=~ xcodebuild install DSTROOT=~
To perform a system-wide inistall, escalate to an administrator and specify To perform a system-wide inistall, escalate to an administrator and specify
the file system root as the DSTROOT: the file system root as the DSTROOT:
......
...@@ -41,6 +41,9 @@ namespace testing { ...@@ -41,6 +41,9 @@ namespace testing {
// The possible outcomes of a test part (i.e. an assertion or an // The possible outcomes of a test part (i.e. an assertion or an
// explicit SUCCEED(), FAIL(), or ADD_FAILURE()). // 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 { enum TestPartResultType {
TPRT_SUCCESS, // Succeeded. TPRT_SUCCESS, // Succeeded.
TPRT_NONFATAL_FAILURE, // Failed but the test can continue. TPRT_NONFATAL_FAILURE, // Failed but the test can continue.
......
...@@ -107,7 +107,6 @@ class Test; // Represents a test. ...@@ -107,7 +107,6 @@ class Test; // Represents a test.
class TestInfo; // Information about a test. class TestInfo; // Information about a test.
class TestPartResult; // Result of a test part. class TestPartResult; // Result of a test part.
class UnitTest; // A collection of test cases. class UnitTest; // A collection of test cases.
class UnitTestEventListenerInterface; // Listens to Google Test events.
namespace internal { namespace internal {
......
...@@ -51,22 +51,6 @@ ...@@ -51,22 +51,6 @@
namespace testing { namespace testing {
namespace internal { 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. // String - a UTF-8 string class.
// //
// We cannot use std::string as Microsoft's STL implementation in // We cannot use std::string as Microsoft's STL implementation in
...@@ -202,14 +186,14 @@ class String { ...@@ -202,14 +186,14 @@ class String {
// C'tors // C'tors
// The default c'tor constructs a NULL string, which is represented // The default c'tor constructs a NULL string.
// by data_ being NULL. String() : c_str_(NULL), length_(0) {}
String() : data_(NULL) {}
// Constructs a String by cloning a 0-terminated C string. // Constructs a String by cloning a 0-terminated C string.
String(const char* c_str) { // NOLINT String(const char* c_str) { // NOLINT
if (c_str == NULL) { if (c_str == NULL) {
data_ = NULL; c_str_ = NULL;
length_ = 0;
} else { } else {
ConstructNonNull(c_str, strlen(c_str)); ConstructNonNull(c_str, strlen(c_str));
} }
...@@ -225,13 +209,11 @@ class String { ...@@ -225,13 +209,11 @@ class String {
// The copy c'tor creates a new copy of the string. The two // The copy c'tor creates a new copy of the string. The two
// String objects do not share content. // 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 // D'tor. String is intended to be a final class, so the d'tor
// doesn't need to be virtual. // doesn't need to be virtual.
~String() { ~String() { delete[] c_str_; }
delete data_;
}
// Allows a String to be implicitly converted to an ::std::string or // Allows a String to be implicitly converted to an ::std::string or
// ::string, and vice versa. Converting a String containing a NULL // ::string, and vice versa. Converting a String containing a NULL
...@@ -285,12 +267,12 @@ class String { ...@@ -285,12 +267,12 @@ class String {
// Returns the length of the encapsulated string, or 0 if the // Returns the length of the encapsulated string, or 0 if the
// string is NULL. // 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. // Gets the 0-terminated C string this String object represents.
// The String object still owns the string. Therefore the caller // The String object still owns the string. Therefore the caller
// should NOT delete the return value. // 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. // Assigns a C string to this object. Self-assignment works.
const String& operator=(const char* c_str) { return *this = String(c_str); } const String& operator=(const char* c_str) { return *this = String(c_str); }
...@@ -298,10 +280,12 @@ class String { ...@@ -298,10 +280,12 @@ class String {
// Assigns a String object to this object. Self-assignment works. // Assigns a String object to this object. Self-assignment works.
const String& operator=(const String& rhs) { const String& operator=(const String& rhs) {
if (this != &rhs) { if (this != &rhs) {
delete data_; delete[] c_str_;
data_ = NULL; if (rhs.c_str() == NULL) {
if (rhs.data_ != NULL) { c_str_ = NULL;
ConstructNonNull(rhs.data_->c_str_, rhs.data_->length_); length_ = 0;
} else {
ConstructNonNull(rhs.c_str(), rhs.length());
} }
} }
...@@ -314,17 +298,15 @@ class String { ...@@ -314,17 +298,15 @@ class String {
// ConstructNonNull(NULL, 0) results in an empty string (""). // ConstructNonNull(NULL, 0) results in an empty string ("").
// ConstructNonNull(NULL, non_zero) is undefined behavior. // ConstructNonNull(NULL, non_zero) is undefined behavior.
void ConstructNonNull(const char* buffer, size_t length) { void ConstructNonNull(const char* buffer, size_t length) {
data_ = new StringData;
char* const str = new char[length + 1]; char* const str = new char[length + 1];
memcpy(str, buffer, length); memcpy(str, buffer, length);
str[length] = '\0'; str[length] = '\0';
data_->c_str_ = str; c_str_ = str;
data_->length_ = length; length_ = length;
} }
// Points to the representation of the String. A NULL String is const char* c_str_;
// represented by data_ == NULL. size_t length_;
StringData* data_;
}; // class String }; // class String
// Streams a String to an ostream. Each '\0' character in the String // Streams a String to an ostream. Each '\0' character in the String
......
...@@ -318,8 +318,9 @@ GtestTest(env, 'gtest_list_tests_unittest_', gtest) ...@@ -318,8 +318,9 @@ GtestTest(env, 'gtest_list_tests_unittest_', gtest)
GtestTest(env, 'gtest_throw_on_failure_test_', gtest) GtestTest(env, 'gtest_throw_on_failure_test_', gtest)
GtestTest(env, 'gtest_xml_outfile1_test_', gtest_main) GtestTest(env, 'gtest_xml_outfile1_test_', gtest_main)
GtestTest(env, 'gtest_xml_outfile2_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-unittest-api_test', gtest)
GtestTest(env, 'gtest-listener_test', gtest)
############################################################ ############################################################
# Tests targets using custom environments. # Tests targets using custom environments.
......
...@@ -469,7 +469,8 @@ bool DeathTestImpl::Passed(bool status_ok) { ...@@ -469,7 +469,8 @@ bool DeathTestImpl::Passed(bool status_ok) {
break; break;
case DIED: case DIED:
if (status_ok) { 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; success = true;
} else { } else {
buffer << " Result: died but not with expected error.\n" buffer << " Result: died but not with expected error.\n"
...@@ -767,6 +768,9 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { ...@@ -767,6 +768,9 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
// concurrent writes to the log files. We capture stderr in the parent // concurrent writes to the log files. We capture stderr in the parent
// process and append the child process' output to a log. // process and append the child process' output to a log.
LogToStderr(); LogToStderr();
// Event forwarding to the listeners of event listener API mush be shut
// down in death test subprocesses.
GetUnitTestImpl()->listeners()->SuppressEventForwarding();
return EXECUTE_TEST; return EXECUTE_TEST;
} else { } else {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
......
...@@ -741,6 +741,9 @@ class UnitTestImpl { ...@@ -741,6 +741,9 @@ class UnitTestImpl {
return test_cases_.GetElementOr(i, NULL); 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 // Returns the TestResult for the test that's currently running, or
// the TestResult for the ad hoc test if no test is running. // the TestResult for the ad hoc test if no test is running.
TestResult* current_test_result(); TestResult* current_test_result();
...@@ -748,18 +751,6 @@ class UnitTestImpl { ...@@ -748,18 +751,6 @@ class UnitTestImpl {
// Returns the TestResult for the ad hoc test. // Returns the TestResult for the ad hoc test.
const 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);
// 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. // Sets the OS stack trace getter.
// //
// Does nothing if the input and the current OS stack trace getter // Does nothing if the input and the current OS stack trace getter
...@@ -907,9 +898,13 @@ class UnitTestImpl { ...@@ -907,9 +898,13 @@ class UnitTestImpl {
} }
#if GTEST_HAS_DEATH_TEST #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 // Returns a pointer to the parsed --gtest_internal_run_death_test
// flag, or NULL if that flag was not specified. // flag, or NULL if that flag was not specified.
// This information is useful only in a death test child process. // 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 { const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
return internal_run_death_test_flag_.get(); return internal_run_death_test_flag_.get();
} }
...@@ -919,9 +914,22 @@ class UnitTestImpl { ...@@ -919,9 +914,22 @@ class UnitTestImpl {
return death_test_factory_.get(); return death_test_factory_.get();
} }
void SuppressTestEventsIfInSubprocess();
friend class ReplaceDeathTestFactory; friend class ReplaceDeathTestFactory;
#endif // GTEST_HAS_DEATH_TEST #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. // Gets the random seed used at the start of the current test run.
int random_seed() const { return random_seed_; } int random_seed() const { return random_seed_; }
...@@ -992,11 +1000,9 @@ class UnitTestImpl { ...@@ -992,11 +1000,9 @@ class UnitTestImpl {
// test, and records the result in ad_hoc_test_result_. // test, and records the result in ad_hoc_test_result_.
TestResult ad_hoc_test_result_; TestResult ad_hoc_test_result_;
// The unit test result printer. Will be deleted when the UnitTest // The list of event listeners that can be used to track events inside
// object is destructed. By default, a plain text printer is used, // Google Test.
// but the user can set this field to use a custom printer if that EventListeners listeners_;
// is desired.
UnitTestEventListenerInterface* result_printer_;
// The OS stack trace getter. Will be deleted when the UnitTest // The OS stack trace getter. Will be deleted when the UnitTest
// object is destructed. By default, an OsStackTraceGetter is used, // object is destructed. By default, an OsStackTraceGetter is used,
...@@ -1004,6 +1010,9 @@ class UnitTestImpl { ...@@ -1004,6 +1010,9 @@ class UnitTestImpl {
// desired. // desired.
OsStackTraceGetterInterface* os_stack_trace_getter_; 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. // The random number seed used at the beginning of the test run.
int random_seed_; int random_seed_;
......
// 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 <gtest/gtest.h>
// 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<String>* 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<String> 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;
}
...@@ -85,7 +85,7 @@ class GTestEnvVarTest(gtest_test_utils.TestCase): ...@@ -85,7 +85,7 @@ class GTestEnvVarTest(gtest_test_utils.TestCase):
TestFlag('break_on_failure', '1', '0') TestFlag('break_on_failure', '1', '0')
TestFlag('color', 'yes', 'auto') TestFlag('color', 'yes', 'auto')
TestFlag('filter', 'FooTest.Bar', '*') TestFlag('filter', 'FooTest.Bar', '*')
TestFlag('output', 'tmp/foo.xml', '') TestFlag('output', 'xml:tmp/foo.xml', '')
TestFlag('print_time', '0', '1') TestFlag('print_time', '0', '1')
TestFlag('repeat', '999', '1') TestFlag('repeat', '999', '1')
TestFlag('throw_on_failure', '1', '0') TestFlag('throw_on_failure', '1', '0')
......
...@@ -44,6 +44,7 @@ import gtest_xml_test_utils ...@@ -44,6 +44,7 @@ import gtest_xml_test_utils
GTEST_OUTPUT_FLAG = "--gtest_output" GTEST_OUTPUT_FLAG = "--gtest_output"
GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml"
GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_"
SUPPORTS_STACK_TRACES = False SUPPORTS_STACK_TRACES = False
...@@ -108,8 +109,7 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): ...@@ -108,8 +109,7 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
Runs a test program that generates a non-empty XML output, and Runs a test program that generates a non-empty XML output, and
tests that the XML output is expected. tests that the XML output is expected.
""" """
self._TestXmlOutput("gtest_xml_output_unittest_", self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1)
EXPECTED_NON_EMPTY_XML, 1)
def testEmptyXmlOutput(self): def testEmptyXmlOutput(self):
""" """
...@@ -142,6 +142,35 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): ...@@ -142,6 +142,35 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
self.assertEquals(0, p.exit_code) self.assertEquals(0, p.exit_code)
self.assert_(os.path.isfile(output_file)) 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): def _TestXmlOutput(self, gtest_prog_name, expected_xml, expected_exit_code):
""" """
......
...@@ -40,6 +40,20 @@ ...@@ -40,6 +40,20 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
// 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 { class SuccessfulTest : public testing::Test {
}; };
...@@ -118,3 +132,17 @@ TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) { ...@@ -118,3 +132,17 @@ TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) {
TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) {
ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); 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();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment