latextestreport.pp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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. {$IFNDEF FPC_DOTTEDUNITS}
  14. unit latextestreport;
  15. {$ENDIF FPC_DOTTEDUNITS}
  16. interface
  17. {$IFDEF FPC_DOTTEDUNITS}
  18. uses
  19. System.Classes, System.SysUtils, FpcUnit.Test, FpcUnit.Reports, System.StrUtils;
  20. {$ELSE FPC_DOTTEDUNITS}
  21. uses
  22. classes, SysUtils, fpcunit, fpcunitreport, strutils;
  23. {$ENDIF FPC_DOTTEDUNITS}
  24. type
  25. { TLatexResultsWriter }
  26. TLatexResultsWriter = class(TCustomResultsWriter)
  27. private
  28. FDoc: TStringList;
  29. FSuiteHeaderIdx: TFPList;
  30. FTempFailure: TTestFailure;
  31. function TimeFormat(ATiming: TDateTime): String;
  32. protected
  33. class function EscapeText(const S: string): String; virtual;
  34. procedure WriteTestHeader(ATest: TTest; ALevel: integer; ACount: integer); override;
  35. procedure WriteTestFooter(ATest: TTest; ALevel: integer; ATiming: TDateTime); override;
  36. procedure WriteSuiteHeader(ATestSuite: TTestSuite; ALevel: integer); override;
  37. procedure WriteSuiteFooter(ATestSuite: TTestSuite; ALevel: integer;
  38. ATiming: TDateTime; ANumRuns: integer; ANumErrors: integer;
  39. ANumFailures: integer; ANumIgnores: integer); override;
  40. public
  41. constructor Create(aOwner: TComponent); override;
  42. destructor Destroy; override;
  43. procedure WriteHeader; override;
  44. procedure WriteFooter; override;
  45. procedure WriteResult(aResult: TTestResult); override;
  46. procedure AddFailure(ATest: TTest; AFailure: TTestFailure); override;
  47. procedure AddError(ATest: TTest; AError: TTestFailure); override;
  48. procedure StartTest(ATest: TTest); override;
  49. procedure EndTest(ATest: TTest); override;
  50. end;
  51. function TestSuiteAsLatex(aSuite:TTest): string;
  52. function GetSuiteAsLatex(aSuite: TTestSuite): string;
  53. implementation
  54. {$IFDEF FPC_DOTTEDUNITS}
  55. uses System.DateUtils;
  56. {$ELSE FPC_DOTTEDUNITS}
  57. uses dateutils;
  58. {$ENDIF FPC_DOTTEDUNITS}
  59. function TLatexResultsWriter.TimeFormat(ATiming: TDateTime): String;
  60. Var
  61. M : Int64;
  62. begin
  63. Result:='ss.zzz';
  64. M:=MinutesBetween(ATiming,0);
  65. if M>60 then
  66. Result:='hh:mm:'+Result
  67. else if M>1 then
  68. Result:='mm:'+Result;
  69. end;
  70. class function TLatexResultsWriter.EscapeText(const S: string): String;
  71. var
  72. i: integer;
  73. begin
  74. SetLength(Result, 0);
  75. for i := 1 to Length(S) do
  76. case S[i] of
  77. '&','{','}','#','_','$','%': // Escape these characters
  78. Result := Result + '\' + S[i];
  79. '~','^':
  80. Result := Result + '\'+S[i]+' ';
  81. '\':
  82. Result := Result + '$\backslash$';
  83. '<':
  84. Result := Result + '$<$';
  85. '>':
  86. Result := Result + '$>$'
  87. else
  88. Result := Result + S[i];
  89. end;
  90. end;
  91. constructor TLatexResultsWriter.Create(aOwner: TComponent);
  92. begin
  93. inherited Create(aOwner);
  94. FDoc := TStringList.Create;
  95. FSuiteHeaderIdx := TFPList.Create;
  96. FTempFailure := nil;
  97. end;
  98. destructor TLatexResultsWriter.Destroy;
  99. begin
  100. FDoc.Free;
  101. FSuiteHeaderIdx.Free;
  102. inherited Destroy;
  103. end;
  104. procedure TLatexResultsWriter.WriteHeader;
  105. begin
  106. inherited WriteHeader;
  107. FDoc.Add('\documentclass[a4paper,12pt]{report}');
  108. FDoc.Add('\usepackage{fullpage}');
  109. FDoc.Add('\usepackage{color}');
  110. FDoc.Add('\definecolor{Blue}{rgb}{0.3,0.3,0.9}');
  111. FDoc.Add('\definecolor{Red}{rgb}{1,0,0}');
  112. FDoc.Add('\definecolor{Pink}{rgb}{1,0,1}');
  113. FDoc.Add('\definecolor{Yellow}{rgb}{1,1,0}');
  114. FDoc.Add('\author{FpcUnit}');
  115. FDoc.Add('\title{Unit tests run by FpcUnit}');
  116. FDoc.Add('\begin{document}');
  117. FDoc.Add('\maketitle');
  118. FDoc.Add('\flushleft');
  119. end;
  120. procedure TLatexResultsWriter.WriteFooter;
  121. begin
  122. inherited WriteFooter;
  123. end;
  124. procedure TLatexResultsWriter.WriteResult(aResult: TTestResult);
  125. var
  126. f: text;
  127. begin
  128. inherited WriteResult(aResult);
  129. with aResult do
  130. begin
  131. FDoc.Insert(11, '\begin{tabular}{ll}');
  132. FDoc.Insert(12, '{\bf Number of run tests:} &' + intToStr(RunTests)+ '\\');
  133. FDoc.Insert(13, '{\bf Number of errors:} &' + intToStr(NumberOfErrors)+ '\\');
  134. FDoc.Insert(14, '{\bf Number of failures:} &' + intToStr(NumberOfFailures)+ '\\');
  135. FDoc.Insert(15, '{\bf Number of ignored tests:} &' + intToStr(NumberOfIgnoredTests)+ '\\');
  136. FDoc.Insert(16, '\end{tabular}');
  137. end;
  138. FDoc.Add('\end{document}');
  139. system.Assign(f, FileName);
  140. rewrite(f);
  141. writeln(f, FDoc.Text);
  142. close(f);
  143. end;
  144. {ITestListener}
  145. procedure TLatexResultsWriter.AddFailure(ATest: TTest; AFailure: TTestFailure);
  146. begin
  147. inherited AddFailure(ATest, AFailure);
  148. FTempFailure := AFailure;
  149. end;
  150. procedure TLatexResultsWriter.AddError(ATest: TTest; AError: TTestFailure);
  151. begin
  152. inherited;
  153. FTempFailure := AError;
  154. end;
  155. procedure TLatexResultsWriter.WriteTestHeader(ATest: TTest; ALevel: integer; ACount: integer);
  156. begin
  157. inherited;
  158. end;
  159. procedure TLatexResultsWriter.WriteTestFooter(ATest: TTest; ALevel: integer; ATiming: TDateTime);
  160. Var
  161. S : String;
  162. begin
  163. inherited;
  164. S:=StringOfChar(' ',ALevel*2)+ ' '+ '\item[-] ';
  165. if Not SkipTiming then
  166. S:=S+FormatDateTime(TimeFormat(ATiming), ATiming);
  167. S:=S+ ' ' + EscapeText(ATest.TestName);
  168. FDoc.Add(S);
  169. if Assigned(FTempFailure) then
  170. begin
  171. //check if it's an error
  172. if not FTempFailure.IsFailure then
  173. begin
  174. FDoc[FDoc.Count -1] := '{\color{Red}'+FDoc[FDoc.Count -1];
  175. FDoc.Add('\begin{description}');
  176. FDoc.Add('\item[Error:] '+ EscapeText(FTempFailure.ExceptionClassName));
  177. FDoc.Add('\item[Exception:] '+ EscapeText(FTempFailure.ExceptionMessage));
  178. FDoc.Add('\item[Source unit:] '+ EscapeText(FTempFailure.SourceUnitName));
  179. FDoc.Add('\item[Method name:] '+ EscapeText(FTempFailure.FailedMethodName));
  180. FDoc.Add('\item[Line number:] '+ IntToStr(FTempFailure.LineNumber));
  181. FDoc.Add('\end{description}}');
  182. end
  183. else
  184. if FTempFailure.IsIgnoredTest then
  185. begin
  186. FDoc[FDoc.Count -1] := '{\color{Yellow}'+FDoc[FDoc.Count -1] + ' {\bf IGNORED TEST: ' +
  187. EscapeText(FTempFailure.ExceptionMessage) +'}}'
  188. end
  189. else
  190. //is a failure
  191. FDoc[FDoc.Count -1] := '{\color{Pink}'+FDoc[FDoc.Count -1] + ' {\bf FAILED: ' +
  192. EscapeText(FTempFailure.ExceptionMessage) +'}}';
  193. end;
  194. FTempFailure := nil;
  195. end;
  196. procedure TLatexResultsWriter.WriteSuiteHeader(ATestSuite: TTestSuite; ALevel: integer);
  197. begin
  198. inherited;
  199. FDoc.Add('{\bf {\color{Blue}'+ StringOfChar(' ',ALevel*2)+ '\item[-] '+
  200. EscapeText(ATestSuite.TestName)+ '}}');
  201. FSuiteHeaderIdx.Add(Pointer(FDoc.Count - 1));
  202. FDoc.Add(StringOfChar(' ',ALevel*2)+ '\begin{itemize}');
  203. end;
  204. procedure TLatexResultsWriter.WriteSuiteFooter(ATestSuite: TTestSuite; ALevel: integer;
  205. ATiming: TDateTime; ANumRuns: integer; ANumErrors: integer; ANumFailures: integer;
  206. ANumIgnores: integer);
  207. var
  208. idx: integer;
  209. S : String;
  210. begin
  211. inherited;
  212. FDoc.Add(StringOfChar(' ',ALevel*2)+ ' \end{itemize}');
  213. idx := Integer(FSuiteHeaderIdx[FSuiteHeaderIdx.Count -1]);
  214. S:= ' {\color{Blue}';
  215. if Not SkipTiming then
  216. S:=S+ ' Time: '+FormatDateTime('ss.zzz', ATiming);
  217. S:=S+' N:'+ IntToStr(ANumRuns)+ ' E:'+ IntToStr(ANumErrors)+ ' F:'+ IntToStr(ANumFailures)+
  218. ' I:'+ IntToStr(ANumIgnores)+'}';
  219. FDoc[idx] := FDoc[idx] +S;
  220. FSuiteHeaderIdx.Delete(FSuiteHeaderIdx.Count -1);
  221. end;
  222. procedure TLatexResultsWriter.StartTest(ATest: TTest);
  223. begin
  224. inherited StartTest(ATest);
  225. end;
  226. procedure TLatexResultsWriter.EndTest(ATest: TTest);
  227. begin
  228. inherited EndTest(ATest);
  229. end;
  230. function TestSuiteAsLatex(aSuite:TTest): string;
  231. var
  232. i,j: integer;
  233. s: TTestSuite;
  234. begin
  235. Result:='';
  236. if (aSuite.TestName<>'') then
  237. begin
  238. Result:=Result + '\item[-] ';
  239. Result:=Result+TLatexResultsWriter.EscapeText(ASuite.TestName)+slineBreak
  240. end;
  241. if aSuite.GetChildTestCount>0 then
  242. begin
  243. Result := Result + '\begin{itemize}'+ System.sLineBreak;
  244. for i:=0 to Pred(aSuite.GetChildTestCount) do
  245. Result:=Result+TestSuiteAsLatex(aSuite.GetChildTest(i));
  246. if (aSuite.TestName<>'') then
  247. Result := Result +'\end{itemize}' + System.sLineBreak;
  248. end
  249. end;
  250. function GetSuiteAsLatex(aSuite: TTestSuite): string;
  251. begin
  252. if aSuite <> nil then
  253. begin
  254. Result := '\documentclass[a4paper,12pt]{article}' + System.sLineBreak;
  255. Result := Result + '\usepackage{array}' + System.sLineBreak;
  256. Result := Result + '\usepackage{mdwlist}' + System.sLineBreak + System.sLineBreak;
  257. Result := Result + '\begin{document}' + System.sLineBreak + System.sLineBreak;
  258. if aSuite.TestName = '' then
  259. aSuite.TestName := 'Test Suite';
  260. Result := Result + '\begin{itemize}'+ System.sLineBreak;
  261. Result := Result + TestSuiteAsLatex(aSuite);
  262. Result := Result +'\end{itemize}' + System.sLineBreak;
  263. Result := Result + '\end{document}';
  264. end
  265. else
  266. Result := '';
  267. end;
  268. end.