scenario_simulator_v2 C++ API
junit5.hpp
Go to the documentation of this file.
1 // Copyright 2015 TIER IV, Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SIMPLE_JUNIT__JUNIT5_HPP_
16 #define SIMPLE_JUNIT__JUNIT5_HPP_
17 
18 #include <optional>
19 #include <pugixml.hpp>
20 #include <stdexcept>
21 #include <string>
22 #include <unordered_map>
23 
24 namespace xs
25 {
26 using string = std::string;
27 } // namespace xs
28 
29 namespace common
30 {
31 inline namespace junit
32 {
33 struct Pass
34 {
35  friend auto operator<<(std::ostream & os, const Pass &) -> std::ostream &
36  {
37  return os << "\x1b[32mPassed\x1b[0m";
38  }
39 };
40 
41 /*
42  <xs:element name="failure">
43  <xs:complexType mixed="true">
44  <xs:attribute name="type" type="xs:string" use="optional"/>
45  <xs:attribute name="message" type="xs:string" use="optional"/>
46  </xs:complexType>
47  </xs:element>
48 */
49 
50 struct Failure
51 {
53 
54  explicit Failure(const xs::string & type, const xs::string & message)
56  {
57  }
58 
59  friend auto operator<<(std::ostream & os, const Failure & failure) -> std::ostream &
60  {
61  return os << "\x1b[1;31m" << failure.type << ": " << failure.message << "\x1b[0m";
62  }
63 
64  friend auto operator<<(pugi::xml_node node, const Failure & failure) -> pugi::xml_node
65  {
66  if (not failure.type.empty()) {
67  node.append_attribute("type") = failure.type.c_str();
68  }
69 
70  if (not failure.message.empty()) {
71  node.append_attribute("message") = failure.message.c_str();
72  }
73 
74  return node;
75  }
76 };
77 
78 /*
79  <xs:element name="error">
80  <xs:complexType mixed="true">
81  <xs:attribute name="type" type="xs:string" use="optional"/>
82  <xs:attribute name="message" type="xs:string" use="optional"/>
83  </xs:complexType>
84  </xs:element>
85 */
86 
87 struct Error
88 {
90 
91  explicit Error(const xs::string & type, const xs::string & message) : type(type), message(message)
92  {
93  }
94 
95  friend auto operator<<(std::ostream & os, const Error & error) -> std::ostream &
96  {
97  return os << "\x1b[1;31m" << error.type << ": " << error.message << "\x1b[0m";
98  }
99 
100  friend auto operator<<(pugi::xml_node node, const Error & error) -> pugi::xml_node
101  {
102  if (not error.type.empty()) {
103  node.append_attribute("type") = error.type.c_str();
104  }
105 
106  if (not error.message.empty()) {
107  node.append_attribute("message") = error.message.c_str();
108  }
109 
110  return node;
111  }
112 };
113 
114 /*
115  <xs:element name="properties">
116  <xs:complexType>
117  <xs:sequence>
118  <xs:element ref="property" maxOccurs="unbounded"/>
119  </xs:sequence>
120  </xs:complexType>
121  </xs:element>
122 */
123 
125 {
127 };
128 
129 /*
130  <xs:element name="property">
131  <xs:complexType>
132  <xs:attribute name="name" type="xs:string" use="required"/>
133  <xs:attribute name="value" type="xs:string" use="required"/>
134  </xs:complexType>
135  </xs:element>
136 */
137 
138 struct Property
139 {
141 };
142 
143 /*
144  <xs:element name="skipped" type="xs:string"/>
145 */
146 
148 
149 /*
150  <xs:element name="system-out" type="xs:string"/>
151 */
152 
154 
155 /*
156  <xs:element name="system-err" type="xs:string"/>
157 */
158 
160 
161 /*
162  <xs:element name="testcase">
163  <xs:complexType>
164  <xs:sequence>
165  <xs:element ref="skipped" minOccurs="0" maxOccurs="1"/>
166  <xs:element ref="error" minOccurs="0" maxOccurs="unbounded"/>
167  <xs:element ref="failure" minOccurs="0" maxOccurs="unbounded"/>
168  <xs:element ref="system-out" minOccurs="0" maxOccurs="unbounded"/>
169  <xs:element ref="system-err" minOccurs="0" maxOccurs="unbounded"/>
170  </xs:sequence>
171  <xs:attribute name="name" type="xs:string" use="required"/>
172  <xs:attribute name="assertions" type="xs:string" use="optional"/>
173  <xs:attribute name="time" type="xs:string" use="optional"/>
174  <xs:attribute name="classname" type="xs:string" use="optional"/>
175  <xs:attribute name="status" type="xs:string" use="optional"/>
176  </xs:complexType>
177  </xs:element>
178 */
179 
181 {
183 
184  std::vector<Pass> pass;
185 
186  std::vector<Error> error;
187 
188  std::vector<Failure> failure;
189 
190  std::vector<SystemOut> system_out;
191 
192  std::vector<SystemErr> system_err;
193 
195 
197 
199 
201 
203 
204  explicit SimpleTestCase(const xs::string & name) : name(name) {}
205 
206  friend auto operator<<(pugi::xml_node node, const SimpleTestCase & testcase) -> pugi::xml_node
207  {
208  auto current_node = node.append_child("testcase");
209 
210  current_node.append_attribute("name") = testcase.name.c_str();
211 
212  if (not testcase.assertions.empty()) {
213  current_node.append_attribute("assertions") = testcase.assertions.c_str();
214  }
215 
216  if (not testcase.time.empty()) {
217  current_node.append_attribute("time") = testcase.time.c_str();
218  }
219 
220  if (not testcase.classname.empty()) {
221  current_node.append_attribute("classname") = testcase.classname.c_str();
222  }
223 
224  if (not testcase.status.empty()) {
225  current_node.append_attribute("status") = testcase.status.c_str();
226  }
227 
229 
230  for (const auto & each : testcase.error) {
231  current_node.append_child("error") << each;
232  }
233 
234  for (const auto & each : testcase.failure) {
235  current_node.append_child("failure") << each;
236  }
237 
239 
241 
242  return node;
243  }
244 };
245 
246 /*
247  <xs:element name="testsuite">
248  <xs:complexType>
249  <xs:sequence>
250  <xs:element ref="properties" minOccurs="0" maxOccurs="1"/>
251  <xs:element ref="testcase" minOccurs="0" maxOccurs="unbounded"/>
252  <xs:element ref="system-out" minOccurs="0" maxOccurs="1"/>
253  <xs:element ref="system-err" minOccurs="0" maxOccurs="1"/>
254  </xs:sequence>
255  <xs:attribute name="name" type="xs:string" use="required"/>
256  <xs:attribute name="tests" type="xs:string" use="required"/>
257  <xs:attribute name="failures" type="xs:string" use="optional"/>
258  <xs:attribute name="errors" type="xs:string" use="optional"/>
259  <xs:attribute name="time" type="xs:string" use="optional"/>
260  <xs:attribute name="disabled" type="xs:string" use="optional"/>
261  <xs:attribute name="skipped" type="xs:string" use="optional"/>
262  <xs:attribute name="timestamp" type="xs:string" use="optional"/>
263  <xs:attribute name="hostname" type="xs:string" use="optional"/>
264  <xs:attribute name="id" type="xs:string" use="optional"/>
265  <xs:attribute name="package" type="xs:string" use="optional"/>
266  </xs:complexType>
267  </xs:element>
268 */
269 
270 struct SimpleTestSuite : private std::unordered_map<xs::string, SimpleTestCase>
271 {
273 
274  explicit SimpleTestSuite(const xs::string & name) : name(name) {}
275 
276  auto getTestcaseNames() const -> std::vector<std::string>
277  {
278  std::vector<std::string> names;
279  for (auto itr = begin(); itr != end(); ++itr) {
280  names.emplace_back(itr->first);
281  }
282  return names;
283  }
284 
285  auto testcase(const xs::string & name) -> auto &
286  {
287  try {
288  return at(name);
289  } catch (const std::out_of_range &) {
290  emplace(name, name);
291  return at(name);
292  }
293  }
294 
295  friend auto operator<<(pugi::xml_node node, const SimpleTestSuite & testsuite) -> pugi::xml_node
296  {
297  auto current_node = node.append_child("testsuite");
298 
299  current_node.append_attribute("name") = testsuite.name.c_str();
300 
301  std::size_t tests = 0;
302  std::size_t failures = 0;
303  std::size_t pass = 0;
304  std::size_t errors = 0;
305  for (const auto & testcase : testsuite) {
306  current_node << testcase.second;
307  pass = pass + testcase.second.pass.size();
308  failures = failures + testcase.second.failure.size();
309  errors = errors + testcase.second.error.size();
310  }
311  tests = pass + failures + errors;
312  current_node.append_attribute("failures") = failures;
313  current_node.append_attribute("errors") = errors;
314  current_node.append_attribute("tests") = tests;
315  return node;
316  }
317 };
318 
319 /*
320  <xs:element name="testsuites">
321  <xs:complexType>
322  <xs:sequence>
323  <xs:element ref="testsuite" minOccurs="0" maxOccurs="unbounded"/>
324  </xs:sequence>
325  <xs:attribute name="name" type="xs:string" use="optional"/>
326  <xs:attribute name="time" type="xs:string" use="optional"/>
327  <xs:attribute name="tests" type="xs:string" use="optional"/>
328  <xs:attribute name="failures" type="xs:string" use="optional"/>
329  <xs:attribute name="disabled" type="xs:string" use="optional"/>
330  <xs:attribute name="errors" type="xs:string" use="optional"/>
331  </xs:complexType>
332  </xs:element>
333 */
334 
335 struct SimpleTestSuites : private std::unordered_map<std::string, SimpleTestSuite>
336 {
338 
339  explicit SimpleTestSuites(const xs::string & name = "") : name(name) {}
340 
341  auto testsuite(const xs::string & name) -> auto &
342  {
343  try {
344  return at(name);
345  } catch (const std::out_of_range &) {
346  emplace(name, name);
347  return at(name);
348  }
349  }
350 
351  friend auto operator<<(pugi::xml_node node, const SimpleTestSuites & testsuites) -> pugi::xml_node
352  {
353  auto current_node = node.append_child("testsuites");
354 
355  if (not testsuites.name.empty()) {
356  current_node.append_attribute("name") = testsuites.name.c_str();
357  }
358  std::size_t tests = 0;
359  std::size_t failures = 0;
360  std::size_t pass = 0;
361  std::size_t errors = 0;
362  for (const auto & testsuite : testsuites) {
363  SimpleTestSuite suite = testsuite.second;
364  current_node << suite;
365  const auto testcase_names = suite.getTestcaseNames();
366  for (const auto & testcase_name : testcase_names) {
367  failures = failures + suite.testcase(testcase_name).failure.size();
368  errors = errors + suite.testcase(testcase_name).error.size();
369  pass = pass + suite.testcase(testcase_name).pass.size();
370  }
371  tests = failures + errors + pass;
372  }
373  current_node.append_attribute("failures") = failures;
374  current_node.append_attribute("errors") = errors;
375  current_node.append_attribute("tests") = tests;
376 
377  return node;
378  }
379 
380  template <typename... Ts>
381  auto write_to(Ts &&... xs) const
382  {
383  pugi::xml_document document;
384 
385  document << *this;
386 
387  document.save_file(std::forward<decltype(xs)>(xs)...);
388  }
389 };
390 
392 } // namespace junit
393 } // namespace common
394 
395 #endif // SIMPLE_JUNIT__JUNIT5_HPP_
xs::string SystemErr
Definition: junit5.hpp:159
xs::string SystemOut
Definition: junit5.hpp:153
xs::string Skipped
Definition: junit5.hpp:147
Definition: concatenate.hpp:24
Definition: test_case.hpp:23
Definition: cache.hpp:27
Definition: junit5.hpp:25
std::string string
Definition: junit5.hpp:26
Definition: junit5.hpp:88
friend auto operator<<(pugi::xml_node node, const Error &error) -> pugi::xml_node
Definition: junit5.hpp:100
friend auto operator<<(std::ostream &os, const Error &error) -> std::ostream &
Definition: junit5.hpp:95
Error(const xs::string &type, const xs::string &message)
Definition: junit5.hpp:91
xs::string message
Definition: junit5.hpp:89
xs::string type
Definition: junit5.hpp:89
Definition: junit5.hpp:51
xs::string type
Definition: junit5.hpp:52
xs::string message
Definition: junit5.hpp:52
Failure(const xs::string &type, const xs::string &message)
Definition: junit5.hpp:54
friend auto operator<<(std::ostream &os, const Failure &failure) -> std::ostream &
Definition: junit5.hpp:59
friend auto operator<<(pugi::xml_node node, const Failure &failure) -> pugi::xml_node
Definition: junit5.hpp:64
Definition: junit5.hpp:34
friend auto operator<<(std::ostream &os, const Pass &) -> std::ostream &
Definition: junit5.hpp:35
Definition: junit5.hpp:125
Definition: junit5.hpp:139
Definition: junit5.hpp:181
std::vector< Pass > pass
Definition: junit5.hpp:184
xs::string time
Definition: junit5.hpp:198
std::vector< SystemErr > system_err
Definition: junit5.hpp:192
const xs::string name
Definition: junit5.hpp:194
std::vector< SystemOut > system_out
Definition: junit5.hpp:190
std::vector< Error > error
Definition: junit5.hpp:186
std::vector< Failure > failure
Definition: junit5.hpp:188
friend auto operator<<(pugi::xml_node node, const SimpleTestCase &testcase) -> pugi::xml_node
Definition: junit5.hpp:206
SimpleTestCase(const xs::string &name)
Definition: junit5.hpp:204
xs::string status
Definition: junit5.hpp:202
xs::string assertions
Definition: junit5.hpp:196
xs::string classname
Definition: junit5.hpp:200
Skipped skipped
Definition: junit5.hpp:182
Definition: junit5.hpp:271
auto testcase(const xs::string &name) -> auto &
Definition: junit5.hpp:285
SimpleTestSuite(const xs::string &name)
Definition: junit5.hpp:274
const xs::string name
Definition: junit5.hpp:272
friend auto operator<<(pugi::xml_node node, const SimpleTestSuite &testsuite) -> pugi::xml_node
Definition: junit5.hpp:295
auto getTestcaseNames() const -> std::vector< std::string >
Definition: junit5.hpp:276
Definition: junit5.hpp:336
xs::string name
Definition: junit5.hpp:337
auto write_to(Ts &&... xs) const
Definition: junit5.hpp:381
SimpleTestSuites(const xs::string &name="")
Definition: junit5.hpp:339
auto testsuite(const xs::string &name) -> auto &
Definition: junit5.hpp:341
friend auto operator<<(pugi::xml_node node, const SimpleTestSuites &testsuites) -> pugi::xml_node
Definition: junit5.hpp:351