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"
......
...@@ -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