atom feed2 messages in com.googlegroups.googletestframework[googletest] [patch] test listener wh...
FromSent OnAttachments
aviad rozenhekOct 4, 2012 11:21 am.cpp, .h
aviad rozenhekOct 4, 2012 11:52 am.cpp, .h
Subject:[googletest] [patch] test listener which progressively outputs XML
From:aviad rozenhek (avia@gmail.com)
Date:Oct 4, 2012 11:21:53 am
List:com.googlegroups.googletestframework
Attachments:

the vanilla XML output for gtest [with --gtest_output="xml:/home/user/src"] will not create an XML if the test application itself fails in any way [a hard exception, an exit(1), timeout, freeze etc].

the attached ProgressiveXmlTestListener is a class that write the XML output after each test, making it easier to see which test killed the test application. comments welcome

usage:

int main(int argc, char **argv) { ::testing::InitGoogleMock(&argc, argv);

if(_stricmp(argv[i], "--gtest_progressive_output") == 0) { if(i+1 >= argc || strstr(argv[i+1],"--") == argv[i+1]) { std::cout << "Missing filename for --output (" << (i + 1) << "," << argc << ", " << strstr(argv[i+1],"--") << ")" ; exit(1); } testing::UnitTest::GetInstance()->listeners().Append(new ProgressiveXmlTestListener(argv[++i])); }

return RUN_ALL_TESTS(); }

#include "ProgressiveXmlTestListener.h" #include <utils/xmlinfobuilder.h> #include <fstream>

using namespace testing; static void WriteCData(XmlInfoBuilder &xml, const char *data) { std::ostringstream strm; strm << "<![CDATA["; for(;;) { const char *const next_segment = strstr(data,"]]>"); if(next_segment != NULL) { strm.write(data, static_cast<std::streamsize>(next_segment -
data)); strm << "]]>]]&gt;<![CDATA["; data = next_segment + strlen("]]>"); } else { strm << data; break; } } strm << "]]>" << std::endl; xml.AppendXML(strm.str().c_str()); }

static bool operator==(const TestInfo& first, const TestInfo& second) {

typedef decltype(&TestInfo::name) TIPtr; TIPtr props[] = { &TestInfo::name , &TestInfo::test_case_name , &TestInfo::type_param , &TestInfo::value_param , nullptr }; for(auto prop = props; *prop != nullptr; prop++) { auto fstVal = ((first).*(*prop))(); auto sndVal = ((second).*(*prop))(); if(fstVal == sndVal) continue; if(fstVal == NULL || sndVal == NULL) return false; if(strcmp(fstVal,sndVal) != 0) return false; } return true; } static bool operator==(const TestCase& first, const TestCase& second) {

typedef decltype(&TestCase::name) TIPtr; TIPtr props[] = { &TestCase::name , &TestCase::type_param , nullptr }; for(auto prop = props; *prop != nullptr; prop++) { auto fstVal = ((first).*(*prop))(); auto sndVal = ((second).*(*prop))(); if(fstVal == sndVal) continue; if(fstVal == NULL || sndVal == NULL) return false; if(strcmp(fstVal,sndVal) != 0) return false; } return true; }

static void WriteTest(XmlInfoBuilder &xml, const TestInfo& test) { const TestResult &result = *test.result(); xml.PrepareAttribute("name", test.name()); if(test.value_param() != NULL) { xml.PrepareAttributeT("value_param",test.value_param()); } if(test.type_param() != NULL) { xml.PrepareAttributeT("type_param",test.type_param()); } xml.PrepareAttribute("status", (test.should_run() && (result.Failed() || result.Passed())) ?"run":"notrun"); xml.PrepareAttributeT("time", result.elapsed_time() / 1000.0); xml.PrepareAttribute("classname", test.test_case_name()); const int propertyCount = result.test_property_count(); for(int i = 0; i < propertyCount; i++) { const TestProperty& prop = result.GetTestProperty(i); xml.PrepareAttributeT(prop.key(), prop.value()); } bool hasFailedParts = false;

XmlInfoBuilder::SequenceGuard test_elt(xml, "testcase"); int partCount = result.total_part_count(); for(int i=0; i < partCount; i++) { const TestPartResult& part = result.GetTestPartResult(i); if(!part.failed()) continue; xml.PrepareAttributeT("message",part.summary()); xml.PrepareAttributeT("type",""); XmlInfoBuilder::SequenceGuard part_elt(xml,"failure"); std::ostringstream strm; strm << (part.file_name() == NULL ? "unknown file" : part.file_name()); if(part.line_number() >= 0) { strm << ':' << part.line_number(); } strm << '\n' << part.message(); WriteCData(xml, strm.str().c_str()); } const TestInfo* runningTest = UnitTest::GetInstance()->current_test_info(); if(runningTest != NULL && (runningTest == &test || *runningTest == test)) { xml.PrepareAttribute("message", "Test did not complete"); xml.PrepareAttribute("type",""); xml.AppendString("failure",""); }

} static void WriteTestCase(XmlInfoBuilder &xml, const TestCase& testCase) { const TestCase* runningTestCase =
UnitTest::GetInstance()->current_test_case(); bool still_running = (runningTestCase != NULL && (runningTestCase ==
&testCase || *runningTestCase == testCase)); xml.PrepareAttribute("name", testCase.name()); xml.PrepareAttributeT("tests", testCase.total_test_count()); xml.PrepareAttributeT("failures", testCase.failed_test_count() +
(still_running?1:0)); xml.PrepareAttributeT("disabled", testCase.disabled_test_count()); xml.PrepareAttributeT("errors",0); xml.PrepareAttributeT("time",testCase.elapsed_time() / 1000.0); XmlInfoBuilder::SequenceGuard testCase_elt(xml,"testsuite"); int testCount = testCase.total_test_count();

for(int i = 0; i < testCount; i++) WriteTest(xml,*testCase.GetTestInfo(i)); } static void WriteUnitTest(XmlInfoBuilder &xml, const UnitTest& unit) { xml.PrepareAttributeT("tests", unit.total_test_count()); xml.PrepareAttributeT("failures",unit.failed_test_count() +
(unit.current_test_info() == NULL?0:1)); xml.PrepareAttributeT("disabled",unit.disabled_test_count()); xml.PrepareAttributeT("errors",0); xml.PrepareAttributeT("time",unit.elapsed_time() / 1000.0); xml.PrepareAttributeT("name","AllTests"); if(unit.random_seed()) xml.PrepareAttributeT("random_seed", unit.random_seed()); XmlInfoBuilder::SequenceGuard unit_elt(xml,"testsuites"); int testCaseCount = unit.total_test_case_count(); for(int i = 0; i < testCaseCount; i++) WriteTestCase(xml,*unit.GetTestCase(i)); }

ProgressiveXmlTestListener::ProgressiveXmlTestListener(const char* filename) : m_filename(filename) { }

ProgressiveXmlTestListener::~ProgressiveXmlTestListener(void) { } void ProgressiveXmlTestListener::OnTestStart(const TestInfo& testinfo) { WriteFile(); }

void ProgressiveXmlTestListener::OnTestEnd(const TestInfo& testinfo) { WriteFile(); }

void ProgressiveXmlTestListener::OnTestIterationEnd(const UnitTest& unit_test,
int iteration) { WriteFile(); }

void ProgressiveXmlTestListener::WriteFile() { std::ofstream file = std::ofstream(m_filename); file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; XmlInfoBuilder xml(file); WriteUnitTest(xml, *UnitTest::GetInstance()); }

#pragma once #include <third_party\gtest\include\gtest\gtest.h> class ProgressiveXmlTestListener : public ::testing::EmptyTestEventListener { public: ProgressiveXmlTestListener(const char* filename); ~ProgressiveXmlTestListener(void);

public: virtual void OnTestStart(const ::testing::TestInfo& test_info) override; virtual void OnTestEnd(const ::testing::TestInfo& test_info) override; virtual void OnTestIterationEnd(const ::testing::UnitTest& unit_test, int
iteration) override; private: const std::string m_filename; void WriteFile(); };