aboutsummaryrefslogtreecommitdiff
path: root/src/gtest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtest.cc')
-rw-r--r--src/gtest.cc531
1 files changed, 410 insertions, 121 deletions
diff --git a/src/gtest.cc b/src/gtest.cc
index 62b6929..6de53dd 100644
--- a/src/gtest.cc
+++ b/src/gtest.cc
@@ -182,6 +182,10 @@ bool g_help_flag = false;
} // namespace internal
+static const char* GetDefaultFilter() {
+ return kUniversalFilter;
+}
+
GTEST_DEFINE_bool_(
also_run_disabled_tests,
internal::BoolFromGTestEnv("also_run_disabled_tests", false),
@@ -204,11 +208,11 @@ GTEST_DEFINE_string_(
"Whether to use colors in the output. Valid values: yes, no, "
"and auto. 'auto' means to use colors if the output is "
"being sent to a terminal and the TERM environment variable "
- "is set to xterm, xterm-color, xterm-256color, linux or cygwin.");
+ "is set to a terminal type that supports colors.");
GTEST_DEFINE_string_(
filter,
- internal::StringFromGTestEnv("filter", kUniversalFilter),
+ internal::StringFromGTestEnv("filter", GetDefaultFilter()),
"A colon-separated list of glob (not regex) patterns "
"for filtering the tests to run, optionally followed by a "
"'-' and a : separated list of negative patterns (tests to "
@@ -731,11 +735,22 @@ int UnitTestImpl::failed_test_count() const {
return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
}
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTestImpl::reportable_disabled_test_count() const {
+ return SumOverTestCaseList(test_cases_,
+ &TestCase::reportable_disabled_test_count);
+}
+
// Gets the number of disabled tests.
int UnitTestImpl::disabled_test_count() const {
return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
}
+// Gets the number of tests to be printed in the XML report.
+int UnitTestImpl::reportable_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count);
+}
+
// Gets the number of all tests.
int UnitTestImpl::total_test_count() const {
return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
@@ -1716,8 +1731,9 @@ void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
// Adds a test property to the list. If a property with the same key as the
// supplied property is already represented, the value of this test_property
// replaces the old value for that key.
-void TestResult::RecordProperty(const TestProperty& test_property) {
- if (!ValidateTestProperty(test_property)) {
+void TestResult::RecordProperty(const std::string& xml_element,
+ const TestProperty& test_property) {
+ if (!ValidateTestProperty(xml_element, test_property)) {
return;
}
internal::MutexLock lock(&test_properites_mutex_);
@@ -1731,21 +1747,94 @@ void TestResult::RecordProperty(const TestProperty& test_property) {
property_with_matching_key->SetValue(test_property.value());
}
-// Adds a failure if the key is a reserved attribute of Google Test
-// testcase tags. Returns true if the property is valid.
-bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
- const std::string& key = test_property.key();
- if (key == "name" || key == "status" || key == "time" || key == "classname") {
- ADD_FAILURE()
- << "Reserved key used in RecordProperty(): "
- << key
- << " ('name', 'status', 'time', and 'classname' are reserved by "
- << GTEST_NAME_ << ")";
+// The list of reserved attributes used in the <testsuites> element of XML
+// output.
+static const char* const kReservedTestSuitesAttributes[] = {
+ "disabled",
+ "errors",
+ "failures",
+ "name",
+ "random_seed",
+ "tests",
+ "time",
+ "timestamp"
+};
+
+// The list of reserved attributes used in the <testsuite> element of XML
+// output.
+static const char* const kReservedTestSuiteAttributes[] = {
+ "disabled",
+ "errors",
+ "failures",
+ "name",
+ "tests",
+ "time"
+};
+
+// The list of reserved attributes used in the <testcase> element of XML output.
+static const char* const kReservedTestCaseAttributes[] = {
+ "classname",
+ "name",
+ "status",
+ "time",
+ "type_param",
+ "value_param"
+};
+
+template <int kSize>
+std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
+ return std::vector<std::string>(array, array + kSize);
+}
+
+static std::vector<std::string> GetReservedAttributesForElement(
+ const std::string& xml_element) {
+ if (xml_element == "testsuites") {
+ return ArrayAsVector(kReservedTestSuitesAttributes);
+ } else if (xml_element == "testsuite") {
+ return ArrayAsVector(kReservedTestSuiteAttributes);
+ } else if (xml_element == "testcase") {
+ return ArrayAsVector(kReservedTestCaseAttributes);
+ } else {
+ GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+ }
+ // This code is unreachable but some compilers may not realizes that.
+ return std::vector<std::string>();
+}
+
+static std::string FormatWordList(const std::vector<std::string>& words) {
+ Message word_list;
+ for (size_t i = 0; i < words.size(); ++i) {
+ if (i > 0 && words.size() > 2) {
+ word_list << ", ";
+ }
+ if (i == words.size() - 1) {
+ word_list << "and ";
+ }
+ word_list << "'" << words[i] << "'";
+ }
+ return word_list.GetString();
+}
+
+bool ValidateTestPropertyName(const std::string& property_name,
+ const std::vector<std::string>& reserved_names) {
+ if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
+ reserved_names.end()) {
+ ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
+ << " (" << FormatWordList(reserved_names)
+ << " are reserved by " << GTEST_NAME_ << ")";
return false;
}
return true;
}
+// Adds a failure if the key is a reserved attribute of the element named
+// xml_element. Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const std::string& xml_element,
+ const TestProperty& test_property) {
+ return ValidateTestPropertyName(test_property.key(),
+ GetReservedAttributesForElement(xml_element));
+}
+
// Clears the object.
void TestResult::Clear() {
test_part_results_.clear();
@@ -1821,12 +1910,12 @@ void Test::TearDown() {
}
// Allows user supplied key value pairs to be recorded for later output.
-void Test::RecordProperty(const char* key, const char* value) {
- UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);
+void Test::RecordProperty(const std::string& key, const std::string& value) {
+ UnitTest::GetInstance()->RecordProperty(key, value);
}
// Allows user supplied key value pairs to be recorded for later output.
-void Test::RecordProperty(const char* key, int value) {
+void Test::RecordProperty(const std::string& key, int value) {
Message value_message;
value_message << value;
RecordProperty(key, value_message.GetString().c_str());
@@ -2264,10 +2353,21 @@ int TestCase::failed_test_count() const {
return CountIf(test_info_list_, TestFailed);
}
+// Gets the number of disabled tests that will be reported in the XML report.
+int TestCase::reportable_disabled_test_count() const {
+ return CountIf(test_info_list_, TestReportableDisabled);
+}
+
+// Gets the number of disabled tests in this test case.
int TestCase::disabled_test_count() const {
return CountIf(test_info_list_, TestDisabled);
}
+// Gets the number of tests to be printed in the XML report.
+int TestCase::reportable_test_count() const {
+ return CountIf(test_info_list_, TestReportable);
+}
+
// Get the number of tests in this test case that should run.
int TestCase::test_to_run_count() const {
return CountIf(test_info_list_, ShouldRunTest);
@@ -2355,6 +2455,7 @@ void TestCase::Run() {
// Clears the results of all tests in this test case.
void TestCase::ClearResult() {
+ ad_hoc_test_result_.Clear();
ForEach(test_info_list_, TestInfo::ClearTestResult);
}
@@ -2497,6 +2598,7 @@ bool ShouldUseColor(bool stdout_is_tty) {
String::CStringEquals(term, "xterm-color") ||
String::CStringEquals(term, "xterm-256color") ||
String::CStringEquals(term, "screen") ||
+ String::CStringEquals(term, "screen-256color") ||
String::CStringEquals(term, "linux") ||
String::CStringEquals(term, "cygwin");
return stdout_is_tty && term_supports_color;
@@ -2562,6 +2664,11 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
va_end(args);
}
+// Text printed in Google Test's text output and --gunit_list_tests
+// output to label the type parameter and value parameter for a test.
+static const char kTypeParamLabel[] = "TypeParam";
+static const char kValueParamLabel[] = "GetParam()";
+
void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
const char* const type_param = test_info.type_param();
const char* const value_param = test_info.value_param();
@@ -2569,12 +2676,12 @@ void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
if (type_param != NULL || value_param != NULL) {
printf(", where ");
if (type_param != NULL) {
- printf("TypeParam = %s", type_param);
+ printf("%s = %s", kTypeParamLabel, type_param);
if (value_param != NULL)
printf(" and ");
}
if (value_param != NULL) {
- printf("GetParam() = %s", value_param);
+ printf("%s = %s", kValueParamLabel, value_param);
}
}
}
@@ -2659,7 +2766,7 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
if (test_case.type_param() == NULL) {
printf("\n");
} else {
- printf(", where TypeParam = %s\n", test_case.type_param());
+ printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
}
fflush(stdout);
}
@@ -2770,7 +2877,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
num_failures == 1 ? "TEST" : "TESTS");
}
- int num_disabled = unit_test.disabled_test_count();
+ int num_disabled = unit_test.reportable_disabled_test_count();
if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
if (!num_failures) {
printf("\n"); // Add a spacer if no FAILURE banner is displayed.
@@ -2924,13 +3031,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
// is_attribute is true, the text is meant to appear as an attribute
// value, and normalizable whitespace is preserved by replacing it
// with character references.
- static std::string EscapeXml(const char* str, bool is_attribute);
+ static std::string EscapeXml(const std::string& str, bool is_attribute);
// Returns the given string with all characters invalid in XML removed.
- static string RemoveInvalidXmlCharacters(const string& str);
+ static std::string RemoveInvalidXmlCharacters(const std::string& str);
// Convenience wrapper around EscapeXml when str is an attribute value.
- static std::string EscapeXmlAttribute(const char* str) {
+ static std::string EscapeXmlAttribute(const std::string& str) {
return EscapeXml(str, true);
}
@@ -2939,6 +3046,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
return EscapeXml(str, false);
}
+ // Verifies that the given attribute belongs to the given element and
+ // streams the attribute as XML.
+ static void OutputXmlAttribute(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value);
+
// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
@@ -2948,10 +3062,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
const TestInfo& test_info);
// Prints an XML representation of a TestCase object
- static void PrintXmlTestCase(FILE* out, const TestCase& test_case);
+ static void PrintXmlTestCase(::std::ostream* stream,
+ const TestCase& test_case);
// Prints an XML summary of unit_test to output stream out.
- static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test);
+ static void PrintXmlUnitTest(::std::ostream* stream,
+ const UnitTest& unit_test);
// Produces a string representing the test properties in a result as space
// delimited XML attributes based on the property key="value" pairs.
@@ -3002,7 +3118,9 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
fflush(stderr);
exit(EXIT_FAILURE);
}
- PrintXmlUnitTest(xmlout, unit_test);
+ std::stringstream stream;
+ PrintXmlUnitTest(&stream, unit_test);
+ fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
fclose(xmlout);
}
@@ -3019,43 +3137,42 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
// TODO(wan): It might be nice to have a minimally invasive, human-readable
// escaping scheme for invalid characters, rather than dropping them.
std::string XmlUnitTestResultPrinter::EscapeXml(
- const char* str, bool is_attribute) {
+ const std::string& str, bool is_attribute) {
Message m;
- if (str != NULL) {
- for (const char* src = str; *src; ++src) {
- switch (*src) {
- case '<':
- m << "&lt;";
- break;
- case '>':
- m << "&gt;";
- break;
- case '&':
- m << "&amp;";
- break;
- case '\'':
- if (is_attribute)
- m << "&apos;";
- else
- m << '\'';
- break;
- case '"':
- if (is_attribute)
- m << "&quot;";
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ switch (ch) {
+ case '<':
+ m << "&lt;";
+ break;
+ case '>':
+ m << "&gt;";
+ break;
+ case '&':
+ m << "&amp;";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "&apos;";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << "&quot;";
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(ch)) {
+ if (is_attribute && IsNormalizableWhitespace(ch))
+ m << "&#x" << String::FormatByte(static_cast<unsigned char>(ch))
+ << ";";
else
- m << '"';
- break;
- default:
- if (IsValidXmlCharacter(*src)) {
- if (is_attribute && IsNormalizableWhitespace(*src))
- m << "&#x" << String::FormatByte(static_cast<unsigned char>(*src))
- << ";";
- else
- m << *src;
- }
- break;
- }
+ m << ch;
+ }
+ break;
}
}
@@ -3065,10 +3182,11 @@ std::string XmlUnitTestResultPrinter::EscapeXml(
// Returns the given string with all characters invalid in XML removed.
// Currently invalid characters are dropped from the string. An
// alternative is to replace them with certain characters such as . or ?.
-string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) {
- string output;
+std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
+ const std::string& str) {
+ std::string output;
output.reserve(str.size());
- for (string::const_iterator it = str.begin(); it != str.end(); ++it)
+ for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
if (IsValidXmlCharacter(*it))
output.push_back(*it);
@@ -3144,30 +3262,47 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
*stream << "]]>";
}
+void XmlUnitTestResultPrinter::OutputXmlAttribute(
+ std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Attribute " << name << " is not allowed for element <" << element_name
+ << ">.";
+
+ *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
+}
+
// Prints an XML representation of a TestInfo object.
// TODO(wan): There is also value in printing properties with the plain printer.
void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
const char* test_case_name,
const TestInfo& test_info) {
const TestResult& result = *test_info.result();
- *stream << " <testcase name=\""
- << EscapeXmlAttribute(test_info.name()).c_str() << "\"";
+ const std::string kTestcase = "testcase";
+
+ *stream << " <testcase";
+ OutputXmlAttribute(stream, kTestcase, "name", test_info.name());
if (test_info.value_param() != NULL) {
- *stream << " value_param=\"" << EscapeXmlAttribute(test_info.value_param())
- << "\"";
+ OutputXmlAttribute(stream, kTestcase, "value_param",
+ test_info.value_param());
}
if (test_info.type_param() != NULL) {
- *stream << " type_param=\"" << EscapeXmlAttribute(test_info.type_param())
- << "\"";
+ OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
}
- *stream << " status=\""
- << (test_info.should_run() ? "run" : "notrun")
- << "\" time=\""
- << FormatTimeInMillisAsSeconds(result.elapsed_time())
- << "\" classname=\"" << EscapeXmlAttribute(test_case_name).c_str()
- << "\"" << TestPropertiesAsXmlAttributes(result).c_str();
+ OutputXmlAttribute(stream, kTestcase, "status",
+ test_info.should_run() ? "run" : "notrun");
+ OutputXmlAttribute(stream, kTestcase, "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(stream, kTestcase, "classname", test_case_name);
+ *stream << TestPropertiesAsXmlAttributes(result);
int failures = 0;
for (int i = 0; i < result.total_part_count(); ++i) {
@@ -3195,45 +3330,68 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
}
// Prints an XML representation of a TestCase object
-void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
+void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream,
const TestCase& test_case) {
- fprintf(out,
- " <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "
- "disabled=\"%d\" ",
- EscapeXmlAttribute(test_case.name()).c_str(),
- test_case.total_test_count(),
- test_case.failed_test_count(),
- test_case.disabled_test_count());
- fprintf(out,
- "errors=\"0\" time=\"%s\">\n",
- FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str());
+ const std::string kTestsuite = "testsuite";
+ *stream << " <" << kTestsuite;
+ OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
+ OutputXmlAttribute(stream, kTestsuite, "tests",
+ StreamableToString(test_case.reportable_test_count()));
+ OutputXmlAttribute(stream, kTestsuite, "failures",
+ StreamableToString(test_case.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "disabled",
+ StreamableToString(test_case.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+ OutputXmlAttribute(stream, kTestsuite, "time",
+ FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
+ *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result())
+ << ">\n";
+
for (int i = 0; i < test_case.total_test_count(); ++i) {
- ::std::stringstream stream;
- OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i));
- fprintf(out, "%s", StringStreamToString(&stream).c_str());
+ if (test_case.GetTestInfo(i)->is_reportable())
+ OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
}
- fprintf(out, " </testsuite>\n");
+ *stream << " </" << kTestsuite << ">\n";
}
// Prints an XML summary of unit_test to output stream out.
-void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
const UnitTest& unit_test) {
- fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- fprintf(out,
- "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
- "errors=\"0\" timestamp=\"%s\" time=\"%s\" ",
- unit_test.total_test_count(),
- unit_test.failed_test_count(),
- unit_test.disabled_test_count(),
- FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()).c_str(),
- FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str());
+ const std::string kTestsuites = "testsuites";
+
+ *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ *stream << "<" << kTestsuites;
+
+ OutputXmlAttribute(stream, kTestsuites, "tests",
+ StreamableToString(unit_test.reportable_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "failures",
+ StreamableToString(unit_test.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuites, "disabled",
+ StreamableToString(unit_test.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+ OutputXmlAttribute(
+ stream, kTestsuites, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
+ OutputXmlAttribute(stream, kTestsuites, "time",
+ FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
+
if (GTEST_FLAG(shuffle)) {
- fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed());
+ OutputXmlAttribute(stream, kTestsuites, "random_seed",
+ StreamableToString(unit_test.random_seed()));
}
- fprintf(out, "name=\"AllTests\">\n");
- for (int i = 0; i < unit_test.total_test_case_count(); ++i)
- PrintXmlTestCase(out, *unit_test.GetTestCase(i));
- fprintf(out, "</testsuites>\n");
+
+ *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
+
+ OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+ *stream << ">\n";
+
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ if (unit_test.GetTestCase(i)->reportable_test_count() > 0)
+ PrintXmlTestCase(stream, *unit_test.GetTestCase(i));
+ }
+ *stream << "</" << kTestsuites << ">\n";
}
// Produces a string representing the test properties in a result as space
@@ -3365,6 +3523,35 @@ const char* const
OsStackTraceGetter::kElidedFramesMarker =
"... " GTEST_NAME_ " internal frames ...";
+// A helper class that creates the premature-exit file in its
+// constructor and deletes the file in its destructor.
+class ScopedPrematureExitFile {
+ public:
+ explicit ScopedPrematureExitFile(const char* premature_exit_filepath)
+ : premature_exit_filepath_(premature_exit_filepath) {
+ // If a path to the premature-exit file is specified...
+ if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') {
+ // create the file with a single "0" character in it. I/O
+ // errors are ignored as there's nothing better we can do and we
+ // don't want to fail the test because of this.
+ FILE* pfile = posix::FOpen(premature_exit_filepath, "w");
+ fwrite("0", 1, 1, pfile);
+ fclose(pfile);
+ }
+ }
+
+ ~ScopedPrematureExitFile() {
+ if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') {
+ remove(premature_exit_filepath_);
+ }
+ }
+
+ private:
+ const char* const premature_exit_filepath_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile);
+};
+
} // namespace internal
// class TestEventListeners
@@ -3451,7 +3638,7 @@ void TestEventListeners::SuppressEventForwarding() {
// We don't protect this under mutex_ as a user is not supposed to
// call this before main() starts, from which point on the return
// value will never change.
-UnitTest * UnitTest::GetInstance() {
+UnitTest* UnitTest::GetInstance() {
// When compiled with MSVC 7.1 in optimized mode, destroying the
// UnitTest object upon exiting the program messes up the exit code,
// causing successful tests to appear failed. We have to use a
@@ -3501,11 +3688,21 @@ int UnitTest::successful_test_count() const {
// Gets the number of failed tests.
int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTest::reportable_disabled_test_count() const {
+ return impl()->reportable_disabled_test_count();
+}
+
// Gets the number of disabled tests.
int UnitTest::disabled_test_count() const {
return impl()->disabled_test_count();
}
+// Gets the number of tests to be printed in the XML report.
+int UnitTest::reportable_test_count() const {
+ return impl()->reportable_test_count();
+}
+
// Gets the number of all tests.
int UnitTest::total_test_count() const { return impl()->total_test_count(); }
@@ -3536,6 +3733,12 @@ const TestCase* UnitTest::GetTestCase(int i) const {
return impl()->GetTestCase(i);
}
+// Returns the TestResult containing information on test failures and
+// properties logged outside of individual test cases.
+const TestResult& UnitTest::ad_hoc_test_result() const {
+ return *impl()->ad_hoc_test_result();
+}
+
// Gets the i-th test case among all the test cases. i can range from 0 to
// total_test_case_count() - 1. If i is not in that range, returns NULL.
TestCase* UnitTest::GetMutableTestCase(int i) {
@@ -3571,13 +3774,12 @@ Environment* UnitTest::AddEnvironment(Environment* env) {
// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
// this to report their results. The user code should use the
// assertion macros instead of calling this directly.
-GTEST_LOCK_EXCLUDED_(mutex_)
void UnitTest::AddTestPartResult(
TestPartResult::Type result_type,
const char* file_name,
int line_number,
const std::string& message,
- const std::string& os_stack_trace) {
+ const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) {
Message msg;
msg << message;
@@ -3634,12 +3836,14 @@ void UnitTest::AddTestPartResult(
}
}
-// Creates and adds a property to the current TestResult. If a property matching
-// the supplied value already exists, updates its value instead.
-void UnitTest::RecordPropertyForCurrentTest(const char* key,
- const char* value) {
- const TestProperty test_property(key, value);
- impl_->current_test_result()->RecordProperty(test_property);
+// Adds a TestProperty to the current TestResult object when invoked from
+// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
+// from SetUpTestCase or TearDownTestCase, or to the global property set
+// when invoked elsewhere. If the result already contains a property with
+// the same key, the value will be updated.
+void UnitTest::RecordProperty(const std::string& key,
+ const std::string& value) {
+ impl_->RecordProperty(TestProperty(key, value));
}
// Runs all tests in this UnitTest object and prints the result.
@@ -3648,14 +3852,39 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key,
// We don't protect this under mutex_, as we only support calling it
// from the main thread.
int UnitTest::Run() {
+ const bool in_death_test_child_process =
+ internal::GTEST_FLAG(internal_run_death_test).length() > 0;
+
+ // Google Test implements this protocol for catching that a test
+ // program exits before returning control to Google Test:
+ //
+ // 1. Upon start, Google Test creates a file whose absolute path
+ // is specified by the environment variable
+ // TEST_PREMATURE_EXIT_FILE.
+ // 2. When Google Test has finished its work, it deletes the file.
+ //
+ // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
+ // running a Google-Test-based test program and check the existence
+ // of the file at the end of the test execution to see if it has
+ // exited prematurely.
+
+ // If we are in the child process of a death test, don't
+ // create/delete the premature exit file, as doing so is unnecessary
+ // and will confuse the parent process. Otherwise, create/delete
+ // the file upon entering/leaving this function. If the program
+ // somehow exits before this function has a chance to return, the
+ // premature-exit file will be left undeleted, causing a test runner
+ // that understands the premature-exit-file protocol to report the
+ // test as having failed.
+ const internal::ScopedPrematureExitFile premature_exit_file(
+ in_death_test_child_process ?
+ NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
+
// Captures the value of GTEST_FLAG(catch_exceptions). This value will be
// used for the duration of the program.
impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
#if GTEST_HAS_SEH
- const bool in_death_test_child_process =
- internal::GTEST_FLAG(internal_run_death_test).length() > 0;
-
// Either the user wants Google Test to catch exceptions thrown by the
// tests or this is executing in the context of death test child
// process. In either case the user does not want to see pop-up dialogs
@@ -3794,7 +4023,6 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent)
start_timestamp_(0),
elapsed_time_(0),
#if GTEST_HAS_DEATH_TEST
- internal_run_death_test_flag_(NULL),
death_test_factory_(new DefaultDeathTestFactory),
#endif
// Will be overridden by the flag before first use.
@@ -3812,6 +4040,28 @@ UnitTestImpl::~UnitTestImpl() {
delete os_stack_trace_getter_;
}
+// Adds a TestProperty to the current TestResult object when invoked in a
+// context of a test, to current test case's ad_hoc_test_result when invoke
+// from SetUpTestCase/TearDownTestCase, or to the global property set
+// otherwise. If the result already contains a property with the same key,
+// the value will be updated.
+void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
+ std::string xml_element;
+ TestResult* test_result; // TestResult appropriate for property recording.
+
+ if (current_test_info_ != NULL) {
+ xml_element = "testcase";
+ test_result = &(current_test_info_->result_);
+ } else if (current_test_case_ != NULL) {
+ xml_element = "testsuite";
+ test_result = &(current_test_case_->ad_hoc_test_result_);
+ } else {
+ xml_element = "testsuites";
+ test_result = &ad_hoc_test_result_;
+ }
+ test_result->RecordProperty(xml_element, test_property);
+}
+
#if GTEST_HAS_DEATH_TEST
// Disables event forwarding if the control is currently in a death test
// subprocess. Must not be called before InitGoogleTest.
@@ -4255,8 +4505,33 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
return num_selected_tests;
}
+// Prints the given C-string on a single line by replacing all '\n'
+// characters with string "\\n". If the output takes more than
+// max_length characters, only prints the first max_length characters
+// and "...".
+static void PrintOnOneLine(const char* str, int max_length) {
+ if (str != NULL) {
+ for (int i = 0; *str != '\0'; ++str) {
+ if (i >= max_length) {
+ printf("...");
+ break;
+ }
+ if (*str == '\n') {
+ printf("\\n");
+ i += 2;
+ } else {
+ printf("%c", *str);
+ ++i;
+ }
+ }
+ }
+}
+
// Prints the names of the tests matching the user-specified filter flag.
void UnitTestImpl::ListTestsMatchingFilter() {
+ // Print at most this many characters for each type/value parameter.
+ const int kMaxParamLength = 250;
+
for (size_t i = 0; i < test_cases_.size(); i++) {
const TestCase* const test_case = test_cases_[i];
bool printed_test_case_name = false;
@@ -4267,9 +4542,23 @@ void UnitTestImpl::ListTestsMatchingFilter() {
if (test_info->matches_filter_) {
if (!printed_test_case_name) {
printed_test_case_name = true;
- printf("%s.\n", test_case->name());
+ printf("%s.", test_case->name());
+ if (test_case->type_param() != NULL) {
+ printf(" # %s = ", kTypeParamLabel);
+ // We print the type parameter on a single line to make
+ // the output easy to parse by a program.
+ PrintOnOneLine(test_case->type_param(), kMaxParamLength);
+ }
+ printf("\n");
+ }
+ printf(" %s", test_info->name());
+ if (test_info->value_param() != NULL) {
+ printf(" # %s = ", kValueParamLabel);
+ // We print the value parameter on a single line to make the
+ // output easy to parse by a program.
+ PrintOnOneLine(test_info->value_param(), kMaxParamLength);
}
- printf(" %s\n", test_info->name());
+ printf("\n");
}
}
}