Skip to content

Commit

Permalink
deps: make gtest output tap
Browse files Browse the repository at this point in the history
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: #8034
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
bnoordhuis committed Oct 3, 2016
1 parent 8dc2b42 commit c56ae16
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 2 deletions.
124 changes: 123 additions & 1 deletion deps/gtest/src/gtest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3498,6 +3498,125 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
// </testsuite>
// </testsuites>

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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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());
Expand Down
1 change: 0 additions & 1 deletion deps/gtest/src/gtest_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

0 comments on commit c56ae16

Please sign in to comment.