diff options
author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-04 18:30:25 (GMT) |
---|---|---|
committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-04 18:30:25 (GMT) |
commit | 16e9dd6e28a8a7fb2d611011e7353e042fcb282f (patch) | |
tree | f990763455e874fb887364bbd9c712386824d20d /test | |
parent | 56a2e686e915d483cb22db091140130b23814127 (diff) | |
download | googletest-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.cc | 230 | ||||
-rwxr-xr-x | test/gtest_env_var_test.py | 2 | ||||
-rw-r--r-- | test/gtest_unittest.cc | 339 | ||||
-rwxr-xr-x | test/gtest_xml_output_unittest.py | 33 | ||||
-rw-r--r-- | test/gtest_xml_output_unittest_.cc | 28 |
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(); +} |