diff options
| author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-04 18:30:25 +0000 | 
|---|---|---|
| committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-04 18:30:25 +0000 | 
| commit | 16e9dd6e28a8a7fb2d611011e7353e042fcb282f (patch) | |
| tree | f990763455e874fb887364bbd9c712386824d20d /test | |
| parent | 56a2e686e915d483cb22db091140130b23814127 (diff) | |
| download | googletest-16e9dd6e28a8a7fb2d611011e7353e042fcb282f.tar.gz googletest-16e9dd6e28a8a7fb2d611011e7353e042fcb282f.tar.bz2 googletest-16e9dd6e28a8a7fb2d611011e7353e042fcb282f.zip  | |
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 00000000..fb6fcf48 --- /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 19fd8103..f8250d4c 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 90d29e56..dcec9dad 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 a0cd4d09..3ee6846e 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 d7ce2c6f..bfeda3d8 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(); +}  | 
