UTPP
Loading...
Searching...
No Matches
reporter_xml.h
Go to the documentation of this file.
1#pragma once
2/*
3 UTPP - A New Generation of UnitTest++
4 (c) Mircea Neacsu 2017-2024
5
6 See LICENSE file for full copyright information.
7*/
8
13
14#include <iostream>
15#include <iomanip>
16#include <ctime>
17
18namespace UnitTest
19{
20
22class ReporterXml : public ReporterDeferred
23{
24public:
25 explicit ReporterXml (std::ostream& ostream = std::cout);
26
27 int Summary () override;
28 void Clear () override;
29
30protected:
31 void BeginTest (const ReporterDeferred::TestResult& result);
32 void AddFailure (const ReporterDeferred::TestResult& result);
33 void EndTest (const ReporterDeferred::TestResult& result);
34
35private:
36 std::string xml_escape (const std::string& value);
37 std::string build_failure_message (const std::string& file, int line, std::string const& message);
38
39 ReporterXml (ReporterXml const&) = delete;
40 ReporterXml& operator=(ReporterXml const&) = delete;
41
42 std::ostream& os;
43 std::string start_time;
44 std::ios orig_state;
45};
46
47inline
48std::string ReporterXml::xml_escape (const std::string& value)
49{
50 //TODO trade style for speed
51 std::string escaped = value;
52 auto replace_char = [&escaped] (char c, const char* repl){
53 for (auto pos = escaped.find(c); pos != std::string::npos; pos = escaped.find(c, pos + 1))
54 escaped.replace(pos, 1, repl);
55
56 };
57 replace_char ('&', "&amp;");
58 replace_char ('<', "&lt;");
59 replace_char ('>', "&gt;");
60 replace_char ('\'', "&apos;");
61 replace_char ('\"', "&quot;");
62
63 return escaped;
64}
65
66inline
67std::string ReporterXml::build_failure_message (const std::string& file, int line, std::string const& message)
68{
69 std::ostringstream failureMessage;
70 failureMessage << file << "(" << line << ") : " << message;
71 return failureMessage.str();
72}
73
79inline
80ReporterXml::ReporterXml (std::ostream& ostream)
81 : os (ostream)
82 , orig_state (nullptr)
83{
84 char tmp[80];
85 time_t now;
86 time (&now);
87 const struct tm* t = gmtime (&now);
88 strftime (tmp, sizeof (tmp), "%Y-%m-%d %H:%M:%SZ", t);
89 start_time = tmp;
90 orig_state.copyfmt (os);
91 os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
92
93}
94
96inline
98{
99 std::string suite;
100 std::string cmd;
101#ifdef _WIN32
102 std::wstring wcmd{ GetCommandLineW () };
103 int nsz = WideCharToMultiByte (CP_UTF8, 0, wcmd.c_str (), -1, 0, 0, 0, 0);
104 if (nsz)
105 {
106 cmd.resize (nsz);
107 WideCharToMultiByte (CP_UTF8, 0, wcmd.c_str (), -1, &cmd[0], nsz, 0, 0);
108 cmd.resize (nsz - 1); //output is null-terminated
109 }
110#endif
111 time_t now;
112 char tmp[80];
113 time (&now);
114 const struct tm* t = gmtime (&now);
115 strftime (tmp, sizeof (tmp), "%Y-%m-%d %H:%M:%SZ", t);
116 os.copyfmt (orig_state);
117
118 os << "<utpp-results"
119 << " total=\"" << total_test_count << '\"'
120 << " failed=\"" << total_failed_count << '\"'
121 << " failures=\"" << total_failures_count << '\"'
122 << " duration=\"" << std::fixed << std::setprecision (3) << total_time_msec / 1000. << '\"'
123 << '>' << std::endl;
124 os << " <start-time>" << start_time << "</start-time>" << std::endl;
125
126 os << " <command-line>" << xml_escape (cmd) << "</command-line>" << std::endl;
127
128 for (auto i = results.cbegin (); i != results.cend (); ++i)
129 {
130 if (i->test_name.empty ()) // New suite flag
131 {
132 if (!suite.empty ())
133 os << " </suite>" << std::endl;
134 suite = i->suite_name;
135 if (suite == DEFAULT_SUITE)
136 os << " <suite";
137 else
138 os << " <suite name=\"" << suite << '\"';
139 if ((i + 1) == results.cend () || (i + 1)->test_name.empty ())
140 {
141 // Next record is another suite. This suite is either empty or disabled
142 os << " /";
143 suite.clear ();
144 }
145 os << '>' << std::endl;
146 }
147 else
148 {
149 BeginTest (*i);
150
151 if (!i->failures.empty ())
152 AddFailure (*i);
153
154 EndTest (*i);
155 }
156 }
157 if (!suite.empty ())
158 os << " </suite>" << std::endl;
159 os << " <end-time>"
160 << tmp
161 << "</end-time>" << std::endl;
162 os << "</utpp-results>" << std::endl;
164}
165
166inline
168{
169 char tmp[80];
170 time_t now;
171 time (&now);
172 const struct tm* t = gmtime (&now);
173 strftime (tmp, sizeof (tmp), "%Y-%m-%d %H:%M:%SZ", t);
174 start_time = tmp;
175
177}
178
179inline
180void ReporterXml::BeginTest (const ReporterDeferred::TestResult& result)
181{
182 os << " <test"
183 << " name=\"" << result.test_name << "\""
184 << " time_ms=\"" << result.test_time_ms << "\"";
185}
186
187inline
188void ReporterXml::EndTest (const ReporterDeferred::TestResult& result)
189{
190 if (result.failures.empty ())
191 os << "/>";
192 else
193 os << " </test>";
194
195 os << std::endl;
196}
197
198inline
199void ReporterXml::AddFailure (const ReporterDeferred::TestResult& result)
200{
201 os << ">" << std::endl; // close <test> element
202
203 for (auto& fail : result.failures)
204 {
205 std::string escapedMessage = xml_escape (fail.message);
206 std::string message = build_failure_message (fail.filename, fail.line_number, escapedMessage);
207
208 os << " <failure" << " message=\"" << message << "\"" << "/>" << std::endl;
209 }
210}
211
212}
void Clear() override
Reset all statistics.
Definition utpp.h:706
std::deque< TestResult > results
Results of all tests.
Definition utpp.h:349
int total_failures_count
total number of failures
Definition utpp.h:317
int total_test_count
total number of tests
Definition utpp.h:315
virtual int Summary()
Generate results report.
Definition utpp.h:304
int total_failed_count
total number of failed tests
Definition utpp.h:316
int total_time_msec
total running time in milliseconds
Definition utpp.h:318
int Summary() override
Generate XML report.
Definition reporter_xml.h:97
void Clear() override
Reset all statistics.
Definition reporter_xml.h:167
ReporterXml(std::ostream &ostream=std::cout)
Definition reporter_xml.h:80
Test results including all failure messages
Definition utpp.h:339
std::string test_name
test name
Definition utpp.h:344
int test_time_ms
test running time in milliseconds
Definition utpp.h:345
#define DEFAULT_SUITE
Name of default suite.
Definition utpp.h:54