fpcunit.pp 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2004 by Dean Zobec, Michael Van Canneyt
  4. Port to Free Pascal of the JUnit framework.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit fpcunit;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$mode objfpc}
  15. {$h+}
  16. {$modeswitch functionreferences}
  17. interface
  18. { Uncomment this define to remove the DUnit compatibility interface. }
  19. {$DEFINE DUnit}
  20. {$IFDEF FPC_DOTTEDUNITS}
  21. uses
  22. System.SysUtils
  23. ,System.Classes
  24. ;
  25. {$ELSE FPC_DOTTEDUNITS}
  26. uses
  27. SysUtils
  28. ,Classes
  29. ;
  30. {$ENDIF FPC_DOTTEDUNITS}
  31. { This lets us use a single include file for both the Interface and
  32. Implementation sections. }
  33. {$define read_interface}
  34. {$undef read_implementation}
  35. type
  36. EAssertionFailedError = class(Exception)
  37. constructor Create; overload;
  38. constructor Create(const msg :string); overload;
  39. end;
  40. EIgnoredTest = class(EAssertionFailedError);
  41. TTestStep = (stSetUp, stRunTest, stTearDown, stNothing);
  42. TRunMethod = procedure of object;
  43. TRunLocalMethod = reference to procedure;
  44. TTestResult = class;
  45. TTestSuite = class;
  46. {$M+}
  47. { TTest }
  48. TTest = class(TObject)
  49. private
  50. protected
  51. FLastStep: TTestStep;
  52. function GetTestName: string; virtual;
  53. function GetTestSuiteName: string; virtual;
  54. function GetEnableIgnores: boolean; virtual;
  55. procedure SetTestSuiteName(const aName: string); virtual; abstract;
  56. procedure SetEnableIgnores(Value: boolean); virtual; abstract;
  57. public
  58. function CountTestCases: integer; virtual;
  59. Function GetChildTestCount : Integer; virtual;
  60. Function GetChildTest(AIndex : Integer) : TTest; virtual;
  61. function FindChildTest(const AName: String): TTest;
  62. Function FindTest(Const AName : String) : TTest;
  63. procedure Run(AResult: TTestResult); virtual;
  64. procedure Ignore(const AMessage: string);
  65. published
  66. property TestName: string read GetTestName;
  67. property TestSuiteName: string read GetTestSuiteName write SetTestSuiteName;
  68. property LastStep: TTestStep read FLastStep;
  69. property EnableIgnores: boolean read GetEnableIgnores write SetEnableIgnores;
  70. end;
  71. {$M-}
  72. { TAssert }
  73. TAssert = class(TTest)
  74. protected
  75. Class var AssertCount : Integer;
  76. public
  77. type
  78. TStatusHook = Procedure(const msg : string);
  79. TStatusEvent = Procedure(const msg : string) of object;
  80. class var StatusHook : TStatusHook;
  81. class var StatusEvent : TStatusEvent;
  82. public
  83. class procedure Status(const aMsg: String); inline;
  84. class procedure Status(const aMsg: String; const aArgs: array of const); inline;
  85. class procedure Fail(const AMessage: string; AErrorAddrs: Pointer = nil);
  86. class procedure Fail(const AFmt: string; Args : Array of const; AErrorAddrs: Pointer = nil);
  87. class procedure FailEquals(const expected, actual: string; const ErrorMsg: string = ''; AErrorAddrs: Pointer = nil);
  88. class procedure FailNotEquals(const expected, actual: string; const ErrorMsg: string = ''; AErrorAddrs: Pointer = nil);
  89. class procedure AssertTrue(const AMessage: string; ACondition: boolean; AErrorAddrs: Pointer = nil); overload;
  90. class procedure AssertTrue(ACondition: boolean); overload;
  91. class procedure AssertFalse(const AMessage: string; ACondition: boolean; AErrorAddrs: Pointer = nil); overload;
  92. class procedure AssertFalse(ACondition: boolean); overload;
  93. class procedure AssertEquals(const AMessage: string; Expected: AnsiString; Actual: UnicodeString); overload;
  94. class procedure AssertEquals(const AMessage: string; Expected: UnicodeString; Actual: AnsiString); overload;
  95. class procedure AssertEquals(const AMessage: string; Expected, Actual: Ansistring); overload;
  96. class procedure AssertEquals(Expected, Actual: Ansistring); overload;
  97. class procedure AssertEquals(const AMessage: string; Expected, Actual: UnicodeString); overload;
  98. class procedure AssertEquals(Expected, Actual: UnicodeString); overload;
  99. class procedure AssertEquals(const AMessage: string; Expected, Actual: integer); overload;
  100. class procedure AssertEquals(Expected, Actual: integer); overload;
  101. class procedure AssertEquals(const AMessage: string; Expected, Actual: int64); overload;
  102. class procedure AssertEquals(Expected, Actual: int64); overload;
  103. class procedure AssertEquals(const AMessage: string; Expected, Actual: QWord); overload;
  104. class procedure AssertEquals(Expected, Actual: QWord); overload;
  105. class procedure AssertEquals(const AMessage: string; Expected, Actual: currency); overload;
  106. class procedure AssertEquals(Expected, Actual: currency); overload;
  107. class procedure AssertEquals(const AMessage: string; Expected, Actual, Delta: double); overload;
  108. class procedure AssertEquals(Expected, Actual, Delta: double); overload;
  109. class procedure AssertEquals(const AMessage: string; Expected, Actual: boolean); overload;
  110. class procedure AssertEquals(Expected, Actual: boolean); overload;
  111. class procedure AssertEquals(const AMessage: string; Expected, Actual: AnsiChar); overload;
  112. class procedure AssertEquals(Expected, Actual: AnsiChar); overload;
  113. class procedure AssertEquals(const AMessage: string; Expected, Actual: TClass); overload;
  114. class procedure AssertEquals(Expected, Actual: TClass); overload;
  115. class procedure AssertSame(const AMessage: string; Expected, Actual: TObject); overload;
  116. class procedure AssertSame(Expected, Actual: TObject); overload;
  117. class procedure AssertSame(const AMessage: string; Expected, Actual: Pointer); overload;
  118. class procedure AssertSame(Expected, Actual: Pointer); overload;
  119. class procedure AssertNotSame(const AMessage: string; Expected, Actual: TObject); overload;
  120. class procedure AssertNotSame(Expected, Actual: TObject); overload;
  121. class procedure AssertNotSame(const AMessage: string; Expected, Actual: Pointer); overload;
  122. class procedure AssertNotSame(Expected, Actual: Pointer); overload;
  123. class procedure AssertNotNull(const AMessage: string; AObject: TObject); overload;
  124. class procedure AssertNotNull(AObject: TObject); overload;
  125. class procedure AssertNotNullIntf(const AMessage: string; AInterface: IInterface); overload;
  126. class procedure AssertNotNullIntf(AInterface: IInterface); overload;
  127. class procedure AssertNotNull(const AMessage: string; APointer: Pointer); overload;
  128. class procedure AssertNotNull(APointer: Pointer); overload;
  129. class procedure AssertNull(const AMessage: string; AObject: TObject); overload;
  130. class procedure AssertNull(AObject: TObject); overload;
  131. class procedure AssertNullIntf(const AMessage: string; AInterface: IInterface); overload;
  132. class procedure AssertNullIntf(AInterface: IInterface); overload;
  133. class procedure AssertNull(const AMessage: string; APointer: Pointer); overload;
  134. class procedure AssertNull(APointer: Pointer); overload;
  135. class procedure AssertNotNull(const AMessage, AString: string); overload;
  136. class procedure AssertNotNull(const AString: string); overload;
  137. class procedure AssertException(const AMessage: string; AExceptionClass: ExceptClass; AMethod: TRunMethod; const AExceptionMessage : String = ''; AExceptionContext : Integer = 0; AErrorAddr : Pointer = Nil); overload;
  138. class procedure AssertException(AExceptionClass: ExceptClass; AMethod: TRunMethod;const AExceptionMessage : String = ''; AExceptionContext : Integer = 0); overload;
  139. class procedure AssertNoException(const AMessage : string; AMethod: TRunMethod); overload;
  140. class procedure AssertNoException(AMethod: TRunMethod); overload;
  141. class procedure AssertException(const AMessage: string; AExceptionClass: ExceptClass; AMethod: TRunLocalMethod; const AExceptionMessage : String = ''; AExceptionContext : Integer = 0; AErrorAddr : Pointer = Nil); overload;
  142. class procedure AssertException(AExceptionClass: ExceptClass; AMethod: TRunLocalMethod;const AExceptionMessage : String = ''; AExceptionContext : Integer = 0); overload;
  143. class procedure AssertNoException(const AMessage : string; AMethod: TRunLocalMethod); overload;
  144. class procedure AssertNoException(AMethod: TRunLocalMethod); overload;
  145. {$IFDEF DUnit}
  146. {$I DUnitCompatibleInterface.inc}
  147. {$ENDIF DUnit}
  148. end;
  149. TTestFailure = class(TObject)
  150. private
  151. FTestName: string;
  152. FTestSuiteName: string;
  153. FLineNumber: longint;
  154. FFailedMethodName: string;
  155. FRaisedExceptionClass: TClass;
  156. FRaisedExceptionMessage: string;
  157. FSourceUnitName: string;
  158. FThrownExceptionAddress: Pointer;
  159. FTestLastStep: TTestStep;
  160. function GetAsString: string;
  161. function GetExceptionMessage: string;
  162. function GetIsFailure: boolean;
  163. function GetIsIgnoredTest: boolean;
  164. function GetExceptionClassName: string;
  165. function GetLocationInfo: string;
  166. procedure SetTestLastStep(const Value: TTestStep);
  167. public
  168. constructor CreateFailure(ATest: TTest; E: Exception; LastStep: TTestStep; ThrownExceptionAddrs: pointer = nil);
  169. property ExceptionClass: TClass read FRaisedExceptionClass;
  170. published
  171. property AsString: string read GetAsString;
  172. property IsFailure: boolean read GetIsFailure;
  173. property IsIgnoredTest: boolean read GetIsIgnoredTest;
  174. property ExceptionMessage: string read GetExceptionMessage;
  175. property ExceptionClassName: string read GetExceptionClassName;
  176. property SourceUnitName: string read FSourceUnitName write FSourceUnitName;
  177. property LineNumber: longint read FLineNumber write FLineNumber;
  178. property LocationInfo: string read GetLocationInfo;
  179. property FailedMethodName: string read FFailedMethodName write FFailedMethodName;
  180. property TestLastStep: TTestStep read FTestLastStep write SetTestLastStep;
  181. end;
  182. ITestListener = interface
  183. ['{0CE9D3AE-882A-D811-9401-ADEB5E4C7FC1}']
  184. procedure AddFailure(ATest: TTest; AFailure: TTestFailure);
  185. procedure AddError(ATest: TTest; AError: TTestFailure);
  186. procedure StartTest(ATest: TTest);
  187. procedure EndTest(ATest: TTest);
  188. procedure StartTestSuite(ATestSuite: TTestSuite);
  189. procedure EndTestSuite(ATestSuite: TTestSuite);
  190. end;
  191. { TTestCase }
  192. TTestCase = class(TAssert)
  193. private
  194. FName: string;
  195. FTestSuiteName: string;
  196. FEnableIgnores: boolean;
  197. FExpectedExceptionFailMessage : String;
  198. FExpectedException : TClass;
  199. FExpectedExceptionMessage: String;
  200. FExpectedExceptionContext: Integer;
  201. FExpectedExceptionCaller : Pointer;
  202. protected
  203. function CreateResult: TTestResult; virtual;
  204. procedure SetUp; virtual;
  205. procedure TearDown; virtual;
  206. procedure RunTest; virtual;
  207. function GetTestName: string; override;
  208. function GetTestSuiteName: string; override;
  209. function GetEnableIgnores: boolean; override;
  210. procedure SetTestSuiteName(const aName: string); override;
  211. procedure SetTestName(const Value: string); virtual;
  212. procedure SetEnableIgnores(Value: boolean); override;
  213. procedure RunBare; virtual;
  214. Class function SingleInstanceForSuite : Boolean; virtual;
  215. Public
  216. Class Var CheckAssertCalled : Boolean;
  217. public
  218. constructor Create; virtual;
  219. constructor CreateWith(const ATestName: string; const ATestSuiteName: string); virtual;
  220. constructor CreateWithName(const AName: string); virtual;
  221. procedure ExpectException(AExceptionClass: TClass; const AExceptionMessage: string=''; AExceptionHelpContext: Integer=0);
  222. procedure ExpectException(const Msg: String; AExceptionClass: TClass; const AExceptionMessage: string=''; AExceptionHelpContext: Integer=0);
  223. function CountTestCases: integer; override;
  224. function CreateResultAndRun: TTestResult; virtual;
  225. procedure Run(AResult: TTestResult); override;
  226. function AsString: string;
  227. class function Suite : TTestSuite;
  228. property TestSuiteName: string read GetTestSuiteName write SetTestSuiteName;
  229. Property ExpectedExceptionFailMessage : String Read FExpectedExceptionFailMessage;
  230. Property ExpectedException : TClass Read FExpectedException;
  231. Property ExpectedExceptionMessage : String Read FExpectedExceptionMessage;
  232. Property ExpectedExceptionContext: Integer Read FExpectedExceptionContext;
  233. published
  234. property TestName: string read GetTestName write SetTestName;
  235. end;
  236. TTestCaseClass = class of TTestCase;
  237. { TTestSuite }
  238. TTestSuite = class(TTest)
  239. private
  240. FOwnsTests: Boolean;
  241. FTests: TFPList;
  242. FName: string;
  243. FTestSuiteName: string;
  244. FEnableIgnores: boolean;
  245. procedure SetOwnsTests(AValue: Boolean);
  246. protected
  247. Procedure SetOwnTestOnTests(AValue: Boolean);
  248. Function DoAddTest(ATest : TTest) : Integer;
  249. function GetTestName: string; override;
  250. function GetTestSuiteName: string; override;
  251. function GetEnableIgnores: boolean; override;
  252. procedure SetTestSuiteName(const aName: string); override;
  253. procedure SetTestName(const Value: string); virtual;
  254. procedure SetEnableIgnores(Value: boolean); override;
  255. property OwnsTests : Boolean Read FOwnsTests Write SetOwnsTests;
  256. public
  257. constructor Create(AClass: TClass; const AName: string); reintroduce; overload; virtual;
  258. constructor Create(AClass: TClass); reintroduce; overload; virtual;
  259. constructor Create(AClassArray: Array of TClass); reintroduce; overload; virtual;
  260. constructor Create(const AName: string); reintroduce; overload; virtual;
  261. constructor Create; reintroduce; overload; virtual;
  262. destructor Destroy; override;
  263. function CountTestCases: integer; override;
  264. Function GetChildTestCount : Integer; override;
  265. Function GetChildTest(AIndex : Integer) : TTest; override;
  266. procedure Run(AResult: TTestResult); override;
  267. procedure RunTest(ATest: TTest; AResult: TTestResult); virtual;
  268. procedure AddTest(ATest: TTest); overload; virtual;
  269. procedure AddTestSuiteFromClass(ATestClass: TClass); virtual;
  270. class function Warning(const aMessage: string): TTestCase;
  271. property Test[Index: integer]: TTest read GetChildTest; default;
  272. Property ChildTestCount : Integer Read GetChildTestCount;
  273. property TestSuiteName: string read GetTestSuiteName write SetTestSuiteName;
  274. property TestName: string read GetTestName write SetTestName;
  275. // Only for backwards compatibility. Use Test and ChildTestCount.
  276. property Tests: TFPList read FTests; deprecated;
  277. end;
  278. TProtect = procedure(aTest: TTest; aResult: TTestResult);
  279. { TTestResult }
  280. TTestResult = class(TObject)
  281. protected
  282. FRunTests: integer;
  283. FFailures: TFPList;
  284. FIgnoredTests: TFPList;
  285. FErrors: TFPList;
  286. FListeners: TFPList;
  287. FSkippedTests: TFPList;
  288. FStartingTime: TDateTime;
  289. function GetNumErrors: integer;
  290. function GetNumFailures: integer;
  291. function GetNumIgnoredTests: integer;
  292. function GetNumSkipped: integer;
  293. public
  294. constructor Create; virtual;
  295. destructor Destroy; override;
  296. procedure ClearErrorLists;
  297. procedure StartTest(ATest: TTest);
  298. procedure AddFailure(ATest: TTest; E: EAssertionFailedError; aFailureList: TFPList; AThrownExceptionAdrs: Pointer);
  299. procedure AddError(ATest: TTest; E: Exception; AThrownExceptionAdrs: Pointer);
  300. procedure EndTest(ATest: TTest);
  301. procedure AddListener(AListener: ITestListener);
  302. procedure RemoveListener(AListener: ITestListener);
  303. procedure Run(ATestCase: TTestCase);
  304. procedure RunProtected(ATestCase: TTest; protect: TProtect);
  305. function WasSuccessful: boolean;
  306. function SkipTest(ATestCase: TTestCase): boolean;
  307. procedure AddToSkipList(ATestCase: TTestCase);
  308. procedure RemoveFromSkipList(ATestCase: TTestCase);
  309. procedure StartTestSuite(ATestSuite: TTestSuite);
  310. procedure EndTestSuite(ATestSuite: TTestSuite);
  311. published
  312. property Listeners: TFPList read FListeners;
  313. property Failures: TFPList read FFailures;
  314. property IgnoredTests: TFPList read FIgnoredTests;
  315. property Errors: TFPList read FErrors;
  316. property RunTests: integer read FRunTests;
  317. property NumberOfErrors: integer read GetNumErrors;
  318. property NumberOfFailures: integer read GetNumFailures;
  319. property NumberOfIgnoredTests: integer read GetNumIgnoredTests;
  320. property NumberOfSkippedTests: integer read GetNumSkipped;
  321. property StartingTime: TDateTime read FStartingTime;
  322. end;
  323. function ComparisonMsg(const aExpected: AnsiString; const aActual: AnsiString; const aCheckEqual: boolean=true): AnsiString; overload;
  324. function ComparisonMsg(const aExpected: UnicodeString; const aActual: UnicodeString; const aCheckEqual: boolean=true): Unicodestring; overload;
  325. function ComparisonMsg(const aMsg: string; const aExpected: string; const aActual: string; const aCheckEqual: boolean=true): string; overload;
  326. // Made public for 3rd party developers extending TTestCase with new AssertXXX methods
  327. function CallerAddr: Pointer;
  328. Resourcestring
  329. SCompare = ' expected: <%s> but was: <%s>';
  330. SCompareNotEqual = ' expected: not equal to <%s> but was: <%s>';
  331. SExpectedNotSame = 'expected not same';
  332. SExceptionCompare = 'Exception %s expected but %s was raised';
  333. SExceptionMessageCompare = 'Exception raised but exception property Message differs: ';
  334. SExceptionHelpContextCompare = 'Exception raised but exception property HelpContext differs: ';
  335. SErrUnexpectedException = 'No exception expected but exception %s was raised with message: %s';
  336. SMethodNotFound = 'Method <%s> not found';
  337. SNoValidInheritance = ' does not inherit from TTestCase';
  338. SNoValidTests = 'No valid tests found in ';
  339. SNoException = 'no exception';
  340. SAssertNotCalled = 'Assert not called during test.';
  341. implementation
  342. {$IFDEF FPC_DOTTEDUNITS}
  343. uses
  344. FpcUnit.Utils;
  345. {$ELSE FPC_DOTTEDUNITS}
  346. uses
  347. testutils;
  348. {$ENDIF FPC_DOTTEDUNITS}
  349. Const
  350. sExpectedButWasFmt = 'Expected:' + LineEnding + '"%s"' + LineEnding + 'But was:' + LineEnding + '"%s"';
  351. sExpectedButWasAndMessageFmt = '%s' + LineEnding + sExpectedButWasFmt;
  352. { This lets us use a single include file for both the Interface and
  353. Implementation sections. }
  354. {$undef read_interface}
  355. {$define read_implementation}
  356. function CallerAddr: Pointer;
  357. Var
  358. address: CodePointer;
  359. nframes: sizeint;
  360. begin
  361. nframes:=CaptureBacktrace(2,1,@address);
  362. if nframes=1 then
  363. result:=address
  364. else
  365. result:=nil;
  366. end;
  367. function AddrsToStr(Addrs: Pointer): string;
  368. begin
  369. if PtrUInt(Addrs) > 0 then
  370. Result := '$'+Format('%p', [Addrs])
  371. else
  372. Result := 'n/a';
  373. end;
  374. function PointerToLocationInfo(Addrs: Pointer): string;
  375. begin
  376. Result := BackTraceStrFunc(Addrs);
  377. if Trim(Result) = '' then
  378. Result := AddrsToStr(Addrs) + ' <no map file>';
  379. end;
  380. // Get the ClassName of C
  381. function GetN(C : TClass) : string;
  382. begin
  383. if C=Nil then
  384. Result:='<NIL>'
  385. else
  386. Result:=C.ClassName;
  387. end;
  388. type
  389. TTestWarning = class(TTestCase)
  390. private
  391. FMessage: String;
  392. protected
  393. procedure RunTest; override;
  394. end;
  395. procedure TTestWarning.RunTest;
  396. begin
  397. Fail(FMessage);
  398. end;
  399. function ComparisonMsg(const aExpected: Ansistring; const aActual: AnsiString; const aCheckEqual: boolean=true): AnsiString;
  400. // aCheckEqual=false gives the error message if the test does *not* expect the results to be the same.
  401. begin
  402. if aCheckEqual then
  403. Result := format(SCompare, [aExpected, aActual])
  404. else {check unequal requires opposite error message}
  405. Result := format(SCompareNotEqual, [aExpected, aActual]);
  406. end;
  407. function ComparisonMsg(const aExpected: Unicodestring; const aActual: Unicodestring; const aCheckEqual: boolean=true): Unicodestring;
  408. // aCheckEqual=false gives the error message if the test does *not* expect the results to be the same.
  409. begin
  410. if aCheckEqual then
  411. Result := unicodeformat(SCompare, [aExpected, aActual])
  412. else {check unequal requires opposite error message}
  413. Result := unicodeformat(SCompareNotEqual, [aExpected, aActual]);
  414. end;
  415. function ComparisonMsg(const aMsg: string; const aExpected: string; const aActual: string; const aCheckEqual: boolean): string;
  416. begin
  417. Result := '"' + aMsg + '"' + ComparisonMsg(aExpected, aActual, aCheckEqual);
  418. end;
  419. constructor EAssertionFailedError.Create;
  420. begin
  421. inherited Create('');
  422. end;
  423. constructor EAssertionFailedError.Create(const msg: string);
  424. begin
  425. inherited Create(msg);
  426. end;
  427. constructor TTestFailure.CreateFailure(ATest: TTest; E: Exception; LastStep: TTestStep; ThrownExceptionAddrs: pointer);
  428. begin
  429. inherited Create;
  430. FTestName := ATest.GetTestName;
  431. FTestSuiteName := ATest.GetTestSuiteName;
  432. FRaisedExceptionClass := E.ClassType;
  433. FRaisedExceptionMessage := E.Message;
  434. FThrownExceptionAddress := ThrownExceptionAddrs;
  435. FTestLastStep := LastStep;
  436. end;
  437. function TTestFailure.GetAsString: string;
  438. var
  439. s: string;
  440. begin
  441. if FTestSuiteName <> '' then
  442. s := FTestSuiteName + '.'
  443. else
  444. s := '';
  445. Result := s + FTestName + ': ' + FRaisedExceptionMessage;
  446. end;
  447. function TTestFailure.GetExceptionClassName: string;
  448. begin
  449. if Assigned(FRaisedExceptionClass) then
  450. Result := FRaisedExceptionClass.ClassName
  451. else
  452. Result := '<NIL>'
  453. end;
  454. function TTestFailure.GetLocationInfo: string;
  455. begin
  456. Result := PointerToLocationInfo(FThrownExceptionAddress);
  457. end;
  458. function TTestFailure.GetExceptionMessage: string;
  459. begin
  460. Result := FRaisedExceptionMessage;
  461. if TestLastStep = stSetUp then
  462. Result := '[SETUP] ' + Result
  463. else if TestLastStep = stTearDown then
  464. Result := '[TEARDOWN] ' + Result;
  465. end;
  466. function TTestFailure.GetIsFailure: boolean;
  467. begin
  468. Result := FRaisedExceptionClass.InheritsFrom(EAssertionFailedError);
  469. end;
  470. function TTestFailure.GetIsIgnoredTest: boolean;
  471. begin
  472. Result := FRaisedExceptionClass.InheritsFrom(EIgnoredTest);
  473. end;
  474. procedure TTestFailure.SetTestLastStep(const Value: TTestStep);
  475. begin
  476. FTestLastStep := Value;
  477. end;
  478. { TTest}
  479. function TTest.GetTestName: string;
  480. begin
  481. Result := 'TTest';
  482. end;
  483. function TTest.GetTestSuiteName: string;
  484. begin
  485. Result := 'TTest';
  486. end;
  487. function TTest.CountTestCases: integer;
  488. begin
  489. Result := 0;
  490. end;
  491. function TTest.GetChildTestCount: Integer;
  492. begin
  493. Result:=0;
  494. end;
  495. function TTest.GetChildTest(AIndex: Integer): TTest;
  496. begin
  497. Result:=Nil;
  498. end;
  499. function TTest.FindChildTest(const AName: String): TTest;
  500. Var
  501. I : Integer;
  502. begin
  503. Result:=Nil;
  504. I:=GetChildTestCount-1;
  505. While (Result=Nil) and (I>=0) do
  506. begin
  507. Result:=GetChildTest(I);
  508. if CompareText(Result.TestName,AName)<>0 then
  509. Result:=Nil;
  510. Dec(I);
  511. end;
  512. end;
  513. function TTest.FindTest(const AName: String): TTest;
  514. Var
  515. S : String;
  516. I,P : Integer;
  517. begin
  518. Result:=Nil;
  519. S:=AName;
  520. if S='' then exit;
  521. P:=Pos('.',S);
  522. If (P=0) then
  523. P:=Length(S)+1;
  524. Result:=FindChildTest(Copy(S,1,P-1));
  525. if (Result<>Nil) then
  526. begin
  527. Delete(S,1,P);
  528. If (S<>'') then
  529. Result:=Result.FindTest(S);
  530. end
  531. else
  532. begin
  533. P:=GetChildTestCount;
  534. I:=0;
  535. While (Result=Nil) and (I<P) do
  536. begin
  537. Result:=GetChildTest(I).FindTest(Aname);
  538. Inc(I);
  539. end;
  540. end;
  541. end;
  542. function TTest.GetEnableIgnores: boolean;
  543. begin
  544. Result := True;
  545. end;
  546. procedure TTest.Run(AResult: TTestResult);
  547. begin
  548. { do nothing }
  549. end;
  550. procedure TTest.Ignore(const AMessage: string);
  551. begin
  552. if EnableIgnores then raise EIgnoredTest.Create(AMessage);
  553. end;
  554. { TAssert }
  555. class procedure TAssert.Status(const aMsg: String);
  556. begin
  557. If Assigned(StatusHook) then
  558. StatusHook(aMsg);
  559. if Assigned(StatusEvent) then
  560. StatusEvent(aMsg);
  561. end;
  562. class procedure TAssert.Status(const aMsg: String; const aArgs: array of const);
  563. begin
  564. Status(SafeFormat(aMsg,aArgs));
  565. end;
  566. class procedure TAssert.Fail(const AMessage: string; AErrorAddrs: Pointer);
  567. begin
  568. Inc(AssertCount);
  569. if AErrorAddrs = nil then
  570. raise EAssertionFailedError.Create(AMessage) at CallerAddr
  571. else
  572. raise EAssertionFailedError.Create(AMessage) at AErrorAddrs;
  573. end;
  574. class procedure TAssert.Fail(const AFmt: string; Args: array of const; AErrorAddrs: Pointer = nil);
  575. begin
  576. Inc(AssertCount);
  577. if AErrorAddrs = nil then
  578. raise EAssertionFailedError.CreateFmt(AFmt,Args) at CallerAddr
  579. else
  580. raise EAssertionFailedError.CreateFmt(AFmt,Args) at AErrorAddrs;
  581. end;
  582. class procedure TAssert.FailEquals(const expected, actual: string; const ErrorMsg: string; AErrorAddrs: Pointer);
  583. begin
  584. Fail(EqualsErrorMessage(expected, actual, ErrorMsg), AErrorAddrs);
  585. end;
  586. class procedure TAssert.FailNotEquals(const expected, actual: string; const ErrorMsg: string; AErrorAddrs: Pointer);
  587. begin
  588. Fail(NotEqualsErrorMessage(expected, actual, ErrorMsg), AErrorAddrs);
  589. end;
  590. class procedure TAssert.AssertTrue(const AMessage: string; ACondition: boolean; AErrorAddrs: Pointer = nil);
  591. begin
  592. if AErrorAddrs=Nil then
  593. AErrorAddrs:=CallerAddr;
  594. if (not ACondition) then
  595. Fail(AMessage,AErrorAddrs)
  596. else
  597. Inc(AssertCount); // Fail will increae AssertCount
  598. end;
  599. class procedure TAssert.AssertTrue(ACondition: boolean);
  600. begin
  601. AssertTrue('', ACondition,CallerAddr);
  602. end;
  603. class procedure TAssert.AssertFalse(const AMessage: string; ACondition: boolean; AErrorAddrs: Pointer = nil
  604. );
  605. begin
  606. if AErrorAddrs=Nil then
  607. AErrorAddrs:=CallerAddr;
  608. AssertTrue(AMessage, not ACondition,AErrorAddrs);
  609. end;
  610. class procedure TAssert.AssertFalse(ACondition: boolean);
  611. begin
  612. AssertFalse('', ACondition,CallerAddr);
  613. end;
  614. class procedure TAssert.AssertEquals(const AMessage: string;
  615. Expected: AnsiString; Actual: UnicodeString);
  616. begin
  617. AssertTrue(ComparisonMsg(AMessage ,UnicodeString(Expected), Actual), UnicodeString(Expected)=Actual,CallerAddr);
  618. end;
  619. class procedure TAssert.AssertEquals(const AMessage: string;
  620. Expected: UnicodeString; Actual: AnsiString);
  621. begin
  622. AssertTrue(ComparisonMsg(AMessage ,Expected, UnicodeString(Actual)), Expected=UnicodeString(Actual),CallerAddr);
  623. end;
  624. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: Ansistring);
  625. begin
  626. AssertTrue(ComparisonMsg(AMessage ,Expected, Actual), Expected=Actual,CallerAddr);
  627. end;
  628. class procedure TAssert.AssertEquals(Expected, Actual: Ansistring);
  629. begin
  630. AssertTrue(ComparisonMsg(Expected, Actual), Expected=Actual,CallerAddr);
  631. end;
  632. class procedure TAssert.AssertEquals(const AMessage: string; Expected,
  633. Actual: UnicodeString);
  634. begin
  635. AssertTrue(ComparisonMsg(AMessage ,Expected, Actual), Expected=Actual,CallerAddr);
  636. end;
  637. class procedure TAssert.AssertEquals(Expected, Actual: UnicodeString);
  638. begin
  639. AssertTrue(ComparisonMsg(Expected, Actual), Expected=Actual,CallerAddr);
  640. end;
  641. class procedure TAssert.AssertNotNull(const AString: string);
  642. begin
  643. AssertNotNull('', AString);
  644. end;
  645. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: integer);
  646. begin
  647. AssertTrue(ComparisonMsg(AMessage,IntToStr(Expected), IntToStr(Actual)), Expected = Actual,CallerAddr);
  648. end;
  649. class procedure TAssert.AssertEquals(Expected, Actual: integer);
  650. begin
  651. AssertTrue(ComparisonMsg(IntToStr(Expected), IntToStr(Actual)), Expected = Actual,CallerAddr);
  652. end;
  653. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: int64);
  654. begin
  655. AssertTrue(ComparisonMsg(AMessage,IntToStr(Expected), IntToStr(Actual)), Expected = Actual,CallerAddr);
  656. end;
  657. class procedure TAssert.AssertEquals(Expected, Actual: int64);
  658. begin
  659. AssertTrue(ComparisonMsg(IntToStr(Expected), IntToStr(Actual)), Expected = Actual,CallerAddr);
  660. end;
  661. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: QWord);
  662. begin
  663. AssertTrue(ComparisonMsg(AMessage,IntToStr(Expected), IntToStr(Actual)), Expected = Actual,CallerAddr);
  664. end;
  665. class procedure TAssert.AssertEquals(Expected, Actual: QWord);
  666. begin
  667. AssertTrue(ComparisonMsg(IntToStr(Expected), IntToStr(Actual)), Expected = Actual,CallerAddr);
  668. end;
  669. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: currency);
  670. begin
  671. AssertTrue(ComparisonMsg(AMessage,FloatToStr(Expected), FloatToStr(Actual)), Expected = Actual,CallerAddr);
  672. end;
  673. class procedure TAssert.AssertEquals(Expected, Actual: currency);
  674. begin
  675. AssertTrue(ComparisonMsg(FloatToStr(Expected), FloatToStr(Actual)), Expected = Actual,CallerAddr);
  676. end;
  677. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual, Delta: double);
  678. begin
  679. AssertTrue(ComparisonMsg(AMessage,FloatToStr(Expected),FloatToStr(Actual)),
  680. (Abs(Expected - Actual) <= Delta),CallerAddr);
  681. end;
  682. class procedure TAssert.AssertEquals(Expected, Actual, Delta: double);
  683. begin
  684. AssertTrue(ComparisonMsg(FloatToStr(Expected),FloatToStr(Actual)),
  685. (Abs(Expected - Actual) <= Delta),CallerAddr);
  686. end;
  687. class procedure TAssert.AssertNotNull(const AMessage, AString: string);
  688. begin
  689. AssertTrue(AMessage, AString <> '',CallerAddr);
  690. end;
  691. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: boolean);
  692. begin
  693. AssertTrue(ComparisonMsg(AMessage,BoolToStr(Expected, true), BoolToStr(Actual, true)), Expected = Actual,CallerAddr);
  694. end;
  695. class procedure TAssert.AssertEquals(Expected, Actual: boolean);
  696. begin
  697. AssertTrue(ComparisonMsg(BoolToStr(Expected, true), BoolToStr(Actual, true)), Expected = Actual,CallerAddr);
  698. end;
  699. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: AnsiChar);
  700. begin
  701. AssertTrue(ComparisonMsg(AMessage,Expected, Actual), Expected = Actual,CallerAddr);
  702. end;
  703. class procedure TAssert.AssertEquals(Expected, Actual: AnsiChar);
  704. begin
  705. AssertTrue(ComparisonMsg(Expected, Actual), Expected = Actual,CallerAddr);
  706. end;
  707. class procedure TAssert.AssertEquals(const AMessage: string; Expected, Actual: TClass);
  708. begin
  709. AssertTrue(ComparisonMsg(AMessage,GetN(Expected), GetN(Actual)), Expected = Actual,CallerAddr);
  710. end;
  711. class procedure TAssert.AssertEquals(Expected, Actual: TClass);
  712. begin
  713. AssertTrue(ComparisonMsg(GetN(Expected), GetN(Actual)), Expected = Actual,CallerAddr);
  714. end;
  715. class procedure TAssert.AssertSame(const AMessage: string; Expected, Actual: TObject);
  716. begin
  717. AssertTrue(ComparisonMsg(AMessage,IntToStr(PtrInt(Expected)), IntToStr(PtrInt(Actual))), Expected = Actual,CallerAddr);
  718. end;
  719. class procedure TAssert.AssertSame(Expected, Actual: TObject);
  720. begin
  721. AssertTrue(ComparisonMsg(IntToStr(PtrInt(Expected)), IntToStr(PtrInt(Actual))), Expected = Actual,CallerAddr);
  722. end;
  723. class procedure TAssert.AssertSame(const AMessage: string; Expected, Actual: Pointer);
  724. begin
  725. AssertTrue(ComparisonMsg(AMessage,IntToStr(PtrInt(Expected)), IntToStr(PtrInt(Actual))), Expected = Actual,CallerAddr);
  726. end;
  727. class procedure TAssert.AssertSame(Expected, Actual: Pointer);
  728. begin
  729. AssertTrue(ComparisonMsg(IntToStr(PtrInt(Expected)), IntToStr(PtrInt(Actual))), Expected = Actual,CallerAddr);
  730. end;
  731. class procedure TAssert.AssertNotSame(const AMessage: string; Expected, Actual: TObject);
  732. begin
  733. AssertFalse('"' + aMessage + '"' + SExpectedNotSame, Expected = Actual,CallerAddr);
  734. end;
  735. class procedure TAssert.AssertNotSame(Expected, Actual: TObject);
  736. begin
  737. AssertFalse(SExpectedNotSame, Expected = Actual);
  738. end;
  739. class procedure TAssert.AssertNotSame(const AMessage: string; Expected, Actual: Pointer);
  740. begin
  741. AssertFalse('"' + aMessage + '"' + SExpectedNotSame, Expected = Actual,CallerAddr);
  742. end;
  743. class procedure TAssert.AssertNotSame(Expected, Actual: Pointer);
  744. begin
  745. AssertFalse(SExpectedNotSame, Expected = Actual,CallerAddr);
  746. end;
  747. class procedure TAssert.AssertNotNull(const AMessage: string; AObject: TObject);
  748. begin
  749. AssertTrue(AMessage, (AObject <> nil),CallerAddr);
  750. end;
  751. class procedure TAssert.AssertNotNull(AObject: TObject);
  752. begin
  753. AssertTrue('',(AObject <> nil),CallerAddr);
  754. end;
  755. class procedure TAssert.AssertNotNullIntf(const AMessage: string; AInterface: IInterface);
  756. begin
  757. AssertTrue(AMessage, (AInterface <> nil),CallerAddr);
  758. end;
  759. class procedure TAssert.AssertNotNullIntf(AInterface: IInterface);
  760. begin
  761. AssertTrue('', (AInterface <> nil),CallerAddr);
  762. end;
  763. class procedure TAssert.AssertNotNull(const AMessage: string; APointer: Pointer);
  764. begin
  765. AssertTrue(AMessage, (APointer <> nil),callerAddr);
  766. end;
  767. class procedure TAssert.AssertNotNull(APointer: Pointer);
  768. begin
  769. AssertTrue('', (APointer <> nil),callerAddr);
  770. end;
  771. class procedure TAssert.AssertNull(const AMessage: string; AObject: TObject);
  772. begin
  773. AssertTrue(AMessage, (AObject = nil),CallerAddr);
  774. end;
  775. class procedure TAssert.AssertNull(AObject: TObject);
  776. begin
  777. AssertTrue('',(AObject = nil),CallerAddr);
  778. end;
  779. class procedure TAssert.AssertNullIntf(const AMessage: string; AInterface: IInterface);
  780. begin
  781. AssertTrue(AMessage, (AInterface = nil),CallerAddr);
  782. end;
  783. class procedure TAssert.AssertNullIntf(AInterface: IInterface);
  784. begin
  785. AssertTrue('', (AInterface = nil),CallerAddr);
  786. end;
  787. class procedure TAssert.AssertNull(const AMessage: string; APointer: Pointer);
  788. begin
  789. AssertTrue(AMessage, (APointer = nil),CallerAddr);
  790. end;
  791. class procedure TAssert.AssertNull(APointer: Pointer);
  792. begin
  793. AssertTrue('', (APointer = nil),CallerAddr);
  794. end;
  795. class procedure TAssert.AssertException(const AMessage: string; AExceptionClass: ExceptClass;
  796. AMethod: TRunMethod;const AExceptionMessage : String = ''; AExceptionContext : Integer = 0; AErrorAddr : Pointer = Nil);
  797. Function MisMatch (const AClassName : String) : String;
  798. begin
  799. Result:=Format(SExceptionCompare,[AExceptionClass.ClassName, AClassName])
  800. end;
  801. var
  802. Msg,FailMsg : string;
  803. begin
  804. If AErrorAddr=Nil then
  805. AErrorAddr:=CallerAddr;
  806. FailMsg:='';
  807. try
  808. AMethod;
  809. FailMsg:=MisMatch(SNoException);
  810. except
  811. on E: Exception do
  812. begin
  813. if Not E.ClassType.InheritsFrom(AExceptionClass) then
  814. FailMsg:=MisMatch(E.ClassName)
  815. else if not (AExceptionClass.ClassName = E.ClassName) then
  816. FailMsg:=MisMatch(E.ClassName)
  817. else if (AExceptionMessage<>'') and (AExceptionMessage<>E.Message) then
  818. FailMsg:=ComparisonMsg(SExceptionMessageCompare,AExceptionMessage,E.Message)
  819. else if (AExceptionContext<>0) and (AExceptionContext<>E.HelpContext) then
  820. FailMsg:=ComparisonMsg(SExceptionHelpContextCompare,IntToStr(AExceptionContext),IntToStr(E.HelpContext))
  821. end;
  822. end;
  823. Msg:=FailMsg;
  824. if aMessage<>'' then
  825. Msg:=AMessage + ': '+Msg;
  826. AssertTrue(Msg, FailMsg='', AErrorAddr);
  827. end;
  828. class procedure TAssert.AssertException(AExceptionClass: ExceptClass;
  829. AMethod: TRunMethod;const AExceptionMessage : String = ''; AExceptionContext : Integer = 0);
  830. begin
  831. AssertException('', AExceptionClass, AMethod, AExceptionMessage, AExceptionContext, CallerAddr);
  832. end;
  833. class procedure TAssert.AssertNoException(const AMessage: string; AMethod: TRunMethod);
  834. var
  835. Msg,aClass,aExceptionMessage : String;
  836. begin
  837. aClass:='';
  838. aExceptionMessage:='';
  839. Try
  840. aMethod;
  841. Except
  842. On E : Exception do
  843. begin
  844. aClass:=E.ClassName;
  845. aExceptionMessage:=E.Message;
  846. end;
  847. end;
  848. Msg:=Format(SErrUnexpectedException,[aClass,aExceptionMessage]);
  849. if aMessage<>'' then
  850. Msg:=aMessage+': '+Msg;
  851. AssertTrue(Msg,aClass='');
  852. end;
  853. class procedure TAssert.AssertNoException(AMethod: TRunMethod);
  854. begin
  855. AssertNoException('',aMethod);
  856. end;
  857. class procedure TAssert.AssertException(const AMessage: string; AExceptionClass: ExceptClass; AMethod: TRunLocalMethod;
  858. const AExceptionMessage: String; AExceptionContext: Integer; AErrorAddr: Pointer);
  859. Function MisMatch (const AClassName : String) : String;
  860. begin
  861. Result:=Format(SExceptionCompare,[AExceptionClass.ClassName, AClassName])
  862. end;
  863. var
  864. Msg,FailMsg : string;
  865. begin
  866. If AErrorAddr=Nil then
  867. AErrorAddr:=CallerAddr;
  868. FailMsg:='';
  869. try
  870. AMethod;
  871. FailMsg:=MisMatch(SNoException);
  872. except
  873. on E: Exception do
  874. begin
  875. if Not E.ClassType.InheritsFrom(AExceptionClass) then
  876. FailMsg:=MisMatch(E.ClassName)
  877. else if not (AExceptionClass.ClassName = E.ClassName) then
  878. FailMsg:=MisMatch(E.ClassName)
  879. else if (AExceptionMessage<>'') and (AExceptionMessage<>E.Message) then
  880. FailMsg:=ComparisonMsg(SExceptionMessageCompare,AExceptionMessage,E.Message)
  881. else if (AExceptionContext<>0) and (AExceptionContext<>E.HelpContext) then
  882. FailMsg:=ComparisonMsg(SExceptionHelpContextCompare,IntToStr(AExceptionContext),IntToStr(E.HelpContext))
  883. end;
  884. end;
  885. Msg:=FailMsg;
  886. if aMessage<>'' then
  887. Msg:=AMessage + ': '+Msg;
  888. AssertTrue(Msg, FailMsg='', AErrorAddr);
  889. end;
  890. class procedure TAssert.AssertException(AExceptionClass: ExceptClass; AMethod: TRunLocalMethod; const AExceptionMessage: String;
  891. AExceptionContext: Integer);
  892. begin
  893. AssertException('', AExceptionClass, AMethod, AExceptionMessage, AExceptionContext, CallerAddr);
  894. end;
  895. class procedure TAssert.AssertNoException(const AMessage: string; AMethod: TRunLocalMethod);
  896. var
  897. Msg,aClass,aExceptionMessage : String;
  898. begin
  899. aClass:='';
  900. aExceptionMessage:='';
  901. Try
  902. aMethod;
  903. Except
  904. On E : Exception do
  905. begin
  906. aClass:=E.ClassName;
  907. aExceptionMessage:=E.Message;
  908. end;
  909. end;
  910. Msg:=Format(SErrUnexpectedException,[aClass,aExceptionMessage]);
  911. if aMessage<>'' then
  912. Msg:=aMessage+': '+Msg;
  913. AssertTrue(Msg,aClass='');
  914. end;
  915. class procedure TAssert.AssertNoException(AMethod: TRunLocalMethod);
  916. begin
  917. AssertNoException('',aMethod);
  918. end;
  919. { DUnit compatibility interface }
  920. {$IFDEF DUnit}
  921. {$I DUnitCompatibleInterface.inc}
  922. {$ENDIF DUnit}
  923. constructor TTestCase.Create;
  924. begin
  925. inherited Create;
  926. FEnableIgnores := True;
  927. end;
  928. constructor TTestCase.CreateWithName(const AName: string);
  929. begin
  930. Create;
  931. FName := AName;
  932. end;
  933. constructor TTestCase.CreateWith(const ATestName: string; const ATestSuiteName: string);
  934. begin
  935. Create;
  936. FName := ATestName;
  937. FTestSuiteName := ATestSuiteName;
  938. end;
  939. function TTestCase.AsString: string;
  940. begin
  941. Result := TestName + '(' + ClassName + ')';
  942. end;
  943. class function TTestCase.Suite: TTestSuite;
  944. begin
  945. Result:=TTestSuite.Create(Self.ClassType);
  946. end;
  947. function TTestCase.CountTestCases: integer;
  948. begin
  949. Result := 1;
  950. end;
  951. function TTestCase.CreateResult: TTestResult;
  952. begin
  953. Result := TTestResult.Create;
  954. end;
  955. function TTestCase.GetTestName: string;
  956. begin
  957. Result := FName;
  958. end;
  959. function TTestCase.GetEnableIgnores: boolean;
  960. begin
  961. Result := FEnableIgnores;
  962. end;
  963. function TTestCase.GetTestSuiteName: string;
  964. begin
  965. Result := FTestSuiteName;
  966. end;
  967. procedure TTestCase.SetTestSuiteName(const aName: string);
  968. begin
  969. if FTestSuiteName <> aName then
  970. FTestSuiteName := aName;
  971. end;
  972. procedure TTestCase.SetTestName(const Value: string);
  973. begin
  974. FName := Value;
  975. end;
  976. procedure TTestCase.SetEnableIgnores(Value: boolean);
  977. begin
  978. FEnableIgnores := Value;
  979. end;
  980. function TTestCase.CreateResultAndRun: TTestResult;
  981. begin
  982. Result := CreateResult;
  983. Run(Result);
  984. end;
  985. procedure TTestCase.Run(AResult: TTestResult);
  986. begin
  987. (AResult).Run(Self);
  988. end;
  989. procedure TTestCase.RunBare;
  990. begin
  991. FLastStep := stSetUp;
  992. SetUp;
  993. try
  994. FLastStep := stRunTest;
  995. RunTest;
  996. FLastStep := stTearDown;
  997. finally
  998. TearDown;
  999. end;
  1000. FLastStep := stNothing;
  1001. end;
  1002. class function TTestCase.SingleInstanceForSuite: Boolean;
  1003. begin
  1004. Result:=False;
  1005. end;
  1006. procedure TTestCase.RunTest;
  1007. var
  1008. m: TMethod;
  1009. RunMethod: TRunMethod;
  1010. pMethod : Pointer;
  1011. FailMessage : String;
  1012. begin
  1013. AssertNotNull('name of the test not assigned', FName);
  1014. pMethod := Self.MethodAddress(FName);
  1015. if (Assigned(pMethod)) then
  1016. begin
  1017. m.Code := pMethod;
  1018. m.Data := self;
  1019. RunMethod := TRunMethod(m);
  1020. ExpectException('',Nil,'',0);
  1021. try
  1022. AssertCount:=0;
  1023. FailMessage:='';
  1024. RunMethod;
  1025. if (FExpectedException<>Nil) then
  1026. FailMessage:=Format(SExceptionCompare, [FExpectedException.ClassName, SNoException]);
  1027. if CheckAssertCalled and (AssertCount=0) then
  1028. FailMessage:=SAssertNotCalled;
  1029. except
  1030. On E : Exception do
  1031. begin
  1032. if FExpectedException=Nil then
  1033. Raise;
  1034. If not (E is FExpectedException) then
  1035. FailMessage:=Format(SExceptionCompare, [FExpectedException.ClassName, E.ClassName]);
  1036. if (FExpectedExceptionMessage<>'') then
  1037. if (FExpectedExceptionMessage<>E.Message) then
  1038. FailMessage:=Format(SExceptionmessageCompare+SCompare, [FExpectedExceptionMessage,E.Message]);
  1039. if (FExpectedExceptionContext<>0) then
  1040. if (FExpectedExceptionContext<>E.HelpContext) then
  1041. FailMessage:=Format(SExceptionHelpContextCompare+SCompare, [IntToStr(FExpectedExceptionContext),IntToStr(E.HelpContext)])
  1042. end;
  1043. end;
  1044. if (FailMessage<>'') then
  1045. begin
  1046. if (FExpectedExceptionFailMessage<>'') then
  1047. FailMessage:=' : '+FailMessage;
  1048. Fail(FExpectedExceptionFailMessage+FailMessage,FExpectedExceptionCaller);
  1049. end;
  1050. end
  1051. else
  1052. begin
  1053. Fail(format(SMethodNotFound, [FName]));
  1054. end;
  1055. end;
  1056. procedure TTestCase.SetUp;
  1057. begin
  1058. { do nothing }
  1059. end;
  1060. procedure TTestCase.TearDown;
  1061. begin
  1062. { do nothing }
  1063. end;
  1064. Type
  1065. { TTestItem }
  1066. TTestItem = Class(TObject)
  1067. private
  1068. FName: String;
  1069. FOwnsTest: Boolean;
  1070. FTest: TTest;
  1071. public
  1072. Constructor Create(T : TTest);
  1073. Destructor Destroy; override;
  1074. Property Test : TTest Read FTest;
  1075. Property TestName : String Read FName;
  1076. Property OwnsTest : Boolean Read FOwnsTest Write FOwnstest;
  1077. end;
  1078. { TTestItem }
  1079. constructor TTestItem.Create(T: TTest);
  1080. begin
  1081. FTest:=T;
  1082. FName:=T.TestName;
  1083. FOwnsTest:=True;
  1084. end;
  1085. destructor TTestItem.Destroy;
  1086. begin
  1087. if FOwnsTest then
  1088. FreeAndNil(FTest);
  1089. inherited Destroy;
  1090. end;
  1091. constructor TTestSuite.Create(AClass: TClass; const AName: string);
  1092. begin
  1093. Create(AClass);
  1094. FName := AName;
  1095. end;
  1096. constructor TTestSuite.Create(AClass: TClass);
  1097. var
  1098. ml: TStringList;
  1099. i,j: integer;
  1100. tc: TTestCaseClass;
  1101. C : TTestCase;
  1102. SN : String;
  1103. begin
  1104. TAssert.AssertNotNull(AClass);
  1105. Create(AClass.ClassName);
  1106. if AClass.InheritsFrom(TTestCase) then
  1107. begin
  1108. tc := TTestCaseClass(AClass);
  1109. ml := TStringList.Create;
  1110. try
  1111. GetMethodList(AClass, ml);
  1112. SN:=tc.ClassName;
  1113. if tc.SingleInstanceForSuite then
  1114. begin
  1115. c:=tc.CreateWith('',SN);
  1116. for i := 0 to ml.Count -1 do
  1117. begin
  1118. C.TestName:=ml[i];
  1119. J:=DoAddTest(C);
  1120. TTestItem(FTests[J]).OwnsTest:=(I=0);
  1121. end;
  1122. end
  1123. else
  1124. for i := 0 to ml.Count -1 do
  1125. AddTest(tc.CreateWith(ml.Strings[i], SN));
  1126. finally
  1127. ml.Free;
  1128. end;
  1129. end
  1130. else
  1131. AddTest(Warning(AClass.ClassName + SNoValidInheritance));
  1132. if FTests.Count = 0 then
  1133. AddTest(Warning(SNoValidTests + AClass.ClassName));
  1134. end;
  1135. constructor TTestSuite.Create(AClassArray: array of TClass);
  1136. var
  1137. i: integer;
  1138. begin
  1139. Create;
  1140. for i := Low(AClassArray) to High(AClassArray) do
  1141. if Assigned(AClassArray[i]) then
  1142. AddTest(TTestSuite.Create(AClassArray[i]));
  1143. end;
  1144. constructor TTestSuite.Create(const AName: string);
  1145. begin
  1146. Create();
  1147. FName := AName;
  1148. end;
  1149. constructor TTestSuite.Create;
  1150. begin
  1151. inherited Create;
  1152. FTests := TFPList.Create;
  1153. FOwnsTests:=True;
  1154. FEnableIgnores := True;
  1155. end;
  1156. destructor TTestSuite.Destroy;
  1157. begin
  1158. FreeObjects(FTests);
  1159. FTests.Free;
  1160. inherited Destroy;
  1161. end;
  1162. function TTestSuite.GetChildTest(AIndex: integer): TTest;
  1163. begin
  1164. Result := TTestItem(FTests[AIndex]).Test;
  1165. end;
  1166. function TTestSuite.GetChildTestCount: Integer;
  1167. begin
  1168. Result:=FTests.Count;
  1169. end;
  1170. procedure TTestSuite.SetOwnsTests(AValue: Boolean);
  1171. begin
  1172. if FOwnsTests=AValue then Exit;
  1173. FOwnsTests:=AValue;
  1174. SetOwnTestOnTests(AValue);
  1175. end;
  1176. procedure TTestSuite.SetOwnTestOnTests(AValue: Boolean);
  1177. Var
  1178. I : Integer;
  1179. begin
  1180. For I:=0 to FTests.Count-1 do
  1181. TTestItem(FTests[i]).OwnsTest:=AValue;
  1182. end;
  1183. function TTestSuite.DoAddTest(ATest: TTest): Integer;
  1184. Var
  1185. I : TTestItem;
  1186. begin
  1187. I:=TTestItem.Create(ATest);
  1188. I.OwnsTest:=OwnsTests;
  1189. Result:=FTests.Add(I);
  1190. if ATest.TestSuiteName = '' then
  1191. ATest.TestSuiteName := Self.TestName;
  1192. ATest.EnableIgnores := Self.EnableIgnores;
  1193. end;
  1194. function TTestSuite.GetTestName: string;
  1195. begin
  1196. Result := FName;
  1197. end;
  1198. function TTestSuite.GetTestSuiteName: string;
  1199. begin
  1200. Result := FTestSuiteName;
  1201. end;
  1202. function TTestSuite.GetEnableIgnores: boolean;
  1203. begin
  1204. Result := FEnableIgnores;
  1205. end;
  1206. procedure TTestSuite.SetTestName(const Value: string);
  1207. begin
  1208. FName := Value;
  1209. end;
  1210. procedure TTestSuite.SetTestSuiteName(const aName: string);
  1211. begin
  1212. if FTestSuiteName <> aName then
  1213. FTestSuiteName := aName;
  1214. end;
  1215. procedure TTestSuite.SetEnableIgnores(Value: boolean);
  1216. var
  1217. i: integer;
  1218. begin
  1219. if FEnableIgnores <> Value then
  1220. begin
  1221. FEnableIgnores := Value;
  1222. for i := 0 to FTests.Count - 1 do
  1223. TTestItem(FTests[i]).Test.EnableIgnores := Value;
  1224. end
  1225. end;
  1226. function TTestSuite.CountTestCases: integer;
  1227. var
  1228. i: integer;
  1229. begin
  1230. Result := 0;
  1231. for i := 0 to FTests.Count - 1 do
  1232. begin
  1233. Result := Result + TTestItem(FTests[i]).Test.CountTestCases;
  1234. end;
  1235. end;
  1236. procedure TTestCase.ExpectException(const Msg: String;
  1237. AExceptionClass: TClass; const AExceptionMessage: string = '';
  1238. AExceptionHelpContext: Integer =0 );
  1239. begin
  1240. FExpectedExceptionFailMessage:=Msg;
  1241. FExpectedException:=AExceptionClass;
  1242. FExpectedExceptionMessage:=AExceptionMessage;
  1243. FExpectedExceptionContext:=AExceptionHelpContext;
  1244. FExpectedExceptionCaller:=CallerAddr;
  1245. end;
  1246. procedure TTestCase.ExpectException(AExceptionClass: TClass;
  1247. const AExceptionMessage: string = ''; AExceptionHelpContext: Integer = 0);
  1248. begin
  1249. FExpectedExceptionFailMessage:='';
  1250. FExpectedException:=AExceptionClass;
  1251. FExpectedExceptionMessage:=AExceptionMessage;
  1252. FExpectedExceptionContext:=AExceptionHelpContext;
  1253. FExpectedExceptionCaller:=CallerAddr;
  1254. end;
  1255. procedure TTestSuite.Run(AResult: TTestResult);
  1256. var
  1257. i: integer;
  1258. ti : TTestItem;
  1259. begin
  1260. if FTests.Count > 0 then
  1261. AResult.StartTestSuite(self);
  1262. for i := 0 to FTests.Count - 1 do
  1263. begin
  1264. ti:=TTestItem(FTests[i]);
  1265. if Ti.Test.InheritsFrom(TTestCase) and TTestCase(Ti.Test).SingleInstanceForSuite then
  1266. TTestCase(Ti.Test).SetTestName(Ti.TestName);
  1267. RunTest(TI.Test, AResult);
  1268. end;
  1269. if FTests.Count > 0 then
  1270. AResult.EndTestSuite(self);
  1271. end;
  1272. procedure TTestSuite.RunTest(ATest: TTest; AResult: TTestResult);
  1273. begin
  1274. ATest.Run(AResult);
  1275. end;
  1276. procedure TTestSuite.AddTest(ATest: TTest);
  1277. begin
  1278. DoAddTest(ATest);
  1279. end;
  1280. procedure TTestSuite.AddTestSuiteFromClass(ATestClass: TClass);
  1281. begin
  1282. AddTest(TTestSuite.Create(ATestClass));
  1283. end;
  1284. class function TTestSuite.Warning(const aMessage: string): TTestCase;
  1285. var
  1286. w: TTestWarning;
  1287. begin
  1288. w := TTestWarning.Create;
  1289. w.FMessage := aMessage;
  1290. Result := w;
  1291. end;
  1292. constructor TTestResult.Create;
  1293. begin
  1294. inherited Create;
  1295. FFailures := TFPList.Create;
  1296. FIgnoredTests := TFPList.Create;
  1297. FErrors := TFPList.Create;
  1298. FListeners := TFPList.Create;
  1299. FSkippedTests := TFPList.Create;
  1300. FStartingTime := Now;
  1301. end;
  1302. destructor TTestResult.Destroy;
  1303. begin
  1304. FreeObjects(FFailures);
  1305. FFailures.Free;
  1306. FreeObjects(FIgnoredTests);
  1307. FIgnoredTests.Free;
  1308. FreeObjects(FErrors);
  1309. FErrors.Free;
  1310. FListeners.Free;
  1311. FSkippedTests.Free;
  1312. end;
  1313. procedure TTestResult.ClearErrorLists;
  1314. begin
  1315. FreeObjects(FFailures);
  1316. FFailures.Clear;
  1317. FreeObjects(FIgnoredTests);
  1318. FIgnoredTests.Clear;
  1319. FreeObjects(FErrors);
  1320. FErrors.Clear;
  1321. end;
  1322. function TTestResult.GetNumErrors: integer;
  1323. begin
  1324. Result := FErrors.Count;
  1325. end;
  1326. function TTestResult.GetNumFailures: integer;
  1327. begin
  1328. Result := FFailures.Count;
  1329. end;
  1330. function TTestResult.GetNumIgnoredTests: integer;
  1331. begin
  1332. Result := FIgnoredTests.Count;
  1333. end;
  1334. function TTestResult.GetNumSkipped: integer;
  1335. begin
  1336. Result := FSkippedTests.Count;
  1337. end;
  1338. procedure TTestResult.AddListener(AListener: ITestListener);
  1339. begin
  1340. FListeners.Add(pointer(AListener));
  1341. end;
  1342. procedure TTestResult.RemoveListener(AListener: ITestListener);
  1343. begin
  1344. FListeners.Remove(pointer(AListener));
  1345. end;
  1346. procedure TTestResult.AddFailure(ATest: TTest; E: EAssertionFailedError; aFailureList: TFPList; AThrownExceptionAdrs: Pointer);
  1347. var
  1348. i: integer;
  1349. f: TTestFailure;
  1350. begin
  1351. //lock mutex
  1352. f := TTestFailure.CreateFailure(ATest, E, ATest.LastStep, AThrownExceptionAdrs);
  1353. aFailureList.Add(f);
  1354. for i := 0 to FListeners.Count - 1 do
  1355. ITestListener(FListeners[i]).AddFailure(ATest, f);
  1356. //unlock mutex
  1357. end;
  1358. procedure TTestResult.AddError(ATest: TTest; E: Exception; AThrownExceptionAdrs: Pointer);
  1359. var
  1360. i: integer;
  1361. f: TTestFailure;
  1362. begin
  1363. //lock mutex
  1364. f := TTestFailure.CreateFailure(ATest, E, ATest.LastStep, AThrownExceptionAdrs);
  1365. FErrors.Add(f);
  1366. for i := 0 to FListeners.Count - 1 do
  1367. ITestListener(FListeners[i]).AddError(ATest, f);
  1368. //unlock mutex
  1369. end;
  1370. procedure TTestResult.EndTest(ATest: TTest);
  1371. var
  1372. i: integer;
  1373. begin
  1374. for i := 0 to FListeners.Count - 1 do
  1375. ITestListener(FListeners[i]).EndTest(ATest);
  1376. end;
  1377. procedure ProtectTest(aTest: TTest; aResult: TTestResult);
  1378. begin
  1379. TTestCase(aTest).RunBare;
  1380. end;
  1381. procedure TTestResult.Run(ATestCase: TTestCase);
  1382. begin
  1383. if not SkipTest(ATestCase) then
  1384. begin
  1385. StartTest(ATestCase);
  1386. RunProtected(ATestCase, @ProtectTest);
  1387. EndTest(ATestCase);
  1388. end;
  1389. end;
  1390. procedure TTestResult.RunProtected(ATestCase: TTest; protect: TProtect);
  1391. begin
  1392. try
  1393. protect(ATestCase, Self);
  1394. except
  1395. on E: EIgnoredTest do
  1396. AddFailure(ATestCase, E, FIgnoredTests, ExceptAddr);
  1397. on E: EAssertionFailedError do
  1398. AddFailure(ATestCase, E, FFailures, ExceptAddr);
  1399. on E: Exception do
  1400. begin
  1401. AddError(ATestCase, E, ExceptAddr);
  1402. end;
  1403. end;
  1404. end;
  1405. procedure TTestResult.StartTest(ATest: TTest);
  1406. var
  1407. count: integer;
  1408. i: integer;
  1409. begin
  1410. count := ATest.CountTestCases;
  1411. //lock mutex
  1412. FRunTests := FRunTests + count;
  1413. for i := 0 to FListeners.Count - 1 do
  1414. ITestListener(FListeners[i]).StartTest(ATest);
  1415. //unlock mutex
  1416. end;
  1417. function TTestResult.WasSuccessful: boolean;
  1418. begin
  1419. //lock mutex
  1420. Result := (FErrors.Count = 0) and (FFailures.Count = 0);
  1421. //unlock mutex
  1422. end;
  1423. function TTestResult.SkipTest(ATestCase: TTestCase): boolean;
  1424. var
  1425. i: integer;
  1426. begin
  1427. Result := false;
  1428. if FSkippedTests.Count = 0 then
  1429. begin
  1430. result := false;
  1431. Exit;
  1432. end
  1433. else
  1434. for i := 0 to FSkippedTests.Count - 1 do
  1435. begin
  1436. if PtrUInt(FSkippedTests[i]) = PtrUInt(ATestCase) then
  1437. begin
  1438. Result := true;
  1439. Exit;
  1440. end;
  1441. end;
  1442. end;
  1443. procedure TTestResult.AddToSkipList(ATestCase: TTestCase);
  1444. begin
  1445. FSkippedTests.Add(ATestCase);
  1446. end;
  1447. procedure TTestResult.RemoveFromSkipList(ATestCase: TTestCase);
  1448. begin
  1449. FSkippedTests.Remove(ATestCase);
  1450. end;
  1451. procedure TTestResult.StartTestSuite(ATestSuite: TTestSuite);
  1452. var
  1453. i: integer;
  1454. begin
  1455. for i := 0 to FListeners.Count - 1 do
  1456. ITestListener(FListeners[i]).StartTestSuite(ATestSuite);
  1457. end;
  1458. procedure TTestResult.EndTestSuite(ATestSuite: TTestSuite);
  1459. var
  1460. i: integer;
  1461. begin
  1462. for i := 0 to FListeners.Count - 1 do
  1463. ITestListener(FListeners[i]).EndTestSuite(ATestSuite);
  1464. end;
  1465. initialization
  1466. TTestCase.CheckAssertCalled:=False;
  1467. end.