@@ -13,10 +13,31 @@ namespace CppSpec::Formatters {
1313// JUnit XML header
1414constexpr static auto junit_xml_header = R"( <?xml version="1.0" encoding="UTF-8"?>)" ;
1515
16- struct XMLSerializable {
17- virtual ~XMLSerializable () = default ;
18- [[nodiscard]] virtual std::string to_xml () const = 0;
19- };
16+ inline std::string encode_xml (const std::string& data) {
17+ std::string buffer;
18+ for (char c : data) {
19+ switch (c) {
20+ case ' <' :
21+ buffer += " <" ;
22+ break ;
23+ case ' >' :
24+ buffer += " >" ;
25+ break ;
26+ case ' &' :
27+ buffer += " &" ;
28+ break ;
29+ case ' "' :
30+ buffer += " "" ;
31+ break ;
32+ case ' \' ' :
33+ buffer += " '" ;
34+ break ;
35+ default :
36+ buffer += c;
37+ }
38+ }
39+ return buffer;
40+ }
2041
2142namespace JUnitNodes {
2243struct Result {
@@ -42,8 +63,8 @@ struct Result {
4263 }
4364
4465 [[nodiscard]] std::string to_xml () const {
45- return std::format (R"( <{} message="{}" type="{}">{}</{}>)" , status_string (), message, type, text ,
46- status_string ());
66+ return std::format (R"( <{} message="{}" type="{}">{}</{}>)" , status_string (), encode_xml ( message) ,
67+ encode_xml (type), encode_xml (text), status_string ());
4768 }
4869};
4970
@@ -58,8 +79,8 @@ struct TestCase {
5879
5980 [[nodiscard]] std::string to_xml () const {
6081 auto start =
61- std::format (R"( <testcase name="{}" classname="{}" assertions="{}" time="{:f}" file="{}" line="{}")" , name,
62- classname, assertions, time.count (), file, line);
82+ std::format (R"( <testcase name="{}" classname="{}" assertions="{}" time="{:f}" file="{}" line="{}")" ,
83+ encode_xml (name), encode_xml ( classname) , assertions, time.count (), file, line);
6384 if (results.empty ()) {
6485 return start + " />" ;
6586 }
@@ -99,10 +120,10 @@ struct TestSuite {
99120
100121 std::stringstream ss;
101122 ss << " "
102- << std::format (R"( <testsuite id="{}" name="{}" time="{:f}" timestamp="{}" tests="{}" failures="{}">)" , id, name,
103- time.count (), timestamp_str, tests, failures);
123+ << std::format (R"( <testsuite id="{}" name="{}" time="{:f}" timestamp="{}" tests="{}" failures="{}">)" , id,
124+ encode_xml (name), time.count (), timestamp_str, tests, failures);
104125 ss << std::endl;
105- for (const auto & test_case : cases) {
126+ for (const TestCase & test_case : cases) {
106127 ss << test_case.to_xml () << std::endl;
107128 }
108129 ss << " </testsuite>" ;
@@ -127,8 +148,8 @@ struct TestSuites {
127148 [[nodiscard]] std::string to_xml () const {
128149 std::stringstream ss;
129150 auto timestamp_str = std::format (" {0:%F}T{0:%T}" , timestamp);
130- ss << std::format (R"( <testsuites name="{}" tests="{}" failures="{}" time="{:f}" timestamp="{}">)" , name, tests ,
131- failures, time.count (), timestamp_str);
151+ ss << std::format (R"( <testsuites name="{}" tests="{}" failures="{}" time="{:f}" timestamp="{}">)" , encode_xml ( name) ,
152+ tests, failures, time.count (), timestamp_str);
132153 ss << std::endl;
133154 for (const TestSuite& suite : suites) {
134155 ss << suite.to_xml () << std::endl;
0 commit comments