ITADN
coderaiser/go-tape
README.md

Tape License Build Status Coverage Status

📼 Supertape for Go — same assertions, same philosophy: one assertion per test, check for duplicates etc.

Install

go install github.com/coderaiser/go-tape/cmd/tape@latest

Usage

tape [options] [path]
tape ./...
tape ./internal/...

API

Import the package aliased as Test to get the Test(...), Test.Only(...), and Test.Skip(...) syntax that mirrors supertape:

import (
    "testing"
    . "github.com/coderaiser/go-tape"
)

func TestEqual(t *testing.T) {
    Test(t, "tape: Equal works", func(t *T) {
        t.Equal(42, 42)
        t.End()
    })
}

func TestNotEqual(t *testing.T) {
    Test(t, "tape: NotEqual works", func(t *T) {
        t.NotEqual(1, 2)
        t.End()
    })
}

func TestOk(t *testing.T) {
    Test(t, "tape: Ok works", func(t *T) {
        t.Ok(true)
        t.End()
    })
}

func TestNotOk(t *testing.T) {
    Test(t, "tape: NotOk works", func(t *T) {
        t.NotOk(false)
        t.End()
    })
}

func TestDeepEqual(t *testing.T) {
    Test(t, "tape: DeepEqual works", func(t *T) {
        t.DeepEqual([]int{1, 2}, []int{1, 2})
        t.End()
    })
}

func TestMatch(t *testing.T) {
    Test(t, "tape: Match works", func(t *T) {
        t.Match("hello 123", `hello \d+`)
        t.End()
    })
    func TestMatch(t *testing.T) {
    Test(t, "tape: Match: RegExp", func(t *T) {
        t.Match("hello 123", regexp.MustCompile(`hello \d+`))
        t.End()
    })
    Test(t, "tape: Match: string", func(t *T) {
        t.Match("hello 123", `hello`)
        t.End()
    })
}

}

func TestComment(t *testing.T) {
    Test(t, "tape: Comment does not count as assertion", func(t *T) {
        t.Comment("just a note")
        t.Ok(true)
        t.End()
    })
}

Test.Only

Run a single test, skipping all others — identical to supertape's test.only:

func TestParser(t *testing.T) {
    Test.Only(t, "parser: run action", func(t *T) {
        t.Ok(true)
        t.End()
    })
    Test(t, "parser: other test", func(t *T) {
        // skipped — only the above runs
        t.Ok(true)
        t.End()
    })
}

tape detects Test.Only calls via AST scan and passes a -run filter to go test automatically. No changes to the test command needed.

Test.Skip

Skip a single test without removing it:

func TestParser(t *testing.T) {
    Test.Skip(t, "parser: known broken", func(t *T) {
        t.Ok(false) // never runs
        t.End()
    })
    Test(t, "parser: works fine", func(t *T) {
        t.Ok(true)
        t.End()
    })
}

Extend

Create a custom assertion type that wraps *Test.T:

type MyT struct{ *T }

func (t *MyT) FileExists(path string) {
    t.TB().Helper()
    _, err := os.Stat(path)
    t.NotOk(err)
}

var MyTest = Test.Extend(func(base *Test.T) *MyT {
    return &MyT{T: base}
})

func TestFiles(t *testing.T) {
    MyTest(t, "files: config exists", func(t *MyT) {
        t.FileExists("config.toml")
        t.End()
    })
}

CLI

Usage: go-tape [options] [path]

Options:
  -h                           display this help and exit
  -v                           output version information and exit
  -f, --format format          use a specific output format
                               default: progress-bar (tap on CI)
                               values: tap|progress-bar|short|fail|time|json-lines
  --no-check-scopes            do not check that messages contain scope: 'scope: message'
  --no-check-assertions-count  do not check that assertion count is no more than 1
  --no-check-duplicates        do not check messages for duplicates

Environment variables

VariableDescription
TAPE_PROGRESS_BARForce progress bar on (1) or off (0)
TAPE_PROGRESS_BAR_MINMinimum test count to show progress bar (default: 10)
TAPE_PROGRESS_BAR_COLORProgress bar color — hex (#f9d472) or ANSI escape
TAPE_PROGRESS_BAR_STACKSet to 0 to hide error stack traces
TAPE_TERM_WIDTHOverride terminal width for the progress bar
TAPE_TIMEOUTPer-test timeout (default: 5s, e.g. TAPE_TIMEOUT=30s)
TAPE_CHECK_SCOPESSet to 0 to disable scope format check
TAPE_CHECK_ASSERTIONS_COUNTSet to 0 to allow more than one assertion per test
TAPE_CHECK_ENDSet to 0 to allow omitting t.End()
TAPE_CHECK_SKIPPEDSet to 1 to exit with error when skipped tests exist
TAPE_TIME_CLOCKOverride the clock emoji used by the time formatter

License

MIT