From 64cdcb69b28fc26e78d95c574187f7dd9830c84c Mon Sep 17 00:00:00 2001 From: shiqian Date: Fri, 26 Sep 2008 16:08:30 +0000 Subject: Lots of changes: * changes the XML report format to match JUnit/Ant's. * improves file path handling. * allows the user to disable RTTI using the GTEST_HAS_RTTI macro. * makes the code compile with -Wswitch-enum. --- src/gtest-death-test.cc | 1 + src/gtest-filepath.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++----- src/gtest.cc | 46 ++++++++++++++++++++++++++++++++--------- 3 files changed, 87 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 971c3005..fa800879 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -416,6 +416,7 @@ bool ForkingDeathTest::Passed(bool status_ok) { << " " << ExitSummary(status_) << "\n"; } break; + case IN_PROGRESS: default: GTEST_LOG(FATAL, "DeathTest::Passed somehow called before conclusion of test"); diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 2a5be8ce..dc0d78f0 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -161,10 +161,13 @@ bool FilePath::FileOrDirectoryExists() const { // that exists. bool FilePath::DirectoryExists() const { bool result = false; -#ifdef _WIN32 - FilePath removed_sep(this->RemoveTrailingPathSeparator()); +#ifdef GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); #ifdef _WIN32_WCE - LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; if ((attributes != kInvalidFileAttributes) && @@ -173,17 +176,32 @@ bool FilePath::DirectoryExists() const { } #else struct _stat file_stat = {}; - result = _stat(removed_sep.c_str(), &file_stat) == 0 && + result = _stat(path.c_str(), &file_stat) == 0 && (_S_IFDIR & file_stat.st_mode) != 0; #endif // _WIN32_WCE #else struct stat file_stat = {}; result = stat(pathname_.c_str(), &file_stat) == 0 && S_ISDIR(file_stat.st_mode); -#endif // _WIN32 +#endif // GTEST_OS_WINDOWS return result; } +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#ifdef GTEST_OS_WINDOWS + const char* const name = pathname_.c_str(); + return pathname_.GetLength() == 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + name[2] == kPathSeparator; +#else + return pathname_ == kPathSeparatorString; +#endif +} + // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension @@ -258,5 +276,31 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { : *this; } +// Normalize removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.GetLength() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.GetLength() + 1); + + while (*src != '\0') { + *dest_ptr++ = *src; + if (*src != kPathSeparator) + src++; + else + while (*src == kPathSeparator) + src++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + } // namespace internal } // namespace testing diff --git a/src/gtest.cc b/src/gtest.cc index 8d2d2a2a..f8c11997 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -134,6 +134,10 @@ static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; +// The text used in failure messages to indicate the start of the +// stack trace. +static const char kStackTraceMarker[] = "\nStack trace:\n"; + GTEST_DEFINE_bool( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), @@ -200,6 +204,14 @@ GTEST_DEFINE_bool( "True iff " GTEST_NAME " should include internal stack frames when " "printing test failure stack traces."); +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + namespace internal { // GTestIsInitialized() returns true iff the user has initialized @@ -2923,13 +2935,28 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str, // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object -// -// <-- individual assertion failures -// +// ... +// ... +// ... +// <-- individual assertion failures // // // +namespace internal { + +// Formats the given time in milliseconds as seconds. The returned +// C-string is owned by this function and cannot be released by the +// caller. Calling the function again invalidates the previous +// result. +const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) { + static String str; + str = (Message() << (ms/1000.0)).GetString(); + return str.c_str(); +} + +} // namespace internal + // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, @@ -2942,7 +2969,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, "classname=\"%s\"%s", EscapeXmlAttribute(test_info->name()).c_str(), test_info->should_run() ? "run" : "notrun", - internal::StreamableToString(result->elapsed_time()).c_str(), + internal::FormatTimeInMillisAsSeconds(result->elapsed_time()), EscapeXmlAttribute(test_case_name).c_str(), TestPropertiesAsXmlAttributes(result).c_str()); @@ -2958,8 +2985,9 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, if (++failures == 1) fprintf(out, ">\n"); fprintf(out, - " \n", - EscapeXmlAttribute(message.c_str()).c_str()); + " " + "\n", + EscapeXmlAttribute(part.summary()).c_str(), message.c_str()); } } @@ -2981,7 +3009,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, test_case->disabled_test_count()); fprintf(out, "errors=\"0\" time=\"%s\">\n", - internal::StreamableToString(test_case->elapsed_time()).c_str()); + internal::FormatTimeInMillisAsSeconds(test_case->elapsed_time())); for (const internal::ListNode* info_node = test_case->test_info_list().Head(); info_node != NULL; @@ -3002,7 +3030,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, impl->total_test_count(), impl->failed_test_count(), impl->disabled_test_count(), - internal::StreamableToString(impl->elapsed_time()).c_str()); + internal::FormatTimeInMillisAsSeconds(impl->elapsed_time())); fprintf(out, "name=\"AllTests\">\n"); for (const internal::ListNode* case_node = impl->test_cases()->Head(); @@ -3153,7 +3181,7 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { - msg << "\nStack trace:\n" << os_stack_trace; + msg << kStackTraceMarker << os_stack_trace; } const TestPartResult result = -- cgit v1.2.3