Skip to content

Latest commit

 

History

History
518 lines (442 loc) · 29.3 KB

File metadata and controls

518 lines (442 loc) · 29.3 KB

Package sztest

Example Contents

Contents

Appendix F: Large Example Function

This example shows several of the types of checks this library is designed to assist with. Suppose we have the following function:

cat ./large_example_function/example.go
// Package example demonstrates a larger test function.
package example

import (
    "fmt"
    "log"
)

// Process returns known changes to its parameters for testing.
func Process(factor int, msg string) (int, string, float64) {
    const mulFactor = 2
    const aThird = 1.0 / 3.0
    // Function being tested.
    log.Printf("Entered process(%d, %q)", factor, msg)

    if factor < 1 || factor > 10 {
        log.Panicf("factor (%d) out of bounds: %q", factor, msg)
    }

    fmt.Println("Processing with factor:", factor, "and message:", msg)

    return factor * mulFactor, "Processed: " + msg, float64(factor) * aThird
}

we could test all of the expected outputs with the following test (with passing and failing version)s

cat ./large_example_function/example_test.go
package example

import (
    "testing"

    "github.com/dancsecs/sztest"
)

// Passing test.
func Test_PASS_GeneralForm(t *testing.T) {
    chk := sztest.CaptureLogAndStdout(t)
    defer chk.Release()

    chk.FailFast(false) // Don't exit test on first failure.

    // Test panic condition.
    chk.Panic(
        func() {
            Process(0, "failing message")
        },
        "factor (0) out of bounds: \"failing message\"",
    )

    // Test valid operation.
    gotInt, gotStr, gotFloat := Process(2, "Hello")

    chk.Int(gotInt, 4)
    chk.Str(gotStr, "Processed: Hello")
    chk.Float64(gotFloat, 0.6666, 0.0005) // Tolerance (± 0.0005)

    // Check output.
    chk.Stdout(
        "Processing with factor: 2 and message: Hello",
    )

    // Check logging.
    chk.Log(chk.TrimAll(`
      Entered process(0, "failing message")
      factor (0) out of bounds: "failing message"
      Entered process(2, "Hello")
  `))
}

// Failing test.
func Test_FAIL_GeneralForm(t *testing.T) {
    chk := sztest.CaptureLogAndStdout(t)
    defer chk.Release()

    chk.FailFast(false) // Don't exit test on first failure.

    // Test panic condition.
    chk.Panic(
        func() {
            Process(0, "failing message")
        },
        "factor (0) out of bounds: \"wrong message\"",
    )

    // Test valid operation.
    gotInt, gotStr, gotFloat := Process(2, "Hello")

    chk.Int(gotInt, 3)
    chk.Str(gotStr, "Hello", "missing", " ", `"Processed"`, " ", "prefix")
    // Tolerance (± 0.0005)
    chk.Float64f(gotFloat, 0.6661, 0.0005, "off by %f", 0.6661-0.6665)

    // Check output.
    chk.Stdout(
        "Processing with factor: 2 and message: Processed Hello",
    )

    // Check logging.
    chk.Log(chk.TrimAll(`
      Entered process(0, "wrong message")
      factor (0) out of bounds: "wrong message"
      Entered process(2, "Processed Hello")
  `))
}

causing the following output when these tests are run:

go test -v -cover ./large_example_function

$\small{\texttt{=== ͏ ͏RUN ͏ ͏ ͏ ͏ ͏ ͏Test ̲ ̲PASS ̲ ̲GeneralForm}}$
$\small{\texttt{‒‒‒ ͏ ͏PASS: ͏ ͏ ͏ ͏Test ̲ ̲PASS ̲ ̲GeneralForm ͏ ͏(0.0s)}}$
$\small{\texttt{=== ͏ ͏RUN ͏ ͏ ͏ ͏ ͏ ͏Test ̲ ̲FAIL ̲ ̲GeneralForm}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:52: ͏ ͏unexpected ͏ ͏panic:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}factor ͏ ͏(0) ͏ ͏out ͏ ͏of ͏ ͏bounds: ͏ ͏"{\color{darkturquoise}{faili}}ng ͏ ͏message"}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}factor ͏ ͏(0) ͏ ͏out ͏ ͏of ͏ ͏bounds: ͏ ͏"{\color{darkturquoise}{wro}}ng ͏ ͏message"}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:62: ͏ ͏unexpected ͏ ͏int:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}{\color{darkturquoise}{4}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}{\color{darkturquoise}{3}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:63: ͏ ͏unexpected ͏ ͏string:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\emph{missing ͏ ͏"Processed" ͏ ͏prefix}}:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}{\color{green}{Processed: ͏ ͏}}Hello}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}Hello}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:65: ͏ ͏unexpected ͏ ͏float64(+/- ͏ ͏0.0005):}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\emph{off ͏ ͏by ͏ ͏-0.000400}}:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}0.666{\color{darkturquoise}{6666666666666}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}0.666{\color{darkturquoise}{1}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:68: ͏ ͏Unexpected ͏ ͏stdout ͏ ͏Entry: ͏ ͏got ͏ ͏(1 ͏ ͏lines) ͏ ͏- ͏ ͏want ͏ ͏(1 ͏ ͏lines)}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{darkturquoise}{0}}:{\color{darkturquoise}{0}} ͏ ͏Processing ͏ ͏with ͏ ͏factor: ͏ ͏2 ͏ ͏and ͏ ͏message: ͏ ͏{\color{red}{Processed ͏ ͏}}Hello}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:73: ͏ ͏Unexpected ͏ ͏log ͏ ͏Entry: ͏ ͏got ͏ ͏(3 ͏ ͏lines) ͏ ͏- ͏ ͏want ͏ ͏(3 ͏ ͏lines)}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{darkturquoise}{0}}:{\color{darkturquoise}{0}} ͏ ͏Entered ͏ ͏process(0, ͏ ͏"{\color{red}{wro}}{\color{yellow}{/}}{\color{green}{faili}}ng ͏ ͏message")}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{darkturquoise}{1}}:{\color{darkturquoise}{1}} ͏ ͏factor ͏ ͏(0) ͏ ͏out ͏ ͏of ͏ ͏bounds: ͏ ͏"{\color{red}{wro}}{\color{yellow}{/}}{\color{green}{faili}}ng ͏ ͏message"}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{darkturquoise}{2}}:{\color{darkturquoise}{2}} ͏ ͏Entered ͏ ͏process(2, ͏ ͏"{\color{red}{Processed ͏ ͏}}Hello")}}$
$\small{\texttt{‒‒‒ ͏ ͏FAIL: ͏ ͏ ͏ ͏Test ̲ ̲FAIL ̲ ̲GeneralForm ͏ ͏(0.0s)}}$
$\small{\texttt{FAIL}}$
$\small{\texttt{coverage: ͏ ͏100.0﹪ ͏ ͏of ͏ ͏statements}}$
$\small{\texttt{FAIL ͏ ͏github.com/dancsecs/sztest/examples/appendix/large ̲ ̲example ̲ ̲function ͏ ͏0.0s}}$
$\small{\texttt{FAIL}}$

Contents

Appendix G: Large Example Main Function

Given the following main.go file:

cat ./large_example_main_function/main.go
package main

import (
    "flag"
    "fmt"
    "log"
    "math"
    "strconv"
    "strings"
)

const radiansPerDegree = math.Pi / 180.0
const degreesPerRadian = 180.0 / math.Pi
const bits64 = 64
const numDecimals = 6

func makeReport(degrees, radians float64, useRadians, verbose bool) []string {
    var rep []string
    addToReport := func(v float64, name string) {
        line := strconv.FormatFloat(v, 'f', numDecimals, bits64)
        if verbose {
            arg := ""
            if !useRadians {
                arg = strconv.FormatFloat(degrees, 'f', numDecimals, bits64) + "°"
            } else {
                arg = strconv.FormatFloat(radians, 'f', numDecimals, bits64)
            }
            line = name + "(" + arg + ") = " + line
        }
        rep = append(rep, line)
    }
    addToReport(math.Sin(radians), "Sin")
    addToReport(math.Cos(radians), "Cos")
    return rep
}

// Program takes an angle and reports its Sin and Cos values.
// -v causes a more detailed response.
// -r cause the angle input to be interrupted as radians.
func main() {
    var degrees, radians float64

    verbose := flag.Bool("v", false, "More detailed information.")
    useRadians := flag.Bool("r", false, "Value is in radians.")

    flag.Parse()

    if flag.NArg() != 1 {
        log.Panic("angle required")
    }
    v, err := strconv.ParseFloat(flag.Args()[0], bits64)

    if err != nil {
        log.Panicf("invalid angle: %s", flag.Args()[0])
    }

    if *useRadians {
        degrees = degreesPerRadian * v
        radians = v
    } else {
        degrees = v
        radians = radiansPerDegree * v
    }

    if *verbose {
        if *useRadians {
            fmt.Printf("Report on %f radians (%f degrees)\n", radians, degrees)
        } else {
            fmt.Printf("Report on %f degrees (%f radians)\n", degrees, radians)
        }
    }

    fmt.Print(
        strings.Join(makeReport(degrees, radians, *useRadians, *verbose), "\n"),
        "\n",
    )
}

we can provide 100% test coverage with the following test file showing both successful and failing responses:

cat ./large_example_main_function/main_test.go
package main

import (
    "fmt"
    "log"
    "math"
    "strconv"
    "testing"

    "github.com/dancsecs/sztest"
)

func Test_PASS_Main_No_Args(t *testing.T) {
    chk := sztest.CaptureLogWithStderrAndStdout(t)
    defer chk.Release()

    log.Println("Testing missing angle")
    chk.SetArgs("progname")
    chk.Panic(
        main,
        "angle required",
    )

    log.Println("Testing invalid angle")
    chk.SetArgs("progname", "notANumber")
    chk.Panic(
        main,
        "invalid angle: notANumber",
    )

    fmt.Println("Testing angle 0 no flags")
    chk.SetArgs("progname", "0")
    chk.NoPanic(main)

    fmt.Println("Testing angle 0 with verbose flag")
    chk.SetArgs("progname", "-v", "0")
    chk.NoPanic(main)

    twoPi := strconv.FormatFloat(math.Pi*2, 'f', -1, 64)
    fmt.Println("Testing angle 2Pi with radian flag")
    chk.SetArgs("progname", "-r", twoPi)
    chk.NoPanic(main)

    fmt.Println("Testing angle 2Pi with radian and verbose flag")
    chk.SetArgs("progname", "-v", "-r", twoPi)
    chk.NoPanic(main)

    chk.Stdout(
        "Testing angle 0 no flags",
        "0.000000",
        "1.000000",
        "Testing angle 0 with verbose flag",
        "Report on 0.000000 degrees (0.000000 radians)",
        "Sin(0.000000°) = 0.000000",
        "Cos(0.000000°) = 1.000000",
        "Testing angle 2Pi with radian flag",
        "-0.000000",
        "1.000000",
        "Testing angle 2Pi with radian and verbose flag",
        "Report on 6.283185 radians (360.000000 degrees)",
        "Sin(6.283185) = -0.000000",
        "Cos(6.283185) = 1.000000",
    )
    chk.Log(
        "Testing missing angle",
        "angle required",
        //
        "Testing invalid angle",
        "invalid angle: notANumber",
        //
    )
}

func Test_FAIL_Main_No_Args(t *testing.T) {
    chk := sztest.CaptureLogWithStderrAndStdout(t)
    defer chk.Release()

    chk.FailFast(false) // Do not terminate function on first error.

    log.Println("Testing missing angle")
    chk.SetArgs("progname")
    chk.Panic(
        main,
        "angle is required",
    )

    log.Println("Testing invalid angle")
    chk.SetArgs("progname", "notANumber")
    chk.Panic(
        main,
        "invalid angle: not A Number",
    )

    fmt.Println("Testing angle 0 no flags")
    chk.SetArgs("progname", "0")
    chk.NoPanic(main)

    fmt.Println("Testing angle 0 with verbose flag")
    chk.SetArgs("progname", "-v", "0")
    chk.NoPanic(main)

    twoPi := strconv.FormatFloat(math.Pi*2, 'f', -1, 64)
    fmt.Println("Testing angle 2Pi with radian flag")
    chk.SetArgs("progname", "-r", twoPi)
    chk.NoPanic(main)

    fmt.Println("Testing angle 2Pi with radian and verbose flag")
    chk.SetArgs("progname", "-v", "-r", twoPi)
    chk.NoPanic(main)

    chk.Stdout(
        "Testing angle 0 no flags",
        "0.000000",
        "1.000000",
        "Testing angle 0 with verbose flag",
        "Report on 0.000000 degrees (0.000000 radians)",
        "Sin(0.000000°) = 0.000000",
        "Cos(0.000000°) = 1.000000",
        "Testing angle 2PI with radian flag",
        "-0.000000",
        "1.000000",
        "Testing angle 2Pi with radian and verbose flag",
        "Report on 6.283185 radians (360.000000 degrees)",
        "Sin(6.283185) = -0.000000",
        "Cos(6.283185) = 1.000000",
    )
    chk.Log(
        "Testing missing angle",
        "angle is required",
        //
        "Testing invalid angle",
        "invalid angle: not A Number",
        //
    )
}
go test -v -cover ./large_example_main_function

$\small{\texttt{=== ͏ ͏RUN ͏ ͏ ͏ ͏ ͏ ͏Test ̲ ̲PASS ̲ ̲Main ̲ ̲No ̲ ̲Args}}$
$\small{\texttt{‒‒‒ ͏ ͏PASS: ͏ ͏ ͏ ͏Test ̲ ̲PASS ̲ ̲Main ̲ ̲No ̲ ̲Args ͏ ͏(0.0s)}}$
$\small{\texttt{=== ͏ ͏RUN ͏ ͏ ͏ ͏ ͏ ͏Test ̲ ̲FAIL ̲ ̲Main ̲ ̲No ̲ ̲Args}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏main ̲ ̲test.go:82: ͏ ͏unexpected ͏ ͏panic:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}angle ͏ ͏required}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}angle{\color{red}{ ͏ ͏is}} ͏ ͏required}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏main ̲ ̲test.go:89: ͏ ͏unexpected ͏ ͏panic:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}invalid ͏ ͏angle: ͏ ͏not{\color{darkturquoise}{A}}Number}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}invalid ͏ ͏angle: ͏ ͏not{\color{darkturquoise}{ ͏ ͏A ͏ ͏}}Number}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏main ̲ ̲test.go:111: ͏ ͏Unexpected ͏ ͏stdout ͏ ͏Entry: ͏ ͏got ͏ ͏(14 ͏ ͏lines) ͏ ͏- ͏ ͏want ͏ ͏(14 ͏ ͏lines)}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏00:00 ͏ ͏Testing ͏ ͏angle ͏ ͏0 ͏ ͏no ͏ ͏flags}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏01:01 ͏ ͏0.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏02:02 ͏ ͏1.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏03:03 ͏ ͏Testing ͏ ͏angle ͏ ͏0 ͏ ͏with ͏ ͏verbose ͏ ͏flag}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏04:04 ͏ ͏Report ͏ ͏on ͏ ͏0.000000 ͏ ͏degrees ͏ ͏(0.000000 ͏ ͏radians)}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏05:05 ͏ ͏Sin(0.000000°) ͏ ͏= ͏ ͏0.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏06:06 ͏ ͏Cos(0.000000°) ͏ ͏= ͏ ͏1.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{darkturquoise}{07}}:{\color{darkturquoise}{07}} ͏ ͏Testing ͏ ͏angle ͏ ͏2P{\color{red}{I}}{\color{yellow}{/}}{\color{green}{i}} ͏ ͏with ͏ ͏radian ͏ ͏flag}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏08:08 ͏ ͏-0.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏09:09 ͏ ͏1.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏10:10 ͏ ͏Testing ͏ ͏angle ͏ ͏2Pi ͏ ͏with ͏ ͏radian ͏ ͏and ͏ ͏verbose ͏ ͏flag}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏11:11 ͏ ͏Report ͏ ͏on ͏ ͏6.283185 ͏ ͏radians ͏ ͏(360.000000 ͏ ͏degrees)}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏12:12 ͏ ͏Sin(6.283185) ͏ ͏= ͏ ͏-0.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏13:13 ͏ ͏Cos(6.283185) ͏ ͏= ͏ ͏1.000000}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏main ̲ ̲test.go:127: ͏ ͏Unexpected ͏ ͏logWithStderr ͏ ͏Entry: ͏ ͏got ͏ ͏(4 ͏ ͏lines) ͏ ͏- ͏ ͏want ͏ ͏(4 ͏ ͏lines)}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏0:0 ͏ ͏Testing ͏ ͏missing ͏ ͏angle}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{darkturquoise}{1}}:{\color{darkturquoise}{1}} ͏ ͏angle{\color{red}{ ͏ ͏is}} ͏ ͏required}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏2:2 ͏ ͏Testing ͏ ͏invalid ͏ ͏angle}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{darkturquoise}{3}}:{\color{darkturquoise}{3}} ͏ ͏invalid ͏ ͏angle: ͏ ͏not{\color{red}{ ͏ ͏A ͏ ͏}}{\color{yellow}{/}}{\color{green}{A}}Number}}$
$\small{\texttt{‒‒‒ ͏ ͏FAIL: ͏ ͏ ͏ ͏Test ̲ ̲FAIL ̲ ̲Main ̲ ̲No ̲ ̲Args ͏ ͏(0.0s)}}$
$\small{\texttt{FAIL}}$
$\small{\texttt{coverage: ͏ ͏100.0﹪ ͏ ͏of ͏ ͏statements}}$
$\small{\texttt{FAIL ͏ ͏github.com/dancsecs/sztest/examples/appendix/large ̲ ̲example ̲ ̲main ̲ ̲function ͏ ͏0.0s}}$
$\small{\texttt{FAIL}}$

Contents