25 #include <pugixml.hpp>
42 std::string formatTimestamp(
44 std::time_t epoche_(std::chrono::system_clock::to_time_t(time_));
46 localtime_r(&epoche_, &broken_);
47 std::ostringstream oss_;
48 oss_ << std::setfill(
'0') << std::dec << std::internal
49 << std::setw(4) << (broken_.tm_year + 1900)
51 << std::setw(2) << (broken_.tm_mon + 1)
53 << std::setw(2) << broken_.tm_mday
55 << std::setw(2) << broken_.tm_hour
57 << std::setw(2) << broken_.tm_min
59 << std::setw(2) << broken_.tm_sec;
63 std::string formatDuration(
66 std::chrono::duration<double> duration_(end_ - start_);
67 std::ostringstream oss_;
68 oss_ << std::setprecision(3) << std::fixed << duration_.count();
74 struct ReporterJUnit::Impl :
public AssertBufferListener {
79 ::pugi::xml_document doc;
86 ::pugi::xml_node node;
94 std::vector<Record> node_stack;
96 std::ostringstream message;
101 const Impl&) =
delete;
103 const Impl&) =
delete;
106 const std::string& file_,
107 bool hide_location_);
110 void cumulateStatistics(
112 const Record& source_);
113 void fillRunningTime(
114 const Context& context_,
117 const Context& context_,
120 const Context& context_,
123 const Context& context_,
125 const std::string& name_);
127 const Context& context_,
128 const std::string& message_);
130 const Context& context_);
134 const Context& context_,
135 const AssertBufferAssertData& data_,
136 const std::string& message_)
override;
138 const Context& context_,
139 const AssertBufferAssertData& data_,
140 const std::string& message_)
override;
142 const Context& context_,
143 const AssertBufferAssertData& data_)
override;
145 const Context& context_,
146 const std::string& message_)
override;
148 const Context& context_,
149 const std::string& message_)
override;
151 const Context& context_)
override;
154 ReporterJUnit::Impl::Impl(
155 const std::string& file_,
156 bool hide_location_) :
158 hide_location(hide_location_),
161 assert_buffer(std::make_shared<AssertBufferStr>(this)) {
165 ReporterJUnit::Impl::~Impl() {
169 void ReporterJUnit::Impl::cumulateStatistics(
171 const Record& source_) {
172 target_.case_count += source_.case_count;
173 target_.case_failures += source_.case_failures;
174 target_.case_errors += source_.case_errors;
177 void ReporterJUnit::Impl::fillRunningTime(
178 const Context& context_,
181 auto end_time_(context_.time_source->now());
182 auto time_(record_.node.append_attribute(
"time"));
183 time_ = formatDuration(record_.start, end_time_).c_str();
186 void ReporterJUnit::Impl::fillStatistics(
187 const Context& context_,
190 auto tests_(record_.node.append_attribute(
"tests"));
191 tests_ = record_.case_count;
194 auto failures_(record_.node.append_attribute(
"failures"));
195 failures_ = record_.case_failures;
198 auto errors_(record_.node.append_attribute(
"errors"));
199 errors_ = record_.case_errors;
202 void ReporterJUnit::Impl::fillTimestamp(
203 const Context& context_,
206 auto timestamp_(record_.node.append_attribute(
"timestamp"));
207 timestamp_ = formatTimestamp(record_.start).c_str();
210 void ReporterJUnit::Impl::fillName(
211 const Context& context_,
213 const std::string& name_) {
215 auto name_node_(record_.node.append_attribute(
"name"));
216 name_node_ = name_.c_str();
219 void ReporterJUnit::Impl::appendMessage(
220 const Context& context_,
221 const std::string& message_) {
222 message <<
"\n" << message_;
225 void ReporterJUnit::Impl::commitMessage(
226 const Context& context_) {
227 auto& top_(node_stack.back());
228 auto node_(top_.node.last_child());
229 auto msg_(node_.append_attribute(
"message"));
230 msg_ = message.str().c_str();
234 void ReporterJUnit::Impl::assertionOpeningMessage(
235 const Context& context_,
236 const AssertBufferAssertData& data_,
237 const std::string& message_) {
239 if(!data_.condition) {
240 auto& top_(node_stack.back());
241 auto failure_(top_.node.append_child(
"failure"));
243 auto line_attr_(failure_.append_attribute(
"line"));
244 line_attr_ = data_.line;
245 auto file_attr_(failure_.append_attribute(
"file"));
246 file_attr_ = data_.file.c_str();
252 void ReporterJUnit::Impl::assertionAdditionalMessage(
253 const Context& context_,
254 const AssertBufferAssertData& data_,
255 const std::string& message_) {
256 appendMessage(context_, message_);
259 void ReporterJUnit::Impl::assertionClose(
260 const Context& context_,
261 const AssertBufferAssertData& data_) {
262 commitMessage(context_);
265 void ReporterJUnit::Impl::errorOpeningMessage(
266 const Context& context_,
267 const std::string& message_) {
268 auto& top_(node_stack.back());
269 auto error_(top_.node.append_child(
"error"));
270 auto msg_(error_.append_attribute(
"message"));
274 void ReporterJUnit::Impl::errorAdditionalMessage(
275 const Context& context_,
276 const std::string& message_) {
277 appendMessage(context_, message_);
280 void ReporterJUnit::Impl::errorClose(
281 const Context& context_) {
282 commitMessage(context_);
286 const std::string& file_,
287 bool hide_location_) :
288 pimpl(new Impl(file_, hide_location_)) {
298 const std::string& name_,
304 auto root_(pimpl->doc.append_child(
"testsuites"));
305 pimpl->node_stack.push_back({
306 root_.append_child(
"testsuite"),
314 pimpl->fillTimestamp(context_, pimpl->node_stack.back());
319 const std::string& name_,
322 pimpl->node_stack.push_back({
323 pimpl->node_stack.back().node.append_child(
"testsuite"),
331 pimpl->fillName(context_, pimpl->node_stack.back(), params_.
mixWithName(name_));
332 pimpl->fillTimestamp(context_, pimpl->node_stack.back());
337 const std::string& name_,
340 pimpl->node_stack.push_back({
341 pimpl->node_stack.back().node.append_child(
"testcase"),
349 pimpl->fillName(context_, pimpl->node_stack.back(), params_.
mixWithName(name_));
354 const std::string& name_) {
361 const std::string& file_,
365 auto& top_(pimpl->node_stack.back());
366 if(top_.first_failure) {
367 top_.first_failure =
false;
368 ++top_.case_failures;
372 pimpl->assert_buffer->openAssertion({condition_, file_, lineno_});
373 return pimpl->assert_buffer;
379 auto& top_(pimpl->node_stack.back());
380 if(top_.first_error) {
381 top_.first_error =
false;
385 pimpl->assert_buffer->openError();
386 return pimpl->assert_buffer;
391 const std::string& name_,
398 const std::string& name_,
401 auto top_(pimpl->node_stack.back());
404 pimpl->fillRunningTime(context_, top_);
407 pimpl->node_stack.pop_back();
408 pimpl->cumulateStatistics(pimpl->node_stack.back(), top_);
413 const std::string& name_,
416 auto top_(pimpl->node_stack.back());
419 pimpl->fillRunningTime(context_, top_);
420 pimpl->fillStatistics(context_, top_);
423 pimpl->node_stack.pop_back();
424 pimpl->cumulateStatistics(pimpl->node_stack.back(), top_);
429 const std::string& name_,
432 auto top_(pimpl->node_stack.back());
435 pimpl->fillRunningTime(context_, top_);
436 pimpl->fillStatistics(context_, top_);
439 pimpl->node_stack.pop_back();
442 pimpl->doc.save_file(pimpl->filename.c_str());