1 #include <cppunit/Exception.h>
2 #include <cppunit/Test.h>
3 #include <cppunit/TestFailure.h>
4 #include <cppunit/TestResultCollector.h>
5 #include <cppunit/XmlOutputter.h>
6 #include <map>
7 #include <stdlib.h>
8
9
10 using std::endl;
11 using std::ostream;
12 using std::pair;
13 using std::string;
14
15
16 namespace CppUnit
17 {
18
19 // XmlOutputter::Node
20 // //////////////////////////////////////////////////////////////////
21
22
Node(string elementName,string content)23 XmlOutputter::Node::Node( string elementName,
24 string content ) :
25 m_name( elementName ),
26 m_content( content )
27 {
28 }
29
30
Node(string elementName,int numericContent)31 XmlOutputter::Node::Node( string elementName,
32 int numericContent ) :
33 m_name( elementName )
34 {
35 m_content = asString( numericContent );
36 }
37
38
~Node()39 XmlOutputter::Node::~Node()
40 {
41 Nodes::iterator itNode = m_nodes.begin();
42 while ( itNode != m_nodes.end() )
43 delete *itNode++;
44 }
45
46
47 void
addAttribute(string attributeName,string value)48 XmlOutputter::Node::addAttribute( string attributeName,
49 string value )
50 {
51 m_attributes.push_back( Attribute( attributeName, value ) );
52 }
53
54
55 void
addAttribute(string attributeName,int numericValue)56 XmlOutputter::Node::addAttribute( string attributeName,
57 int numericValue )
58 {
59 addAttribute( attributeName, asString( numericValue ) );
60 }
61
62
63 void
addNode(Node * node)64 XmlOutputter::Node::addNode( Node *node )
65 {
66 m_nodes.push_back( node );
67 }
68
69
70 string
toString() const71 XmlOutputter::Node::toString() const
72 {
73 string element = "<";
74 element += m_name;
75 element += " ";
76 element += attributesAsString();
77 element += " >\n";
78
79 Nodes::const_iterator itNode = m_nodes.begin();
80 while ( itNode != m_nodes.end() )
81 {
82 const Node *node = *itNode++;
83 element += node->toString();
84 }
85
86 element += m_content;
87
88 element += "</";
89 element += m_name;
90 element += ">\n";
91
92 return element;
93 }
94
95
96 string
attributesAsString() const97 XmlOutputter::Node::attributesAsString() const
98 {
99 string attributes;
100 Attributes::const_iterator itAttribute = m_attributes.begin();
101 while ( itAttribute != m_attributes.end() )
102 {
103 const Attribute &attribute = *itAttribute++;
104 attributes += attribute.first;
105 attributes += "=\"";
106 attributes += escape( attribute.second );
107 attributes += "\"";
108 }
109 return attributes;
110 }
111
112
113 string
escape(string value) const114 XmlOutputter::Node::escape( string value ) const
115 {
116 string escaped;
117 for ( int index =0; index < (int)value.length(); ++index )
118 {
119 char c = value[index ];
120 switch ( c ) // escape all predefined XML entity (safe?)
121 {
122 case '<':
123 escaped += "<";
124 break;
125 case '>':
126 escaped += ">";
127 break;
128 case '&':
129 escaped += "&";
130 break;
131 case '\'':
132 escaped += "'";
133 break;
134 case '"':
135 escaped += """;
136 break;
137 default:
138 escaped += c;
139 }
140 }
141
142 return escaped;
143 }
144
145 // should be somewhere else... Future CppUnit::String ?
146 string
asString(int value)147 XmlOutputter::Node::asString( int value )
148 {
149 OStringStream stream;
150 stream << value;
151 return stream.str();
152 }
153
154
155
156
157 // XmlOutputter
158 // //////////////////////////////////////////////////////////////////
159
XmlOutputter(TestResultCollector * result,ostream & stream,string encoding)160 XmlOutputter::XmlOutputter( TestResultCollector *result,
161 ostream &stream,
162 string encoding ) :
163 m_result( result ),
164 m_stream( stream ),
165 m_encoding( encoding )
166 {
167 }
168
169
~XmlOutputter()170 XmlOutputter::~XmlOutputter()
171 {
172 }
173
174
175 void
write()176 XmlOutputter::write()
177 {
178 writeProlog();
179 writeTestsResult();
180 }
181
182
183 void
writeProlog()184 XmlOutputter::writeProlog()
185 {
186 m_stream << "<?xml version=\"1.0\" "
187 "encoding='" << m_encoding << "' standalone='yes' ?>"
188 << endl;
189 }
190
191
192 void
writeTestsResult()193 XmlOutputter::writeTestsResult()
194 {
195 Node *rootNode = makeRootNode();
196 m_stream << rootNode->toString();
197 delete rootNode;
198 }
199
200
201 XmlOutputter::Node *
makeRootNode()202 XmlOutputter::makeRootNode()
203 {
204 Node *rootNode = new Node( "TestRun" );
205
206 FailedTests failedTests;
207 fillFailedTestsMap( failedTests );
208
209 addFailedTests( failedTests, rootNode );
210 addSucessfulTests( failedTests, rootNode );
211 addStatistics( rootNode );
212
213 return rootNode;
214 }
215
216
217 void
fillFailedTestsMap(FailedTests & failedTests)218 XmlOutputter::fillFailedTestsMap( FailedTests &failedTests )
219 {
220 const TestResultCollector::TestFailures &failures = m_result->failures();
221 TestResultCollector::TestFailures::const_iterator itFailure = failures.begin();
222 while ( itFailure != failures.end() )
223 {
224 TestFailure *failure = *itFailure++;
225 failedTests.insert(
226 pair< CppUnit::Test* const, CppUnit::TestFailure*
227 >(
228 failure->failedTest(), failure
229 )
230 );
231 }
232 }
233
234
235 void
addFailedTests(FailedTests & failedTests,Node * rootNode)236 XmlOutputter::addFailedTests( FailedTests &failedTests,
237 Node *rootNode )
238 {
239 Node *testsNode = new Node( "FailedTests" );
240 rootNode->addNode( testsNode );
241
242 const TestResultCollector::Tests &tests = m_result->tests();
243 for ( int testNumber = 0; testNumber < (int)tests.size(); ++testNumber )
244 {
245 Test *test = tests[testNumber];
246 if ( failedTests.find( test ) != failedTests.end() )
247 addFailedTest( test, failedTests[test], testNumber+1, testsNode );
248 }
249 }
250
251
252 void
addSucessfulTests(FailedTests & failedTests,Node * rootNode)253 XmlOutputter::addSucessfulTests( FailedTests &failedTests,
254 Node *rootNode )
255 {
256 Node *testsNode = new Node( "SucessfulTests" );
257 rootNode->addNode( testsNode );
258
259 const TestResultCollector::Tests &tests = m_result->tests();
260 for ( int testNumber = 0; testNumber < (int)tests.size(); ++testNumber )
261 {
262 Test *test = tests[testNumber];
263 if ( failedTests.find( test ) == failedTests.end() )
264 addSucessfulTest( test, testNumber+1, testsNode );
265 }
266 }
267
268
269 void
addStatistics(Node * rootNode)270 XmlOutputter::addStatistics( Node *rootNode )
271 {
272 Node *statisticsNode = new Node( "Statistics" );
273 rootNode->addNode( statisticsNode );
274 statisticsNode->addNode( new Node( "Tests", m_result->runTests() ) );
275 statisticsNode->addNode( new Node( "FailuresTotal",
276 m_result->testFailuresTotal() ) );
277 statisticsNode->addNode( new Node( "Errors", m_result->testErrors() ) );
278 statisticsNode->addNode( new Node( "Failures", m_result->testFailures() ) );
279 }
280
281
282 void
addFailedTest(Test * test,TestFailure * failure,int testNumber,Node * testsNode)283 XmlOutputter::addFailedTest( Test *test,
284 TestFailure *failure,
285 int testNumber,
286 Node *testsNode )
287 {
288 Exception *thrownException = failure->thrownException();
289
290 Node *testNode = new Node( "FailedTest", thrownException->what() );
291 testsNode->addNode( testNode );
292 testNode->addAttribute( "id", testNumber );
293 testNode->addNode( new Node( "Name", test->getName() ) );
294 testNode->addNode( new Node( "FailureType",
295 failure->isError() ? "Error" : "Assertion" ) );
296
297 if ( failure->sourceLine().isValid() )
298 addFailureLocation( failure, testNode );
299 }
300
301
302 void
addFailureLocation(TestFailure * failure,Node * testNode)303 XmlOutputter::addFailureLocation( TestFailure *failure,
304 Node *testNode )
305 {
306 Node *locationNode = new Node( "Location" );
307 testNode->addNode( locationNode );
308 SourceLine sourceLine = failure->sourceLine();
309 locationNode->addNode( new Node( "File", sourceLine.fileName() ) );
310 locationNode->addNode( new Node( "Line", sourceLine.lineNumber() ) );
311 }
312
313
314 void
addSucessfulTest(Test * test,int testNumber,Node * testsNode)315 XmlOutputter::addSucessfulTest( Test *test,
316 int testNumber,
317 Node *testsNode )
318 {
319 Node *testNode = new Node( "Test" );
320 testsNode->addNode( testNode );
321 testNode->addAttribute( "id", testNumber );
322 testNode->addNode( new Node( "Name", test->getName() ) );
323 }
324
325
326 } // namespace CppUnit
327