latextestreport.pp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. {$mode objfpc}
  2. {$h+}
  3. {
  4. This file is part of the Free Component Library (FCL)
  5. Copyright (c) 2006 by Dean Zobec
  6. an example of latex report for FPCUnit tests.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit latextestreport;
  14. interface
  15. uses
  16. classes, SysUtils, fpcunit, fpcunitreport, strutils;
  17. type
  18. TLatexResultsWriter = class(TCustomResultsWriter)
  19. private
  20. FDoc: TStringList;
  21. FSuiteHeaderIdx: TFPList;
  22. FTempFailure: TTestFailure;
  23. protected
  24. class function EscapeText(const S: string): String; virtual;
  25. procedure WriteTestHeader(ATest: TTest; ALevel: integer; ACount: integer); override;
  26. procedure WriteTestFooter(ATest: TTest; ALevel: integer; ATiming: TDateTime); override;
  27. procedure WriteSuiteHeader(ATestSuite: TTestSuite; ALevel: integer); override;
  28. procedure WriteSuiteFooter(ATestSuite: TTestSuite; ALevel: integer;
  29. ATiming: TDateTime; ANumRuns: integer; ANumErrors: integer;
  30. ANumFailures: integer; ANumIgnores: integer); override;
  31. public
  32. constructor Create(aOwner: TComponent); override;
  33. destructor Destroy; override;
  34. procedure WriteHeader; override;
  35. procedure WriteFooter; override;
  36. procedure WriteResult(aResult: TTestResult); override;
  37. procedure AddFailure(ATest: TTest; AFailure: TTestFailure); override;
  38. procedure AddError(ATest: TTest; AError: TTestFailure); override;
  39. procedure StartTest(ATest: TTest); override;
  40. procedure EndTest(ATest: TTest); override;
  41. end;
  42. function TestSuiteAsLatex(aSuite:TTestSuite): string;
  43. function GetSuiteAsLatex(aSuite: TTestSuite): string;
  44. implementation
  45. class function TLatexResultsWriter.EscapeText(const S: string): String;
  46. var
  47. i: integer;
  48. begin
  49. SetLength(Result, 0);
  50. for i := 1 to Length(S) do
  51. case S[i] of
  52. '&','{','}','#','_','$','%': // Escape these characters
  53. Result := Result + '\' + S[i];
  54. '~','^':
  55. Result := Result + '\'+S[i]+' ';
  56. '\':
  57. Result := Result + '$\backslash$';
  58. '<':
  59. Result := Result + '$<$';
  60. '>':
  61. Result := Result + '$>$'
  62. else
  63. Result := Result + S[i];
  64. end;
  65. end;
  66. constructor TLatexResultsWriter.Create(aOwner: TComponent);
  67. begin
  68. inherited Create(aOwner);
  69. FDoc := TStringList.Create;
  70. FSuiteHeaderIdx := TFPList.Create;
  71. FTempFailure := nil;
  72. end;
  73. destructor TLatexResultsWriter.Destroy;
  74. begin
  75. FDoc.Free;
  76. FSuiteHeaderIdx.Free;
  77. inherited Destroy;
  78. end;
  79. procedure TLatexResultsWriter.WriteHeader;
  80. begin
  81. inherited WriteHeader;
  82. FDoc.Add('\documentclass[a4paper,12pt]{report}');
  83. FDoc.Add('\usepackage{fullpage}');
  84. FDoc.Add('\usepackage{color}');
  85. FDoc.Add('\definecolor{Blue}{rgb}{0.3,0.3,0.9}');
  86. FDoc.Add('\definecolor{Red}{rgb}{1,0,0}');
  87. FDoc.Add('\definecolor{Pink}{rgb}{1,0,1}');
  88. FDoc.Add('\definecolor{Yellow}{rgb}{1,1,0}');
  89. FDoc.Add('\author{FPCUnit}');
  90. FDoc.Add('\title{Unit tests run by FPCUnit}');
  91. FDoc.Add('\begin{document}');
  92. FDoc.Add('\maketitle');
  93. FDoc.Add('\flushleft');
  94. end;
  95. procedure TLatexResultsWriter.WriteFooter;
  96. begin
  97. inherited WriteFooter;
  98. end;
  99. procedure TLatexResultsWriter.WriteResult(aResult: TTestResult);
  100. var
  101. f: text;
  102. begin
  103. inherited WriteResult(aResult);
  104. with aResult do
  105. begin
  106. FDoc.Insert(11, '\begin{tabular}{ll}');
  107. FDoc.Insert(12, '{\bf Number of run tests:} &' + intToStr(RunTests)+ '\\');
  108. FDoc.Insert(13, '{\bf Number of errors:} &' + intToStr(NumberOfErrors)+ '\\');
  109. FDoc.Insert(14, '{\bf Number of failures:} &' + intToStr(NumberOfFailures)+ '\\');
  110. FDoc.Insert(15, '{\bf Number of ignored tests:} &' + intToStr(NumberOfIgnoredTests)+ '\\');
  111. FDoc.Insert(16, '\end{tabular}');
  112. end;
  113. FDoc.Add('\end{document}');
  114. system.Assign(f, FileName);
  115. rewrite(f);
  116. writeln(f, FDoc.Text);
  117. close(f);
  118. end;
  119. {ITestListener}
  120. procedure TLatexResultsWriter.AddFailure(ATest: TTest; AFailure: TTestFailure);
  121. begin
  122. inherited AddFailure(ATest, AFailure);
  123. FTempFailure := AFailure;
  124. end;
  125. procedure TLatexResultsWriter.AddError(ATest: TTest; AError: TTestFailure);
  126. begin
  127. inherited;
  128. FTempFailure := AError;
  129. end;
  130. procedure TLatexResultsWriter.WriteTestHeader(ATest: TTest; ALevel: integer; ACount: integer);
  131. begin
  132. inherited;
  133. end;
  134. procedure TLatexResultsWriter.WriteTestFooter(ATest: TTest; ALevel: integer; ATiming: TDateTime);
  135. begin
  136. inherited;
  137. FDoc.Add(StringOfChar(' ',ALevel*2)+ ' '+ '\item[-] ' + FormatDateTime('ss.zzz', ATiming)
  138. + ' ' + EscapeText(ATest.TestName));
  139. if Assigned(FTempFailure) then
  140. begin
  141. //check if it's an error
  142. if not FTempFailure.IsFailure then
  143. begin
  144. FDoc[FDoc.Count -1] := '{\color{Red}'+FDoc[FDoc.Count -1];
  145. FDoc.Add('\begin{description}');
  146. FDoc.Add('\item[Error:] '+ EscapeText(FTempFailure.ExceptionClassName));
  147. FDoc.Add('\item[Exception:] '+ EscapeText(FTempFailure.ExceptionMessage));
  148. FDoc.Add('\item[Source unit:] '+ EscapeText(FTempFailure.SourceUnitName));
  149. FDoc.Add('\item[Method name:] '+ EscapeText(FTempFailure.FailedMethodName));
  150. FDoc.Add('\item[Line number:] '+ IntToStr(FTempFailure.LineNumber));
  151. FDoc.Add('\end{description}}');
  152. end
  153. else
  154. if FTempFailure.IsIgnoredTest then
  155. begin
  156. FDoc[FDoc.Count -1] := '{\color{Yellow}'+FDoc[FDoc.Count -1] + ' {\bf IGNORED TEST: ' +
  157. EscapeText(FTempFailure.ExceptionMessage) +'}}'
  158. end
  159. else
  160. //is a failure
  161. FDoc[FDoc.Count -1] := '{\color{Pink}'+FDoc[FDoc.Count -1] + ' {\bf FAILED: ' +
  162. EscapeText(FTempFailure.ExceptionMessage) +'}}';
  163. end;
  164. FTempFailure := nil;
  165. end;
  166. procedure TLatexResultsWriter.WriteSuiteHeader(ATestSuite: TTestSuite; ALevel: integer);
  167. begin
  168. inherited;
  169. FDoc.Add('{\bf {\color{Blue}'+ StringOfChar(' ',ALevel*2)+ '\item[-] '+
  170. EscapeText(ATestSuite.TestName)+ '}}');
  171. FSuiteHeaderIdx.Add(Pointer(FDoc.Count - 1));
  172. FDoc.Add(StringOfChar(' ',ALevel*2)+ '\begin{itemize}');
  173. end;
  174. procedure TLatexResultsWriter.WriteSuiteFooter(ATestSuite: TTestSuite; ALevel: integer;
  175. ATiming: TDateTime; ANumRuns: integer; ANumErrors: integer; ANumFailures: integer;
  176. ANumIgnores: integer);
  177. var
  178. idx: integer;
  179. begin
  180. inherited;
  181. FDoc.Add(StringOfChar(' ',ALevel*2)+ ' \end{itemize}');
  182. idx := Integer(FSuiteHeaderIdx[FSuiteHeaderIdx.Count -1]);
  183. FDoc[idx] := FDoc[idx] + ' {\color{Blue}'+ ' Time:'+ FormatDateTime('ss.zzz', ATiming)+
  184. ' N:'+ IntToStr(ANumRuns)+ ' E:'+ IntToStr(ANumErrors)+ ' F:'+ IntToStr(ANumFailures)+
  185. ' I:'+ IntToStr(ANumIgnores)+'}';
  186. FSuiteHeaderIdx.Delete(FSuiteHeaderIdx.Count -1);
  187. end;
  188. procedure TLatexResultsWriter.StartTest(ATest: TTest);
  189. begin
  190. inherited StartTest(ATest);
  191. end;
  192. procedure TLatexResultsWriter.EndTest(ATest: TTest);
  193. begin
  194. inherited EndTest(ATest);
  195. end;
  196. function TestSuiteAsLatex(aSuite:TTestSuite): string;
  197. var
  198. i,j: integer;
  199. s: TTestSuite;
  200. begin
  201. Result := '\flushleft' + System.sLineBreak;
  202. for i := 0 to aSuite.Tests.Count - 1 do
  203. begin
  204. s := TTestSuite(ASuite.Tests.Items[i]);
  205. Result := Result + TLatexResultsWriter.EscapeText(s.TestSuiteName) + System.sLineBreak;
  206. Result := Result + '\begin{itemize}'+ System.sLineBreak;
  207. for j := 0 to s.Tests.Count - 1 do
  208. if TTest(s.Tests.Items[j]) is TTestCase then
  209. Result := Result + '\item[-] ' +
  210. TLatexResultsWriter.EscapeText(TTestcase(s.Tests.Items[j]).TestName)
  211. + System.sLineBreak;
  212. Result := Result +'\end{itemize}' + System.sLineBreak;
  213. end;
  214. end;
  215. function GetSuiteAsLatex(aSuite: TTestSuite): string;
  216. begin
  217. if aSuite <> nil then
  218. begin
  219. Result := '\documentclass[a4paper,12pt]{article}' + System.sLineBreak;
  220. Result := Result + '\usepackage{array}' + System.sLineBreak;
  221. Result := Result + '\usepackage{mdwlist}' + System.sLineBreak + System.sLineBreak;
  222. Result := Result + '\begin{document}' + System.sLineBreak + System.sLineBreak;
  223. if aSuite.TestName = '' then
  224. aSuite.TestName := 'Test Suite';
  225. Result := Result + TestSuiteAsLatex(aSuite);
  226. Result := Result + '\end{document}';
  227. end
  228. else
  229. Result := '';
  230. end;
  231. end.