1#ifndef BANDIT_REPORTERS_XUNIT_REPORTER_H
2#define BANDIT_REPORTERS_XUNIT_REPORTER_H
3
4#include <iostream>
5#include <bandit/reporters/progress_reporter.h>
6
7namespace bandit {
8 namespace detail {
9 struct xunit_reporter : public progress_reporter {
10 xunit_reporter(std::ostream& stm, const failure_formatter& formatter)
11 : progress_reporter(formatter), stm_(stm) {}
12
13 xunit_reporter(const failure_formatter& formatter)
14 : xunit_reporter(std::cout, formatter) {}
15
16 void it_starting(const std::string& desc) override {
17 progress_reporter::it_starting(desc);
18 work_stm_ << "\t<testcase classname=\"" << escape(current_context_name()) << "\" ";
19 work_stm_ << "name=\"" << escape(desc) << "\" time=\"0.0\">\n";
20 }
21
22 void it_succeeded(const std::string& desc) override {
23 progress_reporter::it_succeeded(desc);
24 work_stm_ << "\t</testcase>\n";
25 }
26
27 void it_failed(const std::string& desc, const assertion_exception& ex) override {
28 progress_reporter::it_failed(desc, ex);
29 work_stm_ << "\t\t<failure message=\"" << escape(failure_formatter_.format(ex)) << "\" />\n";
30 work_stm_ << "\t</testcase>\n";
31 }
32
33 void it_unknown_error(const std::string& desc) override {
34 progress_reporter::it_unknown_error(desc);
35 work_stm_ << "\t\t<failure message=\"Unknown exception\" />\n";
36 work_stm_ << "\t</testcase>\n";
37 }
38
39 void it_skip(const std::string& desc) override {
40 progress_reporter::it_skip(desc);
41 work_stm_ << "\t<testcase classname=\"" << escape(current_context_name()) << "\" ";
42 work_stm_ << "name=\"" << escape(desc) << "\" time=\"0.0\">\n";
43 work_stm_ << "\t\t<skipped />\n";
44 work_stm_ << "\t</testcase>\n";
45 }
46
47 void test_run_complete() override {
48 stm_ << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
49 stm_ << "<testsuite name=\"bandit\" tests=\"" << specs_run_ << "\" errors=\"0\" failures=\""
50 << specs_failed_ << "\"";
51
52 if (specs_skipped_ > 0) {
53 stm_ << " skipped=\"" << specs_skipped_ << "\"";
54 }
55
56 stm_ << ">\n";
57
58 stm_ << work_stm_.str();
59
60 stm_ << "</testsuite>\n";
61 }
62
63 private:
64 std::string escape(const std::string& str) {
65 std::stringstream stm;
66
67 for (char c : str) {
68 switch (c) {
69 case '&':
70 stm << "&amp;";
71 break;
72 case '<':
73 stm << "&lt;";
74 break;
75 case '>':
76 stm << "&gt;";
77 break;
78 case '\\':
79 stm << "&apos;";
80 break;
81 case '\"':
82 stm << "&quot;";
83 break;
84 default:
85 stm << c;
86 }
87 }
88
89 return stm.str();
90 }
91
92 private:
93 std::ostream& stm_;
94 std::stringstream work_stm_;
95 };
96 }
97}
98#endif
99