1 #include "XmlTestReporter.h"
2 #include "Config.h"
3 
4 #include <iostream>
5 #include <sstream>
6 #include <string>
7 
8 using std::string;
9 using std::ostringstream;
10 using std::ostream;
11 
12 namespace {
13 
ReplaceChar(string & str,char c,string const & replacement)14 void ReplaceChar(string& str, char c, string const& replacement)
15 {
16     for (size_t pos = str.find(c); pos != string::npos; pos = str.find(c, pos + 1))
17         str.replace(pos, 1, replacement);
18 }
19 
XmlEscape(string const & value)20 string XmlEscape(string const& value)
21 {
22     string escaped = value;
23 
24     ReplaceChar(escaped, '&', "&amp;");
25     ReplaceChar(escaped, '<', "&lt;");
26     ReplaceChar(escaped, '>', "&gt;");
27     ReplaceChar(escaped, '\'', "&apos;");
28     ReplaceChar(escaped, '\"', "&quot;");
29 
30     return escaped;
31 }
32 
BuildFailureMessage(string const & file,int line,string const & message)33 string BuildFailureMessage(string const& file, int line, string const& message)
34 {
35     ostringstream failureMessage;
36     failureMessage << file << "(" << line << ") : " << message;
37     return failureMessage.str();
38 }
39 
40 }
41 
42 namespace UnitTest {
43 
XmlTestReporter(ostream & ostream)44 XmlTestReporter::XmlTestReporter(ostream& ostream)
45     : m_ostream(ostream)
46 {
47 }
48 
ReportSummary(int totalTestCount,int failedTestCount,int failureCount,float secondsElapsed)49 void XmlTestReporter::ReportSummary(int totalTestCount, int failedTestCount,
50                                     int failureCount, float secondsElapsed)
51 {
52     AddXmlElement(m_ostream, NULL);
53 
54     BeginResults(m_ostream, totalTestCount, failedTestCount, failureCount, secondsElapsed);
55 
56     DeferredTestResultList const& results = GetResults();
57     for (DeferredTestResultList::const_iterator i = results.begin(); i != results.end(); ++i)
58     {
59         BeginTest(m_ostream, *i);
60 
61         if (i->failed)
62             AddFailure(m_ostream, *i);
63 
64         EndTest(m_ostream, *i);
65     }
66 
67     EndResults(m_ostream);
68 }
69 
AddXmlElement(ostream & os,char const * encoding)70 void XmlTestReporter::AddXmlElement(ostream& os, char const* encoding)
71 {
72     os << "<?xml version=\"1.0\"";
73 
74     if (encoding != NULL)
75         os << " encoding=\"" << encoding << "\"";
76 
77     os << "?>";
78 }
79 
BeginResults(std::ostream & os,int totalTestCount,int failedTestCount,int failureCount,float secondsElapsed)80 void XmlTestReporter::BeginResults(std::ostream& os, int totalTestCount, int failedTestCount,
81                                    int failureCount, float secondsElapsed)
82 {
83    os << "<unittest-results"
84        << " tests=\"" << totalTestCount << "\""
85        << " failedtests=\"" << failedTestCount << "\""
86        << " failures=\"" << failureCount << "\""
87        << " time=\"" << secondsElapsed << "\""
88        << ">";
89 }
90 
EndResults(std::ostream & os)91 void XmlTestReporter::EndResults(std::ostream& os)
92 {
93     os << "</unittest-results>";
94 }
95 
BeginTest(std::ostream & os,DeferredTestResult const & result)96 void XmlTestReporter::BeginTest(std::ostream& os, DeferredTestResult const& result)
97 {
98     os << "<test"
99         << " suite=\"" << result.suiteName << "\""
100         << " name=\"" << result.testName << "\""
101         << " time=\"" << result.timeElapsed << "\"";
102 }
103 
EndTest(std::ostream & os,DeferredTestResult const & result)104 void XmlTestReporter::EndTest(std::ostream& os, DeferredTestResult const& result)
105 {
106     if (result.failed)
107         os << "</test>";
108     else
109         os << "/>";
110 }
111 
AddFailure(std::ostream & os,DeferredTestResult const & result)112 void XmlTestReporter::AddFailure(std::ostream& os, DeferredTestResult const& result)
113 {
114     os << ">"; // close <test> element
115 
116     for (DeferredTestResult::FailureVec::const_iterator it = result.failures.begin();
117          it != result.failures.end();
118          ++it)
119     {
120         string const escapedMessage = XmlEscape(it->second);
121         string const message = BuildFailureMessage(result.failureFile, it->first, escapedMessage);
122 
123         os << "<failure" << " message=\"" << message << "\"" << "/>";
124     }
125 }
126 
127 }
128