plaintestreport.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2006 by Dean Zobec
  4. Port to Pas2JS by Mattias Gaertner in 2017.
  5. an example of plain text report for FPCUnit tests.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit PlainTestReport;
  13. {$mode objfpc}
  14. interface
  15. uses
  16. Classes, Math, SysUtils, FPCUnit, FPCUnitReport;
  17. type
  18. TTestResultOption = (ttoSkipAddress,ttoSkipExceptionMessage,ttoErrorsOnly);
  19. TTestResultOptions = set of TTestResultOption;
  20. { TPlainResultsWriter }
  21. TPlainResultsWriter = class(TCustomResultsWriter)
  22. private
  23. FTestResultOptions: TTestResultOptions;
  24. FDoc: TStringList;
  25. FSuiteHeaderIdx: TFPList;
  26. FTempFailure: TTestFailure;
  27. function TimeFormat(ATiming: TDateTime): String;
  28. protected
  29. procedure SetSkipAddressInfo(AValue: Boolean); override;
  30. procedure SetSparse(AValue: Boolean); override;
  31. procedure WriteTestHeader(ATest: TTest; ALevel: integer; ACount: integer); override;
  32. procedure WriteTestFooter(ATest: TTest; ALevel: integer; ATiming: TDateTime); override;
  33. procedure WriteSuiteHeader(ATestSuite: TTestSuite; ALevel: integer); override;
  34. procedure WriteSuiteFooter(ATestSuite: TTestSuite; ALevel: integer;
  35. ATiming: TDateTime; ANumRuns: integer; ANumErrors: integer;
  36. ANumFailures: integer; ANumIgnores: integer); override;
  37. public
  38. constructor Create(aOwner: TComponent); override;
  39. destructor Destroy; override;
  40. procedure WriteHeader; override;
  41. procedure WriteResult(aResult: TTestResult); override;
  42. procedure AddFailure(ATest: TTest; AFailure: TTestFailure); override;
  43. procedure AddError(ATest: TTest; AError: TTestFailure); override;
  44. end;
  45. function TestSuiteAsPlain(aSuite:TTestSuite; Options : TTestResultOptions = []): string;
  46. function GetSuiteAsPlain(aSuite: TTestSuite; Options : TTestResultOptions = []): string;
  47. function TestResultAsPlain(aTestResult: TTestResult; Options : TTestResultOptions = []): string;
  48. implementation
  49. function DoTestSuiteAsPlain(aSuite: TTest; Prefix : String;
  50. Options : TTestResultOptions = []): string;
  51. var
  52. i: integer;
  53. begin
  54. if (ASuite.TestSuiteName<>'') then
  55. begin
  56. Prefix:=' '+Prefix;
  57. Prefix:=Prefix+ASuite.TestSuiteName+'.';
  58. end;
  59. if (ASuite.TestName<>'') then
  60. Result := Prefix+ASuite.TestName+System.sLineBreak;
  61. for i := 0 to aSuite.GetChildTestCount - 1 do
  62. Result := Result + DoTestSuiteAsPlain(aSuite.GetChildTest(i),Prefix,Options);
  63. end;
  64. function TestSuiteAsPlain(aSuite: TTestSuite; Options: TTestResultOptions
  65. ): string;
  66. begin
  67. Result:=DoTestSuiteAsPlain(ASuite,'',Options);
  68. end;
  69. function GetSuiteAsPlain(aSuite: TTestSuite; Options: TTestResultOptions
  70. ): string;
  71. begin
  72. Result := '';
  73. if aSuite <> nil then
  74. Result := 'TestSuites: ' + System.sLineBreak + TestSuiteAsPlain(aSuite,Options);
  75. end;
  76. function TestResultAsPlain(aTestResult: TTestResult; Options: TTestResultOptions
  77. ): string;
  78. Procedure WriteFailure(F : TTestFailure; SkipAddress : Boolean = False );
  79. begin
  80. Result := Result + ' Message: ' + f.AsString + System.sLineBreak;
  81. Result := Result + ' Exception class: ' + f.ExceptionClassName + System.sLineBreak;
  82. if not (ttoSkipExceptionMessage in options) then
  83. Result := Result + ' Exception message: ' + f.ExceptionMessage + System.sLineBreak;
  84. if not (SkipAddress or (ttoSkipAddress in options) )then
  85. ;
  86. // Result := Result + ' at ' + f.LocationInfo + System.sLineBreak;
  87. end;
  88. var
  89. i: longint;
  90. begin
  91. with aTestResult do
  92. begin
  93. Result := 'Number of run tests: ' + intToStr(RunTests) + System.sLineBreak;
  94. Result := Result + 'Number of errors: ' + intToStr(NumberOfErrors) + System.sLineBreak;
  95. Result := Result + 'Number of failures: ' + intToStr(NumberOfFailures);
  96. if NumberOfErrors <> 0 then
  97. begin
  98. Result := Result + System.sLineBreak;
  99. Result := Result + System.sLineBreak;
  100. Result := Result + 'List of errors:';
  101. for i := 0 to Errors.Count - 1 do
  102. begin
  103. Result := Result + System.sLineBreak;
  104. Result := Result + ' Error: ' + System.sLineBreak;
  105. WriteFailure(TTestFailure(Errors.Items[i]));
  106. end;
  107. end;
  108. if NumberOfFailures <> 0 then
  109. begin
  110. Result := Result + System.sLineBreak;
  111. Result := Result + System.sLineBreak;
  112. Result := Result + 'List of failures:' + System.sLineBreak;
  113. for i := 0 to Failures.Count - 1 do
  114. begin
  115. Result := Result + ' Failure: ' + System.sLineBreak;
  116. WriteFailure(TTestFailure(Failures.Items[i]));
  117. end;
  118. end;
  119. if NumberOfIgnoredTests <> 0 then
  120. begin
  121. Result := Result + System.sLineBreak;
  122. Result := Result + System.sLineBreak;
  123. Result := Result + 'List of ignored tests:' + System.sLineBreak;
  124. for i := 0 to IgnoredTests.Count - 1 do
  125. begin
  126. Result := Result + ' Ignored test: ' + System.sLineBreak;
  127. WriteFailure(TTestFailure(IgnoredTests.Items[i]),True);
  128. end;
  129. end;
  130. end;
  131. Result := Result + System.sLineBreak;
  132. end;
  133. { TPlainResultsWriter }
  134. function TPlainResultsWriter.TimeFormat(ATiming: TDateTime): String;
  135. const
  136. MinutesPerDay = 24*60;
  137. Var
  138. M : NativeInt;
  139. begin
  140. Result:='ss.zzz';
  141. M:=Round(Floor(ATiming*MinutesPerDay));
  142. if M>60 then
  143. Result:='hh:mm:'+Result
  144. else if M>1 then
  145. Result:='mm:'+Result;
  146. end;
  147. procedure TPlainResultsWriter.SetSkipAddressInfo(AValue: Boolean);
  148. begin
  149. inherited SetSkipAddressInfo(AValue);
  150. if AValue then
  151. Include(FTestResultOptions,ttoSkipAddress)
  152. else
  153. Exclude(FTestResultOptions,ttoSkipAddress);
  154. end;
  155. procedure TPlainResultsWriter.SetSparse(AValue: Boolean);
  156. begin
  157. inherited SetSparse(AValue);
  158. if AValue then
  159. FTestResultOptions:=FTestResultOptions+[ttoSkipExceptionMessage,ttoErrorsOnly]
  160. else
  161. FTestResultOptions:=FTestResultOptions-[ttoSkipExceptionMessage,ttoErrorsOnly];
  162. end;
  163. procedure TPlainResultsWriter.WriteTestHeader(ATest: TTest; ALevel: integer;
  164. ACount: integer);
  165. begin
  166. inherited WriteTestHeader(ATest, ALevel, ACount);
  167. end;
  168. procedure TPlainResultsWriter.WriteTestFooter(ATest: TTest; ALevel: integer;
  169. ATiming: TDateTime);
  170. var
  171. S: String;
  172. begin
  173. inherited WriteTestFooter(ATest, ALevel, ATiming);
  174. S:=' ' + StringOfChar(' ',ALevel*2);
  175. if Not SkipTiming then
  176. S:=S + FormatDateTime(TimeFormat(ATiming), ATiming) + ' ';
  177. S:=S + ATest.TestName;
  178. if Assigned(FTempFailure) or (not Sparse) then
  179. FDoc.Add(S);
  180. if Assigned(FTempFailure) then
  181. begin
  182. //check if it's an error
  183. if not FTempFailure.IsFailure then
  184. begin
  185. FDoc[FDoc.Count -1] := FDoc[FDoc.Count -1] + ' Error: ' + FTempFailure.ExceptionClassName;
  186. FDoc.Add(StringOfChar(' ',ALevel*2) + ' Exception: ' + FTempFailure.ExceptionMessage);
  187. //FDoc.Add(StringOfChar(' ',ALevel*2) + ' at ' + FTempFailure.LocationInfo);
  188. // TODO: Add stack dump output info
  189. end
  190. else
  191. if FTempFailure.IsIgnoredTest then
  192. begin
  193. FDoc[FDoc.Count -1] := FDoc[FDoc.Count -1] + ' Ignored test: '
  194. + FTempFailure.ExceptionMessage;
  195. end
  196. else
  197. begin
  198. //is a failure
  199. FDoc[FDoc.Count -1] := FDoc[FDoc.Count -1] + ' Failed: '
  200. + FTempFailure.ExceptionMessage;
  201. FDoc.Add(StringOfChar(' ',ALevel*2) + ' Exception: ' + FTempFailure.ExceptionMessage);
  202. //FDoc.Add(StringOfChar(' ',ALevel*2) + ' at ' + FTempFailure.LocationInfo);
  203. end;
  204. end;
  205. FTempFailure := nil;
  206. end;
  207. procedure TPlainResultsWriter.WriteSuiteHeader(ATestSuite: TTestSuite;
  208. ALevel: integer);
  209. begin
  210. inherited WriteSuiteHeader(ATestSuite, ALevel);
  211. FDoc.Add(StringOfChar(' ',ALevel*2) + ATestSuite.TestName);
  212. FSuiteHeaderIdx.Add(FDoc.Count - 1);
  213. end;
  214. procedure TPlainResultsWriter.WriteSuiteFooter(ATestSuite: TTestSuite;
  215. ALevel: integer; ATiming: TDateTime; ANumRuns: integer; ANumErrors: integer;
  216. ANumFailures: integer; ANumIgnores: integer);
  217. var
  218. idx: integer;
  219. S: String;
  220. begin
  221. inherited WriteSuiteFooter(ATestSuite, ALevel, ATiming, ANumRuns, ANumErrors,
  222. ANumFailures, ANumIgnores);
  223. idx := Integer(FSuiteHeaderIdx[FSuiteHeaderIdx.Count -1]);
  224. if Not SkipTiming then
  225. S:= ' Time:'+ FormatDateTime(TimeFormat(ATiming), ATiming);
  226. S:=S+ ' N:'+ IntToStr(ANumRuns)+ ' E:'+ IntToStr(ANumErrors)+ ' F:'+ IntToStr(ANumFailures)+
  227. ' I:'+ IntToStr(ANumIgnores) ;
  228. FDoc[idx] := FDoc[idx]+S;
  229. FSuiteHeaderIdx.Delete(FSuiteHeaderIdx.Count -1);
  230. end;
  231. constructor TPlainResultsWriter.Create(aOwner: TComponent);
  232. begin
  233. inherited Create(aOwner);
  234. FDoc := TStringList.Create;
  235. FSuiteHeaderIdx := TFPList.Create;
  236. FTempFailure := nil;
  237. end;
  238. destructor TPlainResultsWriter.Destroy;
  239. begin
  240. FreeAndNil(FDoc);
  241. FreeAndNil(FSuiteHeaderIdx);
  242. inherited Destroy;
  243. end;
  244. procedure TPlainResultsWriter.WriteHeader;
  245. begin
  246. // Do nothing
  247. end;
  248. procedure TPlainResultsWriter.WriteResult(aResult: TTestResult);
  249. begin
  250. FDoc.Add('');
  251. FDoc.Add(TestResultAsPlain(aResult,FTestResultOptions));
  252. if Filename<>'' then
  253. writeln('TPlainResultsWriter.WriteResult FileName="',FileName,'" NOT YET IMPLEMENTED');
  254. writeln(FDoc.Text);
  255. end;
  256. procedure TPlainResultsWriter.AddFailure(ATest: TTest; AFailure: TTestFailure);
  257. begin
  258. inherited AddFailure(ATest, AFailure);
  259. FTempFailure := AFailure;
  260. end;
  261. procedure TPlainResultsWriter.AddError(ATest: TTest; AError: TTestFailure);
  262. begin
  263. inherited AddError(ATest, AError);
  264. FTempFailure := AError;
  265. end;
  266. end.