summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorshiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925>2008-09-26 16:08:30 +0000
committershiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925>2008-09-26 16:08:30 +0000
commitf0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5 (patch)
tree68f49941b72ce8f866c4f762cb3043504804800f /src
parentdc8c9fa9f38a6a8fc2b78d8096e8d3f1c969cb7c (diff)
downloadgtest-f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5.tar.gz
gtest-f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5.tar.bz2
gtest-f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5.tar.xz
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. git-svn-id: http://googletest.googlecode.com/svn/trunk@98 861a406c-534a-0410-8894-cb66d6ee9925
Diffstat (limited to 'src')
-rw-r--r--src/gtest-death-test.cc1
-rw-r--r--src/gtest-filepath.cc54
-rw-r--r--src/gtest.cc46
3 files changed, 87 insertions, 14 deletions
diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc
index 971c300..fa80087 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 2a5be8c..dc0d78f 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_<number>.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 8d2d2a2..f8c1199 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,
// <testsuite name="AllTests"> <-- corresponds to a UnitTest object
// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
// <testcase name="test-name"> <-- corresponds to a TestInfo object
-// <failure message="..." />
-// <failure message="..." /> <-- individual assertion failures
-// <failure message="..." />
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <-- individual assertion failures
// </testcase>
// </testsuite>
// </testsuite>
+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,
- " <failure message=\"%s\" type=\"\"/>\n",
- EscapeXmlAttribute(message.c_str()).c_str());
+ " <failure message=\"%s\" type=\"\"><![CDATA[%s]]>"
+ "</failure>\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<TestInfo*>* 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<TestCase*>* 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 =