diff options
Diffstat (limited to 'gtest/test')
-rw-r--r-- | gtest/test/gtest-death-test_test.cc | 121 | ||||
-rw-r--r-- | gtest/test/gtest-filepath_test.cc | 23 | ||||
-rw-r--r-- | gtest/test/gtest-listener_test.cc | 322 | ||||
-rw-r--r-- | gtest/test/gtest-options_test.cc | 8 | ||||
-rw-r--r-- | gtest/test/gtest-port_test.cc | 13 | ||||
-rw-r--r-- | gtest/test/gtest-test-part_test.cc | 28 | ||||
-rw-r--r-- | gtest/test/gtest-typed-test_test.cc | 22 | ||||
-rw-r--r-- | gtest/test/gtest-unittest-api_test.cc | 66 | ||||
-rwxr-xr-x | gtest/test/gtest_env_var_test.py | 2 | ||||
-rw-r--r-- | gtest/test/gtest_filter_unittest_.cc | 10 | ||||
-rw-r--r-- | gtest/test/gtest_repeat_test.cc | 10 | ||||
-rwxr-xr-x | gtest/test/gtest_shuffle_test.py | 331 | ||||
-rw-r--r-- | gtest/test/gtest_shuffle_test_.cc | 104 | ||||
-rw-r--r-- | gtest/test/gtest_stress_test.cc | 1 | ||||
-rw-r--r-- | gtest/test/gtest_unittest.cc | 983 | ||||
-rwxr-xr-x | gtest/test/gtest_xml_output_unittest.py | 49 | ||||
-rw-r--r-- | gtest/test/gtest_xml_output_unittest_.cc | 25 | ||||
-rwxr-xr-x | gtest/test/gtest_xml_test_utils.py | 48 |
18 files changed, 1936 insertions, 230 deletions
diff --git a/gtest/test/gtest-death-test_test.cc b/gtest/test/gtest-death-test_test.cc index 1881139..288c70a 100644 --- a/gtest/test/gtest-death-test_test.cc +++ b/gtest/test/gtest-death-test_test.cc @@ -35,6 +35,9 @@ #include <gtest/gtest.h> #include <gtest/internal/gtest-filepath.h> +using testing::internal::AlwaysFalse; +using testing::internal::AlwaysTrue; + #if GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS @@ -143,7 +146,7 @@ class MayDie { // A member function that may die. void MemberFunction() const { if (should_die_) { - GTEST_LOG_(FATAL, "death inside MayDie::MemberFunction()."); + GTEST_LOG_(FATAL) << "death inside MayDie::MemberFunction()."; } } @@ -154,26 +157,26 @@ class MayDie { // A global function that's expected to die. void GlobalFunction() { - GTEST_LOG_(FATAL, "death inside GlobalFunction()."); + GTEST_LOG_(FATAL) << "death inside GlobalFunction()."; } // A non-void function that's expected to die. int NonVoidFunction() { - GTEST_LOG_(FATAL, "death inside NonVoidFunction()."); + GTEST_LOG_(FATAL) << "death inside NonVoidFunction()."; return 1; } // A unary function that may die. void DieIf(bool should_die) { if (should_die) { - GTEST_LOG_(FATAL, "death inside DieIf()."); + GTEST_LOG_(FATAL) << "death inside DieIf()."; } } // A binary function that may die. bool DieIfLessThan(int x, int y) { if (x < y) { - GTEST_LOG_(FATAL, "death inside DieIfLessThan()."); + GTEST_LOG_(FATAL) << "death inside DieIfLessThan()."; } return true; } @@ -188,7 +191,7 @@ void DeathTestSubroutine() { int DieInDebugElse12(int* sideeffect) { if (sideeffect) *sideeffect = 12; #ifndef NDEBUG - GTEST_LOG_(FATAL, "debug death inside DieInDebugElse12()"); + GTEST_LOG_(FATAL) << "debug death inside DieInDebugElse12()"; #endif // NDEBUG return 12; } @@ -271,28 +274,28 @@ TEST(ExitStatusPredicateTest, KilledBySignal) { // be followed by operator<<, and that in either case the complete text // comprises only a single C++ statement. TEST_F(TestForDeathTest, SingleStatement) { - if (false) + if (AlwaysFalse()) // This would fail if executed; this is a compilation test only ASSERT_DEATH(return, ""); - if (true) + if (AlwaysTrue()) EXPECT_DEATH(_exit(1), ""); else // This empty "else" branch is meant to ensure that EXPECT_DEATH // doesn't expand into an "if" statement without an "else" ; - if (false) + if (AlwaysFalse()) ASSERT_DEATH(return, "") << "did not die"; - if (false) + if (AlwaysFalse()) ; else EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3; } void DieWithEmbeddedNul() { - fprintf(stderr, "Hello%cworld.\n", '\0'); + fprintf(stderr, "Hello%cmy null world.\n", '\0'); fflush(stderr); _exit(1); } @@ -303,8 +306,8 @@ void DieWithEmbeddedNul() { TEST_F(TestForDeathTest, EmbeddedNulInMessage) { // TODO(wan@google.com): <regex.h> doesn't support matching strings // with embedded NUL characters - find a way to workaround it. - EXPECT_DEATH(DieWithEmbeddedNul(), "w.*ld"); - ASSERT_DEATH(DieWithEmbeddedNul(), "w.*ld"); + EXPECT_DEATH(DieWithEmbeddedNul(), "my null world"); + ASSERT_DEATH(DieWithEmbeddedNul(), "my null world"); } #endif // GTEST_USES_PCRE @@ -656,7 +659,11 @@ static void TestExitMacros() { EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), ""); -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW + // MinGW (as of MinGW 5.1.6 and MSYS 1.0.11) does not tag crashed + // processes with non-zero exit code and does not honor calls to + // SetErrorMode(SEM_NOGPFAULTERRORBOX) that are supposed to suppress + // error pop-ups. EXPECT_EXIT({ testing::GTEST_FLAG(catch_exceptions) = false; *static_cast<int*>(NULL) = 1; @@ -668,7 +675,9 @@ static void TestExitMacros() { *static_cast<int*>(NULL) = 1; }, testing::ExitedWithCode(0), "") << "This failure is expected."; }, "This failure is expected."); +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW +#if GTEST_OS_WINDOWS // Of all signals effects on the process exit code, only those of SIGABRT // are documented on Windows. // See http://msdn.microsoft.com/en-us/library/dwwzkt4c(VS.71).aspx. @@ -824,9 +833,10 @@ void MockDeathTestFactory::SetParameters(bool create, // Sets test to NULL (if create_ is false) or to the address of a new // MockDeathTest object with parameters taken from the last call // to SetParameters (if create_ is true). Always returns true. -bool MockDeathTestFactory::Create(const char* statement, - const ::testing::internal::RE* regex, - const char* file, int line, +bool MockDeathTestFactory::Create(const char* /*statement*/, + const ::testing::internal::RE* /*regex*/, + const char* /*file*/, + int /*line*/, DeathTest** test) { test_deleted_ = false; if (create_) { @@ -1136,7 +1146,7 @@ using testing::internal::GetCapturedStderr; using testing::internal::String; // Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED are still -// defined but do not rigger failures when death tests are not available on +// defined but do not trigger failures when death tests are not available on // the system. TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable) { // Empty statement will not crash, but that should not trigger a failure @@ -1148,16 +1158,89 @@ TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable) { "Death tests are not supported on this platform")); ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); + // The streamed message should not be printed as there is no test failure. + CaptureStderr(); + EXPECT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; + output = GetCapturedStderr(); + ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); + CaptureStderr(); - ASSERT_DEATH_IF_SUPPORTED(;, ""); + ASSERT_DEATH_IF_SUPPORTED(;, ""); // NOLINT output = GetCapturedStderr(); ASSERT_TRUE(NULL != strstr(output.c_str(), "Death tests are not supported on this platform")); ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); + + CaptureStderr(); + ASSERT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; // NOLINT + output = GetCapturedStderr(); + ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); +} + +void FuncWithAssert(int* n) { + ASSERT_DEATH_IF_SUPPORTED(return;, ""); + (*n)++; } +// Tests that ASSERT_DEATH_IF_SUPPORTED does not return from the current +// function (as ASSERT_DEATH does) if death tests are not supported. +TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { + int n = 0; + FuncWithAssert(&n); + EXPECT_EQ(1, n); +} #endif // GTEST_HAS_DEATH_TEST +// Tests that the death test macros expand to code which may or may not +// be followed by operator<<, and that in either case the complete text +// comprises only a single C++ statement. +// +// The syntax should work whether death tests are available or not. +TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { + if (AlwaysFalse()) + // This would fail if executed; this is a compilation test only + ASSERT_DEATH_IF_SUPPORTED(return, ""); + + if (AlwaysTrue()) + EXPECT_DEATH_IF_SUPPORTED(_exit(1), ""); + else + // This empty "else" branch is meant to ensure that EXPECT_DEATH + // doesn't expand into an "if" statement without an "else" + ; // NOLINT + + if (AlwaysFalse()) + ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die"; + + if (AlwaysFalse()) + ; // NOLINT + else + EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3; +} + +// Tests that conditional death test macros expand to code which interacts +// well with switch statements. +TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) { +// Microsoft compiler usually complains about switch statements without +// case labels. We suppress that warning for this test. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4065) +#endif // _MSC_VER + + switch (0) + default: + ASSERT_DEATH_IF_SUPPORTED(_exit(1), "") + << "exit in default switch handler"; + + switch (0) + case 0: + EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case"; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER +} + // Tests that a test case whose name ends with "DeathTest" works fine // on Windows. TEST(NotADeathTest, Test) { diff --git a/gtest/test/gtest-filepath_test.cc b/gtest/test/gtest-filepath_test.cc index adf9746..5bc4daf 100644 --- a/gtest/test/gtest-filepath_test.cc +++ b/gtest/test/gtest-filepath_test.cc @@ -50,17 +50,17 @@ #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE #include <windows.h> // NOLINT #elif GTEST_OS_WINDOWS #include <direct.h> // NOLINT -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE namespace testing { namespace internal { namespace { -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE // TODO(wan@google.com): Move these to the POSIX adapter section in // gtest-port.h. @@ -81,9 +81,7 @@ int _rmdir(const char* path) { return ret; } -#endif // _WIN32_WCE - -#ifndef _WIN32_WCE +#else TEST(GetCurrentDirTest, ReturnsCurrentDir) { const FilePath original_dir = FilePath::GetCurrentDir(); @@ -103,7 +101,7 @@ TEST(GetCurrentDirTest, ReturnsCurrentDir) { #endif } -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE TEST(IsEmptyTest, ReturnsTrueForEmptyPath) { EXPECT_TRUE(FilePath("").IsEmpty()); @@ -156,7 +154,7 @@ TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) { // RemoveFileName "" -> "./" TEST(RemoveFileNameTest, EmptyName) { -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE // On Windows CE, we use the root as the current directory. EXPECT_STREQ(GTEST_PATH_SEP_, FilePath("").RemoveFileName().c_str()); @@ -344,12 +342,12 @@ TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) { } #endif // GTEST_OS_WINDOWS -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE // Windows CE _does_ consider an empty directory to exist. TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) { EXPECT_FALSE(FilePath("").DirectoryExists()); } -#endif // ! _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE TEST(DirectoryTest, CurrentDirectoryExists) { #if GTEST_OS_WINDOWS // We are on Windows. @@ -449,9 +447,8 @@ class DirectoryCreationTest : public Test { } String TempDir() const { -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE return String("\\temp\\"); - #elif GTEST_OS_WINDOWS const char* temp_dir = posix::GetEnv("TEMP"); if (temp_dir == NULL || temp_dir[0] == '\0') @@ -462,7 +459,7 @@ class DirectoryCreationTest : public Test { return String::Format("%s\\", temp_dir); #else return String("/tmp/"); -#endif +#endif // GTEST_OS_WINDOWS_MOBILE } void CreateTextFile(const char* filename) { diff --git a/gtest/test/gtest-listener_test.cc b/gtest/test/gtest-listener_test.cc new file mode 100644 index 0000000..f12f518 --- /dev/null +++ b/gtest/test/gtest-listener_test.cc @@ -0,0 +1,322 @@ +// 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::TestCase; +using ::testing::TestEventListener; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; +using ::testing::internal::String; +using ::testing::internal::Vector; + +// Used by tests to register their events. +Vector<String>* g_events = NULL; + +namespace testing { +namespace internal { + +class EventRecordingListener : public TestEventListener { + public: + EventRecordingListener(const char* name) : name_(name) {} + + protected: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { + g_events->PushBack(GetFullMethodName("OnTestProgramStart")); + } + + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int iteration) { + Message message; + message << GetFullMethodName("OnTestIterationStart") + << "(" << iteration << ")"; + g_events->PushBack(message.GetString()); + } + + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) { + g_events->PushBack(GetFullMethodName("OnEnvironmentsSetUpStart")); + } + + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) { + g_events->PushBack(GetFullMethodName("OnEnvironmentsSetUpEnd")); + } + + virtual void OnTestCaseStart(const TestCase& /*test_case*/) { + g_events->PushBack(GetFullMethodName("OnTestCaseStart")); + } + + virtual void OnTestStart(const TestInfo& /*test_info*/) { + g_events->PushBack(GetFullMethodName("OnTestStart")); + } + + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) { + g_events->PushBack(GetFullMethodName("OnTestPartResult")); + } + + virtual void OnTestEnd(const TestInfo& /*test_info*/) { + g_events->PushBack(GetFullMethodName("OnTestEnd")); + } + + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) { + g_events->PushBack(GetFullMethodName("OnTestCaseEnd")); + } + + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) { + g_events->PushBack(GetFullMethodName("OnEnvironmentsTearDownStart")); + } + + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) { + g_events->PushBack(GetFullMethodName("OnEnvironmentsTearDownEnd")); + } + + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int iteration) { + Message message; + message << GetFullMethodName("OnTestIterationEnd") + << "(" << iteration << ")"; + g_events->PushBack(message.GetString()); + } + + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { + g_events->PushBack(GetFullMethodName("OnTestProgramEnd")); + } + + private: + String GetFullMethodName(const char* name) { + Message message; + message << name_ << "." << name; + return message.GetString(); + } + + String name_; +}; + +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; + +void VerifyResults(const Vector<String>& data, + const char* const* expected_data, + int expected_data_size) { + const int actual_size = data.size(); + // If the following assertion fails, a new entry will be appended to + // data. Hence we save data.size() first. + EXPECT_EQ(expected_data_size, actual_size); + + // Compares the common prefix. + const int shorter_size = expected_data_size <= actual_size ? + expected_data_size : actual_size; + int i = 0; + for (; i < shorter_size; ++i) { + ASSERT_STREQ(expected_data[i], data.GetElement(i).c_str()) + << "at position " << i; + } + + // Prints extra elements in the actual data. + for (; i < actual_size; ++i) { + printf(" Actual event #%d: %s\n", i, data.GetElement(i).c_str()); + } +} + +int main(int argc, char **argv) { + Vector<String> events; + g_events = &events; + InitGoogleTest(&argc, argv); + + UnitTest::GetInstance()->listeners().Append( + new EventRecordingListener("1st")); + UnitTest::GetInstance()->listeners().Append( + new EventRecordingListener("2nd")); + + AddGlobalTestEnvironment(new EnvironmentInvocationCatcher); + + GTEST_CHECK_(events.size() == 0) + << "AddGlobalTestEnvironment should not generate any events itself."; + + ::testing::GTEST_FLAG(repeat) = 2; + int ret_val = RUN_ALL_TESTS(); + + const char* const expected_events[] = { + "1st.OnTestProgramStart", + "2nd.OnTestProgramStart", + "1st.OnTestIterationStart(0)", + "2nd.OnTestIterationStart(0)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "1st.OnTestCaseStart", + "2nd.OnTestCaseStart", + "ListenerTest::SetUpTestCase", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestCase", + "2nd.OnTestCaseEnd", + "1st.OnTestCaseEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "2nd.OnTestIterationEnd(0)", + "1st.OnTestIterationEnd(0)", + "1st.OnTestIterationStart(1)", + "2nd.OnTestIterationStart(1)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "1st.OnTestCaseStart", + "2nd.OnTestCaseStart", + "ListenerTest::SetUpTestCase", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestCase", + "2nd.OnTestCaseEnd", + "1st.OnTestCaseEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "2nd.OnTestIterationEnd(1)", + "1st.OnTestIterationEnd(1)", + "2nd.OnTestProgramEnd", + "1st.OnTestProgramEnd" + }; + VerifyResults(events, + expected_events, + sizeof(expected_events)/sizeof(expected_events[0])); + + // We need to check manually for ad hoc test failures that happen after + // RUN_ALL_TESTS finishes. + if (UnitTest::GetInstance()->Failed()) + ret_val = 1; + + return ret_val; +} diff --git a/gtest/test/gtest-options_test.cc b/gtest/test/gtest-options_test.cc index 43c6d22..31ae327 100644 --- a/gtest/test/gtest-options_test.cc +++ b/gtest/test/gtest-options_test.cc @@ -40,11 +40,11 @@ #include <gtest/gtest.h> -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE #include <windows.h> #elif GTEST_OS_WINDOWS #include <direct.h> -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is @@ -130,7 +130,7 @@ TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) { TEST(OutputFileHelpersTest, GetCurrentExecutableName) { const FilePath executable = GetCurrentExecutableName(); const char* const exe_str = executable.c_str(); -#if defined(_WIN32_WCE) || GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS ASSERT_TRUE(_strcmpi("gtest-options_test", exe_str) == 0 || _strcmpi("gtest-options-ex_test", exe_str) == 0 || _strcmpi("gtest_all_test", exe_str) == 0) @@ -143,7 +143,7 @@ TEST(OutputFileHelpersTest, GetCurrentExecutableName) { String(exe_str) == "gtest_all_test" || String(exe_str) == "lt-gtest_all_test") << "GetCurrentExecutableName() returns " << exe_str; -#endif +#endif // GTEST_OS_WINDOWS } class XmlOutputChangeDirTest : public Test { diff --git a/gtest/test/gtest-port_test.cc b/gtest/test/gtest-port_test.cc index d980b7c..df59f9e 100644 --- a/gtest/test/gtest-port_test.cc +++ b/gtest/test/gtest-port_test.cc @@ -54,16 +54,16 @@ namespace testing { namespace internal { TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { - if (false) + if (AlwaysFalse()) GTEST_CHECK_(false) << "This should never be executed; " "It's a compilation test only."; - if (true) + if (AlwaysTrue()) GTEST_CHECK_(true); else ; // NOLINT - if (false) + if (AlwaysFalse()) ; // NOLINT else GTEST_CHECK_(true) << ""; @@ -133,8 +133,6 @@ TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { } #endif // GTEST_OS_MAC -#if GTEST_HAS_DEATH_TEST - TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; const char regex[] = @@ -145,9 +143,12 @@ TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { #endif // _MSC_VER ".*a_false_condition.*Extra info.*"; - EXPECT_DEATH(GTEST_CHECK_(a_false_condition) << "Extra info", regex); + EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info", + regex); } +#if GTEST_HAS_DEATH_TEST + TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { EXPECT_EXIT({ GTEST_CHECK_(true) << "Extra info"; diff --git a/gtest/test/gtest-test-part_test.cc b/gtest/test/gtest-test-part_test.cc index 93fe156..403c184 100644 --- a/gtest/test/gtest-test-part_test.cc +++ b/gtest/test/gtest-test-part_test.cc @@ -38,10 +38,6 @@ using testing::Test; using testing::TestPartResult; using testing::TestPartResultArray; -using testing::TPRT_FATAL_FAILURE; -using testing::TPRT_NONFATAL_FAILURE; -using testing::TPRT_SUCCESS; - namespace { // Tests the TestPartResult class. @@ -50,18 +46,18 @@ namespace { class TestPartResultTest : public Test { protected: TestPartResultTest() - : r1_(TPRT_SUCCESS, "foo/bar.cc", 10, "Success!"), - r2_(TPRT_NONFATAL_FAILURE, "foo/bar.cc", -1, "Failure!"), - r3_(TPRT_FATAL_FAILURE, NULL, -1, "Failure!") {} + : r1_(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"), + r2_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure!"), + r3_(TestPartResult::kFatalFailure, NULL, -1, "Failure!") {} TestPartResult r1_, r2_, r3_; }; // Tests TestPartResult::type(). TEST_F(TestPartResultTest, type) { - EXPECT_EQ(TPRT_SUCCESS, r1_.type()); - EXPECT_EQ(TPRT_NONFATAL_FAILURE, r2_.type()); - EXPECT_EQ(TPRT_FATAL_FAILURE, r3_.type()); + EXPECT_EQ(TestPartResult::kSuccess, r1_.type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, r2_.type()); + EXPECT_EQ(TestPartResult::kFatalFailure, r3_.type()); } // Tests TestPartResult::file_name(). @@ -114,8 +110,8 @@ TEST_F(TestPartResultTest, NonfatallyFailed) { class TestPartResultArrayTest : public Test { protected: TestPartResultArrayTest() - : r1_(TPRT_NONFATAL_FAILURE, "foo/bar.cc", -1, "Failure 1"), - r2_(TPRT_FATAL_FAILURE, "foo/bar.cc", -1, "Failure 2") {} + : r1_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure 1"), + r2_(TestPartResult::kFatalFailure, "foo/bar.cc", -1, "Failure 2") {} const TestPartResult r1_, r2_; }; @@ -146,8 +142,6 @@ TEST_F(TestPartResultArrayTest, ContainsGivenResultsAfterTwoAppends) { EXPECT_STREQ("Failure 2", results.GetTestPartResult(1).message()); } -#if GTEST_HAS_DEATH_TEST - typedef TestPartResultArrayTest TestPartResultArrayDeathTest; // Tests that the program dies when GetTestPartResult() is called with @@ -156,12 +150,10 @@ TEST_F(TestPartResultArrayDeathTest, DiesWhenIndexIsOutOfBound) { TestPartResultArray results; results.Append(r1_); - EXPECT_DEATH(results.GetTestPartResult(-1), ""); - EXPECT_DEATH(results.GetTestPartResult(1), ""); + EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(-1), ""); + EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(1), ""); } -#endif // GTEST_HAS_DEATH_TEST - // TODO(mheule@google.com): Add a test for the class HasNewFatalFailureHelper. } // namespace diff --git a/gtest/test/gtest-typed-test_test.cc b/gtest/test/gtest-typed-test_test.cc index 8e86ac8..4b6e971 100644 --- a/gtest/test/gtest-typed-test_test.cc +++ b/gtest/test/gtest-typed-test_test.cc @@ -29,8 +29,8 @@ // // Author: wan@google.com (Zhanyong Wan) -#include <list> #include <set> +#include <vector> #include "test/gtest-typed-test_test.h" #include <gtest/gtest.h> @@ -57,7 +57,9 @@ class CommonTest : public Test { // This 'protected:' is optional. There's no harm in making all // members of this fixture class template public. protected: - typedef std::list<T> List; + // We used to use std::list here, but switched to std::vector since + // MSVC's <list> doesn't compile cleanly with /W4. + typedef std::vector<T> Vector; typedef std::set<int> IntSet; CommonTest() : value_(1) {} @@ -99,7 +101,7 @@ TYPED_TEST(CommonTest, ValuesAreCorrect) { // Typedefs in the fixture class template can be visited via the // "typename TestFixture::" prefix. - typename TestFixture::List empty; + typename TestFixture::Vector empty; EXPECT_EQ(0U, empty.size()); typename TestFixture::IntSet empty2; @@ -198,24 +200,22 @@ TEST_F(TypedTestCasePStateTest, IgnoresOrderAndSpaces) { state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); } -#if GTEST_HAS_DEATH_TEST - typedef TypedTestCasePStateTest TypedTestCasePStateDeathTest; TEST_F(TypedTestCasePStateDeathTest, DetectsDuplicates) { - EXPECT_DEATH( + EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, A, C"), "foo\\.cc.1.?: Test A is listed more than once\\."); } TEST_F(TypedTestCasePStateDeathTest, DetectsExtraTest) { - EXPECT_DEATH( + EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C, D"), "foo\\.cc.1.?: No test named D can be found in this test case\\."); } TEST_F(TypedTestCasePStateDeathTest, DetectsMissedTest) { - EXPECT_DEATH( + EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, C"), "foo\\.cc.1.?: You forgot to list test B\\."); } @@ -224,14 +224,12 @@ TEST_F(TypedTestCasePStateDeathTest, DetectsMissedTest) { // a run-time error if the test case has been registered. TEST_F(TypedTestCasePStateDeathTest, DetectsTestAfterRegistration) { state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C"); - EXPECT_DEATH( + EXPECT_DEATH_IF_SUPPORTED( state_.AddTestName("foo.cc", 2, "FooTest", "D"), "foo\\.cc.2.?: Test D must be defined before REGISTER_TYPED_TEST_CASE_P" "\\(FooTest, \\.\\.\\.\\)\\."); } -#endif // GTEST_HAS_DEATH_TEST - // Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor, // and SetUp()/TearDown() work correctly in type-parameterized tests. @@ -318,7 +316,7 @@ INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types<double>); // Tests that the same type-parameterized test case can be // instantiated in different translation units linked together. // (ContainerTest is also instantiated in gtest-typed-test_test.cc.) -typedef Types<std::list<double>, std::set<char> > MyContainers; +typedef Types<std::vector<double>, std::set<char> > MyContainers; INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers); // Tests that a type-parameterized test case can be defined and diff --git a/gtest/test/gtest-unittest-api_test.cc b/gtest/test/gtest-unittest-api_test.cc index 658e298..7e0f8f8 100644 --- a/gtest/test/gtest-unittest-api_test.cc +++ b/gtest/test/gtest-unittest-api_test.cc @@ -38,21 +38,7 @@ #include <string.h> // For strcmp. #include <algorithm> -using ::testing::AddGlobalTestEnvironment; -using ::testing::Environment; using ::testing::InitGoogleTest; -using ::testing::Test; -using ::testing::TestInfo; -using ::testing::TestPartResult; -using ::testing::UnitTest; -using ::testing::internal::TestCase; -using ::testing::internal::TestProperty; - -#if GTEST_HAS_TYPED_TEST -using ::testing::Types; -using ::testing::internal::GetTypeName; -using ::testing::internal::String; -#endif // GTEST_HAS_TYPED_TEST namespace testing { namespace internal { @@ -64,20 +50,20 @@ struct LessByName { } }; -class UnitTestAccessor { +class UnitTestHelper { public: // Returns the array of pointers to all test cases sorted by the test case // name. The caller is responsible for deleting the array. static TestCase const** const GetSortedTestCases() { - UnitTest* unit_test = UnitTest::GetInstance(); + UnitTest& unit_test = *UnitTest::GetInstance(); TestCase const** const test_cases = - new const TestCase*[unit_test->total_test_case_count()]; + new const TestCase*[unit_test.total_test_case_count()]; - for (int i = 0; i < unit_test->total_test_case_count(); ++i) - test_cases[i] = unit_test->GetTestCase(i); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + test_cases[i] = unit_test.GetTestCase(i); std::sort(test_cases, - test_cases + unit_test->total_test_case_count(), + test_cases + unit_test.total_test_case_count(), LessByName<TestCase>()); return test_cases; } @@ -85,9 +71,9 @@ class UnitTestAccessor { // Returns the test case by its name. The caller doesn't own the returned // pointer. static const TestCase* FindTestCase(const char* name) { - UnitTest* unit_test = UnitTest::GetInstance(); - for (int i = 0; i < unit_test->total_test_case_count(); ++i) { - const TestCase* test_case = unit_test->GetTestCase(i); + UnitTest& unit_test = *UnitTest::GetInstance(); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase* test_case = unit_test.GetTestCase(i); if (0 == strcmp(test_case->name(), name)) return test_case; } @@ -104,19 +90,12 @@ class UnitTestAccessor { for (int i = 0; i < test_case->total_test_count(); ++i) tests[i] = test_case->GetTestInfo(i); - std::sort(tests, - tests + test_case->total_test_count(), + std::sort(tests, tests + test_case->total_test_count(), LessByName<TestInfo>()); return tests; } }; -// TODO(vladl@google.com): Put tests into the internal namespace after -// UnitTest methods are published. -} // namespace internal - -using internal::UnitTestAccessor; - #if GTEST_HAS_TYPED_TEST template <typename T> class TestCaseWithCommentTest : public Test {}; TYPED_TEST_CASE(TestCaseWithCommentTest, Types<int>); @@ -147,7 +126,7 @@ TEST(ApiTest, UnitTestImmutableAccessorsWork) { EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count()); EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count()); - const TestCase** const test_cases = UnitTestAccessor::GetSortedTestCases(); + const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); EXPECT_STREQ("ApiTest", test_cases[0]->name()); EXPECT_STREQ("DISABLED_Test", test_cases[1]->name()); @@ -165,7 +144,7 @@ TEST(ApiTest, UnitTestImmutableAccessorsWork) { } TEST(ApiTest, TestCaseImmutableAccessorsWork) { - const TestCase* test_case = UnitTestAccessor::FindTestCase("ApiTest"); + const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("ApiTest", test_case->name()); @@ -175,7 +154,7 @@ TEST(ApiTest, TestCaseImmutableAccessorsWork) { EXPECT_EQ(3, test_case->test_to_run_count()); ASSERT_EQ(4, test_case->total_test_count()); - const TestInfo** tests = UnitTestAccessor::GetSortedTests(test_case); + const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); @@ -205,7 +184,7 @@ TEST(ApiTest, TestCaseImmutableAccessorsWork) { tests = NULL; #if GTEST_HAS_TYPED_TEST - test_case = UnitTestAccessor::FindTestCase("TestCaseWithCommentTest/0"); + test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("TestCaseWithCommentTest/0", test_case->name()); @@ -215,7 +194,7 @@ TEST(ApiTest, TestCaseImmutableAccessorsWork) { EXPECT_EQ(1, test_case->test_to_run_count()); ASSERT_EQ(1, test_case->total_test_count()); - tests = UnitTestAccessor::GetSortedTests(test_case); + tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("Dummy", tests[0]->name()); EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); @@ -229,7 +208,7 @@ TEST(ApiTest, TestCaseImmutableAccessorsWork) { } TEST(ApiTest, TestCaseDisabledAccessorsWork) { - const TestCase* test_case = UnitTestAccessor::FindTestCase("DISABLED_Test"); + const TestCase* test_case = UnitTestHelper::FindTestCase("DISABLED_Test"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("DISABLED_Test", test_case->name()); @@ -265,7 +244,7 @@ class FinalSuccessChecker : public Environment { EXPECT_FALSE(unit_test->Failed()); ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count()); - const TestCase** const test_cases = UnitTestAccessor::GetSortedTestCases(); + const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); EXPECT_STREQ("ApiTest", test_cases[0]->name()); EXPECT_STREQ("", test_cases[0]->comment()); @@ -298,8 +277,8 @@ class FinalSuccessChecker : public Environment { EXPECT_FALSE(test_cases[2]->Failed()); #endif // GTEST_HAS_TYPED_TEST - const TestCase* test_case = UnitTestAccessor::FindTestCase("ApiTest"); - const TestInfo** tests = UnitTestAccessor::GetSortedTests(test_case); + const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); + const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); EXPECT_FALSE(tests[0]->should_run()); @@ -334,8 +313,8 @@ class FinalSuccessChecker : public Environment { delete[] tests; #if GTEST_HAS_TYPED_TEST - test_case = UnitTestAccessor::FindTestCase("TestCaseWithCommentTest/0"); - tests = UnitTestAccessor::GetSortedTests(test_case); + test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); + tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("Dummy", tests[0]->name()); EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); @@ -352,12 +331,13 @@ class FinalSuccessChecker : public Environment { } }; +} // namespace internal } // namespace testing int main(int argc, char **argv) { InitGoogleTest(&argc, argv); - AddGlobalTestEnvironment(new testing::FinalSuccessChecker()); + AddGlobalTestEnvironment(new testing::internal::FinalSuccessChecker()); return RUN_ALL_TESTS(); } diff --git a/gtest/test/gtest_env_var_test.py b/gtest/test/gtest_env_var_test.py index 19fd810..f8250d4 100755 --- a/gtest/test/gtest_env_var_test.py +++ b/gtest/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/gtest/test/gtest_filter_unittest_.cc b/gtest/test/gtest_filter_unittest_.cc index 3cbddcf..325504f 100644 --- a/gtest/test/gtest_filter_unittest_.cc +++ b/gtest/test/gtest_filter_unittest_.cc @@ -92,19 +92,13 @@ TEST(BazTest, DISABLED_TestC) { // Test case HasDeathTest TEST(HasDeathTest, Test1) { -#if GTEST_HAS_DEATH_TEST - EXPECT_DEATH({exit(1);}, - ".*"); -#endif // GTEST_HAS_DEATH_TEST + EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); } // We need at least two death tests to make sure that the all death tests // aren't on the first shard. TEST(HasDeathTest, Test2) { -#if GTEST_HAS_DEATH_TEST - EXPECT_DEATH({exit(1);}, - ".*"); -#endif // GTEST_HAS_DEATH_TEST + EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); } // Test case FoobarTest diff --git a/gtest/test/gtest_repeat_test.cc b/gtest/test/gtest_repeat_test.cc index 39a0601..df6868b 100644 --- a/gtest/test/gtest_repeat_test.cc +++ b/gtest/test/gtest_repeat_test.cc @@ -64,14 +64,14 @@ namespace { do {\ const int expected_val = (expected);\ const int actual_val = (actual);\ - if (expected_val != actual_val) {\ + if (::testing::internal::IsTrue(expected_val != actual_val)) {\ ::std::cout << "Value of: " #actual "\n"\ << " Actual: " << actual_val << "\n"\ << "Expected: " #expected "\n"\ << "Which is: " << expected_val << "\n";\ abort();\ }\ - } while(false) + } while(::testing::internal::AlwaysFalse()) // Used for verifying that global environment set-up and tear-down are @@ -112,13 +112,11 @@ int g_death_test_count = 0; TEST(BarDeathTest, ThreadSafeAndFast) { g_death_test_count++; -#if GTEST_HAS_DEATH_TEST GTEST_FLAG(death_test_style) = "threadsafe"; - EXPECT_DEATH(abort(), ""); + EXPECT_DEATH_IF_SUPPORTED(abort(), ""); GTEST_FLAG(death_test_style) = "fast"; - EXPECT_DEATH(abort(), ""); -#endif // GTEST_HAS_DEATH_TEST + EXPECT_DEATH_IF_SUPPORTED(abort(), ""); } #if GTEST_HAS_PARAM_TEST diff --git a/gtest/test/gtest_shuffle_test.py b/gtest/test/gtest_shuffle_test.py new file mode 100755 index 0000000..a870a01 --- /dev/null +++ b/gtest/test/gtest_shuffle_test.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python +# +# 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. + +"""Verifies that test shuffling works.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import gtest_test_utils + +# Command to run the gtest_shuffle_test_ program. +COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_') + +# The environment variables for test sharding. +TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' +SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' + +TEST_FILTER = 'A*.A:A*.B:C*' + +ALL_TESTS = [] +ACTIVE_TESTS = [] +FILTERED_TESTS = [] +SHARDED_TESTS = [] + +SHUFFLED_ALL_TESTS = [] +SHUFFLED_ACTIVE_TESTS = [] +SHUFFLED_FILTERED_TESTS = [] +SHUFFLED_SHARDED_TESTS = [] + + +def AlsoRunDisabledTestsFlag(): + return '--gtest_also_run_disabled_tests' + + +def FilterFlag(test_filter): + return '--gtest_filter=%s' % (test_filter,) + + +def RepeatFlag(n): + return '--gtest_repeat=%s' % (n,) + + +def ShuffleFlag(): + return '--gtest_shuffle' + + +def RandomSeedFlag(n): + return '--gtest_random_seed=%s' % (n,) + + +def RunAndReturnOutput(extra_env, args): + """Runs the test program and returns its output.""" + + try: + original_env = os.environ.copy() + os.environ.update(extra_env) + return gtest_test_utils.Subprocess([COMMAND] + args).output + finally: + for key in extra_env.iterkeys(): + if key in original_env: + os.environ[key] = original_env[key] + else: + del os.environ[key] + + +def GetTestsForAllIterations(extra_env, args): + """Runs the test program and returns a list of test lists. + + Args: + extra_env: a map from environment variables to their values + args: command line flags to pass to gtest_shuffle_test_ + + Returns: + A list where the i-th element is the list of tests run in the i-th + test iteration. + """ + + test_iterations = [] + for line in RunAndReturnOutput(extra_env, args).split('\n'): + if line.startswith('----'): + tests = [] + test_iterations.append(tests) + elif line.strip(): + tests.append(line.strip()) # 'TestCaseName.TestName' + + return test_iterations + + +def GetTestCases(tests): + """Returns a list of test cases in the given full test names. + + Args: + tests: a list of full test names + + Returns: + A list of test cases from 'tests', in their original order. + Consecutive duplicates are removed. + """ + + test_cases = [] + for test in tests: + test_case = test.split('.')[0] + if not test_case in test_cases: + test_cases.append(test_case) + + return test_cases + + +def CalculateTestLists(): + """Calculates the list of tests run under different flags.""" + + if not ALL_TESTS: + ALL_TESTS.extend( + GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0]) + + if not ACTIVE_TESTS: + ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0]) + + if not FILTERED_TESTS: + FILTERED_TESTS.extend( + GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0]) + + if not SHARDED_TESTS: + SHARDED_TESTS.extend( + GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [])[0]) + + if not SHUFFLED_ALL_TESTS: + SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations( + {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0]) + + if not SHUFFLED_ACTIVE_TESTS: + SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1)])[0]) + + if not SHUFFLED_FILTERED_TESTS: + SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0]) + + if not SHUFFLED_SHARDED_TESTS: + SHUFFLED_SHARDED_TESTS.extend( + GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [ShuffleFlag(), RandomSeedFlag(1)])[0]) + + +class GTestShuffleUnitTest(gtest_test_utils.TestCase): + """Tests test shuffling.""" + + def setUp(self): + CalculateTestLists() + + def testShufflePreservesNumberOfTests(self): + self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS)) + self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS)) + self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS)) + self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS)) + + def testShuffleChangesTestOrder(self): + self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS) + self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS) + self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS, + SHUFFLED_FILTERED_TESTS) + self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS, + SHUFFLED_SHARDED_TESTS) + + def testShuffleChangesTestCaseOrder(self): + self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS), + GetTestCases(SHUFFLED_ALL_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS), + GetTestCases(SHUFFLED_ACTIVE_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS), + GetTestCases(SHUFFLED_FILTERED_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS), + GetTestCases(SHUFFLED_SHARDED_TESTS)) + + def testShuffleDoesNotRepeatTest(self): + for test in SHUFFLED_ALL_TESTS: + self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_ACTIVE_TESTS: + self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_FILTERED_TESTS: + self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_SHARDED_TESTS: + self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test), + '%s appears more than once' % (test,)) + + def testShuffleDoesNotCreateNewTest(self): + for test in SHUFFLED_ALL_TESTS: + self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_ACTIVE_TESTS: + self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_FILTERED_TESTS: + self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_SHARDED_TESTS: + self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,)) + + def testShuffleIncludesAllTests(self): + for test in ALL_TESTS: + self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,)) + for test in ACTIVE_TESTS: + self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,)) + for test in FILTERED_TESTS: + self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,)) + for test in SHARDED_TESTS: + self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,)) + + def testShuffleLeavesDeathTestsAtFront(self): + non_death_test_found = False + for test in SHUFFLED_ACTIVE_TESTS: + if 'DeathTest.' in test: + self.assert_(not non_death_test_found, + '%s appears after a non-death test' % (test,)) + else: + non_death_test_found = True + + def _VerifyTestCasesDoNotInterleave(self, tests): + test_cases = [] + for test in tests: + [test_case, _] = test.split('.') + if test_cases and test_cases[-1] != test_case: + test_cases.append(test_case) + self.assertEqual(1, test_cases.count(test_case), + 'Test case %s is not grouped together in %s' % + (test_case, tests)) + + def testShuffleDoesNotInterleaveTestCases(self): + self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS) + + def testShuffleRestoresOrderAfterEachIteration(self): + # Get the test lists in all 3 iterations, using random seed 1, 2, + # and 3 respectively. Google Test picks a different seed in each + # iteration, and this test depends on the current implementation + # picking successive numbers. This dependency is not ideal, but + # makes the test much easier to write. + [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( + GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) + + # Make sure running the tests with random seed 1 gets the same + # order as in iteration 1 above. + [tests_with_seed1] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1)]) + self.assertEqual(tests_in_iteration1, tests_with_seed1) + + # Make sure running the tests with random seed 2 gets the same + # order as in iteration 2 above. Success means that Google Test + # correctly restores the test order before re-shuffling at the + # beginning of iteration 2. + [tests_with_seed2] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(2)]) + self.assertEqual(tests_in_iteration2, tests_with_seed2) + + # Make sure running the tests with random seed 3 gets the same + # order as in iteration 3 above. Success means that Google Test + # correctly restores the test order before re-shuffling at the + # beginning of iteration 3. + [tests_with_seed3] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(3)]) + self.assertEqual(tests_in_iteration3, tests_with_seed3) + + def testShuffleGeneratesNewOrderInEachIteration(self): + [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( + GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) + + self.assert_(tests_in_iteration1 != tests_in_iteration2, + tests_in_iteration1) + self.assert_(tests_in_iteration1 != tests_in_iteration3, + tests_in_iteration1) + self.assert_(tests_in_iteration2 != tests_in_iteration3, + tests_in_iteration2) + + def testShuffleShardedTestsPreservesPartition(self): + # If we run M tests on N shards, the same M tests should be run in + # total, regardless of the random seeds used by the shards. + [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '0'}, + [ShuffleFlag(), RandomSeedFlag(1)]) + [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [ShuffleFlag(), RandomSeedFlag(20)]) + [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '2'}, + [ShuffleFlag(), RandomSeedFlag(25)]) + sorted_sharded_tests = tests1 + tests2 + tests3 + sorted_sharded_tests.sort() + sorted_active_tests = [] + sorted_active_tests.extend(ACTIVE_TESTS) + sorted_active_tests.sort() + self.assertEqual(sorted_active_tests, sorted_sharded_tests) + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/gtest/test/gtest_shuffle_test_.cc b/gtest/test/gtest_shuffle_test_.cc new file mode 100644 index 0000000..53ecf77 --- /dev/null +++ b/gtest/test/gtest_shuffle_test_.cc @@ -0,0 +1,104 @@ +// 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: wan@google.com (Zhanyong Wan) + +// Verifies that test shuffling works. + +#include <gtest/gtest.h> + +namespace { + +using ::testing::EmptyTestEventListener; +using ::testing::InitGoogleTest; +using ::testing::Message; +using ::testing::Test; +using ::testing::TestEventListeners; +using ::testing::TestInfo; +using ::testing::UnitTest; +using ::testing::internal::String; +using ::testing::internal::scoped_ptr; + +// The test methods are empty, as the sole purpose of this program is +// to print the test names before/after shuffling. + +class A : public Test {}; +TEST_F(A, A) {} +TEST_F(A, B) {} + +TEST(ADeathTest, A) {} +TEST(ADeathTest, B) {} +TEST(ADeathTest, C) {} + +TEST(B, A) {} +TEST(B, B) {} +TEST(B, C) {} +TEST(B, DISABLED_D) {} +TEST(B, DISABLED_E) {} + +TEST(BDeathTest, A) {} +TEST(BDeathTest, B) {} + +TEST(C, A) {} +TEST(C, B) {} +TEST(C, C) {} +TEST(C, DISABLED_D) {} + +TEST(CDeathTest, A) {} + +TEST(DISABLED_D, A) {} +TEST(DISABLED_D, DISABLED_B) {} + +// This printer prints the full test names only, starting each test +// iteration with a "----" marker. +class TestNamePrinter : public EmptyTestEventListener { + public: + virtual void OnTestIterationStart(const UnitTest& /* unit_test */, + int /* iteration */) { + printf("----\n"); + } + + virtual void OnTestStart(const TestInfo& test_info) { + printf("%s.%s\n", test_info.test_case_name(), test_info.name()); + } +}; + +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + // Replaces the default printer with TestNamePrinter, which prints + // the test name only. + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + delete listeners.Release(listeners.default_result_printer()); + listeners.Append(new TestNamePrinter); + + return RUN_ALL_TESTS(); +} diff --git a/gtest/test/gtest_stress_test.cc b/gtest/test/gtest_stress_test.cc index 57ea75a..0034bb8 100644 --- a/gtest/test/gtest_stress_test.cc +++ b/gtest/test/gtest_stress_test.cc @@ -46,7 +46,6 @@ namespace testing { namespace { using internal::String; -using internal::TestProperty; using internal::TestPropertyKeyIs; using internal::Vector; diff --git a/gtest/test/gtest_unittest.cc b/gtest/test/gtest_unittest.cc index 2c08720..5c69b46 100644 --- a/gtest/test/gtest_unittest.cc +++ b/gtest/test/gtest_unittest.cc @@ -80,23 +80,37 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { namespace testing { namespace internal { -const char* FormatTimeInMillisAsSeconds(TimeInMillis ms); +bool ShouldUseColor(bool stdout_is_tty); +const char* FormatTimeInMillisAsSeconds(TimeInMillis ms); bool ParseInt32Flag(const char* str, const char* flag, Int32* value); -} // namespace internal -} // namespace testing +// Provides access to otherwise private parts of the TestEventListeners class +// that are needed to test it. +class TestEventListenersAccessor { + public: + static TestEventListener* GetRepeater(TestEventListeners* listeners) { + return listeners->repeater(); + } -using testing::internal::FormatTimeInMillisAsSeconds; -using testing::internal::ParseInt32Flag; + static void SetDefaultResultPrinter(TestEventListeners* listeners, + TestEventListener* listener) { + listeners->SetDefaultResultPrinter(listener); + } + static void SetDefaultXmlGenerator(TestEventListeners* listeners, + TestEventListener* listener) { + listeners->SetDefaultXmlGenerator(listener); + } -namespace testing { + static bool EventForwardingEnabled(const TestEventListeners& listeners) { + return listeners.EventForwardingEnabled(); + } -GTEST_DECLARE_string_(output); -GTEST_DECLARE_string_(color); + static void SuppressEventForwarding(TestEventListeners* listeners) { + listeners->SuppressEventForwarding(); + } +}; -namespace internal { -bool ShouldUseColor(bool stdout_is_tty); } // namespace internal } // namespace testing @@ -104,6 +118,7 @@ using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; using testing::DoubleLE; +using testing::EmptyTestEventListener; using testing::FloatLE; using testing::GTEST_FLAG(also_run_disabled_tests); using testing::GTEST_FLAG(break_on_failure); @@ -125,19 +140,21 @@ using testing::IsSubstring; using testing::Message; using testing::ScopedFakeTestPartResultReporter; using testing::StaticAssertTypeEq; -using testing::TPRT_FATAL_FAILURE; -using testing::TPRT_NONFATAL_FAILURE; -using testing::TPRT_SUCCESS; using testing::Test; +using testing::TestEventListeners; +using testing::TestCase; using testing::TestPartResult; using testing::TestPartResultArray; +using testing::TestProperty; +using testing::TestResult; using testing::UnitTest; -using testing::internal::kMaxRandomSeed; -using testing::internal::kTestTypeIdInGoogleTest; +using testing::internal::AlwaysFalse; +using testing::internal::AlwaysTrue; using testing::internal::AppendUserMessage; using testing::internal::CodePointToUtf8; using testing::internal::EqFailure; using testing::internal::FloatingPoint; +using testing::internal::FormatTimeInMillisAsSeconds; using testing::internal::GTestFlagSaver; using testing::internal::GetCurrentOsStackTraceExceptTop; using testing::internal::GetNextRandomSeed; @@ -147,19 +164,34 @@ using testing::internal::GetTypeId; using testing::internal::GetUnitTestImpl; using testing::internal::Int32; using testing::internal::Int32FromEnvOrDie; +using testing::internal::ParseInt32Flag; using testing::internal::ShouldRunTestOnShard; using testing::internal::ShouldShard; using testing::internal::ShouldUseColor; using testing::internal::StreamableToString; using testing::internal::String; -using testing::internal::TestCase; -using testing::internal::TestProperty; -using testing::internal::TestResult; +using testing::internal::TestEventListenersAccessor; using testing::internal::TestResultAccessor; using testing::internal::ThreadLocal; +using testing::internal::UInt32; using testing::internal::Vector; using testing::internal::WideStringToUtf8; +using testing::internal::kMaxRandomSeed; using testing::internal::kTestTypeIdInGoogleTest; +using testing::internal::scoped_ptr; + +class TestingVector : public Vector<int> { +}; + +::std::ostream& operator<<(::std::ostream& os, + const TestingVector& vector) { + os << "{ "; + for (int i = 0; i < vector.size(); i++) { + os << vector.GetElement(i) << " "; + } + os << "}"; + return os; +} // This line tests that we can define tests in an unnamed namespace. namespace { @@ -472,6 +504,49 @@ TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { } #endif // !GTEST_WIDE_STRING_USES_UTF16_ +// Tests the Random class. + +TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange) { + testing::internal::Random random(42); + EXPECT_DEATH_IF_SUPPORTED( + random.Generate(0), + "Cannot generate a number in the range \\[0, 0\\)"); + EXPECT_DEATH_IF_SUPPORTED( + random.Generate(testing::internal::Random::kMaxRange + 1), + "Generation of a number in \\[0, 2147483649\\) was requested, " + "but this can only generate numbers in \\[0, 2147483648\\)"); +} + +TEST(RandomTest, GeneratesNumbersWithinRange) { + const UInt32 kRange = 10000; + testing::internal::Random random(12345); + for (int i = 0; i < 10; i++) { + EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i; + } + + testing::internal::Random random2(testing::internal::Random::kMaxRange); + for (int i = 0; i < 10; i++) { + EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i; + } +} + +TEST(RandomTest, RepeatsWhenReseeded) { + const int kSeed = 123; + const int kArraySize = 10; + const UInt32 kRange = 10000; + UInt32 values[kArraySize]; + + testing::internal::Random random(kSeed); + for (int i = 0; i < kArraySize; i++) { + values[i] = random.Generate(kRange); + } + + random.Reseed(kSeed); + for (int i = 0; i < kArraySize; i++) { + EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i; + } +} + // Tests the Vector class template. // Tests Vector::Clear(). @@ -615,6 +690,53 @@ TEST(VectorTest, GetElementOr) { EXPECT_EQ('x', a.GetElementOr(2, 'x')); } +TEST(VectorTest, Swap) { + Vector<int> a; + a.PushBack(0); + a.PushBack(1); + a.PushBack(2); + + // Swaps an element with itself. + a.Swap(0, 0); + ASSERT_EQ(0, a.GetElement(0)); + ASSERT_EQ(1, a.GetElement(1)); + ASSERT_EQ(2, a.GetElement(2)); + + // Swaps two different elements where the indices go up. + a.Swap(0, 1); + ASSERT_EQ(1, a.GetElement(0)); + ASSERT_EQ(0, a.GetElement(1)); + ASSERT_EQ(2, a.GetElement(2)); + + // Swaps two different elements where the indices go down. + a.Swap(2, 0); + ASSERT_EQ(2, a.GetElement(0)); + ASSERT_EQ(0, a.GetElement(1)); + ASSERT_EQ(1, a.GetElement(2)); +} + +TEST(VectorTest, Clone) { + // Clones an empty Vector. + Vector<int> a; + scoped_ptr<Vector<int> > empty(a.Clone()); + EXPECT_EQ(0, empty->size()); + + // Clones a singleton. + a.PushBack(42); + scoped_ptr<Vector<int> > singleton(a.Clone()); + ASSERT_EQ(1, singleton->size()); + EXPECT_EQ(42, singleton->GetElement(0)); + + // Clones a Vector with more elements. + a.PushBack(43); + a.PushBack(44); + scoped_ptr<Vector<int> > big(a.Clone()); + ASSERT_EQ(3, big->size()); + EXPECT_EQ(42, big->GetElement(0)); + EXPECT_EQ(43, big->GetElement(1)); + EXPECT_EQ(44, big->GetElement(2)); +} + // Tests Vector::Erase(). TEST(VectorDeathTest, Erase) { Vector<int> a; @@ -678,23 +800,260 @@ TEST(VectorDeathTest, Erase) { } // Tests the GetElement accessor. -TEST(ListDeathTest, GetElement) { +TEST(VectorDeathTest, GetElement) { Vector<int> a; a.PushBack(0); a.PushBack(1); a.PushBack(2); + const Vector<int>& b = a; - EXPECT_EQ(0, a.GetElement(0)); - EXPECT_EQ(1, a.GetElement(1)); - EXPECT_EQ(2, a.GetElement(2)); + EXPECT_EQ(0, b.GetElement(0)); + EXPECT_EQ(1, b.GetElement(1)); + EXPECT_EQ(2, b.GetElement(2)); EXPECT_DEATH_IF_SUPPORTED( - a.GetElement(3), + b.GetElement(3), "Invalid Vector index 3: must be in range \\[0, 2\\]\\."); EXPECT_DEATH_IF_SUPPORTED( - a.GetElement(-1), + b.GetElement(-1), "Invalid Vector index -1: must be in range \\[0, 2\\]\\."); } +// Tests the GetMutableElement accessor. +TEST(VectorDeathTest, GetMutableElement) { + Vector<int> a; + a.PushBack(0); + a.PushBack(1); + a.PushBack(2); + + EXPECT_EQ(0, a.GetMutableElement(0)); + EXPECT_EQ(1, a.GetMutableElement(1)); + EXPECT_EQ(2, a.GetMutableElement(2)); + + a.GetMutableElement(0) = 42; + EXPECT_EQ(42, a.GetMutableElement(0)); + EXPECT_EQ(1, a.GetMutableElement(1)); + EXPECT_EQ(2, a.GetMutableElement(2)); + + EXPECT_DEATH_IF_SUPPORTED( + a.GetMutableElement(3), + "Invalid Vector index 3: must be in range \\[0, 2\\]\\."); + EXPECT_DEATH_IF_SUPPORTED( + a.GetMutableElement(-1), + "Invalid Vector index -1: must be in range \\[0, 2\\]\\."); +} + +TEST(VectorDeathTest, Swap) { + Vector<int> a; + a.PushBack(0); + a.PushBack(1); + a.PushBack(2); + + EXPECT_DEATH_IF_SUPPORTED( + a.Swap(-1, 1), + "Invalid first swap element -1: must be in range \\[0, 2\\]"); + EXPECT_DEATH_IF_SUPPORTED( + a.Swap(3, 1), + "Invalid first swap element 3: must be in range \\[0, 2\\]"); + EXPECT_DEATH_IF_SUPPORTED( + a.Swap(1, -1), + "Invalid second swap element -1: must be in range \\[0, 2\\]"); + EXPECT_DEATH_IF_SUPPORTED( + a.Swap(1, 3), + "Invalid second swap element 3: must be in range \\[0, 2\\]"); +} + +TEST(VectorDeathTest, ShuffleRange) { + Vector<int> a; + a.PushBack(0); + a.PushBack(1); + a.PushBack(2); + testing::internal::Random random(1); + + EXPECT_DEATH_IF_SUPPORTED( + a.ShuffleRange(&random, -1, 1), + "Invalid shuffle range start -1: must be in range \\[0, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + a.ShuffleRange(&random, 4, 4), + "Invalid shuffle range start 4: must be in range \\[0, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + a.ShuffleRange(&random, 3, 2), + "Invalid shuffle range finish 2: must be in range \\[3, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + a.ShuffleRange(&random, 3, 4), + "Invalid shuffle range finish 4: must be in range \\[3, 3\\]"); +} + +class VectorShuffleTest : public Test { + protected: + static const int kVectorSize = 20; + + VectorShuffleTest() : random_(1) { + for (int i = 0; i < kVectorSize; i++) { + vector_.PushBack(i); + } + } + + static bool VectorIsCorrupt(const TestingVector& vector) { + if (kVectorSize != vector.size()) { + return true; + } + + bool found_in_vector[kVectorSize] = { false }; + for (int i = 0; i < vector.size(); i++) { + const int e = vector.GetElement(i); + if (e < 0 || e >= kVectorSize || found_in_vector[e]) { + return true; + } + found_in_vector[e] = true; + } + + // Vector size is correct, elements' range is correct, no + // duplicate elements. Therefore no corruption has occurred. + return false; + } + + static bool VectorIsNotCorrupt(const TestingVector& vector) { + return !VectorIsCorrupt(vector); + } + + static bool RangeIsShuffled(const TestingVector& vector, int begin, int end) { + for (int i = begin; i < end; i++) { + if (i != vector.GetElement(i)) { + return true; + } + } + return false; + } + + static bool RangeIsUnshuffled( + const TestingVector& vector, int begin, int end) { + return !RangeIsShuffled(vector, begin, end); + } + + static bool VectorIsShuffled(const TestingVector& vector) { + return RangeIsShuffled(vector, 0, vector.size()); + } + + static bool VectorIsUnshuffled(const TestingVector& vector) { + return !VectorIsShuffled(vector); + } + + testing::internal::Random random_; + TestingVector vector_; +}; // class VectorShuffleTest + +const int VectorShuffleTest::kVectorSize; + +TEST_F(VectorShuffleTest, HandlesEmptyRange) { + // Tests an empty range at the beginning... + vector_.ShuffleRange(&random_, 0, 0); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...in the middle... + vector_.ShuffleRange(&random_, kVectorSize/2, kVectorSize/2); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...at the end... + vector_.ShuffleRange(&random_, kVectorSize - 1, kVectorSize - 1); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...and past the end. + vector_.ShuffleRange(&random_, kVectorSize, kVectorSize); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); +} + +TEST_F(VectorShuffleTest, HandlesRangeOfSizeOne) { + // Tests a size one range at the beginning... + vector_.ShuffleRange(&random_, 0, 1); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...in the middle... + vector_.ShuffleRange(&random_, kVectorSize/2, kVectorSize/2 + 1); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...and at the end. + vector_.ShuffleRange(&random_, kVectorSize - 1, kVectorSize); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); +} + +// Because we use our own random number generator and a fixed seed, +// we can guarantee that the following "random" tests will succeed. + +TEST_F(VectorShuffleTest, ShufflesEntireVector) { + vector_.Shuffle(&random_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_FALSE(VectorIsUnshuffled(vector_)) << vector_; + + // Tests the first and last elements in particular to ensure that + // there are no off-by-one problems in our shuffle algorithm. + EXPECT_NE(0, vector_.GetElement(0)); + EXPECT_NE(kVectorSize - 1, vector_.GetElement(kVectorSize - 1)); +} + +TEST_F(VectorShuffleTest, ShufflesStartOfVector) { + const int kRangeSize = kVectorSize/2; + + vector_.ShuffleRange(&random_, 0, kRangeSize); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsShuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsUnshuffled, vector_, kRangeSize, kVectorSize); +} + +TEST_F(VectorShuffleTest, ShufflesEndOfVector) { + const int kRangeSize = kVectorSize / 2; + vector_.ShuffleRange(&random_, kRangeSize, kVectorSize); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, kVectorSize); +} + +TEST_F(VectorShuffleTest, ShufflesMiddleOfVector) { + int kRangeSize = kVectorSize/3; + vector_.ShuffleRange(&random_, kRangeSize, 2*kRangeSize); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, 2*kRangeSize); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 2*kRangeSize, kVectorSize); +} + +TEST_F(VectorShuffleTest, ShufflesRepeatably) { + TestingVector vector2; + for (int i = 0; i < kVectorSize; i++) { + vector2.PushBack(i); + } + + random_.Reseed(1234); + vector_.Shuffle(&random_); + random_.Reseed(1234); + vector2.Shuffle(&random_); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector2); + + for (int i = 0; i < kVectorSize; i++) { + EXPECT_EQ(vector_.GetElement(i), vector2.GetElement(i)) + << " where i is " << i; + } +} + +// Tests the size of the AssertHelper class. + +TEST(AssertHelperTest, AssertHelperIsSmall) { + // To avoid breaking clients that use lots of assertions in one + // function, we cannot grow the size of AssertHelper. + EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*)); +} + // Tests the String class. // Tests String's constructors. @@ -703,19 +1062,49 @@ TEST(StringTest, Constructors) { String s1; // We aren't using EXPECT_EQ(NULL, s1.c_str()) because comparing // pointers with NULL isn't supported on all platforms. + EXPECT_EQ(0U, s1.length()); EXPECT_TRUE(NULL == s1.c_str()); // Implicitly constructs from a C-string. String s2 = "Hi"; + EXPECT_EQ(2U, s2.length()); EXPECT_STREQ("Hi", s2.c_str()); // Constructs from a C-string and a length. String s3("hello", 3); + EXPECT_EQ(3U, s3.length()); EXPECT_STREQ("hel", s3.c_str()); - // Copy ctor. - String s4 = s3; - EXPECT_STREQ("hel", s4.c_str()); + // The empty String should be created when String is constructed with + // a NULL pointer and length 0. + EXPECT_EQ(0U, String(NULL, 0).length()); + EXPECT_FALSE(String(NULL, 0).c_str() == NULL); + + // Constructs a String that contains '\0'. + String s4("a\0bcd", 4); + EXPECT_EQ(4U, s4.length()); + EXPECT_EQ('a', s4.c_str()[0]); + EXPECT_EQ('\0', s4.c_str()[1]); + EXPECT_EQ('b', s4.c_str()[2]); + EXPECT_EQ('c', s4.c_str()[3]); + + // Copy ctor where the source is NULL. + const String null_str; + String s5 = null_str; + EXPECT_TRUE(s5.c_str() == NULL); + + // Copy ctor where the source isn't NULL. + String s6 = s3; + EXPECT_EQ(3U, s6.length()); + EXPECT_STREQ("hel", s6.c_str()); + + // Copy ctor where the source contains '\0'. + String s7 = s4; + EXPECT_EQ(4U, s7.length()); + EXPECT_EQ('a', s7.c_str()[0]); + EXPECT_EQ('\0', s7.c_str()[1]); + EXPECT_EQ('b', s7.c_str()[2]); + EXPECT_EQ('c', s7.c_str()[3]); } #if GTEST_HAS_STD_STRING @@ -724,17 +1113,22 @@ TEST(StringTest, ConvertsFromStdString) { // An empty std::string. const std::string src1(""); const String dest1 = src1; + EXPECT_EQ(0U, dest1.length()); EXPECT_STREQ("", dest1.c_str()); // A normal std::string. const std::string src2("Hi"); const String dest2 = src2; + EXPECT_EQ(2U, dest2.length()); EXPECT_STREQ("Hi", dest2.c_str()); // An std::string with an embedded NUL character. - const char src3[] = "Hello\0world."; + const char src3[] = "a\0b"; const String dest3 = std::string(src3, sizeof(src3)); - EXPECT_STREQ("Hello", dest3.c_str()); + EXPECT_EQ(sizeof(src3), dest3.length()); + EXPECT_EQ('a', dest3.c_str()[0]); + EXPECT_EQ('\0', dest3.c_str()[1]); + EXPECT_EQ('b', dest3.c_str()[2]); } TEST(StringTest, ConvertsToStdString) { @@ -747,6 +1141,11 @@ TEST(StringTest, ConvertsToStdString) { const String src2("Hi"); const std::string dest2 = src2; EXPECT_EQ("Hi", dest2); + + // A String containing a '\0'. + const String src3("x\0y", 3); + const std::string dest3 = src3; + EXPECT_EQ(std::string("x\0y", 3), dest3); } #endif // GTEST_HAS_STD_STRING @@ -757,17 +1156,22 @@ TEST(StringTest, ConvertsFromGlobalString) { // An empty ::string. const ::string src1(""); const String dest1 = src1; + EXPECT_EQ(0U, dest1.length()); EXPECT_STREQ("", dest1.c_str()); // A normal ::string. const ::string src2("Hi"); const String dest2 = src2; + EXPECT_EQ(2U, dest2.length()); EXPECT_STREQ("Hi", dest2.c_str()); // An ::string with an embedded NUL character. - const char src3[] = "Hello\0world."; + const char src3[] = "x\0y"; const String dest3 = ::string(src3, sizeof(src3)); - EXPECT_STREQ("Hello", dest3.c_str()); + EXPECT_EQ(sizeof(src3), dest3.length()); + EXPECT_EQ('x', dest3.c_str()[0]); + EXPECT_EQ('\0', dest3.c_str()[1]); + EXPECT_EQ('y', dest3.c_str()[2]); } TEST(StringTest, ConvertsToGlobalString) { @@ -780,17 +1184,14 @@ TEST(StringTest, ConvertsToGlobalString) { const String src2("Hi"); const ::string dest2 = src2; EXPECT_EQ("Hi", dest2); + + const String src3("x\0y", 3); + const ::string dest3 = src3; + EXPECT_EQ(::string("x\0y", 3), dest3); } #endif // GTEST_HAS_GLOBAL_STRING -// Tests String::ShowCString(). -TEST(StringTest, ShowCString) { - EXPECT_STREQ("(null)", String::ShowCString(NULL)); - EXPECT_STREQ("", String::ShowCString("")); - EXPECT_STREQ("foo", String::ShowCString("foo")); -} - // Tests String::ShowCStringQuoted(). TEST(StringTest, ShowCStringQuoted) { EXPECT_STREQ("(null)", @@ -801,6 +1202,53 @@ TEST(StringTest, ShowCStringQuoted) { String::ShowCStringQuoted("foo").c_str()); } +// Tests String::empty(). +TEST(StringTest, Empty) { + EXPECT_TRUE(String("").empty()); + EXPECT_FALSE(String().empty()); + EXPECT_FALSE(String(NULL).empty()); + EXPECT_FALSE(String("a").empty()); + EXPECT_FALSE(String("\0", 1).empty()); +} + +// Tests String::Compare(). +TEST(StringTest, Compare) { + // NULL vs NULL. + EXPECT_EQ(0, String().Compare(String())); + + // NULL vs non-NULL. + EXPECT_EQ(-1, String().Compare(String(""))); + + // Non-NULL vs NULL. + EXPECT_EQ(1, String("").Compare(String())); + + // The following covers non-NULL vs non-NULL. + + // "" vs "". + EXPECT_EQ(0, String("").Compare(String(""))); + + // "" vs non-"". + EXPECT_EQ(-1, String("").Compare(String("\0", 1))); + EXPECT_EQ(-1, String("").Compare(" ")); + + // Non-"" vs "". + EXPECT_EQ(1, String("a").Compare(String(""))); + + // The following covers non-"" vs non-"". + + // Same length and equal. + EXPECT_EQ(0, String("a").Compare(String("a"))); + + // Same length and different. + EXPECT_EQ(-1, String("a\0b", 3).Compare(String("a\0c", 3))); + EXPECT_EQ(1, String("b").Compare(String("a"))); + + // Different lengths. + EXPECT_EQ(-1, String("a").Compare(String("ab"))); + EXPECT_EQ(-1, String("a").Compare(String("a\0", 2))); + EXPECT_EQ(1, String("abc").Compare(String("aacd"))); +} + // Tests String::operator==(). TEST(StringTest, Equals) { const String null(NULL); @@ -818,6 +1266,9 @@ TEST(StringTest, Equals) { EXPECT_FALSE(foo == ""); // NOLINT EXPECT_FALSE(foo == "bar"); // NOLINT EXPECT_TRUE(foo == "foo"); // NOLINT + + const String bar("x\0y", 3); + EXPECT_FALSE(bar == "x"); } // Tests String::operator!=(). @@ -837,6 +1288,17 @@ TEST(StringTest, NotEquals) { EXPECT_TRUE(foo != ""); // NOLINT EXPECT_TRUE(foo != "bar"); // NOLINT EXPECT_FALSE(foo != "foo"); // NOLINT + + const String bar("x\0y", 3); + EXPECT_TRUE(bar != "x"); +} + +// Tests String::length(). +TEST(StringTest, Length) { + EXPECT_EQ(0U, String().length()); + EXPECT_EQ(0U, String("").length()); + EXPECT_EQ(2U, String("ab").length()); + EXPECT_EQ(3U, String("a\0b", 3).length()); } // Tests String::EndsWith(). @@ -900,9 +1362,17 @@ TEST(StringTest, CanBeAssignedEmpty) { TEST(StringTest, CanBeAssignedNonEmpty) { const String src("hello"); String dest; - dest = src; + EXPECT_EQ(5U, dest.length()); EXPECT_STREQ("hello", dest.c_str()); + + const String src2("x\0y", 3); + String dest2; + dest2 = src2; + EXPECT_EQ(3U, dest2.length()); + EXPECT_EQ('x', dest2.c_str()[0]); + EXPECT_EQ('\0', dest2.c_str()[1]); + EXPECT_EQ('y', dest2.c_str()[2]); } // Tests that a String can be assigned to itself. @@ -913,6 +1383,40 @@ TEST(StringTest, CanBeAssignedSelf) { EXPECT_STREQ("hello", dest.c_str()); } +// Tests streaming a String. +TEST(StringTest, Streams) { + EXPECT_EQ(StreamableToString(String()), "(null)"); + EXPECT_EQ(StreamableToString(String("")), ""); + 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(). @@ -933,7 +1437,7 @@ TEST(StringTest, ShowWideCStringQuoted) { String::ShowWideCStringQuoted(L"foo").c_str()); } -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE TEST(StringTest, AnsiAndUtf16Null) { EXPECT_EQ(NULL, String::AnsiToUtf16(NULL)); EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL)); @@ -956,7 +1460,7 @@ TEST(StringTest, AnsiAndUtf16ConvertPathChars) { EXPECT_EQ(0, wcsncmp(L".:\\ \"*?", utf16, 3)); delete [] utf16; } -#endif // _WIN32_WCE +#endif // GTEST_OS_WINDOWS_MOBILE #endif // GTEST_OS_WINDOWS @@ -1221,12 +1725,12 @@ TEST(TestPartResultTest, ConstructorWorks) { message << static_cast<const char*>(testing::internal::kStackTraceMarker); message << "some unimportant stack trace"; - const TestPartResult result(TPRT_NONFATAL_FAILURE, + const TestPartResult result(TestPartResult::kNonFatalFailure, "some_file.cc", 42, message.GetString().c_str()); - EXPECT_EQ(TPRT_NONFATAL_FAILURE, result.type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, result.type()); EXPECT_STREQ("some_file.cc", result.file_name()); EXPECT_EQ(42, result.line_number()); EXPECT_STREQ(message.GetString().c_str(), result.message()); @@ -1234,13 +1738,16 @@ TEST(TestPartResultTest, ConstructorWorks) { } TEST(TestPartResultTest, ResultAccessorsWork) { - const TestPartResult success(TPRT_SUCCESS, "file.cc", 42, "message"); + const TestPartResult success(TestPartResult::kSuccess, + "file.cc", + 42, + "message"); EXPECT_TRUE(success.passed()); EXPECT_FALSE(success.failed()); EXPECT_FALSE(success.nonfatally_failed()); EXPECT_FALSE(success.fatally_failed()); - const TestPartResult nonfatal_failure(TPRT_NONFATAL_FAILURE, + const TestPartResult nonfatal_failure(TestPartResult::kNonFatalFailure, "file.cc", 42, "message"); @@ -1249,7 +1756,7 @@ TEST(TestPartResultTest, ResultAccessorsWork) { EXPECT_TRUE(nonfatal_failure.nonfatally_failed()); EXPECT_FALSE(nonfatal_failure.fatally_failed()); - const TestPartResult fatal_failure(TPRT_FATAL_FAILURE, + const TestPartResult fatal_failure(TestPartResult::kFatalFailure, "file.cc", 42, "message"); @@ -1274,10 +1781,14 @@ class TestResultTest : public Test { virtual void SetUp() { // pr1 is for success. - pr1 = new TestPartResult(TPRT_SUCCESS, "foo/bar.cc", 10, "Success!"); + pr1 = new TestPartResult(TestPartResult::kSuccess, + "foo/bar.cc", + 10, + "Success!"); // pr2 is for fatal failure. - pr2 = new TestPartResult(TPRT_FATAL_FAILURE, "foo/bar.cc", + pr2 = new TestPartResult(TestPartResult::kFatalFailure, + "foo/bar.cc", -1, // This line number means "unknown" "Failure!"); @@ -1577,7 +2088,7 @@ TEST_F(GTestFlagSaverTest, VerifyGTestFlags) { // value. If the value argument is "", unsets the environment // variable. The caller must ensure that both arguments are not NULL. static void SetEnv(const char* name, const char* value) { -#ifdef _WIN32_WCE +#if GTEST_OS_WINDOWS_MOBILE // Environment variables are not supported on Windows CE. return; #elif defined(__BORLANDC__) @@ -1595,7 +2106,6 @@ static void SetEnv(const char* name, const char* value) { added_env[name] = new String((Message() << name << "=" << value).GetString()); putenv(added_env[name]->c_str()); delete prev_env; - #elif GTEST_OS_WINDOWS // If we are on Windows proper. _putenv((Message() << name << "=" << value).GetString().c_str()); #else @@ -1604,10 +2114,10 @@ static void SetEnv(const char* name, const char* value) { } else { setenv(name, value, 1); } -#endif +#endif // GTEST_OS_WINDOWS_MOBILE } -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE // Environment variables are not supported on Windows CE. using testing::internal::Int32FromGTestEnv; @@ -1655,7 +2165,7 @@ TEST(Int32FromGTestEnvTest, ParsesAndReturnsValidValue) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-321"); EXPECT_EQ(-321, Int32FromGTestEnv("temp", 0)); } -#endif // !defined(_WIN32_WCE) +#endif // !GTEST_OS_WINDOWS_MOBILE // Tests ParseInt32Flag(). @@ -1713,7 +2223,7 @@ TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue) { // Tests that Int32FromEnvOrDie() parses the value of the var or // returns the correct default. // Environment variables are not supported on Windows CE. -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "123"); @@ -1721,7 +2231,7 @@ TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123"); EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); } -#endif // _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE // Tests that Int32FromEnvOrDie() aborts with an error message // if the variable is not an Int32. @@ -1788,7 +2298,7 @@ TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne) { // Tests that sharding is enabled if total_shards > 1 and // we are not in a death test subprocess. // Environment variables are not supported on Windows CE. -#ifndef _WIN32_WCE +#if !GTEST_OS_WINDOWS_MOBILE TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { SetEnv(index_var_, "4"); SetEnv(total_var_, "22"); @@ -1805,7 +2315,7 @@ TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } -#endif // _WIN32_WCE +#endif // !GTEST_OS_WINDOWS_MOBILE // Tests that we exit in error if the sharding values are not valid. @@ -3151,9 +3661,9 @@ TEST_F(NoFatalFailureTest, AssertNoFatalFailureOnFatalFailure) { DoAssertNoFatalFailureOnFails(); } ASSERT_EQ(2, gtest_failures.size()); - EXPECT_EQ(testing::TPRT_FATAL_FAILURE, + EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(0).type()); - EXPECT_EQ(testing::TPRT_FATAL_FAILURE, + EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", gtest_failures.GetTestPartResult(0).message()); @@ -3168,11 +3678,11 @@ TEST_F(NoFatalFailureTest, ExpectNoFatalFailureOnFatalFailure) { DoExpectNoFatalFailureOnFails(); } ASSERT_EQ(3, gtest_failures.size()); - EXPECT_EQ(testing::TPRT_FATAL_FAILURE, + EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(0).type()); - EXPECT_EQ(testing::TPRT_NONFATAL_FAILURE, + EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(1).type()); - EXPECT_EQ(testing::TPRT_NONFATAL_FAILURE, + EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(2).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", gtest_failures.GetTestPartResult(0).message()); @@ -3189,9 +3699,9 @@ TEST_F(NoFatalFailureTest, MessageIsStreamable) { EXPECT_NO_FATAL_FAILURE(FAIL() << "foo") << "my message"; } ASSERT_EQ(2, gtest_failures.size()); - EXPECT_EQ(testing::TPRT_NONFATAL_FAILURE, + EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(0).type()); - EXPECT_EQ(testing::TPRT_NONFATAL_FAILURE, + EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "foo", gtest_failures.GetTestPartResult(0).message()); @@ -3651,19 +4161,19 @@ TEST(HRESULTAssertionTest, Streaming) { // Tests that the assertion macros behave like single statements. TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) { - if (false) + if (AlwaysFalse()) ASSERT_TRUE(false) << "This should never be executed; " "It's a compilation test only."; - if (true) + if (AlwaysTrue()) EXPECT_FALSE(false); else ; // NOLINT - if (false) + if (AlwaysFalse()) ASSERT_LT(1, 3); - if (false) + if (AlwaysFalse()) ; // NOLINT else EXPECT_GT(3, 2) << ""; @@ -3685,26 +4195,26 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { } TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { - if (false) + if (AlwaysFalse()) EXPECT_THROW(ThrowNothing(), bool); - if (true) + if (AlwaysTrue()) EXPECT_THROW(ThrowAnInteger(), int); else ; // NOLINT - if (false) + if (AlwaysFalse()) EXPECT_NO_THROW(ThrowAnInteger()); - if (true) + if (AlwaysTrue()) EXPECT_NO_THROW(ThrowNothing()); else ; // NOLINT - if (false) + if (AlwaysFalse()) EXPECT_ANY_THROW(ThrowNothing()); - if (true) + if (AlwaysTrue()) EXPECT_ANY_THROW(ThrowAnInteger()); else ; // NOLINT @@ -3712,23 +4222,23 @@ TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { #endif // GTEST_HAS_EXCEPTIONS TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) { - if (false) + if (AlwaysFalse()) EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. " << "It's a compilation test only."; else ; // NOLINT - if (false) + if (AlwaysFalse()) ASSERT_NO_FATAL_FAILURE(FAIL()) << ""; else ; // NOLINT - if (true) + if (AlwaysTrue()) EXPECT_NO_FATAL_FAILURE(SUCCEED()); else ; // NOLINT - if (false) + if (AlwaysFalse()) ; // NOLINT else ASSERT_NO_FATAL_FAILURE(SUCCEED()); @@ -6018,3 +6528,320 @@ 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 OnTestProgramStart(const UnitTest& /*unit_test*/) { + if (on_start_counter_ != NULL) + (*on_start_counter_)++; + } + + private: + int* on_start_counter_; + bool* is_destroyed_; +}; + +// Tests the constructor. +TEST(TestEventListenersTest, ConstructionWorks) { + TestEventListeners listeners; + + EXPECT_TRUE(TestEventListenersAccessor::GetRepeater(&listeners) != NULL); + EXPECT_TRUE(listeners.default_result_printer() == NULL); + EXPECT_TRUE(listeners.default_xml_generator() == NULL); +} + +// Tests that the TestEventListeners destructor deletes all the listeners it +// owns. +TEST(TestEventListenersTest, 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); + + { + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, + default_result_printer); + TestEventListenersAccessor::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 a TestEventListeners list starts +// receiving events. +TEST(TestEventListenersTest, Append) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + listeners.Append(listener); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); + } + EXPECT_TRUE(is_destroyed); +} + +// Tests that listeners receive events in the order they were appended to +// the list, except for *End requests, which must be received in the reverse +// order. +class SequenceTestingListener : public EmptyTestEventListener { + public: + SequenceTestingListener(Vector<String>* vector, const char* id) + : vector_(vector), id_(id) {} + + protected: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { + vector_->PushBack(GetEventDescription("OnTestProgramStart")); + } + + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { + vector_->PushBack(GetEventDescription("OnTestProgramEnd")); + } + + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) { + vector_->PushBack(GetEventDescription("OnTestIterationStart")); + } + + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) { + vector_->PushBack(GetEventDescription("OnTestIterationEnd")); + } + + private: + String GetEventDescription(const char* method) { + Message message; + message << id_ << "." << method; + return message.GetString(); + } + + Vector<String>* vector_; + const char* const id_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener); +}; + +TEST(EventListenerTest, AppendKeepsOrder) { + Vector<String> vec; + TestEventListeners listeners; + listeners.Append(new SequenceTestingListener(&vec, "1st")); + listeners.Append(new SequenceTestingListener(&vec, "2nd")); + listeners.Append(new SequenceTestingListener(&vec, "3rd")); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + ASSERT_EQ(3, vec.size()); + EXPECT_STREQ("1st.OnTestProgramStart", vec.GetElement(0).c_str()); + EXPECT_STREQ("2nd.OnTestProgramStart", vec.GetElement(1).c_str()); + EXPECT_STREQ("3rd.OnTestProgramStart", vec.GetElement(2).c_str()); + + vec.Clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramEnd( + *UnitTest::GetInstance()); + ASSERT_EQ(3, vec.size()); + EXPECT_STREQ("3rd.OnTestProgramEnd", vec.GetElement(0).c_str()); + EXPECT_STREQ("2nd.OnTestProgramEnd", vec.GetElement(1).c_str()); + EXPECT_STREQ("1st.OnTestProgramEnd", vec.GetElement(2).c_str()); + + vec.Clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationStart( + *UnitTest::GetInstance(), 0); + ASSERT_EQ(3, vec.size()); + EXPECT_STREQ("1st.OnTestIterationStart", vec.GetElement(0).c_str()); + EXPECT_STREQ("2nd.OnTestIterationStart", vec.GetElement(1).c_str()); + EXPECT_STREQ("3rd.OnTestIterationStart", vec.GetElement(2).c_str()); + + vec.Clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationEnd( + *UnitTest::GetInstance(), 0); + ASSERT_EQ(3, vec.size()); + EXPECT_STREQ("3rd.OnTestIterationEnd", vec.GetElement(0).c_str()); + EXPECT_STREQ("2nd.OnTestIterationEnd", vec.GetElement(1).c_str()); + EXPECT_STREQ("1st.OnTestIterationEnd", vec.GetElement(2).c_str()); +} + +// Tests that a listener removed from a TestEventListeners list stops receiving +// events and is not deleted when the list is destroyed. +TEST(TestEventListenersTest, 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); + { + TestEventListeners listeners; + listeners.Append(listener); + EXPECT_EQ(listener, listeners.Release(listener)); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *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); + + TestEventListeners listeners; + listeners.Append(listener); + ASSERT_TRUE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); + TestEventListenersAccessor::SuppressEventForwarding(&listeners); + ASSERT_FALSE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); +} + +// Tests that events generated by Google Test are not forwarded in +// death test subprocesses. +TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses) { + EXPECT_DEATH_IF_SUPPORTED({ + GTEST_CHECK_(TestEventListenersAccessor::EventForwardingEnabled( + *GetUnitTestImpl()->listeners())) << "expected failure";}, + "expected failure"); +} + +// 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); + + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_result_printer()); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_result_printer with something else should remove it + // from the list and destroy it. + TestEventListenersAccessor::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. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *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); + { + TestEventListeners listeners; + TestEventListenersAccessor::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. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *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); + + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_xml_generator()); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_xml_generator with something else should remove it + // from the list and destroy it. + TestEventListenersAccessor::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. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *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); + { + TestEventListeners listeners; + TestEventListenersAccessor::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. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *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/gtest/test/gtest_xml_output_unittest.py b/gtest/test/gtest_xml_output_unittest.py index a0cd4d0..6d44929 100755 --- a/gtest/test/gtest_xml_output_unittest.py +++ b/gtest/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 @@ -53,7 +54,7 @@ else: STACK_TRACE_TEMPLATE = "" EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?> -<testsuites tests="13" failures="2" disabled="2" errors="0" time="*" name="AllTests"> +<testsuites tests="15" failures="4" disabled="2" errors="0" time="*" name="AllTests"> <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*"> <testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/> </testsuite> @@ -76,6 +77,20 @@ Expected: 2%(stack)s]]></failure> </testcase> <testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/> </testsuite> + <testsuite name="XmlQuotingTest" tests="1" failures="1" disabled="0" errors="0" time="*"> + <testcase name="OutputsCData" status="run" time="*" classname="XmlQuotingTest"> + <failure message="Failed
XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]></top>" type=""><![CDATA[gtest_xml_output_unittest_.cc:* +Failed +XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]><![CDATA[</top>%(stack)s]]></failure> + </testcase> + </testsuite> + <testsuite name="InvalidCharactersTest" tests="1" failures="1" disabled="0" errors="0" time="*"> + <testcase name="InvalidCharactersInMessage" status="run" time="*" classname="InvalidCharactersTest"> + <failure message="Failed
Invalid characters in brackets []" type=""><![CDATA[gtest_xml_output_unittest_.cc:* +Failed +Invalid characters in brackets []%(stack)s]]></failure> + </testcase> + </testsuite> <testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*"> <testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/> </testsuite> @@ -108,8 +123,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 +156,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/gtest/test/gtest_xml_output_unittest_.cc b/gtest/test/gtest_xml_output_unittest_.cc index d7ce2c6..fc07ef4 100644 --- a/gtest/test/gtest_xml_output_unittest_.cc +++ b/gtest/test/gtest_xml_output_unittest_.cc @@ -40,6 +40,10 @@ #include <gtest/gtest.h> +using ::testing::InitGoogleTest; +using ::testing::TestEventListeners; +using ::testing::UnitTest; + class SuccessfulTest : public testing::Test { }; @@ -76,6 +80,17 @@ TEST(MixedResultTest, DISABLED_test) { FAIL() << "Unexpected failure: Disabled test should not be run"; } +TEST(XmlQuotingTest, OutputsCData) { + FAIL() << "XML output: " + "<?xml encoding=\"utf-8\"><top><![CDATA[cdata text]]></top>"; +} + +// Helps to test that invalid characters produced by test code do not make +// it into the XML file. +TEST(InvalidCharactersTest, InvalidCharactersInMessage) { + FAIL() << "Invalid characters in brackets [\x1\x2]"; +} + class PropertyRecordingTest : public testing::Test { }; @@ -118,3 +133,13 @@ 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) { + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + delete listeners.Release(listeners.default_xml_generator()); + } + return RUN_ALL_TESTS(); +} diff --git a/gtest/test/gtest_xml_test_utils.py b/gtest/test/gtest_xml_test_utils.py index 1811c40..c83c3b7 100755 --- a/gtest/test/gtest_xml_test_utils.py +++ b/gtest/test/gtest_xml_test_utils.py @@ -77,19 +77,29 @@ class GTestXMLTestCase(gtest_test_utils.TestCase): expected_attributes = expected_node.attributes actual_attributes = actual_node .attributes - self.assertEquals(expected_attributes.length, actual_attributes.length) + self.assertEquals( + expected_attributes.length, actual_attributes.length, + "attribute numbers differ in element " + actual_node.tagName) for i in range(expected_attributes.length): expected_attr = expected_attributes.item(i) actual_attr = actual_attributes.get(expected_attr.name) - self.assert_(actual_attr is not None) - self.assertEquals(expected_attr.value, actual_attr.value) + self.assert_( + actual_attr is not None, + "expected attribute %s not found in element %s" % + (expected_attr.name, actual_node.tagName)) + self.assertEquals(expected_attr.value, actual_attr.value, + " values of attribute %s in element %s differ" % + (expected_attr.name, actual_node.tagName)) expected_children = self._GetChildren(expected_node) actual_children = self._GetChildren(actual_node) - self.assertEquals(len(expected_children), len(actual_children)) + self.assertEquals( + len(expected_children), len(actual_children), + "number of child elements differ in element " + actual_node.tagName) for child_id, child in expected_children.iteritems(): self.assert_(child_id in actual_children, - '<%s> is not in <%s>' % (child_id, actual_children)) + '<%s> is not in <%s> (in element %s)' % + (child_id, actual_children, actual_node.tagName)) self.AssertEquivalentNodes(child, actual_children[child_id]) identifying_attribute = { @@ -103,14 +113,13 @@ class GTestXMLTestCase(gtest_test_utils.TestCase): """ Fetches all of the child nodes of element, a DOM Element object. Returns them as the values of a dictionary keyed by the IDs of the - children. For <testsuites>, <testsuite> and <testcase> elements, - the ID is the value of their "name" attribute; for <failure> - elements, it is the value of the "message" attribute; for CDATA - section node, it is "detail". An exception is raised if any - element other than the above four is encountered, if two child - elements with the same identifying attributes are encountered, or - if any other type of node is encountered, other than Text nodes - containing only whitespace. + children. For <testsuites>, <testsuite> and <testcase> elements, the ID + is the value of their "name" attribute; for <failure> elements, it is + the value of the "message" attribute; CDATA sections and non-whitespace + text nodes are concatenated into a single CDATA section with ID + "detail". An exception is raised if any element other than the above + four is encountered, if two child elements with the same identifying + attributes are encountered, or if any other type of node is encountered. """ children = {} @@ -121,11 +130,14 @@ class GTestXMLTestCase(gtest_test_utils.TestCase): childID = child.getAttribute(self.identifying_attribute[child.tagName]) self.assert_(childID not in children) children[childID] = child - elif child.nodeType == Node.TEXT_NODE: - self.assert_(child.nodeValue.isspace()) - elif child.nodeType == Node.CDATA_SECTION_NODE: - self.assert_("detail" not in children) - children["detail"] = child + elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: + if "detail" not in children: + if (child.nodeType == Node.CDATA_SECTION_NODE or + not child.nodeValue.isspace()): + children["detail"] = child.ownerDocument.createCDATASection( + child.nodeValue) + else: + children["detail"].nodeValue += child.nodeValue else: self.fail("Encountered unexpected node type %d" % child.nodeType) return children |