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.
This commit is contained in:
parent
e79c3ccb73
commit
64cdcb69b2
|
@ -55,6 +55,7 @@ class TestPartResult {
|
||||||
: type_(type),
|
: type_(type),
|
||||||
file_name_(file_name),
|
file_name_(file_name),
|
||||||
line_number_(line_number),
|
line_number_(line_number),
|
||||||
|
summary_(ExtractSummary(message)),
|
||||||
message_(message) {
|
message_(message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +70,9 @@ class TestPartResult {
|
||||||
// or -1 if it's unknown.
|
// or -1 if it's unknown.
|
||||||
int line_number() const { return line_number_; }
|
int line_number() const { return line_number_; }
|
||||||
|
|
||||||
|
// Gets the summary of the failure message.
|
||||||
|
const char* summary() const { return summary_.c_str(); }
|
||||||
|
|
||||||
// Gets the message associated with the test part.
|
// Gets the message associated with the test part.
|
||||||
const char* message() const { return message_.c_str(); }
|
const char* message() const { return message_.c_str(); }
|
||||||
|
|
||||||
|
@ -86,12 +90,17 @@ class TestPartResult {
|
||||||
private:
|
private:
|
||||||
TestPartResultType type_;
|
TestPartResultType type_;
|
||||||
|
|
||||||
|
// Gets the summary of the failure message by omitting the stack
|
||||||
|
// trace in it.
|
||||||
|
static internal::String ExtractSummary(const char* message);
|
||||||
|
|
||||||
// The name of the source file where the test part took place, or
|
// The name of the source file where the test part took place, or
|
||||||
// NULL if the source file is unknown.
|
// NULL if the source file is unknown.
|
||||||
internal::String file_name_;
|
internal::String file_name_;
|
||||||
// The line in the source file where the test part took place, or -1
|
// The line in the source file where the test part took place, or -1
|
||||||
// if the line number is unknown.
|
// if the line number is unknown.
|
||||||
int line_number_;
|
int line_number_;
|
||||||
|
internal::String summary_; // The test failure summary.
|
||||||
internal::String message_; // The test failure message.
|
internal::String message_; // The test failure message.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,19 @@ class FilePath {
|
||||||
public:
|
public:
|
||||||
FilePath() : pathname_("") { }
|
FilePath() : pathname_("") { }
|
||||||
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
|
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
|
||||||
explicit FilePath(const char* pathname) : pathname_(pathname) { }
|
|
||||||
explicit FilePath(const String& pathname) : pathname_(pathname) { }
|
explicit FilePath(const char* pathname) : pathname_(pathname) {
|
||||||
|
Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit FilePath(const String& pathname) : pathname_(pathname) {
|
||||||
|
Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath& operator=(const FilePath& rhs) {
|
||||||
|
Set(rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void Set(const FilePath& rhs) {
|
void Set(const FilePath& rhs) {
|
||||||
pathname_ = rhs.pathname_;
|
pathname_ = rhs.pathname_;
|
||||||
|
@ -149,11 +160,30 @@ class FilePath {
|
||||||
// This does NOT check that a directory (or file) actually exists.
|
// This does NOT check that a directory (or file) actually exists.
|
||||||
bool IsDirectory() const;
|
bool IsDirectory() const;
|
||||||
|
|
||||||
private:
|
// Returns true if pathname describes a root directory. (Windows has one
|
||||||
String pathname_;
|
// root directory per disk drive.)
|
||||||
|
bool IsRootDirectory() const;
|
||||||
|
|
||||||
// Don't implement operator= because it is banned by the style guide.
|
private:
|
||||||
FilePath& operator=(const FilePath& rhs);
|
// Replaces multiple consecutive separators with a single separator.
|
||||||
|
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
|
||||||
|
// redundancies that might be in a pathname involving "." or "..".
|
||||||
|
//
|
||||||
|
// A pathname with multiple consecutive separators may occur either through
|
||||||
|
// user error or as a result of some scripts or APIs that generate a pathname
|
||||||
|
// with a trailing separator. On other platforms the same API or script
|
||||||
|
// may NOT generate a pathname with a trailing "/". Then elsewhere that
|
||||||
|
// pathname may have another "/" and pathname components added to it,
|
||||||
|
// without checking for the separator already being there.
|
||||||
|
// The script language and operating system may allow paths like "foo//bar"
|
||||||
|
// but some of the functions in FilePath will not handle that correctly. In
|
||||||
|
// particular, RemoveTrailingPathSeparator() only removes one separator, and
|
||||||
|
// it is called in CreateDirectoriesRecursively() assuming that it will change
|
||||||
|
// a pathname from directory syntax (trailing separator) to filename syntax.
|
||||||
|
|
||||||
|
void Normalize();
|
||||||
|
|
||||||
|
String pathname_;
|
||||||
}; // class FilePath
|
}; // class FilePath
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
@ -55,6 +55,9 @@
|
||||||
// is/isn't available (some systems define
|
// is/isn't available (some systems define
|
||||||
// ::wstring, which is different to std::wstring).
|
// ::wstring, which is different to std::wstring).
|
||||||
// Leave it undefined to let Google Test define it.
|
// Leave it undefined to let Google Test define it.
|
||||||
|
// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
|
||||||
|
// enabled. Leave it undefined to let Google
|
||||||
|
// Test define it.
|
||||||
|
|
||||||
// This header defines the following utilities:
|
// This header defines the following utilities:
|
||||||
//
|
//
|
||||||
|
@ -135,6 +138,13 @@
|
||||||
#define GTEST_FLAG_PREFIX "gtest_"
|
#define GTEST_FLAG_PREFIX "gtest_"
|
||||||
#define GTEST_FLAG_PREFIX_UPPER "GTEST_"
|
#define GTEST_FLAG_PREFIX_UPPER "GTEST_"
|
||||||
|
|
||||||
|
// Determines the version of gcc that is used to compile this.
|
||||||
|
#ifdef __GNUC__
|
||||||
|
// 40302 means version 4.3.2.
|
||||||
|
#define GTEST_GCC_VER_ \
|
||||||
|
(__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
|
||||||
|
#endif // __GNUC__
|
||||||
|
|
||||||
// Determines the platform on which Google Test is compiled.
|
// Determines the platform on which Google Test is compiled.
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
#define GTEST_OS_CYGWIN
|
#define GTEST_OS_CYGWIN
|
||||||
|
@ -215,6 +225,42 @@
|
||||||
#include <strstream> // NOLINT
|
#include <strstream> // NOLINT
|
||||||
#endif // GTEST_HAS_STD_STRING
|
#endif // GTEST_HAS_STD_STRING
|
||||||
|
|
||||||
|
// Determines whether RTTI is available.
|
||||||
|
#ifndef GTEST_HAS_RTTI
|
||||||
|
// The user didn't tell us whether RTTI is enabled, so we need to
|
||||||
|
// figure it out.
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled.
|
||||||
|
#define GTEST_HAS_RTTI 1
|
||||||
|
#else
|
||||||
|
#define GTEST_HAS_RTTI 0
|
||||||
|
#endif // _CPPRTTI
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
|
||||||
|
// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
|
||||||
|
#if GTEST_GCC_VER_ >= 40302
|
||||||
|
#ifdef __GXX_RTTI
|
||||||
|
#define GTEST_HAS_RTTI 1
|
||||||
|
#else
|
||||||
|
#define GTEST_HAS_RTTI 0
|
||||||
|
#endif // __GXX_RTTI
|
||||||
|
#else
|
||||||
|
// For gcc versions smaller than 4.3.2, we assume RTTI is enabled.
|
||||||
|
#define GTEST_HAS_RTTI 1
|
||||||
|
#endif // GTEST_GCC_VER >= 40302
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Unknown compiler - assume RTTI is enabled.
|
||||||
|
#define GTEST_HAS_RTTI 1
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // GTEST_HAS_RTTI
|
||||||
|
|
||||||
// Determines whether to support death tests.
|
// Determines whether to support death tests.
|
||||||
#if GTEST_HAS_STD_STRING && defined(GTEST_OS_LINUX)
|
#if GTEST_HAS_STD_STRING && defined(GTEST_OS_LINUX)
|
||||||
#define GTEST_HAS_DEATH_TEST
|
#define GTEST_HAS_DEATH_TEST
|
||||||
|
@ -284,13 +330,11 @@
|
||||||
// following the argument list:
|
// following the argument list:
|
||||||
//
|
//
|
||||||
// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT;
|
// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT;
|
||||||
#if defined(__GNUC__) \
|
#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
|
||||||
&& (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \
|
|
||||||
&& !defined(COMPILER_ICC)
|
|
||||||
#define GTEST_MUST_USE_RESULT __attribute__ ((warn_unused_result))
|
#define GTEST_MUST_USE_RESULT __attribute__ ((warn_unused_result))
|
||||||
#else
|
#else
|
||||||
#define GTEST_MUST_USE_RESULT
|
#define GTEST_MUST_USE_RESULT
|
||||||
#endif // (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,8 @@ struct AssertTypeEq<T, T> {
|
||||||
// GetTypeName<T>() returns a human-readable name of type T.
|
// GetTypeName<T>() returns a human-readable name of type T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
String GetTypeName() {
|
String GetTypeName() {
|
||||||
|
#if GTEST_HAS_RTTI
|
||||||
|
|
||||||
const char* const name = typeid(T).name();
|
const char* const name = typeid(T).name();
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
@ -83,6 +85,10 @@ String GetTypeName() {
|
||||||
#else
|
#else
|
||||||
return name;
|
return name;
|
||||||
#endif // __GNUC__
|
#endif // __GNUC__
|
||||||
|
|
||||||
|
#else
|
||||||
|
return "<type>";
|
||||||
|
#endif // GTEST_HAS_RTTI
|
||||||
}
|
}
|
||||||
|
|
||||||
// A unique type used as the default value for the arguments of class
|
// A unique type used as the default value for the arguments of class
|
||||||
|
|
|
@ -71,6 +71,8 @@ struct AssertTypeEq<T, T> {
|
||||||
// GetTypeName<T>() returns a human-readable name of type T.
|
// GetTypeName<T>() returns a human-readable name of type T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
String GetTypeName() {
|
String GetTypeName() {
|
||||||
|
#if GTEST_HAS_RTTI
|
||||||
|
|
||||||
const char* const name = typeid(T).name();
|
const char* const name = typeid(T).name();
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
@ -83,6 +85,10 @@ String GetTypeName() {
|
||||||
#else
|
#else
|
||||||
return name;
|
return name;
|
||||||
#endif // __GNUC__
|
#endif // __GNUC__
|
||||||
|
|
||||||
|
#else
|
||||||
|
return "<type>";
|
||||||
|
#endif // GTEST_HAS_RTTI
|
||||||
}
|
}
|
||||||
|
|
||||||
// A unique type used as the default value for the arguments of class
|
// A unique type used as the default value for the arguments of class
|
||||||
|
|
|
@ -416,6 +416,7 @@ bool ForkingDeathTest::Passed(bool status_ok) {
|
||||||
<< " " << ExitSummary(status_) << "\n";
|
<< " " << ExitSummary(status_) << "\n";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case IN_PROGRESS:
|
||||||
default:
|
default:
|
||||||
GTEST_LOG(FATAL,
|
GTEST_LOG(FATAL,
|
||||||
"DeathTest::Passed somehow called before conclusion of test");
|
"DeathTest::Passed somehow called before conclusion of test");
|
||||||
|
|
|
@ -161,10 +161,13 @@ bool FilePath::FileOrDirectoryExists() const {
|
||||||
// that exists.
|
// that exists.
|
||||||
bool FilePath::DirectoryExists() const {
|
bool FilePath::DirectoryExists() const {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
#ifdef _WIN32
|
#ifdef GTEST_OS_WINDOWS
|
||||||
FilePath removed_sep(this->RemoveTrailingPathSeparator());
|
// 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
|
#ifdef _WIN32_WCE
|
||||||
LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
|
LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
|
||||||
const DWORD attributes = GetFileAttributes(unicode);
|
const DWORD attributes = GetFileAttributes(unicode);
|
||||||
delete [] unicode;
|
delete [] unicode;
|
||||||
if ((attributes != kInvalidFileAttributes) &&
|
if ((attributes != kInvalidFileAttributes) &&
|
||||||
|
@ -173,17 +176,32 @@ bool FilePath::DirectoryExists() const {
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
struct _stat file_stat = {};
|
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;
|
(_S_IFDIR & file_stat.st_mode) != 0;
|
||||||
#endif // _WIN32_WCE
|
#endif // _WIN32_WCE
|
||||||
#else
|
#else
|
||||||
struct stat file_stat = {};
|
struct stat file_stat = {};
|
||||||
result = stat(pathname_.c_str(), &file_stat) == 0 &&
|
result = stat(pathname_.c_str(), &file_stat) == 0 &&
|
||||||
S_ISDIR(file_stat.st_mode);
|
S_ISDIR(file_stat.st_mode);
|
||||||
#endif // _WIN32
|
#endif // GTEST_OS_WINDOWS
|
||||||
return result;
|
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
|
// Returns a pathname for a file that does not currently exist. The pathname
|
||||||
// will be directory/base_name.extension or
|
// will be directory/base_name.extension or
|
||||||
// directory/base_name_<number>.extension if directory/base_name.extension
|
// directory/base_name_<number>.extension if directory/base_name.extension
|
||||||
|
@ -258,5 +276,31 @@ FilePath FilePath::RemoveTrailingPathSeparator() const {
|
||||||
: *this;
|
: *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 internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
46
src/gtest.cc
46
src/gtest.cc
|
@ -134,6 +134,10 @@ static const char kUniversalFilter[] = "*";
|
||||||
// The default output file for XML output.
|
// The default output file for XML output.
|
||||||
static const char kDefaultOutputFile[] = "test_detail.xml";
|
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(
|
GTEST_DEFINE_bool(
|
||||||
break_on_failure,
|
break_on_failure,
|
||||||
internal::BoolFromGTestEnv("break_on_failure", false),
|
internal::BoolFromGTestEnv("break_on_failure", false),
|
||||||
|
@ -200,6 +204,14 @@ GTEST_DEFINE_bool(
|
||||||
"True iff " GTEST_NAME " should include internal stack frames when "
|
"True iff " GTEST_NAME " should include internal stack frames when "
|
||||||
"printing test failure stack traces.");
|
"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 {
|
namespace internal {
|
||||||
|
|
||||||
// GTestIsInitialized() returns true iff the user has initialized
|
// 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="AllTests"> <-- corresponds to a UnitTest object
|
||||||
// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
|
// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
|
||||||
// <testcase name="test-name"> <-- corresponds to a TestInfo object
|
// <testcase name="test-name"> <-- corresponds to a TestInfo object
|
||||||
// <failure message="..." />
|
// <failure message="...">...</failure>
|
||||||
// <failure message="..." /> <-- individual assertion failures
|
// <failure message="...">...</failure>
|
||||||
// <failure message="..." />
|
// <failure message="...">...</failure>
|
||||||
|
// <-- individual assertion failures
|
||||||
// </testcase>
|
// </testcase>
|
||||||
// </testsuite>
|
// </testsuite>
|
||||||
// </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.
|
// Prints an XML representation of a TestInfo object.
|
||||||
// TODO(wan): There is also value in printing properties with the plain printer.
|
// TODO(wan): There is also value in printing properties with the plain printer.
|
||||||
void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
|
void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
|
||||||
|
@ -2942,7 +2969,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
|
||||||
"classname=\"%s\"%s",
|
"classname=\"%s\"%s",
|
||||||
EscapeXmlAttribute(test_info->name()).c_str(),
|
EscapeXmlAttribute(test_info->name()).c_str(),
|
||||||
test_info->should_run() ? "run" : "notrun",
|
test_info->should_run() ? "run" : "notrun",
|
||||||
internal::StreamableToString(result->elapsed_time()).c_str(),
|
internal::FormatTimeInMillisAsSeconds(result->elapsed_time()),
|
||||||
EscapeXmlAttribute(test_case_name).c_str(),
|
EscapeXmlAttribute(test_case_name).c_str(),
|
||||||
TestPropertiesAsXmlAttributes(result).c_str());
|
TestPropertiesAsXmlAttributes(result).c_str());
|
||||||
|
|
||||||
|
@ -2958,8 +2985,9 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
|
||||||
if (++failures == 1)
|
if (++failures == 1)
|
||||||
fprintf(out, ">\n");
|
fprintf(out, ">\n");
|
||||||
fprintf(out,
|
fprintf(out,
|
||||||
" <failure message=\"%s\" type=\"\"/>\n",
|
" <failure message=\"%s\" type=\"\"><![CDATA[%s]]>"
|
||||||
EscapeXmlAttribute(message.c_str()).c_str());
|
"</failure>\n",
|
||||||
|
EscapeXmlAttribute(part.summary()).c_str(), message.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2981,7 +3009,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
|
||||||
test_case->disabled_test_count());
|
test_case->disabled_test_count());
|
||||||
fprintf(out,
|
fprintf(out,
|
||||||
"errors=\"0\" time=\"%s\">\n",
|
"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 =
|
for (const internal::ListNode<TestInfo*>* info_node =
|
||||||
test_case->test_info_list().Head();
|
test_case->test_info_list().Head();
|
||||||
info_node != NULL;
|
info_node != NULL;
|
||||||
|
@ -3002,7 +3030,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
|
||||||
impl->total_test_count(),
|
impl->total_test_count(),
|
||||||
impl->failed_test_count(),
|
impl->failed_test_count(),
|
||||||
impl->disabled_test_count(),
|
impl->disabled_test_count(),
|
||||||
internal::StreamableToString(impl->elapsed_time()).c_str());
|
internal::FormatTimeInMillisAsSeconds(impl->elapsed_time()));
|
||||||
fprintf(out, "name=\"AllTests\">\n");
|
fprintf(out, "name=\"AllTests\">\n");
|
||||||
for (const internal::ListNode<TestCase*>* case_node =
|
for (const internal::ListNode<TestCase*>* case_node =
|
||||||
impl->test_cases()->Head();
|
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()) {
|
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 =
|
const TestPartResult result =
|
||||||
|
|
|
@ -123,8 +123,6 @@ TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath) {
|
||||||
EXPECT_FALSE(FilePath("a\\b\\").IsEmpty());
|
EXPECT_FALSE(FilePath("a\\b\\").IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilePath's functions used by UnitTestOptions::GetOutputFile.
|
|
||||||
|
|
||||||
// RemoveDirectoryName "" -> ""
|
// RemoveDirectoryName "" -> ""
|
||||||
TEST(RemoveDirectoryNameTest, WhenEmptyName) {
|
TEST(RemoveDirectoryNameTest, WhenEmptyName) {
|
||||||
EXPECT_STREQ("", FilePath("").RemoveDirectoryName().c_str());
|
EXPECT_STREQ("", FilePath("").RemoveDirectoryName().c_str());
|
||||||
|
@ -257,6 +255,110 @@ TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) {
|
||||||
FilePath("foo" PATH_SEP "bar").RemoveTrailingPathSeparator().c_str());
|
FilePath("foo" PATH_SEP "bar").RemoveTrailingPathSeparator().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DirectoryTest, RootDirectoryExists) {
|
||||||
|
#ifdef GTEST_OS_WINDOWS // We are on Windows.
|
||||||
|
char current_drive[_MAX_PATH];
|
||||||
|
current_drive[0] = _getdrive() + 'A' - 1;
|
||||||
|
current_drive[1] = ':';
|
||||||
|
current_drive[2] = '\\';
|
||||||
|
current_drive[3] = '\0';
|
||||||
|
EXPECT_TRUE(FilePath(current_drive).DirectoryExists());
|
||||||
|
#else
|
||||||
|
EXPECT_TRUE(FilePath("/").DirectoryExists());
|
||||||
|
#endif // GTEST_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GTEST_OS_WINDOWS
|
||||||
|
TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) {
|
||||||
|
const int saved_drive_ = _getdrive();
|
||||||
|
// Find a drive that doesn't exist. Start with 'Z' to avoid common ones.
|
||||||
|
for (char drive = 'Z'; drive >= 'A'; drive--)
|
||||||
|
if (_chdrive(drive - 'A' + 1) == -1) {
|
||||||
|
char non_drive[_MAX_PATH];
|
||||||
|
non_drive[0] = drive;
|
||||||
|
non_drive[1] = ':';
|
||||||
|
non_drive[2] = '\\';
|
||||||
|
non_drive[3] = '\0';
|
||||||
|
EXPECT_FALSE(FilePath(non_drive).DirectoryExists());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_chdrive(saved_drive_);
|
||||||
|
}
|
||||||
|
#endif // GTEST_OS_WINDOWS
|
||||||
|
|
||||||
|
TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) {
|
||||||
|
EXPECT_FALSE(FilePath("").DirectoryExists());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DirectoryTest, CurrentDirectoryExists) {
|
||||||
|
#ifdef GTEST_OS_WINDOWS // We are on Windows.
|
||||||
|
#ifndef _WIN32_CE // Windows CE doesn't have a current directory.
|
||||||
|
EXPECT_TRUE(FilePath(".").DirectoryExists());
|
||||||
|
EXPECT_TRUE(FilePath(".\\").DirectoryExists());
|
||||||
|
#endif // _WIN32_CE
|
||||||
|
#else
|
||||||
|
EXPECT_TRUE(FilePath(".").DirectoryExists());
|
||||||
|
EXPECT_TRUE(FilePath("./").DirectoryExists());
|
||||||
|
#endif // GTEST_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NormalizeTest, NullStringsEqualEmptyDirectory) {
|
||||||
|
EXPECT_STREQ("", FilePath(NULL).c_str());
|
||||||
|
EXPECT_STREQ("", FilePath(String(NULL)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// "foo/bar" == foo//bar" == "foo///bar"
|
||||||
|
TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) {
|
||||||
|
EXPECT_STREQ("foo" PATH_SEP "bar",
|
||||||
|
FilePath("foo" PATH_SEP "bar").c_str());
|
||||||
|
EXPECT_STREQ("foo" PATH_SEP "bar",
|
||||||
|
FilePath("foo" PATH_SEP PATH_SEP "bar").c_str());
|
||||||
|
EXPECT_STREQ("foo" PATH_SEP "bar",
|
||||||
|
FilePath("foo" PATH_SEP PATH_SEP PATH_SEP "bar").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// "/bar" == //bar" == "///bar"
|
||||||
|
TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) {
|
||||||
|
EXPECT_STREQ(PATH_SEP "bar",
|
||||||
|
FilePath(PATH_SEP "bar").c_str());
|
||||||
|
EXPECT_STREQ(PATH_SEP "bar",
|
||||||
|
FilePath(PATH_SEP PATH_SEP "bar").c_str());
|
||||||
|
EXPECT_STREQ(PATH_SEP "bar",
|
||||||
|
FilePath(PATH_SEP PATH_SEP PATH_SEP "bar").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// "foo/" == foo//" == "foo///"
|
||||||
|
TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) {
|
||||||
|
EXPECT_STREQ("foo" PATH_SEP,
|
||||||
|
FilePath("foo" PATH_SEP).c_str());
|
||||||
|
EXPECT_STREQ("foo" PATH_SEP,
|
||||||
|
FilePath("foo" PATH_SEP PATH_SEP).c_str());
|
||||||
|
EXPECT_STREQ("foo" PATH_SEP,
|
||||||
|
FilePath("foo" PATH_SEP PATH_SEP PATH_SEP).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) {
|
||||||
|
FilePath default_path;
|
||||||
|
FilePath non_default_path("path");
|
||||||
|
non_default_path = default_path;
|
||||||
|
EXPECT_STREQ("", non_default_path.c_str());
|
||||||
|
EXPECT_STREQ("", default_path.c_str()); // RHS var is unchanged.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) {
|
||||||
|
FilePath non_default_path("path");
|
||||||
|
FilePath default_path;
|
||||||
|
default_path = non_default_path;
|
||||||
|
EXPECT_STREQ("path", default_path.c_str());
|
||||||
|
EXPECT_STREQ("path", non_default_path.c_str()); // RHS var is unchanged.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AssignmentOperatorTest, ConstAssignedToNonConst) {
|
||||||
|
const FilePath const_default_path("const_path");
|
||||||
|
FilePath non_default_path("path");
|
||||||
|
non_default_path = const_default_path;
|
||||||
|
EXPECT_STREQ("const_path", non_default_path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
class DirectoryCreationTest : public Test {
|
class DirectoryCreationTest : public Test {
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -58,10 +58,12 @@
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
const char* FormatTimeInMillisAsSeconds(TimeInMillis ms);
|
||||||
bool ParseInt32Flag(const char* str, const char* flag, Int32* value);
|
bool ParseInt32Flag(const char* str, const char* flag, Int32* value);
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
|
using testing::internal::FormatTimeInMillisAsSeconds;
|
||||||
using testing::internal::ParseInt32Flag;
|
using testing::internal::ParseInt32Flag;
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
@ -118,6 +120,28 @@ using testing::internal::WideStringToUtf8;
|
||||||
// This line tests that we can define tests in an unnamed namespace.
|
// This line tests that we can define tests in an unnamed namespace.
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Tests FormatTimeInMillisAsSeconds().
|
||||||
|
|
||||||
|
TEST(FormatTimeInMillisAsSecondsTest, FormatsZero) {
|
||||||
|
EXPECT_STREQ("0", FormatTimeInMillisAsSeconds(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatTimeInMillisAsSecondsTest, FormatsPositiveNumber) {
|
||||||
|
EXPECT_STREQ("0.003", FormatTimeInMillisAsSeconds(3));
|
||||||
|
EXPECT_STREQ("0.01", FormatTimeInMillisAsSeconds(10));
|
||||||
|
EXPECT_STREQ("0.2", FormatTimeInMillisAsSeconds(200));
|
||||||
|
EXPECT_STREQ("1.2", FormatTimeInMillisAsSeconds(1200));
|
||||||
|
EXPECT_STREQ("3", FormatTimeInMillisAsSeconds(3000));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber) {
|
||||||
|
EXPECT_STREQ("-0.003", FormatTimeInMillisAsSeconds(-3));
|
||||||
|
EXPECT_STREQ("-0.01", FormatTimeInMillisAsSeconds(-10));
|
||||||
|
EXPECT_STREQ("-0.2", FormatTimeInMillisAsSeconds(-200));
|
||||||
|
EXPECT_STREQ("-1.2", FormatTimeInMillisAsSeconds(-1200));
|
||||||
|
EXPECT_STREQ("-3", FormatTimeInMillisAsSeconds(-3000));
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef __SYMBIAN32__
|
#ifndef __SYMBIAN32__
|
||||||
// NULL testing does not work with Symbian compilers.
|
// NULL testing does not work with Symbian compilers.
|
||||||
|
|
||||||
|
|
|
@ -122,8 +122,8 @@ class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase):
|
||||||
actual = minidom.parse(output_file1)
|
actual = minidom.parse(output_file1)
|
||||||
else:
|
else:
|
||||||
actual = minidom.parse(output_file2)
|
actual = minidom.parse(output_file2)
|
||||||
self._NormalizeXml(actual.documentElement)
|
self.NormalizeXml(actual.documentElement)
|
||||||
self._AssertEquivalentElements(expected.documentElement,
|
self.AssertEquivalentNodes(expected.documentElement,
|
||||||
actual.documentElement)
|
actual.documentElement)
|
||||||
expected.unlink()
|
expected.unlink()
|
||||||
actual.unlink()
|
actual.unlink()
|
||||||
|
|
|
@ -54,14 +54,20 @@ EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<testsuite name="FailedTest" tests="1" failures="1" disabled="0" errors="0" time="*">
|
<testsuite name="FailedTest" tests="1" failures="1" disabled="0" errors="0" time="*">
|
||||||
<testcase name="Fails" status="run" time="*" classname="FailedTest">
|
<testcase name="Fails" status="run" time="*" classname="FailedTest">
|
||||||
<failure message="gtest_xml_output_unittest_.cc:*
Value of: 2
Expected: 1" type=""/>
|
<failure message="Value of: 2
Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||||
|
Value of: 2
|
||||||
|
Expected: 1]]></failure>
|
||||||
</testcase>
|
</testcase>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<testsuite name="MixedResultTest" tests="3" failures="1" disabled="1" errors="0" time="*">
|
<testsuite name="MixedResultTest" tests="3" failures="1" disabled="1" errors="0" time="*">
|
||||||
<testcase name="Succeeds" status="run" time="*" classname="MixedResultTest"/>
|
<testcase name="Succeeds" status="run" time="*" classname="MixedResultTest"/>
|
||||||
<testcase name="Fails" status="run" time="*" classname="MixedResultTest">
|
<testcase name="Fails" status="run" time="*" classname="MixedResultTest">
|
||||||
<failure message="gtest_xml_output_unittest_.cc:*
Value of: 2
Expected: 1" type=""/>
|
<failure message="Value of: 2
Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||||
<failure message="gtest_xml_output_unittest_.cc:*
Value of: 3
Expected: 2" type=""/>
|
Value of: 2
|
||||||
|
Expected: 1]]></failure>
|
||||||
|
<failure message="Value of: 3
Expected: 2" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||||
|
Value of: 3
|
||||||
|
Expected: 2]]></failure>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/>
|
<testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
@ -160,8 +166,8 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
|
||||||
|
|
||||||
expected = minidom.parseString(expected_xml)
|
expected = minidom.parseString(expected_xml)
|
||||||
actual = minidom.parse(xml_path)
|
actual = minidom.parse(xml_path)
|
||||||
self._NormalizeXml(actual.documentElement)
|
self.NormalizeXml(actual.documentElement)
|
||||||
self._AssertEquivalentElements(expected.documentElement,
|
self.AssertEquivalentNodes(expected.documentElement,
|
||||||
actual.documentElement)
|
actual.documentElement)
|
||||||
expected.unlink()
|
expected.unlink()
|
||||||
actual .unlink()
|
actual .unlink()
|
||||||
|
@ -169,5 +175,5 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
os.environ['GTEST_STACK_TRACE_DEPTH'] = '0'
|
os.environ['GTEST_STACK_TRACE_DEPTH'] = '1'
|
||||||
gtest_test_utils.Main()
|
gtest_test_utils.Main()
|
||||||
|
|
|
@ -47,27 +47,35 @@ class GTestXMLTestCase(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def _AssertEquivalentElements(self, expected_element, actual_element):
|
def AssertEquivalentNodes(self, expected_node, actual_node):
|
||||||
"""
|
"""
|
||||||
Asserts that actual_element (a DOM element object) is equivalent to
|
Asserts that actual_node (a DOM node object) is equivalent to
|
||||||
expected_element (another DOM element object), in that it meets all
|
expected_node (another DOM node object), in that either both of
|
||||||
of the following conditions:
|
them are CDATA nodes and have the same value, or both are DOM
|
||||||
* It has the same tag name as expected_element.
|
elements and actual_node meets all of the following conditions:
|
||||||
* It has the same set of attributes as expected_element, each with
|
|
||||||
the same value as the corresponding attribute of expected_element.
|
|
||||||
An exception is any attribute named "time", which need only be
|
|
||||||
convertible to a long integer.
|
|
||||||
* Each child element is equivalent to a child element of
|
|
||||||
expected_element. Child elements are matched according to an
|
|
||||||
attribute that varies depending on the element; "name" for
|
|
||||||
<testsuite> and <testcase> elements, "message" for <failure>
|
|
||||||
elements. This matching is necessary because child elements are
|
|
||||||
not guaranteed to be ordered in any particular way.
|
|
||||||
"""
|
|
||||||
self.assertEquals(expected_element.tagName, actual_element.tagName)
|
|
||||||
|
|
||||||
expected_attributes = expected_element.attributes
|
* It has the same tag name as expected_node.
|
||||||
actual_attributes = actual_element .attributes
|
* It has the same set of attributes as expected_node, each with
|
||||||
|
the same value as the corresponding attribute of expected_node.
|
||||||
|
An exception is any attribute named "time", which needs only be
|
||||||
|
convertible to a floating-point number.
|
||||||
|
* It has an equivalent set of child nodes (including elements and
|
||||||
|
CDATA sections) as expected_node. Note that we ignore the
|
||||||
|
order of the children as they are not guaranteed to be in any
|
||||||
|
particular order.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if expected_node.nodeType == Node.CDATA_SECTION_NODE:
|
||||||
|
self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType)
|
||||||
|
self.assertEquals(expected_node.nodeValue, actual_node.nodeValue)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType)
|
||||||
|
self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType)
|
||||||
|
self.assertEquals(expected_node.tagName, actual_node.tagName)
|
||||||
|
|
||||||
|
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)
|
||||||
for i in range(expected_attributes.length):
|
for i in range(expected_attributes.length):
|
||||||
expected_attr = expected_attributes.item(i)
|
expected_attr = expected_attributes.item(i)
|
||||||
|
@ -75,13 +83,13 @@ class GTestXMLTestCase(unittest.TestCase):
|
||||||
self.assert_(actual_attr is not None)
|
self.assert_(actual_attr is not None)
|
||||||
self.assertEquals(expected_attr.value, actual_attr.value)
|
self.assertEquals(expected_attr.value, actual_attr.value)
|
||||||
|
|
||||||
expected_child = self._GetChildElements(expected_element)
|
expected_children = self._GetChildren(expected_node)
|
||||||
actual_child = self._GetChildElements(actual_element)
|
actual_children = self._GetChildren(actual_node)
|
||||||
self.assertEquals(len(expected_child), len(actual_child))
|
self.assertEquals(len(expected_children), len(actual_children))
|
||||||
for child_id, element in expected_child.iteritems():
|
for child_id, child in expected_children.iteritems():
|
||||||
self.assert_(child_id in actual_child,
|
self.assert_(child_id in actual_children,
|
||||||
'<%s> is not in <%s>' % (child_id, actual_child))
|
'<%s> is not in <%s>' % (child_id, actual_children))
|
||||||
self._AssertEquivalentElements(element, actual_child[child_id])
|
self.AssertEquivalentNodes(child, actual_children[child_id])
|
||||||
|
|
||||||
identifying_attribute = {
|
identifying_attribute = {
|
||||||
"testsuite": "name",
|
"testsuite": "name",
|
||||||
|
@ -89,18 +97,20 @@ class GTestXMLTestCase(unittest.TestCase):
|
||||||
"failure": "message",
|
"failure": "message",
|
||||||
}
|
}
|
||||||
|
|
||||||
def _GetChildElements(self, element):
|
def _GetChildren(self, element):
|
||||||
"""
|
"""
|
||||||
Fetches all of the Element type child nodes of element, a DOM
|
Fetches all of the child nodes of element, a DOM Element object.
|
||||||
Element object. Returns them as the values of a dictionary keyed by
|
Returns them as the values of a dictionary keyed by the IDs of the
|
||||||
the value of one of the node's attributes. For <testsuite> and
|
children. For <testsuite> and <testcase> elements, the ID is the
|
||||||
<testcase> elements, the identifying attribute is "name"; for
|
value of their "name" attribute; for <failure> elements, it is the
|
||||||
<failure> elements, it is "message". An exception is raised if
|
value of the "message" attribute; for CDATA section node, it is
|
||||||
any element other than the above three is encountered, if two
|
"detail". An exception is raised if any element other than the
|
||||||
child elements with the same identifying attributes are encountered,
|
above four is encountered, if two child elements with the same
|
||||||
or if any other type of node is encountered, other than Text nodes
|
identifying attributes are encountered, or if any other type of
|
||||||
containing only whitespace.
|
node is encountered, other than Text nodes containing only
|
||||||
|
whitespace.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
children = {}
|
children = {}
|
||||||
for child in element.childNodes:
|
for child in element.childNodes:
|
||||||
if child.nodeType == Node.ELEMENT_NODE:
|
if child.nodeType == Node.ELEMENT_NODE:
|
||||||
|
@ -111,11 +121,14 @@ class GTestXMLTestCase(unittest.TestCase):
|
||||||
children[childID] = child
|
children[childID] = child
|
||||||
elif child.nodeType == Node.TEXT_NODE:
|
elif child.nodeType == Node.TEXT_NODE:
|
||||||
self.assert_(child.nodeValue.isspace())
|
self.assert_(child.nodeValue.isspace())
|
||||||
|
elif child.nodeType == Node.CDATA_SECTION_NODE:
|
||||||
|
self.assert_("detail" not in children)
|
||||||
|
children["detail"] = child
|
||||||
else:
|
else:
|
||||||
self.fail("Encountered unexpected node type %d" % child.nodeType)
|
self.fail("Encountered unexpected node type %d" % child.nodeType)
|
||||||
return children
|
return children
|
||||||
|
|
||||||
def _NormalizeXml(self, element):
|
def NormalizeXml(self, element):
|
||||||
"""
|
"""
|
||||||
Normalizes Google Test's XML output to eliminate references to transient
|
Normalizes Google Test's XML output to eliminate references to transient
|
||||||
information that may change from run to run.
|
information that may change from run to run.
|
||||||
|
@ -126,13 +139,20 @@ class GTestXMLTestCase(unittest.TestCase):
|
||||||
* The line number reported in the first line of the "message"
|
* The line number reported in the first line of the "message"
|
||||||
attribute of <failure> elements is replaced with a single asterisk.
|
attribute of <failure> elements is replaced with a single asterisk.
|
||||||
* The directory names in file paths are removed.
|
* The directory names in file paths are removed.
|
||||||
|
* The stack traces are removed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if element.tagName in ("testsuite", "testcase"):
|
if element.tagName in ("testsuite", "testcase"):
|
||||||
time = element.getAttributeNode("time")
|
time = element.getAttributeNode("time")
|
||||||
time.value = re.sub(r"^\d+$", "*", time.value)
|
time.value = re.sub(r"^\d+(\.\d+)?$", "*", time.value)
|
||||||
elif element.tagName == "failure":
|
elif element.tagName == "failure":
|
||||||
message = element.getAttributeNode("message")
|
for child in element.childNodes:
|
||||||
message.value = re.sub(r"^.*/(.*:)\d+\n", "\\1*\n", message.value)
|
if child.nodeType == Node.CDATA_SECTION_NODE:
|
||||||
|
# Removes the source line number.
|
||||||
|
cdata = re.sub(r"^.*/(.*:)\d+\n", "\\1*\n", child.nodeValue)
|
||||||
|
# Removes the actual stack trace.
|
||||||
|
child.nodeValue = re.sub(r"\nStack trace:\n(.|\n)*",
|
||||||
|
"", cdata)
|
||||||
for child in element.childNodes:
|
for child in element.childNodes:
|
||||||
if child.nodeType == Node.ELEMENT_NODE:
|
if child.nodeType == Node.ELEMENT_NODE:
|
||||||
self._NormalizeXml(child)
|
self.NormalizeXml(child)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user