44a6c2462a
[GB.TEST] * NEW: Show bad plans in summary. * BUG: Set recently added TestAssertion properties from TapPrinter as well.
200 lines
5.4 KiB
Text
200 lines
5.4 KiB
Text
' Gambas class file
|
|
|
|
''' Low-level class for planning and printing test results in Test Anything Protocol ([TAP]) format.
|
|
'''
|
|
''' [TAP]: http://testanything.org/tap-specification.html
|
|
|
|
Event Filter
|
|
|
|
Property {Output} As Stream Use $hOutput
|
|
Property Read Session As TapContext
|
|
|
|
Property Line As String Use $sLine
|
|
|
|
Private $aSubtests As New TapContext[]
|
|
Private $hCurrent As New TapContext
|
|
|
|
Public Sub _new(Optional Tests As Integer, Optional Comment As String, Optional {Output} As Stream = File.Out)
|
|
|
|
$hOutput = {Output}
|
|
With $hCurrent
|
|
.Plan = Test.NO_PLAN
|
|
.TestsRun = 0
|
|
.LastId = 0
|
|
.Finished = False
|
|
End With
|
|
If Not IsMissing(Tests) Then Plan(Tests, Comment)
|
|
|
|
End
|
|
|
|
Public Sub Subtest(Description As String, Optional Tests As Integer, Optional Comment As String)
|
|
|
|
Print(Subst$("Test &1", Description))
|
|
$aSubtests.Push($hCurrent)
|
|
With $hCurrent = New TapContext
|
|
.Summary.Description = Description
|
|
.Summary.Comment = Comment
|
|
.Plan = Test.NO_PLAN
|
|
.TestsRun = 0
|
|
.LastId = 0
|
|
.Finished = False
|
|
End With
|
|
If Tests Then Plan(Tests)
|
|
|
|
End
|
|
|
|
Public Sub Plan(Tests As Integer, Optional Comment As String)
|
|
|
|
With $hCurrent
|
|
If .Finished Or .SkipAll Then Error.Raise(("Tests already finished"))
|
|
If .TestsRun Then Error.Raise(Subst$(("Too late to plan. Already ran &1 tests"), .TestsRun))
|
|
' TAP specification lists '1..0 # Skipped: WWW::Mechanize not installed'
|
|
' as a valid example.
|
|
If Tests <= Test.NO_PLAN Then Error.Raise(("Number of tests must be non-negative"))
|
|
.Plan = Tests
|
|
End With
|
|
Print(Subst$("1..&1&2", Tests, IIf(Comment, " # " & Comment, "")))
|
|
|
|
End
|
|
|
|
Public Sub SkipAll(Optional Comment As String)
|
|
|
|
Plan(0, "SKIP" & IIf(Comment, " ", "") & Comment)
|
|
$hCurrent.SkipAll = True
|
|
|
|
End
|
|
|
|
Public Sub Finish()
|
|
|
|
Dim hFinished As TapContext
|
|
|
|
With $hCurrent
|
|
Dim hTest As TestAssertion
|
|
|
|
If .Finished Then Error.Raise(("Tests already finished"))
|
|
|
|
' Print a plan line after the fact
|
|
If .Plan = Test.NO_PLAN Then
|
|
.Plan = .TestsRun
|
|
Print("1.." & .Plan)
|
|
Endif
|
|
|
|
' Sum up this subtest
|
|
.Finished = True
|
|
.Summary.SubPlanned = .Plan
|
|
.Summary.SubSkippedAll = .SkipAll
|
|
.Summary.Ok = (.Plan > 0 Or .SkipAll) And (.TestsRun = .Plan)
|
|
For Each hTest In .Summary.Subtests
|
|
.Summary.Ok = .Summary.Ok And hTest.Success
|
|
Next
|
|
End With
|
|
|
|
' Go one level up if possible. Unless we are the top-level test,
|
|
' we add one assertion for this finishing subtest.
|
|
hFinished = $hCurrent
|
|
Try $hCurrent = $aSubtests.Pop()
|
|
If Not Error Then
|
|
Assert(hFinished.Summary)
|
|
Endif
|
|
|
|
End
|
|
|
|
Public Sub Assert(Assertion As TestAssertion) As TestAssertion
|
|
|
|
Dim sDirective As String
|
|
Dim sLine As String
|
|
|
|
With Assertion
|
|
If $hCurrent.Finished Or $hCurrent.SkipAll Then Error.Raise(("Tests already finished"))
|
|
|
|
' It is not advised to start a description with a number token because
|
|
' it will be interpreted as the (optional) test ID. We issue a warning
|
|
' about this but fix it anyway by always printing the ID before *and*
|
|
' prefixing the Description with a dash, as is common.
|
|
If .Description Match "^[0-9]+(\\s|$)" Then
|
|
Error Subst$(("Warning: Description '&1' should not start with a number"), .Description)
|
|
Endif
|
|
' If .Description Like "*#*" Then
|
|
' Error.Raise(Subst$(("Description '&1' may not contain a '#' character"), .Description))
|
|
' Endif
|
|
|
|
Inc $hCurrent.TestsRun
|
|
If Not .Id Then .Id = $hCurrent.TestsRun
|
|
$hCurrent.LastId = .Id
|
|
sLine = Subst$("&1 &2 - &3", IIf(.Ok, "ok", "not ok"), .Id, .Description)
|
|
|
|
If .Directive <> TestAssertion.NONE Then
|
|
' Matches the values of the Enum TestAssertion.TODO, TestAssertion.SKIP
|
|
sDirective = Choose(.Directive, "TODO", "SKIP")
|
|
If Not sDirective Then Error.Raise(Subst$(("Unsupported directive '&1'"), .Directive))
|
|
sLine &= " # " & sDirective
|
|
If .Comment Then sLine &= " " & .Comment
|
|
Endif
|
|
End With
|
|
|
|
Print(sLine)
|
|
$hCurrent.Summary.Subtests.Push(Assertion)
|
|
Return Assertion
|
|
|
|
End
|
|
|
|
'' Unwinds the subtest stack. BailOut will always bail out of all the subtests.
|
|
Private Sub Unwind()
|
|
|
|
While $aSubtests.Count > 0
|
|
Note("Unwinding subtest stack!")
|
|
Finish()
|
|
Wend
|
|
|
|
End
|
|
|
|
Public Sub BailOut(Optional Comment As String)
|
|
|
|
Unwind()
|
|
'The string "Bail out!" must not be changed!
|
|
Print("Bail out!" & IIf(Comment, " " & Comment, ""))
|
|
$hCurrent.Finished = True
|
|
|
|
End
|
|
|
|
Public Sub Diagnostic(Comment As String)
|
|
|
|
Dim sLine As String
|
|
|
|
' Split on these doesn't do what I mean: on the empty string, we get
|
|
' zero lines, on a newline we get two. I want one in both cases.
|
|
If Not Comment Or If Comment = gb.Lf Then
|
|
Print("#")
|
|
Return
|
|
Endif
|
|
|
|
For Each sLine In Split(Comment, "\n")
|
|
Print("# " & sLine)
|
|
Next
|
|
|
|
End
|
|
|
|
Public Sub Note(Comment As String)
|
|
|
|
Diagnostic(Comment)
|
|
|
|
End
|
|
|
|
Public Sub Print({Line} As String)
|
|
|
|
Dim bCancel As Boolean
|
|
|
|
$sLine = {Line}
|
|
bCancel = Raise Filter
|
|
If bCancel Then Return
|
|
Print #$hOutput, String$($aSubtests.Count, " "); $sLine
|
|
Flush #$hOutput
|
|
|
|
End
|
|
|
|
Private Function Session_Read() As TapContext
|
|
|
|
If $aSubtests.Count Then Return $aSubtests[0]
|
|
Return $hCurrent
|
|
|
|
End
|