summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2009-09-04 18:30:25 (GMT)
committerzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2009-09-04 18:30:25 (GMT)
commit16e9dd6e28a8a7fb2d611011e7353e042fcb282f (patch)
treef990763455e874fb887364bbd9c712386824d20d /test
parent56a2e686e915d483cb22db091140130b23814127 (diff)
downloadgoogletest-16e9dd6e28a8a7fb2d611011e7353e042fcb282f.zip
googletest-16e9dd6e28a8a7fb2d611011e7353e042fcb282f.tar.gz
googletest-16e9dd6e28a8a7fb2d611011e7353e042fcb282f.tar.bz2
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).
Diffstat (limited to 'test')
-rw-r--r--test/gtest-listener_test.cc230
-rwxr-xr-xtest/gtest_env_var_test.py2
-rw-r--r--test/gtest_unittest.cc339
-rwxr-xr-xtest/gtest_xml_output_unittest.py33
-rw-r--r--test/gtest_xml_output_unittest_.cc28
5 files changed, 625 insertions, 7 deletions
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 <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;
+}
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("<formatting error or buffer exceeded>",
+ 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("<formatting error or buffer exceeded>",
+ 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<const char*>* vector, const char* signature)
+ : vector_(vector), signature_(signature) {}
+
+ protected:
+ virtual void OnUnitTestStart(const UnitTest& /*unit_test*/) {
+ if (vector_ != NULL)
+ vector_->PushBack(signature_);
+ }
+
+ private:
+ Vector<const char*>* vector_;
+ const char* const signature_;
+};
+
+TEST(EventListenerTest, AppendKeepsOrder) {
+ Vector<const char*> 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 <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 {
};
@@ -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();
+}