xref: /haiku/src/tools/cppunit/cppunit/XmlOutputter.cpp (revision 58481f0f6ef1a61ba07283f012cafbc2ed874ead)
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 += "&lt;";
124       break;
125     case '>':
126       escaped += "&gt;";
127       break;
128     case '&':
129       escaped += "&amp;";
130       break;
131     case '\'':
132       escaped += "&apos;";
133       break;
134     case '"':
135       escaped += "&quot;";
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