' Gambas class file ''' Assertions which print TAP. Export Create Static Public Struct Subtest Printer As TapPrinter Description As String Indent As Integer Success As Boolean ' Directive to apply to the next "ok" line Directive As Integer Comment As String End Struct Private $aActiveTests As New Subtest[] Private $hCurrent As New Subtest Public Sub _new() With $hCurrent = New Subtest .Printer = New TapPrinter As "Printer" .Indent = 0 .Success = True .Directive = Tap.NONE End With End Public Sub Setup(Optional Tests As Integer, Optional Comment As String, Optional {Output} As Stream) If IsMissing({Output}) Then {Output} = $hCurrent.Printer.Output If Not {Output} Then {Output} = File.Out Endif $hCurrent.Printer.Output = {Output} Plan(Tests, Comment) End Public Sub Subtest(Description As String, Optional Tests As Integer) Dim iIndent As Integer = $hCurrent.Indent $aActiveTests.Push($hCurrent) With $hCurrent = New Subtest .Printer = New TapPrinter As "Printer" .Description = Description .Indent = iIndent + 1 .Success = True .Directive = Tap.NONE End With If Tests Then Plan(Tests) End Public Sub Finish() Dim hFinished As Subtest $hCurrent.Printer.Finish() hFinished = $hCurrent Try $hCurrent = $aActiveTests.Pop() If Not Error Then $hCurrent.Printer.Test(hFinished.Success,, hFinished.Description) Endif End Public Sub Printer_Filter() Last.Line = String$($hCurrent.Indent, "\t") & Last.Line End Public Sub Plan(Tests As Integer, Optional Comment As String) $hCurrent.Printer.Plan(Tests, Comment) End Public Sub Ok(Result As Boolean, Optional Description As String) As Boolean With $hCurrent If .Directive <> Tap.NONE Then .Printer.Test(Result,, Description, .Directive, .Comment) Else .Printer.Test(Result,, Description) .Success = .Success And Result Endif .Directive = Tap.NONE .Comment = Null End With Return Result End Public Sub Todo(Optional Comment As String) $hCurrent.Directive = Tap.TODO $hCurrent.Comment = Comment End Public Sub Skip(Optional Comment As String) $hCurrent.Directive = Tap.SKIP $hCurrent.Comment = Comment Ok(True) End Public Sub Diagnostic(Comment As String) $hCurrent.Printer.Diagnostic(Comment) End Public Sub Note(Comment As String) Diagnostic(Comment) End Public Sub Print({Line} As String) $hCurrent.Printer.Print({Line}) End ' -------------------- High-level test functions -------------------- Public Sub Pass(Optional Description As String) As Boolean Return Ok(True, Description) End Public Sub Fail(Optional Description As String) As Boolean Return Ok(False, Description) End Public Sub NotOk(Result As Boolean, Optional Description As String) As Boolean Return Ok(Not Result, Description) End Public Sub Equals(Got As Variant, Expected As Variant, Optional Description As String) As Boolean Return Ok(Got = Expected, Description) End Public Sub NotEquals(Got As Variant, UnExpected As Variant, Optional Description As String) As Boolean Return Ok(Got <> UnExpected, Description) End Public Sub LessEqual(Got As Variant, Bound As Variant, Optional Description As String) As Boolean Return Ok(Got <= Bound, Description) End Public Sub Less(Got As Variant, Bound As Variant, Optional Description As String) As Boolean Return Ok(Got < Bound, Description) End Public Sub GreaterEqual(Got As Variant, Bound As Variant, Optional Description As String) As Boolean Return Ok(Got >= Bound, Description) End Public Sub Greater(Got As Variant, Bound As Variant, Optional Description As String) As Boolean Return Ok(Got > Bound, Description) End Public Sub Approximate(Got As Float, Expected As Float, Precision As Float, Optional Description As String) As Boolean Return Ok(Abs(Got - Expected) <= Precision, Description) End Public Sub RelativeApproximate(Got As Float, Expected As Float, RelPrecision As Float, Optional Description As String) As Boolean Return Ok(Abs((Got - Expected) / Expected) <= RelPrecision, Description) End Public Sub IsType(Got As Variant, Type As Integer, Optional Description As String) As Boolean Return Ok(TypeOf(Got) = Type, Description) End Public Sub Null(Got As Variant, Optional Description As String) As Boolean Return Equals(Got, Null, Description) End Public Sub NotNull(Got As Variant, Optional Description As String) As Boolean Return NotEquals(Got, Null, Description) End Public Sub Like(Got As String, Pattern As String, Optional Description As String) As Boolean Return Ok(Got Like Pattern, Description) End Public Sub Match(Got As String, Pattern As String, Optional Description As String) As Boolean Return Ok(Got Match Pattern, Description) End Public Sub StringEquals(Got As String, Expected As String, Optional Description As String) As Boolean Dim bRes As Boolean Dim iPos As Integer bRes = Equals(Got, Expected, Description) If Not bRes Then If Len(Got) <> Len(Expected) Then Note(("Strings are of different length.")) Note(Subst$((" Got: &1"), Len(Got))) Note(Subst$((" Expected: &1"), Len(Expected))) Endif For iPos = 1 To Min(Len(Got), Len(Expected)) If Mid$(Got, iPos, 1) <> Mid$(Expected, iPos, 1) Then Break Next Note(Subst$(("Strings differ at position &1"), iPos)) Note(Subst$((" Got: &1"), Quote$(Mid$(Got, iPos, 20)) & IIf(Len(Got) > iPos + 20, "...", ""))) Note(Subst$((" Expected: &1"), Quote$(Mid$(Expected, iPos, 20)) & IIf(Len(Expected) > iPos + 20, "...", ""))) Endif Return bRes End Public Sub Error(Optional Description As String) As Boolean Return Ok( Error , Description) End Public Sub ErrorCode(Code As Integer, Optional Description As String) As Boolean Dim bRes As Boolean If Not Error Then bRes = Fail(Description) Note(("No error happened")) Else bRes = Equals(Error.Code, Code) If Not bRes Then Note(Subst$(("Error was: &1 (code: &2) at &3"), Error.Text, Error.Code, Error.Where)) Endif Endif Error.Clear() Return bRes End Public Sub NotError(Optional Description As String) As Boolean Dim bRes As Boolean bRes = Ok(Not Error , Description) If Not bRes Then Note(Subst$(("Error was: &1 (code: &2) at &3"), Error.Text, Error.Code, Error.Where)) Endif Error.Clear() Return bRes End