]> git.stg.codes - stg.git/blob - tests/tut/tut_cppunit_reporter.hpp
Merge branch 'master' into full-month-stats
[stg.git] / tests / tut / tut_cppunit_reporter.hpp
1 \r
2 #ifndef TUT_CPPUNIT_REPORTER\r
3 #define TUT_CPPUNIT_REPORTER\r
4 \r
5 #include <tut/tut.hpp>\r
6 #include <string>\r
7 #include <fstream>\r
8 #include <vector>\r
9 #include <stdexcept>\r
10 \r
11 namespace tut\r
12 {\r
13 \r
14 /**\r
15  * CppUnit TUT reporter\r
16  */\r
17 class cppunit_reporter : public tut::callback\r
18 {\r
19     private:\r
20         std::vector<tut::test_result> failed_tests;\r
21         std::vector<tut::test_result> passed_tests;\r
22         std::string filename;\r
23 \r
24         std::string encode(const std::string & text)\r
25         {\r
26             std::string out;\r
27 \r
28             for (unsigned int i=0; i<text.length(); ++i) {\r
29                 char c = text[i];\r
30                 switch (c) {\r
31                     case '<':\r
32                         out += "&lt;";\r
33                         break;\r
34                     case '>':\r
35                         out += "&gt;";\r
36                         break;\r
37                     case '&':\r
38                         out += "&amp;";\r
39                         break;\r
40                     case '\'':\r
41                         out += "&apos;";\r
42                         break;\r
43                     case '"':\r
44                         out += "&quot;";\r
45                         break;\r
46                     default:\r
47                         out += c;\r
48                 }\r
49             }\r
50 \r
51             return out;\r
52         }\r
53 \r
54 public:\r
55 \r
56     cppunit_reporter(const std::string & _filename = "")\r
57     {\r
58         setFilename(_filename);\r
59     }\r
60 \r
61     void setFilename(const std::string & _filename)\r
62     {\r
63         if (_filename == "")\r
64         {\r
65             filename = "testResult.xml";\r
66         }\r
67         else\r
68         {\r
69             filename = _filename;\r
70         }\r
71     }\r
72 \r
73     void run_started()\r
74     {\r
75         failed_tests.clear();\r
76         passed_tests.clear();\r
77     }\r
78 \r
79     void test_completed(const tut::test_result& tr)\r
80     {\r
81         if (tr.result == test_result::ok) {\r
82             passed_tests.push_back(tr);\r
83         } else {\r
84             failed_tests.push_back(tr);\r
85         }\r
86     }\r
87 \r
88     void run_completed()\r
89     {\r
90         int errors = 0;\r
91         int failures = 0;\r
92         std::string failure_type;\r
93         std::string failure_msg;\r
94         std::ofstream xmlfile;\r
95 \r
96         xmlfile.open(filename.c_str(), std::ios::in | std::ios::trunc);\r
97         if (!xmlfile.is_open()) {\r
98             throw (std::runtime_error("Cannot open file for output"));\r
99         }\r
100 \r
101         /* *********************** header ***************************** */\r
102         xmlfile << "<?xml version=\"1.0\" encoding='ISO-8859-1' standalone='yes' ?>" << std::endl\r
103                 << "<TestRun>" << std::endl;\r
104 \r
105         /* *********************** failed tests ***************************** */\r
106         if (failed_tests.size() > 0) {\r
107             xmlfile << "  <FailedTests>" << std::endl;\r
108 \r
109             for (unsigned int i=0; i<failed_tests.size(); i++) {\r
110                 switch (failed_tests[i].result) {\r
111                     case test_result::fail:\r
112                         failure_type = "Assertion";\r
113                         failure_msg  = "";\r
114                         failures++;\r
115                         break;\r
116                     case test_result::ex:\r
117                         failure_type = "Assertion";\r
118                         failure_msg  = "Thrown exception: " + failed_tests[i].exception_typeid + '\n';\r
119                         failures++;\r
120                         break;\r
121                     case test_result::warn:\r
122                         failure_type = "Assertion";\r
123                         failure_msg  = "Destructor failed.\n";\r
124                         failures++;\r
125                         break;\r
126                     case test_result::term:\r
127                         failure_type = "Error";\r
128                         failure_msg  = "Test application terminated abnormally.\n";\r
129                         errors++;\r
130                         break;\r
131                     case test_result::ex_ctor:\r
132                         failure_type = "Error";\r
133                         failure_msg  = "Constructor has thrown an exception: " + failed_tests[i].exception_typeid + '\n';\r
134                         errors++;\r
135                         break;\r
136                     case test_result::rethrown:\r
137                         failure_type = "Assertion";\r
138                         failure_msg  = "Child failed";\r
139                         failures++;\r
140                         break;\r
141                     default:\r
142                         failure_type = "Error";\r
143                         failure_msg  = "Unknown test status, this should have never happened. "\r
144                                        "You may just have found a BUG in TUT CppUnit reporter, please report it immediately.\n";\r
145                         errors++;\r
146                         break;\r
147                 }\r
148 \r
149                 xmlfile << "    <FailedTest id=\"" << failed_tests[i].test << "\">" << std::endl\r
150                         << "      <Name>" << encode(failed_tests[i].group) + "::" + encode(failed_tests[i].name) << "</Name>" << std::endl\r
151                         << "      <FailureType>" << failure_type << "</FailureType>" << std::endl\r
152                         << "      <Location>" << std::endl\r
153                         << "        <File>Unknown</File>" << std::endl\r
154                         << "        <Line>Unknown</Line>" << std::endl\r
155                         << "      </Location>" << std::endl\r
156                         << "      <Message>" << encode(failure_msg + failed_tests[i].message) << "</Message>" << std::endl\r
157                         << "    </FailedTest>" << std::endl;\r
158             }\r
159 \r
160             xmlfile << "  </FailedTests>" << std::endl;\r
161         }\r
162 \r
163         /* *********************** passed tests ***************************** */\r
164         if (passed_tests.size() > 0) {\r
165             xmlfile << "  <SuccessfulTests>" << std::endl;\r
166 \r
167             for (unsigned int i=0; i<passed_tests.size(); i++) {\r
168                 xmlfile << "    <Test id=\"" << passed_tests[i].test << "\">" << std::endl\r
169                         << "      <Name>" << encode(passed_tests[i].group) + "::" + encode(passed_tests[i].name) << "</Name>" << std::endl\r
170                         << "    </Test>" << std::endl;\r
171             }\r
172 \r
173             xmlfile << "  </SuccessfulTests>" << std::endl;\r
174         }\r
175 \r
176         /* *********************** statistics ***************************** */\r
177         xmlfile << "  <Statistics>" << std::endl\r
178                 << "    <Tests>" << (failed_tests.size() + passed_tests.size()) << "</Tests>" << std::endl\r
179                 << "    <FailuresTotal>" << failed_tests.size() << "</FailuresTotal>" << std::endl\r
180                 << "    <Errors>" << errors << "</Errors>" << std::endl\r
181                 << "    <Failures>" << failures << "</Failures>" << std::endl\r
182                 << "  </Statistics>" << std::endl;\r
183 \r
184         /* *********************** footer ***************************** */\r
185         xmlfile << "</TestRun>" << std::endl;\r
186 \r
187         xmlfile.close();\r
188     }\r
189 \r
190     bool all_ok() const\r
191     {\r
192         return failed_tests.empty();\r
193     };\r
194 \r
195 \r
196 };\r
197 \r
198 }\r
199 \r
200 #endif\r
201 \r