From 62f0576714cb50e0045b8a9d935d1057a5e9077d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 9 Aug 2016 16:37:21 +0200 Subject: [PATCH] deps: make gtest output tap Teach gtest to produce TAP so we can integrate it better with our CI tooling. TAP is printed to stdout but it can also be written to file by passing the `--gtest_output=tap:filename.tap` switch to cctest. PR-URL: https://github.com/nodejs/node/pull/8034 Reviewed-By: James M Snell --- deps/gtest/src/gtest.cc | 124 ++++++++++++++++++++++++++++++++++- deps/gtest/src/gtest_main.cc | 1 - 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/deps/gtest/src/gtest.cc b/deps/gtest/src/gtest.cc index 7fd5f298dc..970c0976cb 100644 --- a/deps/gtest/src/gtest.cc +++ b/deps/gtest/src/gtest.cc @@ -3498,6 +3498,125 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // // +class TapUnitTestResultPrinter : public EmptyTestEventListener { + public: + TapUnitTestResultPrinter(); + explicit TapUnitTestResultPrinter(const char* output_file); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + static void PrintTapUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + static void PrintTapTestCase(int* count, + ::std::ostream* stream, + const TestCase& test_case); + static void OutputTapTestInfo(int* count, + ::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + static void OutputTapComment(::std::ostream* stream, const char* comment); + + const std::string output_file_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(TapUnitTestResultPrinter); +}; + +TapUnitTestResultPrinter::TapUnitTestResultPrinter() {} + +TapUnitTestResultPrinter::TapUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "TAP output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +void TapUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* tapout = stdout; + + if (!output_file_.empty()) { + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + tapout = NULL; + if (output_dir.CreateDirectoriesRecursively()) + tapout = posix::FOpen(output_file_.c_str(), "w"); + + if (tapout == NULL) { + fprintf(stderr, "Unable to open file \"%s\"\n", output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + } + + std::stringstream stream; + PrintTapUnitTest(&stream, unit_test); + fprintf(tapout, "%s", StringStreamToString(&stream).c_str()); + fflush(tapout); + + if (tapout != stdout) + fclose(tapout); +} + +void TapUnitTestResultPrinter::PrintTapUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + *stream << "TAP version 13\n"; + *stream << "1.." << unit_test.reportable_test_count() << "\n"; + + int count = 1; + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (test_case.reportable_test_count() > 0) + PrintTapTestCase(&count, stream, test_case); + } + + *stream << "# failures: " << unit_test.failed_test_count() << "\n"; +} + +void TapUnitTestResultPrinter::PrintTapTestCase(int* count, + std::ostream* stream, + const TestCase& test_case) { + for (int i = 0; i < test_case.total_test_count(); ++i) { + const TestInfo& test_info = *test_case.GetTestInfo(i); + if (test_info.is_reportable()) + OutputTapTestInfo(count, stream, test_case.name(), test_info); + } +} + +void TapUnitTestResultPrinter::OutputTapTestInfo(int* count, + ::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const char* status = result.Passed() ? "ok" : "not ok"; + + *stream << status << " " << *count << " - " << + test_case_name << "." << test_info.name() << "\n"; + *stream << " ---\n"; + *stream << " duration_ms: " << + FormatTimeInMillisAsSeconds(result.elapsed_time()) << "\n"; + *stream << " ...\n"; + + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + OutputTapComment(stream, part.message()); + } + + *count += 1; +} + +void TapUnitTestResultPrinter::OutputTapComment(::std::ostream* stream, + const char* comment) { + const char* start = comment; + while (const char* end = strchr(start, '\n')) { + *stream << "# " << std::string(start, end) << "\n"; + start = end + 1; + } + if (*start) + *stream << "# " << start << "\n"; +} + // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; @@ -4314,7 +4433,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) #endif // Will be overridden by the flag before first use. catch_exceptions_(false) { - listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); + listeners()->SetDefaultResultPrinter(new TapUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { @@ -4365,6 +4484,9 @@ void UnitTestImpl::ConfigureXmlOutput() { if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format == "tap") { + listeners()->SetDefaultXmlGenerator(new TapUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); diff --git a/deps/gtest/src/gtest_main.cc b/deps/gtest/src/gtest_main.cc index f302822552..4cf03e59ba 100644 --- a/deps/gtest/src/gtest_main.cc +++ b/deps/gtest/src/gtest_main.cc @@ -32,7 +32,6 @@ #include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { - printf("Running main() from gtest_main.cc\n"); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }