punit.pp 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2014 by Michael Van Canneyt,
  4. member of the Free Pascal development team.
  5. Complete Test unit framework relying only on system unit.
  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. {$mode objfpc} // needed for exceptions
  13. {$IFDEF UNICODERTL}
  14. {$DEFINE USEUNICODE} // define this if you want to use unicode.
  15. {$ENDIF}
  16. unit punit;
  17. interface
  18. Type
  19. {$IFDEF USEUNICODE}
  20. TTestString = UnicodeString;
  21. {$ELSE}
  22. TTestString = AnsiString;
  23. {$ENDIF}
  24. {$IF NOT DECLARED(RTLString)}
  25. RTLString = TTestString;
  26. {$endif}
  27. { ---------------------------------------------------------------------
  28. Some configuration
  29. ---------------------------------------------------------------------}
  30. Var
  31. InitListLength : Integer = 10; // Initial length of test/suite lists
  32. GrowFactor : Double = 3/2; // Grow factor when list needs to be grown.
  33. DefaultSuiteName : Shortstring = 'Globals'; // Default name to use
  34. RequirePassed : Boolean = False; // If set to true, tests must explicitly call passed.
  35. DefaultDoubleDelta : Double = 1E-14;
  36. DefaultSingleDelta : Single = 1E-9;
  37. DefaultExtendedDelta : Extended = 1E-14;
  38. { ---------------------------------------------------------------------
  39. Some test structures
  40. ---------------------------------------------------------------------}
  41. Type
  42. // General status code
  43. TTestError = (
  44. teOK, // All ok
  45. teTestsRunning, // Tests already running
  46. teRegistryEmpty, // no tests in registry
  47. teNoMemory, // Could not allocate memory
  48. teNoSuite, // No suite specified
  49. teNoSuiteName, // No suite name specified
  50. teSuiteSetupFailed, // Suite setup failed
  51. teSuiteTeardownFailed, // Suite teardown failed
  52. teDuplicateSuite, // Duplicate suite name
  53. teSuiteInactive, // Attempt to run inactive suite
  54. teNoTest, // No test specified
  55. teNoTestName, // No test name specified
  56. teDuplicateTest, // Duplicate test name specified
  57. teTestNotInSuite, // Given Test not member of given suite
  58. teTestInactive, // Attempt to run inactive test
  59. teRunStartHandler, // An error occurred during the run start handler;
  60. teRunCompleteHandler // An error occurred during the run complete handler;
  61. );
  62. // What to do if an error occurs during test suite
  63. TErrorAction = (
  64. eaIgnore, // Ignore errors, continue testing
  65. eaFail, // Fail current test run.
  66. eaAbort // Abort all (Halt(1));
  67. );
  68. // Test prototypes. Empty result inficate succes, nonempty means failure
  69. // test suite setup.
  70. TTestSetup = Function : TTestString;
  71. // test suite teardown.
  72. TTestTearDown = Function : TTestString;
  73. // test run.
  74. TTestRun = Function : TTestString;
  75. // test run procedure.
  76. TTestRunProc = Procedure;
  77. // A single test
  78. TTestOption = (toInactive);
  79. TTestOptions = Set of TTestOption;
  80. PTest = ^TTest;
  81. TTest = Record
  82. Run : TTestRun; // Function to execute when test is run.
  83. RunProc : TTestRunProc; // Procedure to execute when test is run. Run takes precedence.
  84. Name : TTestString; // Name of the test. Must not be empty.
  85. Options : TTestOptions; // True if the test is active (default). Inactive tests are not run.
  86. Data : Pointer; // Data to be associated with the test.
  87. end;
  88. TTestArray = Array of PTest;
  89. // List of tests structure.
  90. TTestList = Record
  91. Items : TTestArray; // Array of Test pointers. Can be oversized. Initialized to InitListLength
  92. Count : Integer; // Actual number of tests in list.
  93. end;
  94. PTestList = ^TTestList;
  95. // A testsuite.
  96. TSuiteOption = (soInactive,soSetupTearDownPerTest);
  97. TSuiteOptions = Set of TSuiteOption;
  98. PSuiteList = ^TSuiteList;
  99. PSuite = ^TSuite;
  100. TSuiteArray = Array of PSuite;
  101. TSuiteList = Record
  102. Items : TSuiteArray; // Array of Suite pointers. Can be oversized. Initialized to InitListLength
  103. Count : Integer; // Actual number of suites in list.
  104. end;
  105. TSuite = Record
  106. Suites : TSuiteList; // Test Suites inside this suite
  107. Tests : TTestList; // Tests in this suite
  108. Setup : TTestSetup; // Setup function, executed once at start of suite.
  109. Teardown : TTestTearDown; // Teardown function. By Default executed once at end of suite (regardless of errors)
  110. Name : TTestString; // Name of the suite, must not be empty.
  111. Options: TSuiteOptions; // True if the suite is active (
  112. ParentSuite : PSuite; // Parent suites of this suite
  113. Data : Pointer; // Data to be associated with the suite
  114. end;
  115. TTestResult = (
  116. trEmpty, // test didn't call any assert or didn't report error.
  117. trOK, // Test ran OK
  118. trSuiteInactive, // Suite was inactive (only on suite records)
  119. trSuiteSetupFailed, // Suite setup failed (only on suite records)
  120. trSuiteTearDownFailed, // Suite setup failed (only on suite records)
  121. trTestInactive, // test was inactive
  122. trTestIgnore, // test was ignored
  123. trAssertFailed, // An assertion failed.
  124. trTestError, // An error happened during the test (exception)
  125. trHandlerError // An error occurred during the global test hooks (exception)
  126. );
  127. {
  128. Results are stored in a tree. At each level if the
  129. }
  130. PResultRecord = ^TResultRecord;
  131. TResultRecord = record
  132. Suite : PSuite; // Testsuite from which this is a result. If the global run handlers have an error, a result record is created with Suite=Nil.
  133. Test : PTest; // Test from which this is the result. If this is nil, then the result is the global testsuite result.
  134. ElapsedTime : Integer; // time spent in test, in milliseconds. Only calculated if time hook is set
  135. TestResult : TTestResult; // Result.
  136. TestMessage : TTestString; // Error message, if any. If an exception is expected, then the message is set PRIOR to the error.
  137. ExpectException : TClass; // Exception to expect.
  138. ParentResult, // Parent result (suite result)
  139. ChildResults, // Child result (tests or suites)
  140. NextResult : PResultRecord; // Next result at this level.
  141. end;
  142. // Statistics about a suite test run.
  143. TSuiteStats = Record
  144. Suites, // Number of sub suites (recursively)
  145. TestsFailed, // Number of failed tests.
  146. TestsInactive, // Number of inactive tests.
  147. TestsIgnored, // Number of ignored tests.
  148. TestsRun, // Number of run tests.
  149. TestsError, // Number of tests with an error.
  150. TestsUnimplemented : Integer; // Number of unimplemented tests (no result or no Assert calls)
  151. end;
  152. TRunSummary = Record
  153. SuitesRun: Integer; // Number of suites that were run.
  154. SuitesFailed : Integer; // Number of suites that failed in setup/teardown).
  155. SuitesInactive : Integer; // Number of inactive suites in the test run
  156. TestsRun : Integer; // Number of tests that were run.
  157. TestsFailed : Integer; // Number of tests that failed.
  158. TestsIgnored : Integer; // Number of tests that were ignored.
  159. TestsUnimplemented : Integer; // Number of unimplemented tests.
  160. TestsInactive : Integer; // Number of inactive tests.
  161. AssertCount : Integer; // Number of times assert was called.
  162. Results : TResultRecord; // Detailed results for all tests/suites
  163. ElapsedTime : Integer; // time spent in test run, in milliseconds; Only calculated if time hook is set
  164. end;
  165. PRunSummary = ^TRunSummary;
  166. { EFail }
  167. // This exception can be raised to exit from a test. When caught, it will mark the test as failed, and copy the message to the testresult.
  168. EFail = Class(TObject)
  169. Private
  170. FMessage : TTestString;
  171. Public
  172. Constructor Create(Const AMessage : TTestString);
  173. Function ToString : RTLString; override;
  174. end;
  175. // This exception can be raised to exit from a test. When caught, it will mark the test as ignored, and copy the message to the testresult.
  176. EIgnore = Class(EFail);
  177. { ---------------------------------------------------------------------
  178. Test Registry management
  179. ---------------------------------------------------------------------}
  180. // Initialize the testregistry. The registry is implicitly initialized by the management functions
  181. Function SetupTestRegistry : TTestError;
  182. // Clean up the testregistry. The registry is implicitly cleaned up on program exit.
  183. Function TearDownTestRegistry : TTestError;
  184. // Check if the testregistry was initialized.
  185. Function TestRegistryOK : Boolean;
  186. // Suite management
  187. // Add a suite with name AName (Required, duplicates forbidden) and Setup/TearDown functions. Returns the new suite or nil on error.
  188. Function AddSuite(Const AName : TTestString; ASetup : TTestSetup = nil; ATearDown : TTestTearDown = Nil; AParent : PSuite = nil; aPerTestSetupTearDown : Boolean = false) : PSuite;
  189. Function AddSuite(Const AName : TTestString; AParent : PSuite) : PSuite;
  190. // Number of currently registered suites. If Recurse is false, only top-level suites are counted.
  191. Function GetSuiteCount(Recurse : Boolean = True) : Integer;
  192. // Number of currently registered nested suites. If Recurse is false, only directly nested suites are counted.
  193. Function GetSuiteCount(ASuite : PSuite; Recurse : Boolean = True) : Integer;
  194. // Return the 0-based index of the suite names AName (case sensitive). -1 if not found.
  195. Function GetSuiteIndex(Const AName : TTestString) : Integer;
  196. // Return the 0-based index of the nested suite names AName (case sensitive). -1 if not found.
  197. Function GetSuiteIndex(ASuite : PSuite; Const AName : TTestString) : Integer;
  198. // Return the suite at position AIndex. Nil on error.
  199. Function GetSuite(Const AIndex : Integer) : PSuite;overload;
  200. // Return the suite named AName, starting at AParent. Nil if it is not found. Suite can be named Suite1.Sub2.Sub3
  201. Function GetSuite(Const AName : TTestString; AParent : PSuite = Nil) : PSuite;overload;
  202. // Test management
  203. // Register a test with name ATestName in suite ASuiteName. The test function is ARun.
  204. // If Suitename is empty, DefaultSuiteName is used, and registered if it does not exist yet.
  205. // Returns the newly created test.
  206. // It is allowed to register the same function with different names
  207. Function AddTest(Const ATestName : TTestString; ARun : TTestRun; Const ASuiteName : TTestString = '') : PTest;
  208. Function AddTest(Const ATestName : TTestString; ARun : TTestRunProc; Const ASuiteName : TTestString = '') : PTest;
  209. // Same as above, only the suite is explitly given. It may not be nil.
  210. Function AddTest(Const ATestName : TTestString; ARUn : TTestRun; Const ASuite : PSuite) : PTest;
  211. Function AddTest(Const ATestName : TTestString; ARUn : TTestRunProc; Const ASuite : PSuite) : PTest;
  212. // Return the 0-Based index of ATestName in suite ASuitename. Returns -1 on error or if nor found.
  213. Function GetTestIndex(Const ASuiteName : TTestString; Const ATestName : TTestString) : Integer;
  214. // Return the 0-Based index of ATestName in suite ASuit. Returns -1 on error or if nor found.
  215. Function GetTestIndex(Const ASuite : PSuite; Const ATestName : TTestString) : Integer;
  216. // Return 0-Based index of ATest in ASuite. Returns -1 if not found or on error.
  217. Function GetTestIndex(Const ASuite : PSuite; Const ATest : PTest) : Integer;
  218. // Return the number of tests in testsuite. On Error -1 is returned.
  219. Function GetTestCount(Const ASuiteName : TTestString) : Integer;
  220. // Return the number of tests in testsuite. On Error -1 is returned.
  221. Function GetTestCount(Const ASuite : PSuite) : Integer;
  222. // Return the test named ATestName in ASuiteName. Returns Nil if not found.
  223. Function GetTest(Const ASuiteName : TTestString; Const ATestName : TTestString) : PTest;
  224. // Return the test named ATestName in ASuite. Returns Nil if not found.
  225. Function GetTest(Const ASuite : PSuite; Const ATestName : TTestString) : PTest;
  226. // Return the test with index ATestindex in ASuite. Returns Nil if not found.
  227. Function GetTest(Const ASuite : PSuite; Const ATestIndex : Integer) : PTest;
  228. // Return True if ATest is part of ASuite. False otherwise or on error.
  229. Function TestIsInSuite(Const ASuite : PSuite; Const ATest : PTest) : Boolean;
  230. { ---------------------------------------------------------------------
  231. Running tests
  232. ---------------------------------------------------------------------}
  233. // The following are always complete test runs.
  234. // Results from previous runs are cleared when one of these functions is called.
  235. // Run all tests. Returns teOK if all tests were run without problems (failure is not a problem)
  236. Function RunAllTests : TTestError;
  237. // Run suite AName from the testsuite. Results can be viewed in GetCurrentRun.
  238. Function RunSuite(Const ASuiteName : TTestString) : TTestError;
  239. // Run suite ASuiteIndex in the testsuite. Results can be viewed in GetCurrentRun.
  240. Function RunSuite(ASuiteIndex : Integer) : TTestError;
  241. // Run suite ASuite (need not be registeredà. Results can be viewed in GetCurrentRun.
  242. Function RunSuite(ASuite : PSuite) : TTestError;
  243. // Running a test
  244. // Run test ATestName from Suite ASuiteName in the testsuite. Results can be viewed in GetCurrentRun.
  245. Function RunTest(Const ASuiteName : TTestString; Const ATestName: TTestString) : TTestError;
  246. // Run test ATestName from Suite ASuite. ASuite need not be registered. Results can be viewed in GetCurrentRun.
  247. Function RunTest(ASuite : PSuite; Const ATestName : TTestString) : TTestError;
  248. // Run test ATest from Suite ASuite. ASuite need not be registered. Results can be viewed in GetCurrentRun.
  249. Function RunTest(ASuite : PSuite; ATest : PTest) : TTestError;
  250. // Special function: will register a default test and runs all tests.
  251. // Intended for fast test suite creation and execution.
  252. // It will halt the program with the exit codes of RunAllSysTests
  253. // Additionally, an exit code of 2 may result if there was no test
  254. // Doing this will disable -t and -s command-line options..
  255. Procedure RunTest(ARun : TTestRun);
  256. // Get run summary of the current test run. Remains available after run is finished, before a new run is started.
  257. Function GetCurrentRun : TRunSummary;
  258. // Get currently running suite, may be nil.
  259. Function GetCurrentSuite : PSuite;
  260. // Get currently running test, may be nil.
  261. Function GetCurrentTest : PTest;
  262. // Get currently test result record, may be nil.
  263. Function GetCurrentResult : PResultRecord;
  264. // Get result stats for a suite result record.
  265. Procedure GetSuiteStats(AResults : PResultRecord; Out Stats : TSuiteStats);
  266. { ---------------------------------------------------------------------
  267. Test Result management
  268. ---------------------------------------------------------------------}
  269. Function CountResults(Results : PResultRecord) : Integer;
  270. { ---------------------------------------------------------------------
  271. Assertions
  272. ---------------------------------------------------------------------}
  273. // Mark test as ignored with given message. Always returns false.
  274. Function Ignore(Const Msg : TTestString) : Boolean;
  275. // Mark test as failed with given message.
  276. Function Fail(Const Msg : TTestString) : Boolean;
  277. // Mark test as failed with given message, raising EFail.
  278. // will not return, but for symmetry has the same call signature
  279. Function FailExit(Const Msg : TTestString) : Boolean;
  280. // Mark test as ignored with given message, raising EIgnore.
  281. // will not return, but for symmetry has the same call signature
  282. Function IgnoreExit(Const Msg : TTestString) : Boolean;
  283. // If RequirePassed = True, then this must be called to mark a test as passed.
  284. // Otherwise it is marked 'unimplemented' if assert was never called during execution of the test.
  285. Function AssertPassed (AMessage : TTestString=''): Boolean;
  286. // Mark test as passed if ACondition = true, failed if False. Returns ACondition
  287. Function AssertTrue(const AMessage : TTestString; ACondition : Boolean): Boolean;
  288. // Mark test as passed if ACondition = false, failed if true. Returns Not ACondition
  289. Function AssertFalse(const AMessage : TTestString; ACondition : Boolean): Boolean;
  290. // Check if 2 strings are equal. Mark test as failed if not.
  291. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : ShortString): Boolean;
  292. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : AnsiString): Boolean;
  293. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : UTF8String): Boolean;
  294. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : UnicodeString): Boolean;
  295. Function AssertEquals(AMessage : TTestString; const AExpected: Char; AActual : UnicodeString): Boolean;
  296. // Check if 2 ordinals are equal. Mark test as failed if not.
  297. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Boolean): Boolean;
  298. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Shortint): Boolean;
  299. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Byte): Boolean;
  300. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Smallint): Boolean;
  301. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Word): Boolean;
  302. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Longint): Boolean;
  303. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Cardinal): Boolean;
  304. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Int64): Boolean;
  305. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : QWord): Boolean;
  306. // Floating point types
  307. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Currency): Boolean;
  308. Function AssertEquals(AMessage : TTestString; const AExpected, AActual: Double; ADelta : Double = 0): Boolean;
  309. Function AssertEquals(AMessage : TTestString; const AExpected, AActual: Single; ADelta : Single = 0): Boolean;
  310. Function AssertEquals(AMessage : TTestString; const AExpected, AActual: Extended; ADelta : Extended = 0): Boolean;
  311. // Assert null
  312. Function AssertNull(AMessage : TTestString; const AValue : Pointer): Boolean;
  313. Function AssertNotNull(AMessage : TTestString; const AValue : Pointer): Boolean;
  314. // Check if 2 pointers are equal. Mark test as failed if not.
  315. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : Pointer): Boolean;
  316. Function AssertDiffers(AMessage : TTestString; const AExpected, AActual : Pointer): Boolean;
  317. // Check if 2 class types are equal. Mark test as failed if not.
  318. Function AssertEquals(AMessage : TTestString; const AExpected, AActual : TClass): Boolean;
  319. // Check if 2 class types are equal. Mark test as failed if not.
  320. Function AssertInheritsFrom(AMessage : TTestString; const AChild, AParent : TObject): Boolean;
  321. Function AssertInheritsFrom(AMessage : TTestString; const AChild, AParent : TClass): Boolean;
  322. // Check if 2 object instances are equal. Mark test as failed if not.
  323. Function AssertSame(AMessage : TTestString; const AExpected, AActual : TObject): Boolean;
  324. // Check if 2 object instances are different. Mark test as failed if they are equal.
  325. Function AssertNotSame(AMessage : TTestString; const AExpected, AActual : TObject): Boolean;
  326. // Run procedure ARun. Expect an exception. If none is raised, or the class differs, mark the test as failed.
  327. Function AssertException(const AMessage: string; AExceptionClass: TClass; ARun: TProcedure) : boolean;
  328. Function AssertException(const AMessage: string; AExceptionClass: TClass; ARun: TTestRun) : boolean;
  329. // Tell the testsuite that the test will raise an exception of class ACLass.
  330. // If the test does not raise an exception, or the exception class differs, the test is marked as failed.
  331. Function ExpectException(AMessage : TTestString; AClass : TClass) : Boolean;
  332. { ---------------------------------------------------------------------
  333. Test Hooks (Decorators)
  334. ---------------------------------------------------------------------}
  335. Type
  336. // All arguments must be considered read-only.
  337. // Test Run hooks.
  338. // Handler called at the start of a testrun. Suites is an array of suites that will be run.
  339. TRunStartHandler = Procedure(Const Suites : TSuiteArray);
  340. // Handler called at the completion of a testrun. ARunResult is the run summary.
  341. TRunCompleteHandler = Procedure(Const ARunResult : TRunSummary);
  342. // Test suite hooks.
  343. // Handler called at the start of a suite, before suite setup. ASuite is the result.
  344. TSuiteStartHandler = Procedure(ASuite : PSuite);
  345. // Handler called at the end of a suite, after suite teardown. SuiteResults is an array of test results. The first record is a global suite result.
  346. TSuiteCompleteHandler = Procedure(ASuite : PSuite; Const SuiteResults : PResultRecord);
  347. // Handler called if the suite setup function failed (non-empty string returned or exception)
  348. TSuiteSetupFailureHandler = Procedure(ASuite : PSuite; Const AError : TTestString);
  349. // Handler called if the suite teardown function failed.(non-empty string returned or exception)
  350. TSuiteTearDownFailureHandler = Procedure(ASuite : PSuite; Const AError : TTestString);
  351. // Test hooks.
  352. // Handler called at the start of a test run.
  353. TTestStartHandler = Procedure(ATest : PTest; ASuite : PSuite);
  354. // Handler called at the end of a test run (regardless of pass/fail);
  355. TTestCompleteHandler = Procedure(ATest: PTest; ASuite : PSuite; Const TestResult : PResultRecord);
  356. // Other hooks
  357. // The sysutils or dos unit are not available to get the time. Support for getting time
  358. // can be enabled by including a function with the correct signature. For example:
  359. // using sysutils: SetTimeHook(@SysUtils.Now);
  360. TTimeHook = Function : TDateTime;
  361. // These functions set the various hooks. The old value is returned, so hooks can be chained.
  362. Function SetRunStartHandler(AHandler : TRunStartHandler) : TRunStartHandler;
  363. Function SetRunCompleteHandler(AHandler : TRunCompleteHandler) : TRunCompleteHandler;
  364. Function SetSuiteStartHandler(AHandler : TSuiteStartHandler) : TSuiteStartHandler;
  365. Function SetSuiteCompleteHandler(AHandler : TSuiteCompleteHandler) : TSuiteCompleteHandler;
  366. Function SetSuitesetupFailureHandler(AHandler : TSuitesetupFailureHandler) : TSuitesetupFailureHandler;
  367. Function SetSuiteTearDownFailureHandler(AHandler : TSuiteTearDownFailureHandler) : TSuiteTearDownFailureHandler;
  368. Function SetTestStartHandler(AHandler : TTestStartHandler) : TTestStartHandler;
  369. Function SetTestCompleteHandler(AHandler : TTestCompleteHandler) : TTestCompleteHandler;
  370. // These functions get the current value of the various hooks.
  371. Function GetSuiteStartHandler : TSuiteStartHandler;
  372. Function GetTestStartHandler : TTestStartHandler;
  373. Function GetTestCompleteHandler : TTestCompleteHandler;
  374. Function GetSuiteCompleteHandler : TSuiteCompleteHandler;
  375. Function GetRunStartHandler : TRunStartHandler;
  376. Function GetRunCompleteHandler : TRunCompleteHandler;
  377. Function GetSuitesetupFailureHandler : TSuitesetupFailureHandler;
  378. Function GetSuiteTearDownFailureHandler : TSuiteTearDownFailureHandler;
  379. // Clear all handlers
  380. Procedure ClearTestHooks;
  381. // Time hook management:
  382. Function GetTimeHook : TTimeHook;
  383. Function SetTimeHook(AHook : TTimeHook) : TTimeHook;
  384. // Is the time hook set ?
  385. Function HaveTimeHook : Boolean; inline;
  386. // Current time as returned by hook, or 0 if hook not set.
  387. Function GetTimeFromHook : TDateTime;
  388. // Timespan in milliseconds between Current time as returned by hook and From. 0 if hook not set.
  389. Function GetTimeDiff(From : TDateTime) : Integer;
  390. // Convert timespan in milliseconds to human readable string hh:nn:ss.ZZZ (z milliseconds)
  391. Function SysTimeString(MSec : Integer) : TTestString;
  392. { ---------------------------------------------------------------------
  393. Errors
  394. ---------------------------------------------------------------------}
  395. // Get the current error status.
  396. Function GetTestError : TTestError;
  397. // Get a message corresponding to the error.
  398. Function GetTestErrorMessage : TTestString;
  399. // Set test error. If the current is not teOK, it cannot be overwritten except by teOK.
  400. Function SetTestError(AError : TTestError) : TTestError;
  401. // What to do if a non-teOK value is set ?
  402. Function GetErrorAction : TErrorAction;
  403. // Set the error action, returns the old value.
  404. Function SetErrorAction(AError : TErrorAction) : TErrorAction;
  405. // System hooks
  406. Type
  407. // Verbosity of system hooks
  408. TSysRunVerbosity = (
  409. rvQuiet, // No messages at all
  410. rvFailures, // only output failures
  411. rvNormal, // normal messages
  412. rvVerbose // Lots of messages
  413. );
  414. // Setup system hooks. Called by unit initialization.
  415. Procedure SetupSysHandlers;
  416. // Teardown system hooks. Called by unit finalization.
  417. Procedure TearDownSysHandlers;
  418. // Get current run mode.
  419. Function GetSysRunVerbosity: TSysRunVerbosity;
  420. /// Set currentsystem run mode
  421. Function SetSysRunVerbosity(AMode : TSysRunVerbosity) : TSysRunVerbosity;
  422. // Set system hook variables based on commandline.
  423. // -v --verbose: verbose messaging
  424. // -f --failures: only output failures
  425. // -q --quiet: no messaging
  426. // -n --normal: no messaging
  427. // -o --output=Name: write to named file.
  428. // -s --suite=Suite: name of suite to run
  429. // -t --test=name of test to run. If no suite is specified, DefaultSuiteName is assumed.
  430. // -l --list simply list all tests.
  431. // -h --help show help
  432. Procedure ProcessSysCommandline;
  433. // Process command line, run tests based on variables set.
  434. // Program exit codes:
  435. // 0 : All tests completed succesfully
  436. // 1 : tests completed with failures.
  437. // 3 : Suite not found (-s --suite)
  438. // 4 : Testsuite didn't run correct.
  439. // 6 : Test not found (-t --test)
  440. Procedure RunAllSysTests;
  441. // Return the OS for which the system was compiled, as a lowercase string.
  442. // This can help when registering tests.
  443. Function GetSysTestOS : TTestString;
  444. // Get test setting. The settings file is by default a file called punit.cfg
  445. // Format is Name = Value. Comment lines start with ; or #
  446. Function SysGetSetting(Const AName : TTestString) : TTestString;
  447. implementation
  448. Const
  449. SExpected = 'Expected';
  450. SActual = 'Actual';
  451. SErrNoTestProcedure = 'No test procedure';
  452. // SIsNotNil = 'Is not nil';
  453. // SIsNil = 'Is nil';
  454. Var
  455. CurrentError : TTestError;
  456. CurrentErrorAction : TErrorAction;
  457. CurrentTimeHook : TTimeHook;
  458. TestRegistry : TSuiteList;
  459. GlobalSuiteStartHandler : TSuiteStartHandler;
  460. GlobalTestStartHandler : TTestStartHandler;
  461. GlobalTestCompleteHandler : TTestCompleteHandler;
  462. GlobalSuiteCompleteHandler : TSuiteCompleteHandler;
  463. GlobalRunStartHandler : TRunStartHandler;
  464. GlobalRunCompleteHandler : TRunCompleteHandler;
  465. GlobalSuitesetupFailureHandler : TSuitesetupFailureHandler;
  466. GlobalSuiteTearDownFailureHandler : TSuiteTearDownFailureHandler;
  467. CurrentSuite : PSuite;
  468. CurrentTest : PTest;
  469. CurrentRun : TRunSummary;
  470. CurrentSuiteResult,
  471. CurrentResult : PResultRecord;
  472. { ---------------------------------------------------------------------
  473. Handler management
  474. ---------------------------------------------------------------------}
  475. function GetTimeHook: TTimeHook;
  476. begin
  477. Result:=CurrentTimeHook;
  478. end;
  479. function SetTimeHook(AHook: TTimeHook): TTimeHook;
  480. begin
  481. Result:=CurrentTimeHook;
  482. CurrentTimeHook:=AHook;
  483. end;
  484. function HaveTimeHook: Boolean;
  485. begin
  486. Result:=Assigned(CurrentTimeHook);
  487. end;
  488. function GetTimeFromHook: TDateTime;
  489. begin
  490. if HaveTimeHook then
  491. Result:=CurrentTimeHook()
  492. else
  493. Result:=0;
  494. end;
  495. function GetTimeDiff(From: TDateTime): Integer;
  496. const // Copied from sysutils;
  497. HoursPerDay = 24;
  498. MinsPerHour = 60;
  499. SecsPerMin = 60;
  500. MSecsPerSec = 1000;
  501. MinsPerDay = HoursPerDay * MinsPerHour;
  502. SecsPerDay = MinsPerDay * SecsPerMin;
  503. MSecsPerDay = SecsPerDay * MSecsPerSec;
  504. Var
  505. T : TDateTime;
  506. begin
  507. T:=GetTimeFromHook;
  508. if (T=0) or (From=0) then
  509. Result:=0
  510. else
  511. Result:=Round((T-From)*MSecsPerDay);
  512. end;
  513. function SetSuiteStartHandler(AHandler: TSuiteStartHandler): TSuiteStartHandler;
  514. begin
  515. Result:=GlobalSuiteStartHandler;
  516. GlobalSuiteStartHandler:=AHandler;
  517. end;
  518. function SetTestStartHandler(AHandler: TTestStartHandler): TTestStartHandler;
  519. begin
  520. Result:=GlobalTestStartHandler;
  521. GlobalTestStartHandler:=AHandler;
  522. end;
  523. function SetTestCompleteHandler(AHandler: TTestCompleteHandler
  524. ): TTestCompleteHandler;
  525. begin
  526. Result:=GlobalTestCompleteHandler;
  527. GlobalTestCompleteHandler:=AHandler;
  528. end;
  529. function SetSuiteCompleteHandler(AHandler: TSuiteCompleteHandler
  530. ): TSuiteCompleteHandler;
  531. begin
  532. Result:=GlobalSuiteCompleteHandler;
  533. GlobalSuiteCompleteHandler:=AHandler;
  534. end;
  535. function SetRunCompleteHandler(AHandler: TRunCompleteHandler
  536. ): TRunCompleteHandler;
  537. begin
  538. Result:=GlobalRunCompleteHandler;
  539. GlobalRunCompleteHandler:=AHandler;
  540. end;
  541. function SetRunStartHandler(AHandler: TRunStartHandler): TRunStartHandler;
  542. begin
  543. Result:=GlobalRunStartHandler;
  544. GlobalRunStartHandler:=AHandler;
  545. end;
  546. function SetSuitesetupFailureHandler(AHandler: TSuitesetupFailureHandler
  547. ): TSuitesetupFailureHandler;
  548. begin
  549. Result:=GlobalSuitesetupFailureHandler;
  550. GlobalSuitesetupFailureHandler:=AHandler;
  551. end;
  552. function SetSuiteTearDownFailureHandler(AHandler: TSuiteTearDownFailureHandler
  553. ): TSuiteTearDownFailureHandler;
  554. begin
  555. Result:=GlobalSuiteTearDownFailureHandler;
  556. GlobalSuiteTearDownFailureHandler:=AHandler;
  557. end;
  558. function GetSuiteStartHandler: TSuiteStartHandler;
  559. begin
  560. Result:=GlobalSuiteStartHandler;
  561. end;
  562. function GetTestStartHandler: TTestStartHandler;
  563. begin
  564. Result:=GlobalTestStartHandler;
  565. end;
  566. function GetTestCompleteHandler: TTestCompleteHandler;
  567. begin
  568. Result:=GlobalTestCompleteHandler;
  569. end;
  570. function GetSuiteCompleteHandler: TSuiteCompleteHandler;
  571. begin
  572. Result:=GlobalSuiteCompleteHandler;
  573. end;
  574. function GetRunStartHandler: TRunStartHandler;
  575. begin
  576. Result:=GlobalRunStartHandler;
  577. end;
  578. function GetRunCompleteHandler: TRunCompleteHandler;
  579. begin
  580. Result:=GlobalRunCompleteHandler;
  581. end;
  582. function GetSuitesetupFailureHandler: TSuitesetupFailureHandler;
  583. begin
  584. Result:=GlobalSuiteSetupFailureHandler;
  585. end;
  586. function GetSuiteTearDownFailureHandler: TSuiteTearDownFailureHandler;
  587. begin
  588. Result:=GlobalSuiteTearDownFailureHandler;
  589. end;
  590. procedure ClearTestHooks;
  591. begin
  592. SetSuiteStartHandler(Nil);
  593. SetTestStartHandler(Nil);
  594. SetTestCompleteHandler(Nil);
  595. SetSuiteCompleteHandler(Nil);
  596. SetRunStartHandler(Nil);
  597. SetRunCompleteHandler(Nil);
  598. SetSuiteSetupFailureHandler(Nil);
  599. SetSuiteTearDownFailureHandler(Nil);
  600. end;
  601. { ---------------------------------------------------------------------
  602. Error management
  603. ---------------------------------------------------------------------}
  604. Const
  605. SErrUnknown = 'Unknown error';
  606. SErrOK = 'OK';
  607. SErrTestsRunning = 'Tests already running';
  608. SErrRegistryEmpty = 'Testregistry emmpty';
  609. SErrNoMemory = 'No memory available';
  610. SErrNoSuite = 'No suite available';
  611. SErrNoSuiteName = 'No suite name specified';
  612. SErrSuiteSetupFailed = 'Suite setup failed';
  613. SerrSuiteTeardownFailed = 'Suite teardown failed';
  614. SErrDuplicateSuite = 'Duplicate suite name';
  615. SErrSuiteInactive = 'Attempt to run inactive suite';
  616. SErrNoTest = 'No test specified';
  617. SErrNoTestName = 'No test name specified';
  618. SErrDuplicateTest = 'Duplicate test name specified';
  619. SErrTestNotInSuite = 'Test not member of suite';
  620. SErrTestInactive = 'Attempt to run inactive test';
  621. function GetTestError: TTestError;
  622. begin
  623. Result:=CurrentError;
  624. end;
  625. function GetTestErrorMessage: TTestString;
  626. begin
  627. Case GetTestError of
  628. teOK: Result:=SErrOK;
  629. teTestsRunning: Result:=SErrTestsRunning;
  630. teRegistryEmpty: Result:=SErrRegistryEmpty;
  631. teNoMemory: Result:=SErrNoMemory;
  632. teNoSuite: Result:=SErrNoSuite;
  633. teNoSuiteName: Result:=SErrNoSuiteName;
  634. teSuiteSetupFailed: Result:=SErrSuiteSetupFailed;
  635. teSuiteTeardownFailed: Result:=SErrSuiteTeardownFailed;
  636. teDuplicateSuite: Result:=SErrDuplicateSuite;
  637. teSuiteInactive: Result:=SErrSuiteInactive;
  638. teNoTest: Result:=SErrNoTest;
  639. teNoTestName: Result:=SErrNoTestName;
  640. teDuplicateTest: Result:=SErrDuplicateTest;
  641. teTestNotInSuite: Result:=SErrTestNotInSuite;
  642. teTestInactive: Result:=SErrTestInactive;
  643. else
  644. Result:=SErrUnknown;
  645. end;
  646. end;
  647. function SetTestError(AError: TTestError): TTestError;
  648. begin
  649. // Forces us to reset the error at all points
  650. if (AError=teOK) or (CurrentError=teOK) then
  651. CurrentError:=AError;
  652. Result:=CurrentError;
  653. If (AError<>teOK) and (CurrentErrorAction=eaAbort) then
  654. Halt(1);
  655. end;
  656. Function CombineError(Original, Additional : TTestError) : TTestError;
  657. begin
  658. if (teOK=Original) then
  659. Result:=Additional
  660. else
  661. Result:=Original;
  662. end;
  663. function GetErrorAction: TErrorAction;
  664. begin
  665. Result:=CurrentErrorAction;
  666. end;
  667. function SetErrorAction(AError: TErrorAction): TErrorAction;
  668. begin
  669. Result:=CurrentErrorAction;
  670. CurrentErrorAction:=AError;
  671. end;
  672. { ---------------------------------------------------------------------
  673. List management.
  674. ---------------------------------------------------------------------}
  675. Procedure CheckGrowSuiteList(AList : PSuiteList);
  676. Var
  677. L : Integer;
  678. begin
  679. L:=Length(AList^.Items);
  680. if (AList^.Count=L) then
  681. begin
  682. if (L=0) then
  683. L:=InitListLength
  684. else
  685. L:=Round(L*3/2);
  686. SetLength(AList^.Items,L);
  687. end;
  688. end;
  689. Procedure DoneSuiteList(Var Suites : TSuiteList); forward;
  690. Function DoneSuite(ASuite : PSuite) : TTestError;
  691. Var
  692. I : Integer;
  693. begin
  694. SetTestError(teOK);
  695. With ASuite^ do
  696. begin
  697. DoneSuiteList(Suites);
  698. For I:=0 to Tests.Count-1 do
  699. Dispose(Tests.Items[i]);
  700. SetLength(Tests.Items,0);
  701. Tests.Count:=0;
  702. end;
  703. Dispose(ASuite);
  704. Result:=GetTestError;
  705. end;
  706. Procedure DoneSuiteList(Var Suites : TSuiteList);
  707. Var
  708. I : Integer;
  709. begin
  710. For I:=0 to Suites.Count-1 do
  711. DoneSuite(Suites.Items[i]);
  712. SetLength(Suites.Items,0);
  713. Suites.Count:=0;
  714. end;
  715. Procedure CheckGrowTests(Var AList : TTestList);
  716. Var
  717. L : Integer;
  718. begin
  719. L:=Length(AList.Items);
  720. if (L=AList.Count) then
  721. begin
  722. if L=0 then
  723. L:=InitListLength
  724. else
  725. L:=Round(L*GrowFactor);
  726. SetLength(AList.Items,L);
  727. end;
  728. end;
  729. { ---------------------------------------------------------------------
  730. Testsuite Registry management
  731. ---------------------------------------------------------------------}
  732. function TestRegistryOK: Boolean;
  733. begin
  734. Result:=Length(TestRegistry.Items)<>0;
  735. end;
  736. Procedure InitSuiteList(Var Suites: TSuiteList);
  737. begin
  738. Suites.Count:=0;
  739. CheckGrowSuiteList(@Suites);
  740. end;
  741. Procedure DoSetupTestRegistry;
  742. begin
  743. if TestRegistry.Count<>0 then exit;
  744. InitSuiteList(TestRegistry);
  745. end;
  746. function SetupTestRegistry: TTestError;
  747. begin
  748. Result:=SetTestError(teOK);
  749. Result:=TearDownTestRegistry;
  750. if Result=teOK then
  751. DoSetupTestRegistry;
  752. end;
  753. function TearDownTestRegistry: TTestError;
  754. begin
  755. SetTestError(teOK);
  756. DoneSuiteList(TestRegistry);
  757. Result:=GetTestError;
  758. end;
  759. { ---------------------------------------------------------------------
  760. Suite management
  761. ---------------------------------------------------------------------}
  762. Function CheckInactive : Boolean;
  763. begin
  764. Result:=(CurrentSuite=Nil);
  765. If Not Result then
  766. SetTestError(teTestsRunning);
  767. end;
  768. function AddSuite(const AName: TTestString; AParent: PSuite): PSuite;
  769. begin
  770. Result:=AddSuite(AName,Nil,Nil,AParent);
  771. end;
  772. function GetSuiteCount(ASuite: PSuiteList; Recurse: Boolean): Integer;
  773. Var
  774. I : Integer;
  775. begin
  776. Result:=ASuite^.Count;
  777. if Recurse then
  778. For I:=0 to ASuite^.Count-1 do
  779. Result:=Result+GetSuiteCount(ASuite^.Items[i],True);
  780. end;
  781. function GetSuiteCount(Recurse: Boolean): Integer;
  782. begin
  783. Result:=GetSuiteCount(PsuiteList(@TestRegistry),Recurse);
  784. end;
  785. Function GetSuiteCount(ASuite : PSuite; Recurse : Boolean = True) : Integer;
  786. begin
  787. if (ASuite=Nil) then
  788. Result:=0
  789. else
  790. Result:=GetSuiteCount(PSuiteList(@ASuite^.Suites),Recurse);
  791. end;
  792. Function GetSuiteIndex(Const AList : PSuiteList; Const AName: TTestString): Integer;
  793. begin
  794. Result:=-1;
  795. if (AList=Nil) then
  796. begin
  797. SetTestError(teNoSuite);
  798. Exit;
  799. end;
  800. SetTestError(teOK);
  801. Result:=AList^.Count-1;
  802. While (Result>=0) and (AList^.Items[Result]^.Name<>AName) do
  803. Dec(Result);
  804. end;
  805. function GetSuiteIndex(ASuite : PSuite; const AName: TTestString): Integer;
  806. begin
  807. if ASuite=Nil then
  808. Result:=0
  809. else
  810. Result:=GetSuiteIndex(PSuiteList(@ASuite^.Suites),AName);
  811. end;
  812. function GetSuiteIndex(const AName: TTestString): Integer;
  813. begin
  814. Result:=GetSuiteIndex(PSuiteList(@TestRegistry),AName);
  815. end;
  816. Function GetSuite(const AList : PSuiteList; Const AIndex: Integer): PSuite;
  817. begin
  818. If (AIndex>=0) And (AIndex<AList^.Count) then
  819. Result:=Alist^.Items[AIndex]
  820. else
  821. Result:=Nil;
  822. end;
  823. Function GetSuite(AList : PSuiteList; Const AName : TTestString) : PSuite;
  824. Var
  825. I,P : Integer;
  826. N : TTestString;
  827. L : PSuiteList;
  828. begin
  829. if AList=Nil then
  830. Result:=Nil
  831. else
  832. begin
  833. N:=AName;
  834. L:=AList;
  835. P:=0;
  836. For I:=1 to Length(N) do
  837. if N[i]='.' then
  838. P:=I;
  839. if (P>0) then
  840. begin
  841. Result:=GetSuite(L,Copy(N,1,P-1));
  842. if (Result<>Nil) then
  843. L:=@Result^.Suites
  844. else
  845. L:=Nil;
  846. Delete(N,1,P);
  847. end;
  848. I:=GetSuiteIndex(L,N);
  849. If I<0 then
  850. Result:=Nil
  851. else
  852. Result:=L^.Items[I];
  853. end;
  854. end;
  855. Function GetSuite(Const AName : TTestString; AParent : PSuite = Nil) : PSuite;
  856. Var
  857. L : PSuiteList;
  858. begin
  859. Result:=Nil;
  860. if (AParent<>Nil) then
  861. L:=@AParent^.Suites
  862. else
  863. L:=@TestRegistry;
  864. if L<>Nil then
  865. Result:=GetSuite(L,AName);
  866. end;
  867. function GetSuite(const AIndex: Integer): PSuite;
  868. begin
  869. Result:=GetSuite(@TestRegistry,AIndex);
  870. end;
  871. function AddSuite(const AName: TTestString; ASetup: TTestSetup;
  872. ATearDown: TTestTearDown; AParent: PSuite; aPerTestSetupTearDown : Boolean = false): PSuite;
  873. Var
  874. S : PSuite;
  875. L : PSuiteList;
  876. begin
  877. Result:=Nil;
  878. SetTestError(teOK);
  879. If not CheckInactive then
  880. exit;
  881. DoSetupTestRegistry;
  882. if AName='' then
  883. begin
  884. SetTestError(teNoSuiteName);
  885. Exit;
  886. end;
  887. S:=GetSuite(AName,AParent);
  888. if (S<>Nil) then
  889. begin
  890. SetTestError(teDuplicateSuite);
  891. Exit;
  892. end;
  893. if AParent<>Nil then
  894. L:=@AParent^.Suites
  895. else
  896. L:=@TestRegistry;
  897. CheckGrowSuiteList(L);
  898. New(Result);
  899. if (Result=Nil) then
  900. SetTestError(teNoMemory)
  901. else
  902. begin
  903. L^.Items[L^.Count]:=Result;
  904. FillChar(Result^,Sizeof(TSuite),0);
  905. Result^.Name:=AName;
  906. Result^.Setup:=ASetup;
  907. Result^.Teardown:=ATearDown;
  908. Result^.Options:=[];
  909. if aPerTestSetupTearDown then
  910. Include(Result^.Options,soSetupTearDownPerTest);
  911. Result^.Tests.Count:=0;
  912. Result^.ParentSuite:=AParent;
  913. CheckGrowTests(Result^.Tests);
  914. Inc(L^.Count);
  915. end;
  916. end;
  917. { ---------------------------------------------------------------------
  918. Test management
  919. ---------------------------------------------------------------------}
  920. function DoAddTest(const ATestName: TTestString; const ASuite: PSuite): PTest;
  921. Var
  922. I : Integer;
  923. List : PTestList;
  924. begin
  925. Result:=Nil;
  926. SetTestError(teOK);
  927. if not CheckInactive then
  928. Exit;
  929. if (ASuite=Nil) then
  930. SetTestError(teNoSuite)
  931. else If (ATestName='') then
  932. SetTestError(teNoTestName)
  933. else
  934. begin
  935. I:=GetTestIndex(ASuite,ATestName);
  936. if (I<>-1) then
  937. SetTestError(teDuplicateTest)
  938. else
  939. begin
  940. List:=@ASuite^.Tests;
  941. CheckGrowTests(List^);
  942. New(Result);
  943. if (Result=Nil) then
  944. SetTestError(teNoMemory)
  945. else
  946. begin
  947. FillChar(Result^,SizeOf(TTest),0);
  948. Result^.Name:=ATestName;
  949. Result^.Options:=[];
  950. List^.Items[List^.Count]:=Result;
  951. Inc(List^.Count);
  952. end;
  953. end;
  954. end;
  955. end;
  956. function AddTest(const ATestName: TTestString; ARun: TTestRun; const ASuite: PSuite): PTest;
  957. begin
  958. Result:=DoAddTest(aTestName,aSuite);
  959. if assigned(Result) then
  960. Result^.Run:=ARun;
  961. end;
  962. function AddTest(const ATestName: TTestString; ARun: TTestRunProc; const ASuite: PSuite): PTest;
  963. begin
  964. Result:=DoAddTest(aTestName,aSuite);
  965. if assigned(Result) then
  966. Result^.RunProc:=ARun;
  967. end;
  968. // Easy access function
  969. function EnsureSuite(aSuiteName : TTestString) : PSuite;
  970. var
  971. SN : TTestString;
  972. begin
  973. SetTestError(teOK);
  974. SN:=ASuiteName;
  975. if (SN='') then
  976. SN:=DefaultSuiteName;
  977. Result:=GetSuite(SN);
  978. if (Result=Nil) and (ASuiteName<>'') then
  979. SetTestError(teNoSuite)
  980. else
  981. begin
  982. If (Result=Nil) then
  983. Result:=AddSuite(SN,Nil,Nil);
  984. end;
  985. end;
  986. function AddTest(const ATestName: TTestString; ARun: TTestRun;
  987. const ASuiteName: TTestString): PTest;
  988. Var
  989. S : PSuite;
  990. begin
  991. Result:=Nil;
  992. S:=EnsureSuite(aSuiteName);
  993. If (S<>Nil) then
  994. Result:=AddTest(ATestName,ARun,S);
  995. end;
  996. Function AddTest(Const ATestName : TTestString; ARun : TTestRunProc; Const ASuiteName : TTestString = '') : PTest;
  997. Var
  998. S : PSuite;
  999. begin
  1000. Result:=Nil;
  1001. S:=EnsureSuite(aSuiteName);
  1002. If (S<>Nil) then
  1003. Result:=AddTest(ATestName,ARun,S);
  1004. end;
  1005. Function GetTestIndex(Const ASuiteIndex: Integer; Const ATestName: TTestString): Integer;
  1006. begin
  1007. Result:=GetTestIndex(GetSuite(ASuiteIndex),ATestName);
  1008. end;
  1009. function GetTestIndex(const ASuiteName: TTestString;
  1010. const ATestName: TTestString): Integer;
  1011. begin
  1012. Result:=GetTestIndex(GetSuite(ASuiteName),ATestName);
  1013. end;
  1014. function GetTestIndex(const ASuite: PSuite; const ATestName: TTestString
  1015. ): Integer;
  1016. Var
  1017. A : TTestArray;
  1018. begin
  1019. Result:=-1;
  1020. SetTestError(teOK);
  1021. if (ASuite=Nil) then
  1022. SetTestError(teNoSuite)
  1023. else
  1024. begin
  1025. Result:=ASuite^.Tests.Count-1;
  1026. A:=ASuite^.Tests.Items;
  1027. While (Result>=0) and (A[Result]^.Name<>ATestName) do
  1028. Dec(Result);
  1029. end;
  1030. end;
  1031. Function GetTest(Const ASuiteIndex: Integer; Const ATestName: TTestString
  1032. ): PTest;
  1033. begin
  1034. Result:=GetTest(GetSuite(ASuiteIndex),ATestName);
  1035. end;
  1036. function GetTestCount(const ASuiteName: TTestString): Integer;
  1037. begin
  1038. Result:=GetTestCount(GetSuite(ASuiteName));
  1039. end;
  1040. function GetTestCount(const ASuite: PSuite): Integer;
  1041. begin
  1042. SetTestError(teOK);
  1043. Result:=-1;
  1044. if (ASuite=Nil) then
  1045. SetTestError(teNoSuite)
  1046. else
  1047. Result:=ASuite^.Tests.Count;
  1048. end;
  1049. function GetTest(const ASuiteName: TTestString; const ATestName: TTestString
  1050. ): PTest;
  1051. begin
  1052. Result:=GetTest(GetSuite(ASuiteName),ATestName);
  1053. end;
  1054. function GetTest(const ASuite: PSuite; const ATestName: TTestString): PTest;
  1055. Var
  1056. I,P : Integer;
  1057. N : TTestString;
  1058. S : PSuite;
  1059. begin
  1060. N:=ATestName;
  1061. S:=ASuite;
  1062. P:=0;
  1063. For I:=1 to Length(N) do
  1064. if ATestName[I]='.' then
  1065. P:=i;
  1066. If (P>0) then
  1067. begin
  1068. S:=GetSuite(Copy(N,1,P-1),S);
  1069. Delete(N,1,P);
  1070. end;
  1071. if (S=Nil) then
  1072. begin
  1073. SetTestError(teNoSuite);
  1074. Exit;
  1075. end;
  1076. I:=GetTestIndex(S,N);
  1077. If (I=-1) then
  1078. Result:=Nil
  1079. else
  1080. Result:=S^.Tests.items[i];
  1081. end;
  1082. function GetTest(const ASuite: PSuite; const ATestIndex: Integer): PTest;
  1083. begin
  1084. SetTestError(teOK);
  1085. Result:=Nil;
  1086. if (ASuite=Nil) then
  1087. SetTestError(teNoSuite)
  1088. else If (ATestIndex>=0) and (ATestIndex<GetTestCount(ASuite)) then
  1089. Result:=ASuite^.Tests.Items[ATestindex]
  1090. end;
  1091. function GetTestIndex(const ASuite: PSuite; const ATest: PTest): Integer;
  1092. Var
  1093. T : TTestArray;
  1094. begin
  1095. SetTestError(teOK);
  1096. Result:=-1;
  1097. if (ASuite=Nil) then
  1098. SetTestError(teNoSuite)
  1099. else if (ATest=Nil) then
  1100. SetTestError(teNoTest)
  1101. else
  1102. begin
  1103. Result:=GetTestCount(ASuite)-1;
  1104. T:=ASuite^.Tests.Items;
  1105. While (Result>=0) and (ATest<>T[Result]) do
  1106. Dec(Result);
  1107. end;
  1108. end;
  1109. function TestIsInSuite(const ASuite: PSuite; const ATest: PTest): Boolean;
  1110. begin
  1111. Result:=GetTestIndex(ASuite,ATest)<>-1;
  1112. end;
  1113. { ---------------------------------------------------------------------
  1114. Test result management
  1115. ---------------------------------------------------------------------}
  1116. Procedure SetTestResult(Var AResult : TResultRecord; AResultType : TTestResult; AMessage : TTestString; Force : Boolean = False);
  1117. Var
  1118. Prev : TTestResult;
  1119. begin
  1120. if Not ((AResult.TestResult=trEmpty) or Force) then
  1121. Exit;
  1122. Prev:=AResult.TestResult;
  1123. AResult.TestResult:=AResultType;
  1124. AResult.TestMessage:=AMessage;
  1125. // Only increas in case of switch from non-error -> error
  1126. if (Prev In [trEmpty,trOK]) and not (AResult.TestResult In [trEmpty,trOK]) And (AResult.Test<>Nil) then
  1127. if AResult.TestResult=trTestIgnore then
  1128. Inc(CurrentRun.TestsIgnored)
  1129. else
  1130. Inc(CurrentRun.TestsFailed);
  1131. end;
  1132. Procedure SetTestResult(AResultType : TTestResult; AMessage : TTestString; Force : Boolean = False);
  1133. begin
  1134. if Assigned(CurrentResult) then
  1135. SetTestResult(CurrentResult^,AResultType,AMessage,Force);
  1136. end;
  1137. Function DoAssert(AResult : Boolean; ACondition : TTestString) : Boolean;
  1138. begin
  1139. Inc(CurrentRun.AssertCount);
  1140. Result:=AResult;
  1141. if (Not Result) and (Assigned(CurrentResult)) then
  1142. SetTestResult(CurrentResult^,trAssertFailed,ACondition);
  1143. end;
  1144. function CountResults(Results: PResultRecord): Integer;
  1145. begin
  1146. Result:=0;
  1147. While Results<>Nil do
  1148. begin
  1149. Inc(Result);
  1150. Results:=Results^.NextResult;
  1151. end;
  1152. end;
  1153. function Ignore(const Msg: TTestString): Boolean;
  1154. begin
  1155. SetTestResult(CurrentResult^,trTestIgnore,Msg);
  1156. Result:=False;
  1157. end;
  1158. function Fail(const Msg: TTestString): Boolean;
  1159. begin
  1160. Result:=DoAssert(False,Msg);
  1161. end;
  1162. function FailExit(const Msg: TTestString): Boolean;
  1163. begin
  1164. Result:=False;
  1165. Raise EFail.Create(Msg);
  1166. end;
  1167. function IgnoreExit(const Msg: TTestString): Boolean;
  1168. begin
  1169. Result:=False;
  1170. Raise EIgnore.Create(Msg);
  1171. end;
  1172. function AssertPassed(AMessage: TTestString): Boolean;
  1173. begin
  1174. Result:=DoAssert(True,'');
  1175. if Assigned(CurrentResult) then
  1176. SetTestResult(CurrentResult^,trOK,AMessage);
  1177. end;
  1178. function AssertTrue(const AMessage: TTestString; ACondition: Boolean): Boolean;
  1179. begin
  1180. DoAssert(ACondition,AMessage);
  1181. Result:=ACondition;
  1182. end;
  1183. Function ExpectMessage(AExpect,AActual : ShortString; Quote : Boolean = False) : ShortString;
  1184. begin
  1185. if Quote then
  1186. begin
  1187. AExpect:='"'+AExpect+'"';
  1188. AActual:='"'+AActual+'"';
  1189. end;
  1190. Result:=SExpected+': '+AExpect+' '+SActual+': '+AActual;
  1191. end;
  1192. Function ExpectMessage(AExpect,AActual : AnsiString; Quote : Boolean = False) : AnsiString;
  1193. begin
  1194. if Quote then
  1195. begin
  1196. AExpect:='"'+AExpect+'"';
  1197. AActual:='"'+AActual+'"';
  1198. end;
  1199. Result:=SExpected+': '+AExpect+' '+SActual+': '+AActual;
  1200. end;
  1201. Function ExpectMessage(AExpect,AActual : UnicodeString; Quote : Boolean = False) : UnicodeString;
  1202. begin
  1203. if Quote then
  1204. begin
  1205. AExpect:='"'+AExpect+'"';
  1206. AActual:='"'+AActual+'"';
  1207. end;
  1208. Result:=SExpected+': '+AExpect+' '+SActual+': '+AActual;
  1209. end;
  1210. Function ExpectMessage(AExpect,AActual : UTF8String; Quote : Boolean = False) : UTF8String;
  1211. begin
  1212. Result:=UTF8Encode(ExpectMessage(UTF8Decode(aExpect),UTF8Decode(aActual),Quote))
  1213. end;
  1214. function AssertFalse(const AMessage: TTestString; ACondition: Boolean): Boolean;
  1215. begin
  1216. Result:=AssertTrue(AMessage,Not ACondition);
  1217. end;
  1218. function AssertEquals(AMessage: TTestString; const AExpected,
  1219. AActual: ShortString): Boolean;
  1220. begin
  1221. Result:=AssertTrue(AMessage+'. '+ExpectMessage(AExpected,AActual,True),AExpected=AActual);
  1222. end;
  1223. function AssertEquals(AMessage: TTestString; const AExpected,
  1224. AActual: AnsiString): Boolean;
  1225. begin
  1226. Result:=AssertTrue(AMessage+'. '+ExpectMessage(AExpected,AActual,True),AExpected=AActual);
  1227. end;
  1228. function AssertEquals(AMessage: TTestString; const AExpected,
  1229. AActual: UTF8String): Boolean;
  1230. begin
  1231. Result:=AssertTrue(AMessage+'. '+ExpectMessage(AExpected,AActual,True),AExpected=AActual);
  1232. end;
  1233. function AssertEquals(AMessage: TTestString; const AExpected,
  1234. AActual: UnicodeString): Boolean;
  1235. begin
  1236. Result:=AssertTrue(AMessage+'. '+UTF8Encode(ExpectMessage(AExpected,AActual,True)),AExpected=AActual);
  1237. end;
  1238. Function AssertEquals(AMessage : TTestString; const AExpected: Char; AActual : UnicodeString): Boolean;
  1239. begin
  1240. Result:=AssertEquals(AMessage,RTLString(aExpected),aActual);
  1241. end;
  1242. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Boolean
  1243. ): Boolean;
  1244. Const
  1245. BStrs : Array[Boolean] of TTestString = ('False','True');
  1246. begin
  1247. Result:=AssertTrue(AMessage+'. '+ExpectMessage(BStrs[AExpected],BStrs[AActual],False),AExpected=AActual);
  1248. end;
  1249. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Shortint
  1250. ): Boolean;
  1251. Var
  1252. SE,SA : TTestString;
  1253. begin
  1254. Str(AExpected,SE);
  1255. Str(AActual,SA);
  1256. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1257. end;
  1258. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Byte
  1259. ): Boolean;
  1260. Var
  1261. SE,SA : TTestString;
  1262. begin
  1263. Str(AExpected,SE);
  1264. Str(AActual,SA);
  1265. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1266. end;
  1267. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Smallint
  1268. ): Boolean;
  1269. Var
  1270. SE,SA : TTestString;
  1271. begin
  1272. Str(AExpected,SE);
  1273. Str(AActual,SA);
  1274. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1275. end;
  1276. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Word
  1277. ): Boolean;
  1278. Var
  1279. SE,SA : TTestString;
  1280. begin
  1281. Str(AExpected,SE);
  1282. Str(AActual,SA);
  1283. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1284. end;
  1285. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Longint
  1286. ): Boolean;
  1287. Var
  1288. SE,SA : TTestString;
  1289. begin
  1290. Str(AExpected,SE);
  1291. Str(AActual,SA);
  1292. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1293. end;
  1294. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Cardinal
  1295. ): Boolean;
  1296. Var
  1297. SE,SA : TTestString;
  1298. begin
  1299. Str(AExpected,SE);
  1300. Str(AActual,SA);
  1301. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1302. end;
  1303. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Int64
  1304. ): Boolean;
  1305. Var
  1306. SE,SA : TTestString;
  1307. begin
  1308. Str(AExpected,SE);
  1309. Str(AActual,SA);
  1310. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1311. end;
  1312. function AssertEquals(AMessage: TTestString; const AExpected, AActual: QWord
  1313. ): Boolean;
  1314. Var
  1315. SE,SA : TTestString;
  1316. begin
  1317. Str(AExpected,SE);
  1318. Str(AActual,SA);
  1319. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1320. end;
  1321. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Currency
  1322. ): Boolean;
  1323. Var
  1324. SE,SA : TTestString;
  1325. begin
  1326. Str(AExpected,SE);
  1327. Str(AActual,SA);
  1328. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1329. end;
  1330. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Double;
  1331. ADelta: Double): Boolean;
  1332. Var
  1333. SE,SA : TTestString;
  1334. begin
  1335. Str(AExpected,SE);
  1336. Str(AActual,SA);
  1337. If ADelta=0 then
  1338. ADelta:=DefaultDoubleDelta;
  1339. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),Abs(AExpected-AActual)<ADelta);
  1340. end;
  1341. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Single;
  1342. ADelta: Single): Boolean;
  1343. Var
  1344. SE,SA : TTestString;
  1345. begin
  1346. Str(AExpected,SE);
  1347. Str(AActual,SA);
  1348. If ADelta=0 then
  1349. ADelta:=DefaultSingleDelta;
  1350. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),Abs(AExpected-AActual)<ADelta);
  1351. end;
  1352. function AssertEquals(AMessage: TTestString; const AExpected,
  1353. AActual: Extended; ADelta: Extended): Boolean;
  1354. Var
  1355. SE,SA : TTestString;
  1356. begin
  1357. Str(AExpected,SE);
  1358. Str(AActual,SA);
  1359. If ADelta=0 then
  1360. ADelta:=DefaultExtendedDelta;
  1361. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),Abs(AExpected-AActual)<ADelta);
  1362. end;
  1363. function AssertNull(AMessage: TTestString; const AValue: Pointer): Boolean;
  1364. begin
  1365. Result:=AssertEquals(AMessage,Nil,AValue);
  1366. end;
  1367. function AssertNotNull(AMessage: TTestString; const AValue: Pointer): Boolean;
  1368. begin
  1369. Result:=AssertDiffers(AMessage,Nil,AValue);
  1370. end;
  1371. Function PointerToStr(P : Pointer) : TTestString;
  1372. begin
  1373. if P=Nil then
  1374. Result:='Nil'
  1375. else
  1376. Result:=HexStr(P);
  1377. end;
  1378. function AssertEquals(AMessage: TTestString; const AExpected, AActual: Pointer
  1379. ): Boolean;
  1380. Var
  1381. SE,SA : TTestString;
  1382. begin
  1383. SE:=PointerToStr(AExpected);
  1384. SA:=PointerToStr(AActual);
  1385. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1386. end;
  1387. function AssertDiffers(AMessage: TTestString; const AExpected, AActual: Pointer
  1388. ): Boolean;
  1389. Var
  1390. SE,SA : TTestString;
  1391. begin
  1392. SE:=PointerToStr(AExpected);
  1393. SA:=PointerToStr(AActual);
  1394. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected<>AActual)
  1395. end;
  1396. function AssertEquals(AMessage: TTestString; const AExpected, AActual: TClass
  1397. ): Boolean;
  1398. Function CN (AClass : TClass) : TTestString;
  1399. begin
  1400. If Assigned(AClass) then
  1401. Result:=AClass.ClassName
  1402. else
  1403. Result:='Nil'
  1404. end;
  1405. Var
  1406. SE,SA : TTestString;
  1407. begin
  1408. SE:=CN(AExpected);
  1409. SA:=CN(AActual);
  1410. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1411. end;
  1412. function AssertInheritsFrom(AMessage: TTestString; const AChild,
  1413. AParent: TObject): Boolean;
  1414. Var
  1415. CC,CP : TClass;
  1416. begin
  1417. if Assigned(AParent) then
  1418. CP:=AParent.ClassType
  1419. else
  1420. CP:=Nil;
  1421. if Assigned(AChild) then
  1422. CC:=AChild.ClassType
  1423. else
  1424. CC:=Nil;
  1425. Result:=AssertInheritsFrom(AMessage,CC,CP)
  1426. end;
  1427. function AssertInheritsFrom(AMessage: TTestString; const AChild, AParent: TClass
  1428. ): Boolean;
  1429. begin
  1430. Result:=AssertNotNull(AMessage,AChild);
  1431. if Result then
  1432. begin
  1433. Result:=AssertNotNull(AMessage,AParent);
  1434. if Result then
  1435. Result:=AssertTrue(AMessage,AChild.InheritsFrom(AParent));
  1436. end;
  1437. end;
  1438. function AssertSame(AMessage: TTestString; const AExpected, AActual: TObject
  1439. ): Boolean;
  1440. Function CN (AClass : TObject) : TTestString;
  1441. begin
  1442. If Assigned(ACLass) then
  1443. Result:=AClass.ClassName
  1444. else
  1445. Result:='Nil'
  1446. end;
  1447. Var
  1448. SE,SA : TTestString;
  1449. begin
  1450. SE:=CN(AExpected);
  1451. if AExpected<>Nil then
  1452. SE:=SE+'('+HexStr(AExpected)+')';
  1453. SA:=CN(AActual);
  1454. if AActual<>Nil then
  1455. SA:=SA+'('+HexStr(AActual)+')';
  1456. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected=AActual);
  1457. end;
  1458. function AssertNotSame(AMessage: TTestString; const AExpected, AActual: TObject
  1459. ): Boolean;
  1460. Function CN (AClass : TObject) : TTestString;
  1461. begin
  1462. If Assigned(ACLass) then
  1463. Result:=AClass.ClassName
  1464. else
  1465. Result:='Nil'
  1466. end;
  1467. Var
  1468. SE,SA : TTestString;
  1469. begin
  1470. SE:=CN(AExpected);
  1471. if AExpected<>Nil then
  1472. SE:=SE+'('+HexStr(AExpected)+')';
  1473. SA:=CN(AActual);
  1474. if AActual<>Nil then
  1475. SA:=SA+'('+HexStr(AActual)+')';
  1476. Result:=AssertTrue(AMessage+'. '+ExpectMessage(SE,SA),AExpected<>AActual);
  1477. end;
  1478. function AssertException(const AMessage: string; AExceptionClass: TClass;
  1479. ARun: TProcedure): boolean;
  1480. Var
  1481. EC : TClass;
  1482. begin
  1483. EC:=Nil;
  1484. Try
  1485. ARun();
  1486. except
  1487. On E : TObject do
  1488. EC:=E.ClassType;
  1489. end;
  1490. Result:=AssertNotNull(AMessage,EC);
  1491. if Result then
  1492. Result:=AssertEquals(AMessage,AExceptionClass,EC);
  1493. end;
  1494. function AssertException(const AMessage: string; AExceptionClass: TClass;
  1495. ARun: TTestRun): boolean;
  1496. Var
  1497. EC : TClass;
  1498. S : TTestString;
  1499. begin
  1500. EC:=Nil;
  1501. S:='';
  1502. Try
  1503. S:=ARun();
  1504. except
  1505. On E : TObject do
  1506. EC:=E.ClassType;
  1507. end;
  1508. Result:=AssertNotNull(AMessage,EC) and AssertEquals(AMessage,TTestString(''),S);
  1509. if Result then
  1510. Result:=AssertEquals(AMessage,AExceptionClass,EC);
  1511. end;
  1512. function ExpectException(AMessage: TTestString; AClass: TClass): Boolean;
  1513. begin
  1514. Result:=SetTestError(teOK)=teOK;
  1515. Result:=AssertTrue(AMessage,Result and Assigned(CurrentResult) and (CurrentResult^.TestResult in [trEmpty,trOK]));
  1516. If Result then
  1517. begin
  1518. CurrentResult^.ExpectException:=AClass;
  1519. CurrentResult^.TestMessage:=AMessage;
  1520. end;
  1521. end;
  1522. { ---------------------------------------------------------------------
  1523. Auxiliary test run routines
  1524. ---------------------------------------------------------------------}
  1525. // Reset run summary results
  1526. Procedure FreeResultRecord(P : PResultRecord; Recurse : Boolean);
  1527. Var
  1528. N : PResultRecord;
  1529. begin
  1530. if Not Assigned(P) then
  1531. exit;
  1532. Repeat
  1533. Finalize(p^);
  1534. N:=P^.NextResult;
  1535. If Recurse then
  1536. FreeResultRecord(P^.ChildResults,Recurse);
  1537. FreeMem(P);
  1538. P:=N;
  1539. Until (P=Nil);
  1540. end;
  1541. Procedure ResetRun(Var ARun : TRunSummary);
  1542. begin
  1543. FreeResultRecord(ARun.Results.ChildResults,True);
  1544. ARun:=Default(TRunSummary);
  1545. ARun.Results:=Default(TResultRecord);
  1546. CurrentSuiteResult:[email protected];
  1547. CurrentResult:[email protected];
  1548. end;
  1549. // Check if the test run must be continued ?
  1550. Function ContinueTest(AResult : TTestError) : Boolean;
  1551. begin
  1552. Result:=(AResult=teOK) or (CurrentErrorAction=eaIgnore);;
  1553. end;
  1554. // Set current test result
  1555. Function AllocateCurrentSuiteResult(ASuite: PSuite; IsChild : Boolean): TTestError;
  1556. Var
  1557. P : PResultRecord;
  1558. begin
  1559. Result:=SetTestError(teOK);
  1560. New(P);
  1561. If (P=Nil) then
  1562. SetTestError(teNoMemory)
  1563. else
  1564. begin
  1565. P^:=Default(TResultRecord);
  1566. p^.Suite:=ASuite;
  1567. If IsChild then
  1568. begin
  1569. CurrentSuiteResult^.ChildResults:=P;
  1570. P^.ParentResult:=CurrentSuiteResult;
  1571. end
  1572. else
  1573. Begin
  1574. CurrentSuiteResult^.NextResult:=P;
  1575. P^.ParentResult:=CurrentSuiteResult^.ParentResult;
  1576. end;
  1577. CurrentSuiteResult:=P;
  1578. CurrentResult:=CurrentSuiteResult;
  1579. end;
  1580. end;
  1581. Function AllocateCurrentResult(ASuite: PSuite; ATest: PTest): TTestError;
  1582. Var
  1583. N,P : PResultRecord;
  1584. begin
  1585. Result:=SetTestError(teOK);
  1586. New(P);
  1587. If (P=Nil) then
  1588. SetTestError(teNoMemory)
  1589. else
  1590. begin
  1591. P^:=Default(TResultRecord);
  1592. P^.TestResult:=trEmpty;
  1593. P^.Suite:=ASuite;
  1594. P^.Test:=ATest;
  1595. P^.ExpectException:=Nil;
  1596. // Hook up in tree.
  1597. N:=CurrentSuiteResult^.ChildResults;
  1598. if N=Nil then
  1599. begin
  1600. CurrentSuiteResult^.ChildResults:=P;
  1601. P^.ParentResult:=CurrentSuiteResult;
  1602. end
  1603. else
  1604. begin
  1605. While (N^.NextResult<>Nil) do
  1606. N:=N^.NextResult;
  1607. N^.NextResult:=P;
  1608. P^.ParentResult:=N^.ParentResult;
  1609. end;
  1610. CurrentResult:=P;
  1611. end;
  1612. end;
  1613. { ---------------------------------------------------------------------
  1614. Protected run of hook handlers. Catch exceptions and report them.
  1615. ---------------------------------------------------------------------}
  1616. // Run start hook
  1617. Function RunGLobalRunStartHandler(Suites : TSuiteArray) : TTestError;
  1618. begin
  1619. Result:=SetTestError(teOK);
  1620. Try
  1621. GlobalRunStartHandler(Suites);
  1622. except
  1623. On E : TObject do
  1624. begin
  1625. CurrentResult:[email protected];
  1626. SetTestResult(trHandlerError,E.ToString,True);
  1627. Result:=(SetTestError(teRunStartHandler));
  1628. end;
  1629. end;
  1630. end;
  1631. // Run complete hook
  1632. Function RunGLobalRunCompleteHandler(Run : TRunSummary) : TTestError;
  1633. begin
  1634. Result:=SetTestError(teOK);
  1635. if Assigned(GlobalRunCompleteHandler) then
  1636. Try
  1637. GlobalRunCompleteHandler(Run);
  1638. except
  1639. On E : TObject do
  1640. begin
  1641. CurrentResult:[email protected];
  1642. SetTestResult(trHandlerError,E.ToString,False);
  1643. Result:=(SetTestError(teRunCompleteHandler));
  1644. end;
  1645. end;
  1646. end;
  1647. // Run suite start hook
  1648. Function RunGlobalSuiteStartHandler(ASuite : PSuite) : TTestError;
  1649. begin
  1650. Result:=SetTestError(teOK);
  1651. If Assigned(GlobalSuiteStartHandler) then
  1652. try
  1653. GlobalSuiteStartHandler(ASuite);
  1654. except
  1655. On E : EIgnore do
  1656. SetTestResult(trTestIgnore,E.ToString);
  1657. On E : EFail do
  1658. SetTestResult(trAssertFailed,E.ToString);
  1659. On E : TObject do
  1660. SetTestResult(trHandlerError,E.ToString);
  1661. end;
  1662. end;
  1663. // Run suite complete hook
  1664. Function RunGlobalSuiteCompleteHandler(ASuite : PSuite; SuiteResult : PResultRecord) : TTestError;
  1665. Var
  1666. C : PresultRecord;
  1667. begin
  1668. Result:=SetTestError(teOK);
  1669. If Assigned(GlobalSuiteCompleteHandler) then
  1670. begin
  1671. C:=CurrentResult;
  1672. CurrentResult:=SuiteResult;
  1673. try
  1674. GlobalSuiteCompleteHandler(ASuite,SuiteResult);
  1675. except
  1676. On E : EIgnore do
  1677. SetTestResult(trTestIgnore,E.ToString);
  1678. On E : EFail do
  1679. SetTestResult(SuiteResult^,trAssertFailed,E.ToString);
  1680. On E : TObject do
  1681. SetTestResult(SuiteResult^,trHandlerError,E.ToString);
  1682. end;
  1683. CurrentResult:=C;
  1684. end;
  1685. end;
  1686. // Run suite setup
  1687. Function RunSuiteSetup(ASuite : PSuite; SuiteResult : PResultRecord) : TTestError;
  1688. var
  1689. S : TTestString;
  1690. begin
  1691. Result:=SetTestError(teOK);
  1692. if Not Assigned(ASuite^.Setup) then
  1693. exit;
  1694. S:='';
  1695. try
  1696. S:=ASuite^.Setup();
  1697. Except
  1698. On E : TObject Do
  1699. S:=E.ToString;
  1700. end;
  1701. if (S<>'') then
  1702. begin
  1703. SetTestResult(SuiteResult^,trSuiteSetupFailed,S,True);
  1704. Result:=SetTestError(teSuiteSetupFailed);
  1705. Inc(CurrentRun.SuitesFailed);
  1706. If Assigned(GlobalSuiteSetupFailureHandler) then
  1707. GlobalSuiteSetupFailureHandler(ASuite,S);
  1708. end
  1709. end;
  1710. // Run suite teardown
  1711. Function RunSuiteTearDown(ASuite : PSuite; SuiteResult : PResultRecord) : TTestError;
  1712. var
  1713. S : TTestString;
  1714. C : PresultRecord;
  1715. begin
  1716. Result:=SetTestError(teOK);
  1717. if Not Assigned(ASuite^.Teardown) then
  1718. exit;
  1719. C:=CurrentResult;
  1720. CurrentResult:=SuiteResult;
  1721. S:='';
  1722. try
  1723. S:=ASuite^.TearDown();
  1724. Except
  1725. On E : TObject Do
  1726. S:=E.ToString;
  1727. end;
  1728. if (S<>'') then
  1729. begin
  1730. SetTestResult(SuiteResult^,trSuiteTearDownFailed,S,True);
  1731. Result:=SetTestError(teSuiteTeardownFailed);
  1732. Inc(CurrentRun.SuitesFailed);
  1733. If Assigned(GlobalSuiteTearDownFailureHandler) then
  1734. GlobalSuiteTearDownFailureHandler(ASuite,S);
  1735. end;
  1736. CurrentResult:=C;
  1737. end;
  1738. // Run test handler
  1739. Var
  1740. SavedDefaultSystemCodePage,
  1741. SavedDefaultUnicodeCodePage,
  1742. SavedDefaultFileSystemCodePage,
  1743. SavedDefaultRTLFileSystemCodePage,
  1744. SavedUTF8CompareLocale : TSystemCodePage;
  1745. Procedure SaveCodePages;
  1746. begin
  1747. SavedDefaultSystemCodePage:=DefaultSystemCodePage;
  1748. SavedDefaultUnicodeCodePage:=DefaultUnicodeCodePage;
  1749. SavedDefaultFileSystemCodePage:=DefaultFileSystemCodePage;
  1750. SavedDefaultRTLFileSystemCodePage:=DefaultRTLFileSystemCodePage;
  1751. SavedUTF8CompareLocale:=UTF8CompareLocale;
  1752. end;
  1753. Procedure RestoreCodePages;
  1754. begin
  1755. DefaultSystemCodePage:=SavedDefaultSystemCodePage;
  1756. DefaultUnicodeCodePage:=SavedDefaultUnicodeCodePage;
  1757. DefaultFileSystemCodePage:=SavedDefaultFileSystemCodePage;
  1758. DefaultRTLFileSystemCodePage:=SavedDefaultRTLFileSystemCodePage;
  1759. UTF8CompareLocale:=SavedUTF8CompareLocale;
  1760. end;
  1761. Function RunTestHandler(aTest : PTest) : String;
  1762. Var
  1763. EC : TClass;
  1764. EM : TTestString;
  1765. begin
  1766. Result:='';
  1767. EC:=Nil;
  1768. EM:='';
  1769. SaveCodePages;
  1770. try
  1771. if assigned(aTest^.Run) then
  1772. Result:=aTest^.Run()
  1773. else if assigned(aTest^.RunProc) then
  1774. begin
  1775. Result:='';
  1776. aTest^.RunProc();
  1777. end
  1778. else
  1779. Result:=SErrNoTestProcedure;
  1780. RestoreCodePages;
  1781. except
  1782. On E : TObject do
  1783. begin
  1784. RestoreCodePages;
  1785. EC:=E.ClassType;
  1786. EM:=E.TOString;
  1787. end;
  1788. end;
  1789. // Read IOResult so it is reset.
  1790. if IOResult<>0 then;
  1791. // Treat exception.
  1792. if (EC<>CurrentResult^.ExpectException) then
  1793. begin
  1794. if (CurrentResult^.ExpectException=Nil) then
  1795. Result:=EM
  1796. else
  1797. With CurrentResult^ do
  1798. if (EC=Nil) then
  1799. Result:=TestMessage+' '+ExpectMessage(ExpectException.ClassName,'Nil')
  1800. else
  1801. Result:=TestMessage+' '+ExpectMessage(ExpectException.ClassName,EC.ClassName);
  1802. end;
  1803. end;
  1804. { ---------------------------------------------------------------------
  1805. Running tests
  1806. ---------------------------------------------------------------------}
  1807. Function RunSingleTest(T : PTest) : TTestError;
  1808. Type
  1809. TTestStage = (tsStartHandler,tsSetup,tsRun,tsTearDown,tsCompleteHandler);
  1810. Const
  1811. Prefixes : Array[TTestStage] of TTestString =
  1812. ('Test start handler','Test Setup','','Test TearDown','Test complete handler');
  1813. Errors : Array[TTestStage] of TTestResult =
  1814. (trHandlerError,trSuiteSetupFailed, trTestError,trSuiteTearDownFailed,trHandlerError);
  1815. Var
  1816. S : TTestString;
  1817. Stage : TTestStage;
  1818. StartTime : TDateTime;
  1819. CurrentAsserts : Integer;
  1820. begin
  1821. SetTestError(teOK);
  1822. Assert(CurrentSuite<>Nil);
  1823. CurrentTest:=T;
  1824. try
  1825. CurrentAsserts:=CurrentRun.AssertCount;
  1826. Result:=AllocateCurrentResult(CurrentSuite,T);
  1827. if (Result<>teOK) then
  1828. Exit;
  1829. Stage:=tsStartHandler;
  1830. // We don't use a protected method. We use 1 try/except block that keeps track of the 'stage'.
  1831. If Assigned(GlobalTestStartHandler) then
  1832. GlobalTestStartHandler(T,CurrentSuite);
  1833. if (soSetupTearDownPerTest in CurrentSuite^.Options) then
  1834. begin
  1835. Stage:=tsSetup;
  1836. Result:=RunSuiteSetup(CurrentSuite,CurrentResult);
  1837. end;
  1838. if (Result=teOK) then
  1839. If Not (toInactive in T^.Options) then
  1840. begin
  1841. StartTime:=GetTimeFromHook;
  1842. try
  1843. Stage:=tsRun;
  1844. S:=RunTestHandler(T); // Protect and handle exception.
  1845. if (S<>'') then
  1846. Fail(S)
  1847. else if (CurrentResult^.TestResult=trEmpty) then
  1848. if (CurrentAsserts=CurrentRun.AssertCount) and RequirePassed then
  1849. Inc(CurrentRun.TestsUnimplemented)
  1850. else
  1851. SetTestResult(trOK,'');
  1852. Finally
  1853. CurrentResult^.ElapsedTime:=GetTimeDiff(StartTime);
  1854. Inc(CurrentRun.TestsRun);
  1855. end;
  1856. if (soSetupTearDownPerTest in CurrentSuite^.Options) then
  1857. begin
  1858. Stage:=tsTearDown;
  1859. Result:=RunSuiteTearDown(CurrentSuite,CurrentResult);
  1860. end;
  1861. Stage:=tsCompleteHandler;
  1862. end
  1863. else
  1864. begin
  1865. Inc(CurrentRun.TestsInactive);
  1866. SetTestResult(trTestInactive,'',True);
  1867. Result:=SetTestError(teTestInactive);
  1868. end;
  1869. if Assigned(GlobalTestCompleteHandler) then
  1870. GlobalTestCompleteHandler(T,CurrentSuite,CurrentResult);
  1871. except
  1872. On E : TObject do
  1873. begin
  1874. S:=Prefixes[Stage];
  1875. if (S<>'') then S:='['+S+'] ';
  1876. S:=S+E.Tostring;
  1877. SetTestResult(CurrentResult^,Errors[Stage],S,True);
  1878. end;
  1879. end;
  1880. CurrentTest:=Nil;
  1881. end;
  1882. // Internal, run a single suite, collect results in RunSummary.
  1883. Function RunSingleSuite(ASuite : PSuite; isChild : Boolean) : TTestError;
  1884. Type
  1885. TSuiteStage = (ssStartHandler,ssSetup,ssRun,ssTearDown,ssEndHandler);
  1886. Const
  1887. Prefixes : Array [TSuiteStage] of TTestString =
  1888. ('Start handler','Setup','','Teardown','End Handler');
  1889. StageErrors : Array [TSuiteStage] of TTestResult =
  1890. (trHandlerError,trSuiteSetupFailed,trTestError,trSuiteTearDownFailed,trHandlerError);
  1891. Var
  1892. S : TTestString;
  1893. T : PTest;
  1894. Stage : TSuiteStage;
  1895. I : Integer;
  1896. StartTime : TDateTime;
  1897. R2 : TTestError;
  1898. OldCurrentSuite : PSuite;
  1899. SuiteResult : PResultRecord;
  1900. begin
  1901. if AllocateCurrentSuiteResult(ASuite,IsChild)<>teOK then
  1902. exit;
  1903. SetTestError(teOK);
  1904. OldCurrentSuite:=CurrentSuite;
  1905. SuiteResult:=CurrentSuiteResult;
  1906. CurrentSuite:=ASuite;
  1907. try
  1908. Result:=teOK;
  1909. Stage:=ssStartHandler;
  1910. RunGlobalSuiteStartHandler(ASuite);
  1911. // First, run all sub suites.
  1912. If (soInactive in ASuite^.Options) then
  1913. Inc(CurrentRun.SuitesInactive)
  1914. else
  1915. begin
  1916. StartTime:=GetTimeFromHook;
  1917. S:='';
  1918. try
  1919. if not (soSetupTearDownPerTest in ASuite^.Options) then
  1920. begin
  1921. Stage:=ssSetup;
  1922. Result:=RunSuiteSetup(ASuite,SuiteResult);
  1923. end;
  1924. Stage:=ssRun;
  1925. For I:=0 to Asuite^.Suites.Count-1 do
  1926. If (Result=teOK) or (CurrentErrorAction=eaIgnore) then
  1927. Result:=RunSingleSuite(ASuite^.Suites.Items[i],I=0);
  1928. // Reset current result
  1929. CurrentSuiteResult:=SuiteResult;
  1930. CurrentResult:=SuiteResult;
  1931. For I:=0 to Asuite^.Tests.Count-1 do
  1932. If (Result=teOK) or (CurrentErrorAction=eaIgnore) then
  1933. begin
  1934. T:=Asuite^.Tests.Items[i];
  1935. if Not (toInactive in T^.Options) then
  1936. Result:=RunSingleTest(T)
  1937. else
  1938. Inc(CurrentRun.TestsInactive)
  1939. end;
  1940. Stage:=ssTeardown;
  1941. Result:=RunSuiteTearDown(ASuite,SuiteResult);
  1942. Finally
  1943. Inc(CurrentRun.SuitesRun);
  1944. SuiteResult^.ElapsedTime:=GetTimeDiff(StartTime);
  1945. end;
  1946. Stage:=ssEndHandler;
  1947. R2:=RunGLobalSuiteCompleteHandler(ASuite,SuiteResult);
  1948. if (Result=teOK) and (R2<>teOK) then
  1949. Result:=R2;
  1950. SetTestResult(SuiteResult^,trOK,'',False);
  1951. end;
  1952. except
  1953. On E : TObject do
  1954. begin
  1955. S:=Prefixes[Stage];
  1956. if (S<>'') then S:='['+S+'] ';
  1957. S:=S+E.Tostring;
  1958. SetTestResult(SuiteResult^,StageErrors[Stage],S,True);
  1959. end;
  1960. end;
  1961. CurrentSuite:=OldCurrentSuite;
  1962. end;
  1963. // Internal. At this point, ASuite and ATest are valid.
  1964. Function DoRunTest(ASuite: PSuite; ATest: PTest): TTestError;
  1965. Var
  1966. A : TSuiteArray;
  1967. StartTime : TDateTime;
  1968. SuiteResult : PResultRecord;
  1969. begin
  1970. A:=[];
  1971. ResetRun(CurrentRun);
  1972. if AllocateCurrentSuiteResult(ASuite,True)<>teOK then
  1973. exit;
  1974. Result:=SetTestError(teOK);
  1975. SuiteResult:=CurrentResult;
  1976. If Assigned(GlobalRunStartHandler) then
  1977. begin
  1978. SetLength(A,1);
  1979. A[0]:=ASuite;
  1980. Result:=RunGlobalRunStartHandler(A);
  1981. SetLength(A,0);
  1982. If not ContinueTest(Result) then
  1983. exit;
  1984. end;
  1985. if (soInactive in ASuite^.Options) then
  1986. begin
  1987. SetTestResult(trSuiteInactive,'',True);
  1988. Inc(CurrentRun.SuitesInactive);
  1989. Inc(CurrentRun.SuitesFailed);
  1990. RunGlobalRunCompleteHandler(CurrentRun); // Ignore status
  1991. Exit(SetTestError(teSuiteInactive));
  1992. end;
  1993. StartTime:=GetTimeFromHook;
  1994. if Not ContinueTest(Result)then
  1995. begin
  1996. Result:=CombineError(Result,RunGlobalRunCompleteHandler(CurrentRun));
  1997. exit;
  1998. end;
  1999. CurrentSuite:=ASuite;
  2000. try
  2001. Result:=RunGlobalSuiteStartHandler(ASuite);
  2002. if ContinueTest(Result) then
  2003. begin
  2004. Result:=RunSuiteSetup(ASuite,SuiteResult);
  2005. if ContinueTest(Result) then
  2006. begin
  2007. Result:=CombineError(Result,RunSingleTest(ATest));
  2008. Result:=CombineError(Result,RunSuiteTearDown(ASuite,SuiteResult));
  2009. end;
  2010. end;
  2011. finally
  2012. SetTestResult(SuiteResult^,trOK,'');
  2013. Inc(CurrentRun.SuitesRun);
  2014. CurrentSuite:=Nil;
  2015. end;
  2016. Result:=CombineError(Result,RunGlobalSuiteCompleteHandler(ASuite,SuiteResult));
  2017. CurrentRun.ElapsedTime:=GetTimeDiff(StartTime);
  2018. Result:=CombineError(Result,RunGlobalRunCompleteHandler(CurrentRun));
  2019. end;
  2020. // Internal. At this point, ASuite is valid.
  2021. Function DoRunSuite(ASuite: PSuite): TTestError;
  2022. Var
  2023. A : TSuiteArray;
  2024. StartTime : TDateTime;
  2025. begin
  2026. A:=[];
  2027. SetTestError(teOK);
  2028. ResetRun(CurrentRun);
  2029. If Assigned(GlobalRunStartHandler) then
  2030. begin
  2031. SetLength(A,1);
  2032. A[0]:=ASuite;
  2033. Result:=RunGlobalRunStartHandler(A);
  2034. SetLength(A,0);
  2035. if not ContinueTest(Result) then
  2036. Exit;
  2037. end;
  2038. SetTestError(teOK);
  2039. StartTime:=GetTimeFromHook;
  2040. Result:=teOK;
  2041. Result:=RunSingleSuite(ASuite,True);
  2042. CurrentRun.ElapsedTime:=GetTimeDiff(StartTime);
  2043. Result:=CombineError(Result,RunGlobalRunCompleteHandler(CurrentRun));
  2044. end;
  2045. function RunSuite(ASuite: PSuite): TTestError;
  2046. begin
  2047. SetTestError(teOK);
  2048. if (ASuite=Nil) then
  2049. Result:=SetTestError(teNoSuite)
  2050. else
  2051. Result:=DoRunSuite(ASuite);
  2052. end;
  2053. function RunSuite(const ASuiteName: TTestString): TTestError;
  2054. begin
  2055. Result:=RunSuite(GetSuite(ASuiteName));
  2056. end;
  2057. function RunSuite(ASuiteIndex: Integer): TTestError;
  2058. begin
  2059. Result:=RunSuite(GetSuite(ASuiteIndex))
  2060. end;
  2061. Function RunTest(ASuiteIndex: Integer; Const ATestName: TTestString): TTestError;
  2062. Var
  2063. S : PSuite;
  2064. begin
  2065. S:=GetSuite(ASuiteIndex);
  2066. Result:=RunTest(S,GetTest(S,ATestName));
  2067. end;
  2068. Function RunTest(ASuite: PSuite; ATestIndex: Integer): TTestError;
  2069. begin
  2070. Result:=RunTest(ASuite,GetTest(ASuite,ATestIndex));
  2071. end;
  2072. function RunTest(ASuite: PSuite; const ATestName: TTestString): TTestError;
  2073. begin
  2074. Result:=RunTest(ASuite,GetTest(ASuite,ATestName));
  2075. end;
  2076. function RunTest(const ASuiteName: TTestString; const ATestName: TTestString
  2077. ): TTestError;
  2078. Var
  2079. S : PSuite;
  2080. begin
  2081. S:=GetSuite(ASuiteName);
  2082. Result:=RunTest(S,GetTest(S,ATestName));
  2083. end;
  2084. function RunTest(ASuite: PSuite; ATest: PTest): TTestError;
  2085. begin
  2086. Result:=SetTestError(teOK);
  2087. ProcessSysCommandline;
  2088. if (ASuite=Nil) then
  2089. Result:=SetTestError(teNoSuite)
  2090. else if (ATest=Nil) then
  2091. Result:=SetTestError(teNoTest)
  2092. else if not TestIsInSuite(ASuite,ATest) then
  2093. Result:=SetTestError(teTestNotInSuite)
  2094. else
  2095. Result:=DoRunTest(ASuite,ATest);
  2096. end;
  2097. Procedure SysHalt;
  2098. begin
  2099. if CurrentRun.TestsFailed<>0 then
  2100. Halt(1)
  2101. else
  2102. Halt(0);
  2103. end;
  2104. Procedure DoRunSysTests(S : PSuite; T : PTest); forward;
  2105. procedure RunTest(ARun: TTestRun);
  2106. begin
  2107. ProcessSysCommandLine;
  2108. if ARun=Nil then
  2109. Halt(2);
  2110. if (AddTest('Global',ARun)=Nil) then
  2111. Halt(3);
  2112. DoRunSysTests(Nil,Nil);
  2113. end;
  2114. function GetCurrentRun: TRunSummary;
  2115. begin
  2116. Result:=CurrentRun;
  2117. end;
  2118. function GetCurrentSuite: PSuite;
  2119. begin
  2120. Result:=CurrentSuite;
  2121. end;
  2122. function GetCurrentTest: PTest;
  2123. begin
  2124. Result:=CurrentTest;
  2125. end;
  2126. function GetCurrentResult: PResultRecord;
  2127. begin
  2128. Result:=CurrentResult;
  2129. end;
  2130. function RunAllTests: TTestError;
  2131. Var
  2132. I : Integer;
  2133. A : TSuiteArray;
  2134. StartTime : TDateTime;
  2135. begin
  2136. A:=[];
  2137. Result:=SetTestError(teOK);
  2138. ResetRun(CurrentRun);
  2139. StartTime:=GetTimeFromHook;
  2140. If Assigned(GlobalRunStartHandler) then
  2141. begin
  2142. // Array of actual size.
  2143. SetLength(A,TestRegistry.Count);
  2144. For I:=0 to TestRegistry.Count-1 do
  2145. A[I]:=TestRegistry.Items[i];
  2146. GlobalRunStartHandler(A);
  2147. SetLength(A,0);
  2148. end;
  2149. If (TestRegistry.Count=0) then
  2150. Result:=SetTestError(teRegistryEmpty)
  2151. else
  2152. begin
  2153. I:=0;
  2154. While (I<TestRegistry.Count) and ContinueTest(Result) do
  2155. begin
  2156. Result:=CombineError(Result,RunSingleSuite(TestRegistry.Items[I],I=0));
  2157. Inc(I);
  2158. end;
  2159. end;
  2160. CurrentRun.ElapsedTime:=GetTimeDiff(StartTime);
  2161. Result:=CombineError(Result,RunGlobalRunCompleteHandler(CurrentRun));
  2162. end;
  2163. { ---------------------------------------------------------------------
  2164. Systemm hooks
  2165. ---------------------------------------------------------------------}
  2166. Const
  2167. // Run
  2168. STestRun = 'Test run';
  2169. SRunSummary = 'Run summary';
  2170. // Suites
  2171. SSuites = 'Suites';
  2172. SSuite = 'Suite';
  2173. SSummary = 'summary';
  2174. SSuitesSummary = 'Suites summary';
  2175. // Tests
  2176. STests = 'Tests';
  2177. STest = 'Test';
  2178. STestsSummary = 'Tests summary';
  2179. // Counts
  2180. SInactiveCount = 'Inactive';
  2181. SIgnoredCount = 'Ignored';
  2182. SRunCount = 'Run';
  2183. SFailedCount = 'Failed';
  2184. SUnimplementedCount = 'Unimplemented';
  2185. // test Status/Result
  2186. SPassed = 'Passed';
  2187. SIgnored = 'Ignored';
  2188. SFailed = 'Failed';
  2189. SError = 'Error';
  2190. SInactive = 'Inactive';
  2191. SNotImplemented = 'Not implemented';
  2192. SUnknown = 'Unknown';
  2193. SErrorMessage = 'Error message';
  2194. SSuiteSetupFailed = 'Suite setup failed';
  2195. SSuiteTearDownFailed = 'Suite setup failed';
  2196. // Elapsed time
  2197. STime = 'Time';
  2198. SUsage = 'Usage:';
  2199. SHelpL = '-l --list list all tests (observes -s)';
  2200. SHelpF = '-f --failures only show names and errors of failed tests';
  2201. SHelpH = '-h --help this help message';
  2202. SHelpN = '-n --normal normal log level';
  2203. SHelpO = '-o --output=file log output file name (default is standard output)';
  2204. SHelpQ = '-q --quiet Do not display messages ';
  2205. SHelpS = '-s --suite=name Only run/list tests in given suite';
  2206. SHelpT = '-t --test=name Only run/list tests matching given test (requires -s)';
  2207. SHelpV = '-v --verbose Verbose output logging';
  2208. SHelpHasTime = 'This binary has support for displaying time';
  2209. SHelpNoTime = 'This binary has no support for displaying time';
  2210. SHelpExitCodes = 'Possible exit codes:';
  2211. SHelpExit0 = '0 - All actions (tests) completed successfully';
  2212. SHelpExit1 = '1 - All tests were run, but some tests failed.';
  2213. SHelpExit2 = '2 - An empty test function was given to runtest';
  2214. SHelpExit3 = '3 - The requested suite was not found';
  2215. SHelpExit4 = '4 - The requested test was not found';
  2216. SHelpExit5 = '5 - An unexpected error occurred in the testsuite';
  2217. Type
  2218. TRunMode = (rmHelp,rmList,rmTest);
  2219. Var
  2220. FSys : ^Text;
  2221. LogFile : Text;
  2222. CurrentRunMode : TSysRunVerbosity;
  2223. SysSuite : PSuite;
  2224. SysOutputFileName : TTestString;
  2225. SysTestName : TTestString;
  2226. SysSuiteName : TTestString;
  2227. SysRunMode : TRunMode;
  2228. SysSuiteIndent : String;
  2229. Procedure SysSuiteStartHandler (ASuite : PSuite);
  2230. begin
  2231. if (ASuite<>SysSuite) then
  2232. begin
  2233. SysSuiteIndent:=SysSuiteIndent+' ';
  2234. Write(FSys^,SysSuiteIndent,SSuite,' ',ASuite^.Name,':');
  2235. if CurrentRunMode=rvVerbose then
  2236. Writeln(FSys^,' (',ASuite^.Tests.Count,' ',STests+')')
  2237. else
  2238. Writeln(FSys^);
  2239. SysSuite:=ASuite;
  2240. end;
  2241. end;
  2242. Procedure SysTestStartHandler (ATest : PTest; ASuite : PSuite);
  2243. begin
  2244. if CurrentRunMode in [rvQuiet,rvFailures] then
  2245. Exit;
  2246. Write(FSys^,SysSuiteIndent+' ',STest,' ',ATest^.Name,': ');
  2247. end;
  2248. function SysTimeString(MSec: Integer): TTestString;
  2249. Var
  2250. S : TTestString;
  2251. begin
  2252. S:='';
  2253. Str(Msec mod 1000,Result);
  2254. MSec:=Msec div 1000;
  2255. If (Msec=0) then
  2256. Result:='0.'+Result
  2257. else
  2258. begin
  2259. Str(Msec mod 60,S);
  2260. Result:=S+'.'+Result;
  2261. Msec:=Msec div 60;
  2262. If (Msec<>0) then
  2263. begin
  2264. Str(Msec mod 60,S);
  2265. Result:=S+':'+Result;
  2266. Msec:=Msec div 60;
  2267. If (Msec<>0) then
  2268. begin
  2269. Str(Msec,S);
  2270. Result:=S+':'+Result;
  2271. end;
  2272. end;
  2273. end;
  2274. Result:=STime+': '+Result;
  2275. end;
  2276. Procedure SysTestCompleteHandler (ATest: PTest; ASuite : PSuite; Const AResultRecord : PResultRecord);
  2277. Var
  2278. S : TTestString;
  2279. F,O : Boolean;
  2280. TR : TTestResult;
  2281. begin
  2282. if (CurrentRunMode=rvQuiet) then exit;
  2283. F:=CurrentRunMode=rvFailures;
  2284. O:=False;
  2285. S:=AResultRecord^.TestMessage;
  2286. TR:=AResultRecord^.TestResult;
  2287. Case TR of
  2288. trEmpty :
  2289. if not F then
  2290. Write(FSys^,SNotImplemented);
  2291. trOK :
  2292. if not F then
  2293. Write(FSys^,SPassed);
  2294. trTestIgnore:
  2295. if not F then
  2296. Write(FSys^,SIgnored,' (',S,')');
  2297. trSuiteSetupFailed,
  2298. trSuiteTearDownFailed,
  2299. trAssertFailed,
  2300. trTestError,
  2301. trHandlerError:
  2302. begin
  2303. if F then
  2304. Write(FSys^,STest,' ',ASuite^.Name,'.',ATest^.Name,': ');
  2305. if TR in [trTestError,trHandlerError] then
  2306. Write(FSys^,SError)
  2307. else
  2308. Write(FSys^,SFailed);
  2309. Write(FSys^,' (',SErrorMessage,': ',S,')');
  2310. O:=True;
  2311. end;
  2312. trTestInactive:
  2313. if not F then
  2314. Write(FSys^,SInactive);
  2315. else
  2316. if not F then
  2317. Write(FSys^,SUnknown,' : ',AResultRecord^.TestMessage);
  2318. end;
  2319. if (not F) and HaveTimeHook then
  2320. Writeln(FSys^,' ',SysTimeString(AResultRecord^.ElapsedTime))
  2321. else if (O or Not F) then
  2322. Writeln(FSys^);
  2323. end;
  2324. Procedure GetResultStats(AResults : PResultRecord; Var Stats : TSuiteStats);
  2325. begin
  2326. If AResults^.Test<>Nil then
  2327. begin
  2328. Inc(Stats.TestsRun);
  2329. Case AResults^.TestResult of
  2330. trEmpty : Inc(Stats.TestsUnimplemented);
  2331. trAssertFailed : Inc(Stats.TestsFailed);
  2332. trTestInactive : Inc(Stats.TestsInactive);
  2333. trTestIgnore : Inc(Stats.TestsIgnored);
  2334. trTestError : Inc(Stats.TestsError);
  2335. else
  2336. // Do nothing, silence compiler warning
  2337. end;
  2338. end;
  2339. end;
  2340. Procedure DoGetSuiteStats(AResults : PResultRecord; Var Stats : TSuiteStats);
  2341. Var
  2342. R : PResultRecord;
  2343. begin
  2344. if AResults^.Test<>Nil then
  2345. Exit;
  2346. Inc(Stats.Suites);
  2347. R:=AResults^.ChildResults;
  2348. While R<>Nil do
  2349. begin
  2350. if R^.Test=Nil then
  2351. DoGetSuiteStats(R,Stats)
  2352. else
  2353. GetResultStats(R,Stats);
  2354. R:=R^.NextResult;
  2355. end;
  2356. end;
  2357. Procedure GetSuiteStats(AResults : PResultRecord; Out Stats : TSuiteStats);
  2358. begin
  2359. Stats:=Default(TSuiteStats);
  2360. DoGetSuiteStats(AResults,Stats);
  2361. end;
  2362. Procedure SysSuiteCompleteHandler (ASuite : PSuite; Const AResults : PResultRecord);
  2363. Var
  2364. Stats : TSuiteStats;
  2365. begin
  2366. if CurrentRunMode=rvFailures then
  2367. Delete(SysSuiteIndent,1,2);
  2368. if CurrentRunMode in [rvQuiet,rvFailures] then
  2369. exit;
  2370. Write(FSys^,SysSuiteIndent,SSuite,' ',ASuite^.Name,' ',SSummary,': ');
  2371. GetSuiteStats(AResults,Stats);
  2372. With Stats do
  2373. begin
  2374. Write(FSys^,SRunCount,': ',TestsRun,' ',SFailedCount,': ',TestsFailed,' ',SInactiveCount,': ',TestsInactive,' ',SIgnoredCount,': ',TestsIgnored);
  2375. if RequirePassed then
  2376. Write(FSys^,' ',SUnimplementedCount,': ',TestsUnimplemented);
  2377. end;
  2378. if HaveTimeHook then
  2379. Writeln(FSys^,' ',SysTimeString(AResults^.ElapsedTime))
  2380. else
  2381. Writeln(FSys^);
  2382. Flush(FSys^);
  2383. Delete(SysSuiteIndent,1,2);
  2384. end;
  2385. Procedure SysRunStartHandler (Const Suites: TSuiteArray);
  2386. Var
  2387. I,TC : Integer;
  2388. begin
  2389. if (CurrentRunmode in [rvQuiet,rvFailures]) then
  2390. exit;
  2391. TC:=0;
  2392. For I:=0 to Length(Suites)-1 do
  2393. Inc(TC,Suites[i]^.Tests.Count);
  2394. Write(FSys^,STestRun,':');
  2395. If (CurrentRunMode<>rvVerbose) then
  2396. Writeln(FSys^)
  2397. else
  2398. Writeln(FSys^,' ',Length(Suites),' ',SSuites,', ',TC,' ',STests);
  2399. end;
  2400. Procedure SysRunCompleteHandler (Const AResult : TRunSummary);
  2401. begin
  2402. if (CurrentRunMode=rvQuiet) then exit;
  2403. if (CurrentRunMode=rvFailures) then
  2404. begin
  2405. Writeln(FSys^,SFailedCount,': ',AResult.TestsFailed);
  2406. exit;
  2407. end;
  2408. Writeln(FSys^);
  2409. Write(FSys^,SRunSummary,':');
  2410. if HaveTimeHook then
  2411. Writeln(FSys^,' ',SysTimeString(AResult.ElapsedTime))
  2412. else
  2413. Writeln(FSys^);
  2414. Write(FSys^,' ',SSuitesSummary,':');
  2415. With AResult do
  2416. if CurrentRunMode=rvVerbose then
  2417. begin
  2418. Writeln(FSys^);
  2419. Writeln(FSys^,' ',SRunCount,': ',SuitesRun);
  2420. Writeln(FSys^,' ',SFailedCount,': ',SuitesFailed);
  2421. Writeln(FSys^,' ',SInactiveCount,': ',SuitesInactive);
  2422. end
  2423. else
  2424. Writeln(FSys^,' ',SRunCount,': ',SuitesRun,' ',SFailedCount,': ',SuitesFailed,' ',SInactiveCount,': ',SuitesInactive);
  2425. Write(FSys^,' ',STestsSummary,':');
  2426. With AResult do
  2427. if CurrentRunMode=rvVerbose then
  2428. begin
  2429. Writeln(FSys^);
  2430. Writeln(FSys^,' ',SRunCount,': ',TestsRun);
  2431. Writeln(FSys^,' ',SInactiveCount,': ',TestsInactive);
  2432. Writeln(FSys^,' ',SFailedCount,': ',TestsFailed);
  2433. Writeln(FSys^,' ',SIgnoredCount,': ',TestsIgnored);
  2434. if RequirePassed then
  2435. Writeln(FSys^,' ',SUnimplementedCount,': ',TestsUnimplemented);
  2436. end
  2437. else
  2438. begin
  2439. Write(FSys^,' ',SRunCount,': ',TestsRun,' ',SFailedCount,': ',TestsFailed,' ',SInactiveCount,': ',TestsInactive,' ',SIgnoredCount,': ',TestsIgnored);
  2440. if RequirePassed then
  2441. Writeln(FSys^,' ',SUnimplementedCount,': ',TestsUnimplemented)
  2442. else
  2443. Writeln(FSys^);
  2444. end;
  2445. Flush(FSys^);
  2446. end;
  2447. Procedure SysSuiteSetupFailedHandler (ASuite : PSuite; Const AError : TTestString);
  2448. begin
  2449. If (CurrentRunMode=rvVerbose) then
  2450. Writeln(FSys^,SSuiteSetupFailed,' : ',ASuite^.Name,' : ',AError)
  2451. end;
  2452. Procedure SysSuiteTearDownFailedHandler (ASuite : PSuite; Const AError : TTestString);
  2453. begin
  2454. If (CurrentRunMode=rvVerbose) then
  2455. Writeln(FSys^,SSuiteTeardownFailed,' : ',ASuite^.Name,' : ',AError)
  2456. end;
  2457. procedure SetupSysIO;
  2458. begin
  2459. FSys:=@Output;
  2460. CurrentRunmode:=rvNormal;
  2461. end;
  2462. procedure SetupSysHandlers;
  2463. begin
  2464. // Run
  2465. SetRunStartHandler(@SysRunStartHandler);
  2466. SetRunCompleteHandler(@SysRunCompleteHandler);
  2467. // Suite
  2468. SetSuiteCompleteHandler(@SysSuiteCompleteHandler);
  2469. SetSuiteStartHandler(@SysSuiteStartHandler);
  2470. SetSuiteSetupFailureHandler(@SysSuiteSetupFailedHandler);
  2471. SetSuiteTearDownFailureHandler(@SysSuiteTearDownFailedHandler);
  2472. // Test
  2473. SetTestStartHandler(@SysTestStartHandler);
  2474. SetTestCompleteHandler(@SysTestCompleteHandler);
  2475. end;
  2476. procedure TearDownSysHandlers;
  2477. begin
  2478. {$I-}
  2479. Close(LogFile);
  2480. {$I+}
  2481. ClearTestHooks;
  2482. end;
  2483. function GetSysRunVerbosity: TSysRunVerbosity;
  2484. begin
  2485. Result:=CurrentRunMode;
  2486. end;
  2487. function SetSysRunVerbosity(AMode: TSysRunVerbosity): TSysRunVerbosity;
  2488. begin
  2489. Result:=CurrentRunMode;
  2490. CurrentRunMode:=AMode;
  2491. end;
  2492. Function FullSuiteName(ASuite : PSuite) : AnsiString;
  2493. begin
  2494. Result:='';
  2495. While (ASuite<>Nil) do
  2496. begin
  2497. If (Result<>'') then
  2498. Result:='.'+Result;
  2499. Result:=ASuite^.Name+Result;
  2500. ASuite:=ASuite^.ParentSuite;
  2501. end;
  2502. end;
  2503. Procedure SysListTests(ASuiteList : PSuiteList; ASuite : Psuite; ATest : PTest);
  2504. Var
  2505. I,J : Integer;
  2506. S : PSuite;
  2507. T : PTest;
  2508. begin
  2509. if ASuiteList=Nil then
  2510. exit;
  2511. For i:=0 to ASuiteList^.Count-1 do
  2512. begin
  2513. S:=ASuiteList^.Items[I];
  2514. If (ASuite=Nil) or (ASuite=S) then
  2515. Begin
  2516. if (CurrentRunMode=rvVerbose) then
  2517. Writeln(FSys^,SSuite,': ',FullSuiteName(S));
  2518. // First, list all sub suites.
  2519. SysListTests(@S^.Suites,ASuite,ATest);
  2520. For J:=0 to S^.Tests.Count-1 do
  2521. begin
  2522. T:=S^.Tests.Items[J];
  2523. If (ATest=Nil) or (ATest=T) then
  2524. begin
  2525. if (CurrentRunMode=rvVerbose) then
  2526. Write(FSys^,' ',STest,': ');
  2527. Writeln(FSys^,FullSuiteName(S),'.',T^.Name);
  2528. end;
  2529. end;
  2530. end;
  2531. end;
  2532. end;
  2533. procedure ProcessSysCommandline;
  2534. Var
  2535. i: Integer;
  2536. S: TTestString;
  2537. Function TestO(Const Short,Long: TTestString) : Boolean;
  2538. Var
  2539. L : Integer;
  2540. LO : String;
  2541. begin
  2542. Result:=(S='-'+Short);
  2543. if Result then
  2544. begin
  2545. Inc(I);
  2546. S:=Paramstr(i);
  2547. end
  2548. else
  2549. begin
  2550. Lo:='--'+Long+'=';
  2551. L:=Length(Lo);
  2552. Result:=(Copy(S,1,L)=LO);
  2553. if Result then
  2554. Delete(S,1,L);
  2555. end;
  2556. end;
  2557. begin
  2558. SysRunMode:=rmTest;
  2559. I:=1;
  2560. While I<=ParamCount do
  2561. begin
  2562. S:=ParamStr(i);
  2563. if (S='-v') or (S='--verbose') then
  2564. SetSysRunVerbosity(rvverbose)
  2565. else if (S='-q') or (S='--quiet') then
  2566. SetSysRunVerbosity(rvQuiet)
  2567. else if (S='-n') or (S='--normal') then
  2568. SetSysRunVerbosity(rvNormal)
  2569. else if (S='-f') or (S='--failures') then
  2570. SetSysRunVerbosity(rvFailures)
  2571. else if (S='-l') or (S='--list') then
  2572. SysRunMode:=rmList
  2573. else if (S='-h') or (S='--help') then
  2574. SysRunMode:=rmHelp
  2575. else if TestO('o','output') then
  2576. begin
  2577. If (S='') then
  2578. begin
  2579. S:=ParamStr(0)
  2580. end;
  2581. SysOutputFileName:=S;
  2582. end
  2583. else if TestO('s','suite') then
  2584. SysSuiteName:=S
  2585. else if TestO('t','test') then
  2586. SysTestName:=S;
  2587. Inc(i);
  2588. end;
  2589. if (SysOutputFileName<>'') then
  2590. begin
  2591. {$i-}
  2592. Close(LogFile);
  2593. Assign(LogFile,SysOutputFileName);
  2594. Rewrite(LogFile);
  2595. if (IOResult<>0) then
  2596. FSys:=@LogFile
  2597. else
  2598. CurrentRunMode:=rvQuiet
  2599. {$i+}
  2600. end
  2601. else
  2602. end;
  2603. Procedure SysShowHelp;
  2604. begin
  2605. Writeln(SUsage);
  2606. Writeln(SHelpF);
  2607. Writeln(SHelpH);
  2608. Writeln(SHelpL);
  2609. Writeln(SHelpN);
  2610. Writeln(SHelpO);
  2611. Writeln(SHelpQ);
  2612. Writeln(SHelpS);
  2613. Writeln(SHelpT);
  2614. Writeln(SHelpV);
  2615. If HaveTimeHook then
  2616. Writeln(SHelpHasTime)
  2617. else
  2618. Writeln(SHelpNoTime);
  2619. Writeln(SHelpExitCodes);
  2620. Writeln(SHelpExit0);
  2621. Writeln(SHelpExit1);
  2622. Writeln(SHelpExit2);
  2623. Writeln(SHelpExit3);
  2624. Writeln(SHelpExit4);
  2625. Writeln(SHelpExit5);
  2626. end;
  2627. procedure DoRunSysTests(S: PSuite; T: PTest);
  2628. Var
  2629. r : TTestError;
  2630. begin
  2631. Case SysRunMode of
  2632. rmHelp:
  2633. begin
  2634. SysShowHelp;
  2635. Halt(0);
  2636. end;
  2637. rmList:
  2638. begin
  2639. SysListTests(@TestRegistry,S,T);
  2640. Halt(0);
  2641. end;
  2642. rmTest:
  2643. begin
  2644. if Assigned(T) then
  2645. R:=RunTest(S,T)
  2646. else if Assigned(S) then
  2647. R:=RunSuite(S)
  2648. else
  2649. R:=RunAllTests;
  2650. If (R<>teOK) then
  2651. Halt(5)
  2652. else
  2653. SysHalt;
  2654. end;
  2655. end;
  2656. end;
  2657. procedure RunAllSysTests;
  2658. Var
  2659. S : PSuite;
  2660. T : PTest;
  2661. P : Integer;
  2662. begin
  2663. S:=Nil;
  2664. T:=Nil;
  2665. ProcessSysCommandline;
  2666. P:=Pos('.',SysTestName);
  2667. if (P>0) then
  2668. begin
  2669. SysSuiteName:=Copy(SysTestName,1,P-1);
  2670. Delete(SysTestName,1,P);
  2671. P:=Pos('.',SysTestName);
  2672. While P<>0 do
  2673. begin
  2674. SysSuiteName:=SysSuiteName+'.'+Copy(SysTestName,1,P-1);
  2675. Delete(SysTestName,1,P);
  2676. P:=Pos('.',SysTestName);
  2677. end;
  2678. end;
  2679. if (SysSuiteName<>'') then
  2680. begin
  2681. S:=GetSuite(SysSuiteName);
  2682. if (S=Nil) then
  2683. Halt(3);
  2684. end;
  2685. if (SysTestName<>'') then
  2686. begin
  2687. if (S=Nil) then
  2688. begin
  2689. S:=GetSuite(DefaultSuiteName);
  2690. if (S=Nil) then
  2691. Halt(3);
  2692. end;
  2693. T:=GetTest(S,SysTestName);
  2694. if (T=Nil) then
  2695. Halt(4);
  2696. end;
  2697. DoRunSysTests(S,T);
  2698. end;
  2699. { EFail }
  2700. Constructor EFail.Create(Const AMessage: TTestString);
  2701. begin
  2702. FMessage:=AMessage;
  2703. end;
  2704. Function EFail.ToString: RTLString;
  2705. begin
  2706. Result:=FMessage;
  2707. end;
  2708. function GetSysTestOS: TTestString;
  2709. begin
  2710. GetSysTestOS := lowercase({$I %FPCTARGETOS%});
  2711. end;
  2712. function SysGetSetting(const AName: TTestString): TTestString;
  2713. Procedure Trim(Var S : TTestString);
  2714. begin
  2715. While (S<>'') and (S[1] in [' ',#9]) do Delete(S,1,1);
  2716. While (S<>'') and (S[Length(S)] in [' ',#9]) do S:=Copy(S,1,Length(S)-1);
  2717. end;
  2718. Var
  2719. F : Text;
  2720. I: Integer;
  2721. FN,N,V : TTestString;
  2722. begin
  2723. Result:='';
  2724. FN:=paramstr(0);
  2725. I:=Length(Fn);
  2726. While (I>0) and (FN[I]<>DirectorySeparator) do
  2727. Dec(I);
  2728. FN:=Copy(FN,1,I);
  2729. Assign(f,FN+'punit.cfg');
  2730. {$i-}
  2731. Reset(f);
  2732. if IOResult<>0 then
  2733. exit;
  2734. {$i+}
  2735. While (Result='') and not EOF(F) do
  2736. begin
  2737. ReadLn(F,V);
  2738. N:='';
  2739. I:=Pos('=',V);
  2740. if I>0 then
  2741. begin
  2742. N:=Copy(V,1,I-1);
  2743. Delete(V,1,I);
  2744. end;
  2745. if (N<>'') and (Pos(';',N)<>1) and (Pos('#',N)<>1) then
  2746. begin
  2747. Trim(N);
  2748. If upcase(N)=upcase(AName) then
  2749. begin
  2750. Result:=V;
  2751. Trim(Result);
  2752. end;
  2753. end;
  2754. end;
  2755. Close(F);
  2756. end;
  2757. initialization
  2758. SetupSysIO;
  2759. SetupTestRegistry;
  2760. SetupSysHandlers;
  2761. finalization
  2762. TearDownSysHandlers;
  2763. TearDownTestRegistry;
  2764. ResetRun(CurrentRun);
  2765. end.