' Gambas module file Export Property Read Printer As TapPrinter Property Output As Stream Property Read Session As TapContext Property Read Finished As Boolean Property _Next As TestAssertion Private $hPrinter As New TapPrinter Private $hNext As TestAssertion ''' The static procedure Test.Main() starts test(s). '' Runs all tests in all testcontainers and prints the result to the console. '' With Test.Main(NameTestModule) the tests can be restricted to only those of a single test module. '' With Test.Main(NameTestModule, NameProcedure) only a single test can be accomplished. Public Sub Main(Optional Tests As String) Test.Reset() ' only if you run this Main multiple times per process, which you shouldn't RunTests(Tests) PrintSummary() End Private Sub PrintSummary() 'needed for debugging, to doubleclick on it Dim Session As TapContext Session = Test.Session With Session Test.Print(gb.Lf) ' better readability for humans Test.Note(Subst$(("&2 - ran: '&1' "), .Summary.Description, IIf(.Summary.Success, "PASSED", "FAILED"))) If .TestsRun <> .Plan Then Test.Note(Subst$(("Planned &1 tests but ran &2"), .Plan, .TestsRun)) Test.Note(gb.Lf) If Not .Summary.Success Then ShowTestCollection(("&1 tests failed:"), FindFailures(.Summary.Subtests, "")) ShowTestCollection(("&1 tests skipped:"), FindSkips(.Summary.Subtests, "")) ShowTestCollection(("&1 tests todo:"), FindTodos(.Summary.Subtests, "")) ShowTestCollection(("&1 tests bonus:"), FindBonus(.Summary.Subtests, "")) End With End '' Prints a Collection[] of tests as returned by FindFailures, FindSkips, FindTodos. '' _Description_ can contain '&1' which is substituted for _TestCollection_.Count. Private Sub ShowTestCollection(Description As String, TestCollection As Collection[]) Dim cTest As Collection If TestCollection.Count Then Test.Note(Subst$(Description, TestCollection.Count)) For Each cTest In TestCollection Dim hTest As TestAssertion = cTest!Assertion Test.Note(Subst$(("&2: &1 -- &3 &4"), cTest["Path"], hTest.Id, hTest.Description, IIf(hTest.Comment, "# " & hTest.Comment, ""))) Next Test.Note(gb.Lf) Endif End Private Function FindFailures(Tests As TestAssertion[], Prefix As String) As Collection[] Dim hTest As TestAssertion Dim sName As String Dim aRet As New Collection[] For Each hTest In Tests sName = Prefix &/ hTest.Description ' Only show the deepest subtests that caused failures. If Not hTest.Success And If Not hTest.Subtests.Count Then aRet.Add(["Path": Prefix, "Assertion": hTest]) aRet.Insert(FindFailures(hTest.Subtests, sName)) Next Return aRet End Private Function FindSkips(Tests As TestAssertion[], Prefix As String) As Collection[] Dim hTest As TestAssertion Dim sName As String Dim aRet As New Collection[] For Each hTest In Tests sName = Prefix &/ hTest.Description If hTest.Directive = Tap.SKIP Then aRet.Add(["Path": Prefix, "Assertion": hTest]) aRet.Insert(FindSkips(hTest.Subtests, sName)) Next Return aRet End Private Function FindTodos(Tests As TestAssertion[], Prefix As String) As Collection[] Dim hTest As TestAssertion Dim sName As String Dim aRet As New Collection[] For Each hTest In Tests sName = Prefix &/ hTest.Description If hTest.Directive = Tap.TODO And If Not hTest.Ok Then aRet.Add(["Path": Prefix, "Assertion": hTest]) aRet.Insert(FindTodos(hTest.Subtests, sName)) Next Return aRet End Private Function FindBonus(Tests As TestAssertion[], Prefix As String) As Collection[] Dim hTest As TestAssertion Dim sName As String Dim aRet As New Collection[] For Each hTest In Tests sName = Prefix &/ hTest.Description If hTest.Directive = Tap.TODO And If hTest.Ok Then aRet.Add(["Path": Prefix, "Assertion": hTest]) aRet.Insert(FindBonus(hTest.Subtests, sName)) Next Return aRet End '' Run all tests, optional limited by Container or TestCaseName. Track contains . Private Function RunTests(Tests As String) Dim aTestCommands As TestCommand[] Dim sTestModule As String Dim TestModule As Class Dim Suite As New TestSuite aTestCommands = TestCommand.ParseCommands(Tests) For Each sTestModule In GetAllTestModules(aTestCommands) TestModule = Class.Load(sTestModule) Suite.AddAllTestCases(TestModule, aTestCommands) Next Test.Session.Summary.Description = Tests Suite.Run() If Not Test.Finished Then Test.Finish() End Function GetAllTestModules(Commands As TestCommand[]) As String[] Dim TestClass As Class Dim TestModuleNames As New String[] Dim sNames As New String[] Dim sName As String Dim Command As TestCommand If Exist(".../.test") sNames = Split(File.Load(".../.test"), gb.Lf, Null, True) Endif Assert sNames sNames.Sort For Each sName In sNames TestClass = Class.Load(sName) If Not TestClass Then Error.Raise(Subst$(("Could not load test module '&1'"), sName)) If TestModuleNames.Exist(sName) Then Continue If Commands.Count = 0 Then 'Add every Testmodule TestModuleNames.Add(sName) Else 'Add only testmodules whose names exist in Commands For Each Command In Commands If Not sNames.Exist(Command.ModuleName) Then Test.BailOut(Subst$(("There is no test called &1."), Command.ModuleName)) Endif If Lower(Command.ModuleName) = Lower(sName) Then TestModuleNames.Add(sName) Endif Next Endif Next TestModuleNames.Sort Return TestModuleNames Catch Test.BailOut("Error in " & Error.Where & ": " & Error.Text) End ' ------------------------------------------------- Test controls Public Sub BailOut(Optional Comment As String) $hPrinter.BailOut(Comment) Quit 1 End '' Synonym for Note Public Sub Diagnostic(Comment As String) $hPrinter.Diagnostic(Comment) End '' Synonym for Diagnostic Public Sub Note(Comment As String) $hPrinter.Note(Comment) End Public Sub Print({Line} As String) $hPrinter.Print({Line}) End Private Function Printer_Read() As TapPrinter Return $hPrinter End Private Function Output_Read() As Stream Return $hPrinter.Output End Private Sub Output_Write(Value As Stream) $hPrinter.Output = Value End Private Function Session_Read() As TapContext Return $hPrinter.Session End Private Function Finished_Read() As Boolean Return $hPrinter.Session.Finished End Public Sub Reset() $hPrinter = New TapPrinter As "Printer" End Private Function _Next_Read() As TestAssertion If $hNext = Null Then $hNext = New TestAssertion Endif Return $hNext End Private Sub _Next_Write(Value As TestAssertion) $hNext = Value End Public Sub Subtest(Description As String, Optional Tests As Integer, Optional Comment As String) Test.Printer.Subtest(Description, Tests, Comment) End Public Sub Plan(Tests As Integer, Optional Comment As String) Test.Printer.Plan(Tests, Comment) End Public Sub SkipAll(Optional Comment As String) Test.Printer.SkipAll(Comment) End Public Sub Finish() Test.Printer.Finish() End