xmlreporter.pas 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. {
  2. Copyright (C) 2006 Graeme Geldenhuys <[email protected]>
  3. This source is free software; you can redistribute it and/or modify it under
  4. the terms of the GNU General Public License as published by the Free
  5. Software Foundation; either version 2 of the License, or (at your option)
  6. any later version.
  7. This code is distributed in the hope that it will be useful, but WITHOUT ANY
  8. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. details.
  11. A copy of the GNU General Public License is available on the World Wide Web
  12. at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
  13. to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  14. MA 02111-1307, USA.
  15. Purpose:
  16. This unit contains a XML TestListener for use with the fpcUnit testing
  17. framework. It uses the XMLWrite unit, which is part of FPC, to generate
  18. the XML document. The benefit of using the XMLWrite unit, is that the
  19. data generated is valid XML, with resevered characters correctly escaped.
  20. This allows the XML document to be further processed with XSTL etc without
  21. any issues.
  22. }
  23. unit xmlreporter;
  24. {$mode objfpc}{$H+}
  25. interface
  26. uses
  27. Classes
  28. ,SysUtils
  29. ,fpcUnit
  30. ,TestUtils
  31. ,dom
  32. ,XMLWrite
  33. ;
  34. type
  35. { XML Test Listner }
  36. TXMLResultsWriter = class(TNoRefCountObject, ITestListener)
  37. private
  38. FDoc: TXMLDocument;
  39. { These TDOMNodes are for easy access and a bit of optimization }
  40. FResults: TDOMNode;
  41. FListing: TDOMNode;
  42. FFailures: TDOMNode;
  43. FErrors: TDOMNode;
  44. { Converts the actual test results into XML nodes. This gets called
  45. by the public method WriteResult. }
  46. procedure TestResultAsXML(pTestResult: TTestResult);
  47. { This gets called in the class constructor and sets up the starting nodes }
  48. procedure WriteHeader;
  49. public
  50. constructor Create;
  51. destructor Destroy; override;
  52. procedure WriteResult(aResult: TTestResult);
  53. { ITestListener interface requirements }
  54. procedure AddFailure(ATest: TTest; AFailure: TTestFailure);
  55. procedure AddError(ATest: TTest; AError: TTestFailure);
  56. procedure StartTest(ATest: TTest);
  57. procedure EndTest(ATest: TTest);
  58. { A public property to the internal XML document }
  59. property Document: TXMLDocument read FDoc;
  60. end;
  61. implementation
  62. { TXMLResultsWriter }
  63. procedure TXMLResultsWriter.TestResultAsXML(pTestResult: TTestResult);
  64. var
  65. i: longint;
  66. n, lResults: TDOMNode;
  67. begin
  68. lResults := FDoc.FindNode('TestResults');
  69. n := FDoc.CreateElement('NumberOfRunnedTests');
  70. n.AppendChild(FDoc.CreateTextNode(IntToStr(pTestResult.RunTests)));
  71. lResults.AppendChild(n);
  72. n := FDoc.CreateElement('NumberOfErrors');
  73. n.AppendChild(FDoc.CreateTextNode(IntToStr(pTestResult.NumberOfErrors)));
  74. lResults.AppendChild(n);
  75. n := FDoc.CreateElement('NumberOfFailures');
  76. n.AppendChild(FDoc.CreateTextNode(IntToStr(pTestResult.NumberOfFailures)));
  77. lResults.AppendChild(n);
  78. if pTestResult.NumberOfErrors <> 0 then
  79. begin
  80. for i := 0 to pTestResult.Errors.Count - 1 do
  81. AddError(nil, TTestFailure(pTestResult.Errors.Items[i]));
  82. end;
  83. if pTestResult.NumberOfFailures <> 0 then
  84. begin
  85. for i := 0 to pTestResult.Failures.Count - 1 do
  86. AddFailure(nil, TTestFailure(pTestResult.Failures.Items[i]));
  87. end;
  88. end;
  89. procedure TXMLResultsWriter.WriteHeader;
  90. begin
  91. FResults := FDoc.CreateElement('TestResults');
  92. FResults.AppendChild(FDoc.CreateComment(' Generated using FPCUnit on '
  93. + FormatDateTime('yyyy-mm-dd hh:mm ', Now) ));
  94. FDoc.AppendChild(FResults);
  95. FListing := FDoc.CreateElement('TestListing');
  96. FResults.AppendChild(FListing);
  97. end;
  98. constructor TXMLResultsWriter.Create;
  99. begin
  100. FDoc := TXMLDocument.Create;
  101. FResults := nil;
  102. FFailures := nil;
  103. FErrors := nil;
  104. WriteHeader;
  105. end;
  106. destructor TXMLResultsWriter.Destroy;
  107. begin
  108. FDoc.Free;
  109. inherited Destroy;
  110. end;
  111. procedure TXMLResultsWriter.WriteResult(aResult: TTestResult);
  112. begin
  113. TestResultAsXML(aResult);
  114. end;
  115. procedure TXMLResultsWriter.AddFailure(ATest: TTest; AFailure: TTestFailure);
  116. var
  117. n: TDOMElement;
  118. begin
  119. { Try and find the node first }
  120. if not Assigned(FFailures) then
  121. FFailures := FDoc.FindNode('ListOfFailures');
  122. { If we couldn't find it, create it }
  123. if not Assigned(FFailures) then
  124. begin
  125. FFailures := FDoc.CreateElement('ListOfFailures');
  126. FResults.AppendChild(FFailures);
  127. end;
  128. n := FDoc.CreateElement('Failure');
  129. n.AppendChild(FDoc.CreateElement('Message') ).AppendChild(FDoc.CreateTextNode(AFailure.AsString));
  130. n.AppendChild(FDoc.CreateElement('ExceptionClass') ).AppendChild(FDoc.CreateTextNode(AFailure.ExceptionClassName));
  131. n.AppendChild(FDoc.CreateElement('ExceptionMessage')).AppendChild(FDoc.CreateTextNode(AFailure.ExceptionMessage));
  132. FFailures.AppendChild(n);
  133. end;
  134. procedure TXMLResultsWriter.AddError(ATest: TTest; AError: TTestFailure);
  135. var
  136. n: TDOMElement;
  137. begin
  138. { Try and find the node first }
  139. if not Assigned(FErrors) then
  140. FErrors := FDoc.FindNode('ListOfErrors');
  141. { If we couldn't find it, create it }
  142. if not Assigned(FErrors) then
  143. begin
  144. FErrors := FDoc.CreateElement('ListOfErrors');
  145. FResults.AppendChild(FErrors);
  146. end;
  147. n := FDoc.CreateElement('Error');
  148. n.AppendChild(FDoc.CreateElement('Message') ).AppendChild(FDoc.CreateTextNode(AError.AsString));
  149. n.AppendChild(FDoc.CreateElement('ExceptionClass') ).AppendChild(FDoc.CreateTextNode(AError.ExceptionClassName));
  150. n.AppendChild(FDoc.CreateElement('ExceptionMessage')).AppendChild(FDoc.CreateTextNode(AError.ExceptionMessage));
  151. n.AppendChild(FDoc.CreateElement('SourceUnitName') ).AppendChild(FDoc.CreateTextNode(AError.SourceUnitName));
  152. n.AppendChild(FDoc.CreateElement('LineNumber') ).AppendChild(FDoc.CreateTextNode(IntToStr(AError.LineNumber)));
  153. n.AppendChild(FDoc.CreateElement('FailedMethodName')).AppendChild(FDoc.CreateTextNode(AError.FailedMethodName));
  154. FErrors.AppendChild(n);
  155. end;
  156. procedure TXMLResultsWriter.StartTest(ATest: TTest);
  157. var
  158. n: TDOMElement;
  159. begin
  160. if not Assigned(FListing) then
  161. exit;
  162. n := FDoc.CreateElement('Test');
  163. n['Name'] := ATest.TestSuiteName + '.' + ATest.TestName;
  164. FListing.AppendChild(n);
  165. end;
  166. procedure TXMLResultsWriter.EndTest(ATest: TTest);
  167. begin
  168. { do nothing }
  169. end;
  170. end.