Skip to content

Readable Go tests made simple — with assertions, colorful diffs, deterministic clocks, I/O shims, and full output capture.

License

Notifications You must be signed in to change notification settings

dancsecs/sztest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

80 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Package sztest

package sztest

Package sztest provides a self-contained test helper library built entirely on the Go standard library. It is designed to make tests cleaner, more readable, and more reliable, while offering features that go beyond the default testing framework.

Core features include:

  • Uniform assertions across all built-in types, with consistent reporting.
  • Automatic diffs on failure, rendered with ANSI colors for clarity. Diff behavior is configurable, including character- and line-window sizes.
  • Flow control with FailFast, allowing tests to stop on the first error or continue gathering results.
  • String helpers (Str, Strf) for concise assertions on string values.
  • Support for slice comparisons and interval checks (bounded and unbounded).
  • Error and panic assertions for verifying expected failures.
  • Output capture of stdout, stderr, and package logs, with diffs against expected results.
  • Temporary resource and environment variable helpers to isolate tests.
  • I/O interface shims (io.Reader, io.Writer, io.Seeker, io.Closer) for simulating success and failure modes in code under test.
  • Clock utilities to capture and format test timestamps in multiple layouts.
  • Full integration with testing.T through a minimal internal interface, enabling sztest to be tested itself with complete coverage.
  • The library executes with negligible overhead making it practical for continuous test driven development without breaking flow.

The library emphasizes a minimal usage pattern:

chk := sztest.CaptureNothing(t)
defer chk.Release()
chk.Str(got, wnt)

By keeping the API uniform and predictable, sztest helps reduce boilerplate and highlight only what matters in a test: the behavior being verified.


Dedication

This project is dedicated to Reem. Your brilliance, courage, and quiet strength continue to inspire me. Every line is written in gratitude for the light and hope you brought into my life.


NOTE: Documentation reviewed and polished with the assistance of ChatGPT from OpenAI.


Contents

Usage

A'*sztest.Chk' object is created in the test function by calling one of the sztest.Capture* functions and then deferring its Release() method to run on the completion of the test function. Common got/want type testing is provided for all go builtin types as well as some common aliases and interfaces.

Example: General Form

cat ./examples/general_form/example_test.go
package example

import (
    "testing"

    "github.com/dancsecs/sztest"
)

func Test_PASS_GeneralForm(t *testing.T) {
    chk := sztest.CaptureNothing(t)
    defer chk.Release()

    s1 := "Value Got/Wnt"
    s2 := "Value Got/Wnt"

    chk.Str(s1, s2)
    chk.Str(s1, s2, "unformatted", " message", " not", " displayed")
    chk.Strf(s1, s2, "formatted %s %s %s", "message", "not", "displayed")
}

func Test_FAIL_GeneralForm(t *testing.T) {
    chk := sztest.CaptureNothing(t)
    defer chk.Release()

    chk.FailFast(false) // Do not stop on first problem.

    s1 := "Value Got"
    s2 := "Value Wnt"

    chk.Str(s1, s2)
    chk.Str(s1, s2, "unformatted", " message", " displayed")
    chk.Strf(s1, s2, "formatted %s %s", "message", "displayed")
}
go test -v -cover ./examples/general_form

$\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:30: ͏ ͏unexpected ͏ ͏string:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}Value ͏ ͏{\color{darkturquoise}{Got}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}Value ͏ ͏{\color{darkturquoise}{Wnt}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:31: ͏ ͏unexpected ͏ ͏string:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\emph{unformatted ͏ ͏message ͏ ͏displayed}}:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}Value ͏ ͏{\color{darkturquoise}{Got}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}Value ͏ ͏{\color{darkturquoise}{Wnt}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏example ̲ ̲test.go:32: ͏ ͏unexpected ͏ ͏string:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\emph{formatted ͏ ͏message ͏ ͏displayed}}:}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{magenta}{GOT: ͏ ͏}}Value ͏ ͏{\color{darkturquoise}{Got}}}}$
$\small{\texttt{ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏{\color{cyan}{WNT: ͏ ͏}}Value ͏ ͏{\color{darkturquoise}{Wnt}}}}$
$\small{\texttt{‒‒‒ ͏ ͏FAIL: ͏ ͏ ͏ ͏Test ̲ ̲FAIL ̲ ̲GeneralForm ͏ ͏(0.0s)}}$
$\small{\texttt{FAIL}}$
$\small{\texttt{coverage: ͏ ͏[no ͏ ͏statements]}}$
$\small{\texttt{FAIL ͏ ͏github.com/dancsecs/sztest/examples/general ̲ ̲form ͏ ͏0.0s}}$
$\small{\texttt{FAIL}}$

The *sztest.Chk object is created without capturing anything with the Release method being deferred until the function exits (This opening pattern will be used by all test functions). There are three string tests. The first two pass but the third fails producing the highlighted test differences.

Contents

Builtin Got/Wnt Checks

The most basic test is to compare something "Got" from the code being tested to the "Wnt" expected by the test. If the values do not exactly match an error is registered for the test using the (testing.T.Error) function and the error is displayed as exampled above. Got/Want functions are provided for all core data types as well as some aliases and interfaces. The general forms are:

func (*CHK) Type(got, wnt Type, msg ...any) bool
func (*CHK) Typef(got, wnt Type, msgFmt string, msgArgs ...any) bool

/*
Were Type is one of:

    // Basic Types
        Bool,
        Byte,
        Complex64, Complex128
        Float32, Float64,  // Includes extra tolerance parameter.
        Int, Int8, Int16, Int32, Int64,
        Rune, Str,
        Uint, Uint8, Uint16 , Uint32, Uint64,
        Uintptr

    // Aliases.
        Dur  // time.Duration
*/

providing for an optional message and returning true if the test passed.

Contents

Array Slices

Array slice tests are provided for all core data types. The arrays must match exactly (except for float types which have a tolerance argument) otherwise a failure will be registered. The general forms are:

func (*CHK) TypeSlice(got, wnt []Type, msg ...any)
func (*CHK) TypeSlicef(got, wnt []Type, fmtMsg string, msgArgs ...any)

/*
Were Type is one of:

    // Basic Types
        Bool,
        Byte,
        Complex64, Complex128,
        Float32, Float64,  // Includes extra tolerance parameter.
        Int, Int8, Int16, Int32, Int64,
        Rune, Str,
        Uint, Uint8, Uint16 , Uint32, Uint64,
        Uintptr

    // Aliases
        Dur  // time.Duration
*/

with error slices tested with:

// Errors NOTE:  Got/Wnt are different types.
func (*Chk) ErrSlice(got []error, wnt []string, msg ...any) bool

For a complete list of builtin got/wnt slice tests and their helpers see Appendix C: List of got/wnt slice test methods.

Contents

Bounded Intervals

These tests compare a comparable got against a range of values. The general forms are:

// BoundedOption specifies the inclusivity of bounds in a closed interval
// check.
type BoundedOption int
// List of bounded options.
const (
    // BoundedOpen checks (a,b) = { x | a < x < b }.
    BoundedOpen BoundedOption = iota

    // BoundedClosed checks [a,b] = { x | a <= x <= b }.
    BoundedClosed

    // BoundedMinOpen checks (a,b] = { x | a < x <= b }.
    // Alias of BoundedMaxClosed.
    BoundedMinOpen

    // BoundedMaxClosed checks (a,b] = { x | a < x <= b }.
    // Alias of BoundedMinOpen.
    BoundedMaxClosed

    // BoundedMaxOpen checks [a,b) = { x | a <= x < b }.
    // Alias of BoundedMinClosed.
    BoundedMaxOpen

    // BoundedMinClosed checks [a,b) = { x | a <= x < b }.
    // Alias of BoundedMaxOpen.
    BoundedMinClosed
)
func (*CHK) TypeBounded(got Type, option BoundedOption,  min, max Type, msg ...any)
func (*CHK) TypeBoundedf(got Type, option BoundedOption,  min, max Type, fmtMsg string, msgArgs ...any)

/*
Were Type is one of:

    // Basic Types
        Byte,
        Float32, Float64,
        Int, Int8, Int16, Int32, Int64,
        Rune, Str,
        Uint, Uint8, Uint16 , Uint32, Uint64

    // Aliases
        Dur  // time.Duration
*/

Contents

Unbounded Intervals

These tests compare a comparable got against a range of values. The general forms are:

// UnboundedOption specifies the inclusivity of bounds in a half-infinite
// interval check.
type UnboundedOption int
// 
const (
    // UnboundedMinOpen checks (a,+∞) = { x | x > a }.
    UnboundedMinOpen UnboundedOption = iota

    // UnboundedMinClosed checks [a,+∞) = { x | x >= a }.
    UnboundedMinClosed

    // UnboundedMaxOpen checks (-∞, b) = { x | x < b }.
    UnboundedMaxOpen

    // UnboundedMaxClosed checks (-∞, b] = { x | x <= b }.
    UnboundedMaxClosed
)
func (*CHK) TypeUnbounded(got Type, option UnboundedOption, bound Type, msg ...any)
func (*CHK) TypeUnboundedf(got Type, option UnboundedOption, bound Type, fmtMsg string, msgArgs ...any)

/*
Were Type is one of:

    // Basic Types
        Byte,
        Float32, Float64,
        Int, Int8, Int16, Int32, Int64,
        Rune, Str,
        Uint, Uint8, Uint16 , Uint32, Uint64

    // Aliases
        Dur  // time.Duration
*/

Contents

Errors

Error conditions are checked using the following method:

func (chk *Chk) Err(got error, want string, msg ...any) bool

and its helper methods:

func (chk *Chk) Errf(got error, want string, msgFmt string, msgArgs ...any) bool
func (chk *Chk) NoErr(got error, msg ...any) bool
func (chk *Chk) NoErrf(got error, msgFmt string, msgArgs ...any) bool

Please note with these methods the got and wnt are different data types with the got being an error and the wnt being a string. So what happens if the error is not nil but empty?

errors.New("")

then the error returned is represented by the constant

const BlankErrorMessage = "sztest.BlankErrorMessage"

Contents

Panics

Insuring that your code properly terminates when it encounters an untenable state is important to verify. To facilitate this the library defines a panic check function:

func (chk *Chk) Panic(gotF func(), want string, msg ...any) bool

where gotF is a function that is expected to issue a panic and wnt is the string representation of the expected panic. An empty ("") wnt string represents that no panic should be thrown. The string

const BlankPanicMessage = "sztest.BlankPanicMessage"

is returned to represent an empty ("") panic was thrown differentiating it from no panic being thrown.

There are three helper functions:

func (chk *Chk) Panicf(gotF func(), want string, msgFmt string, msgArgs ...any) bool
func (chk *Chk) NoPanic(gotF func(), msg ...any) bool
func (chk *Chk) NoPanicf(gotF func(), msgFmt string, msgArgs ...any) bool

Contents

Output

Programs writing to standard outputs (os.Stdout, os.Stderr) and the go log package (which may be distinct from os.Stderr) can have the outputs captured and reviewed as part of testing. This can be to confirm failing conditions are properly logged and reported as part of full testing.

Each can be captured individually or the log package and os.Stderr can be combined together into a single captured feed. Selection of the feeds is instantiated when the check object is initially created. See Appendix A: Capture* creation functions for a complete list.

Contents

IO Interface

The check object implements some io interfaces permitting easy simulation of hard to duplicate error and panic situations. IO interface methods implemented by the *Chk object are:

func (chk *Chk) Seek(_ int64, _ int) (int64, error)
func (chk *Chk) Read(dataBuf []byte) (int, error)
func (chk *Chk) Write(data []byte) (int, error)
func (chk *Chk) Close() error

Each of the above functions can have errors set to be returned on the next call with the following methods:

func (chk *Chk) SetReadError(pos int, err error)
func (chk *Chk) SetWriteError(pos int, err error)
func (chk *Chk) SetSeekError(pos int64, err error)
func (chk *Chk) SetCloseError(err error)

Once set the next call to the corresponding io method (read, Write ,Seek, Close or a composition function) will return the pos and error provided. The error is cleared so subsequent calls result in the default action.

Data for read actions (and position errors) is setup using the following methods:

func (chk *Chk) SetIOReaderData(d ...string)
func (chk *Chk) SetIOReaderError(byteCount int, err error)

The data will be returned (one byte at time) until the data is exhausted resulting in an io.EOF error or the optional byteCount is reached then the supplied error will be returned.

Data written can be retrieved using the following method:

func (chk *Chk) GetIOWriterData() []byte

while a positional error condition can be setup to be returned when the nth byte is written. This is setup with:

func (chk *Chk) SetIOWriterError(n int, err error)

Contents

Arguments And Flags

In order to test main default argument processing, test args and a clean flag environment are implemented with:

func (chk *Chk) SetArgs(progName string, args ...string)

where both os.Args and flags.CommandLine are saved and replaced with the provided args and a NewFlagSet respectively. Original vales are restored when the chk.Release() method is called. NOTE: The new default flag set is set to panicOnError.

Contents

Environment Variables

System environment variables mat be set or deleted using the following:

func (chk *Chk) SetEnv(name, value string)
func (chk *Chk) DelEnv(name string)

Original values are restores when the chk.Release() method is called.

Contents

Temporary directories, files, scripts

Testing underlying os file interfacing code can be somewhat automated by using some builtin helpers. Directories, files and scripts created through *chk methods will be automatically deleted on a successful test. The items are not deleted on failure or if the following helper method is invoked from the test.

func (chk *Chk) KeepTmpFiles()

The default temporary dir for the current test function is both created and identified with:

func (chk *Chk) CreateTmpDir() string

directly (or indirectly by one of these helper functions)

func (chk *Chk) CreateTmpFile(data []byte) string
func (chk *Chk) CreateTmpFileIn(path string, data []byte) string
func (chk *Chk) CreateTmpFileAs(path, fName string, data []byte) string
func (chk *Chk) CreateTmpUnixScript(lines []string) string
func (chk *Chk) CreateTmpUnixScriptIn(path string, lines []string) string
func (chk *Chk) CreateTmpUnixScriptAs(path, fName string, lines []string) string
func (chk *Chk) CreateTmpSubDir(subDirs ...string) string

which all return the path constructed by creating a new sub directory in the default temp directory.

This can be set using the environment variable:

SZTEST_TMP_DIR="/custom/tmp"

or set from within the test with:

func (chk *Chk) SetTmpDir(dir string) string

otherwise it defaults to

os.TempDir()

Permissions used when creating these objects can be defined with the following environment variables

SZTEST_PERM_DIR="0700"
SZTEST_PERM_FILE="0600"
SZTEST_PERM_EXE="0700"

or from within the test with:

func (chk *Chk) SetPermDir(p os.FileMode) os.FileMode
func (chk *Chk) SetPermFile(p os.FileMode) os.FileMode
func (chk *Chk) SetPermExe(p os.FileMode) os.FileMode

Contents

Timestamps

Predictable timestamps are provided to permit full testing of applications using timestamps. In order to facilitate this the application must use its own timestamp function pointer that defaults to be the standardtime.Now function and can be replaced by the the testing clock function (*Chk).ClockNext.

Replacing the internal time.Now method is possible using an external monkey patch library such as go-mpatch using something similar to:

//  ...

import (
   "github.com/dancsecs/sztest"
   "github.com/undefinedlabs/go-mpatch"
)

func Test_UsesTimeStamps(t *testing) {
  chk:=sztest.CaptureStdout(t)
  defer chk.Release()

  patch,err:=mpatch.PatchMethod(time.Now, chk.ClockNext)
  chk.NoErr(err)
  defer func() {
    _ = patch.Unpatch()
  }()

  // Run tests that use golang's default time.Now function.
  // ...
}

Chk.ClockNext may be invoked indirectly with the formatting convenience methods:

func (chk *Chk) ClockNextFmtTime() string
func (chk *Chk) ClockNextFmtDate() string
func (chk *Chk) ClockNextFmtTS() string
func (chk *Chk) ClockNextFmtNano() string
func (chk *Chk) ClockNextFmtCusA() string
func (chk *Chk) ClockNextFmtCusB() string
func (chk *Chk) ClockNextFmtCusC() string

As timestamps are generated they are saved and can be queried with the function:

func (chk *Chk) ClockTick(i int) time.Time

ClockTick returns the i'th time value that was generated by the test clock.

Further chk substitutions can be generated for each timestamp produced including up to three custom date formats with the following constants and methods:

// ClkFmt represents supported clock formats.
type ClkFmt int
// Clock formats and substitutions.
// Substitution strings allow clock ticks to be referenced in output and
// string assertions. If the corresponding format is enabled, {{clkXXXX#}}
// is replaced with the tick at the given sequence index (#):
// 
//     ClkFmtTime  {{clkTime#}} // HHmmSS
//     ClkFmtDate  {{clkDate#}} // YYYYMMDD
//     ClkFmtTS    {{clkTS#}}   // YYYYMMDDHHmmSS
//     ClkFmtNano  {{clkNano#}} // YYYYMMDDHHmmSS.#########
//     ClkFmtCusA  {{clkCusA#}} // custom format string
//     ClkFmtCusB  {{clkCusB#}} // custom format string
//     ClkFmtCusC  {{clkCusC#}} // custom format string
// 
// Multiple substitution formats can be active at once, since the format
// flags are combined bitwise.
const (
    ClkFmtNone ClkFmt = 0         // No formats.
    ClkFmtTime ClkFmt = 1 << iota // {{clkTime#}} = HHmmSS.
    ClkFmtDate                    // {{clkDate#}} = YYYYMMDD.
    ClkFmtTS                      // {{clkTS#}}   = YYYYMMDDHHmmSS.
    ClkFmtNano                    // {{clkNano#}} = YYYYMMDDHHmmSS.#########.
    ClkFmtCusA                    // {{clkCusA#}} = definable format string.
    ClkFmtCusB                    // {{clkCusB#}} = definable format string.
    ClkFmtCusC                    // {{clkCusC#}} = definable format string.

    ClkFmtAll = math.MaxInt // All defined formats.
)
func (chk *Chk) ClockSetSub(clkFmt ClkFmt)

ClockSetSub replaces the active substitution formats with the specified set.

func (chk *Chk) ClockAddSub(clkFmt ClkFmt)

ClockAddSub enables an additional substitution format.

func (chk *Chk) ClockRemoveSub(clkFmt ClkFmt)

ClockRemoveSub disables a previously enabled substitution format.

func (chk *Chk) ClockSetCusA(f string)

ClockSetCusA defines the format string used for {{clkCusA#}} substitutions. The format must follow Go’s time layout conventions.

func (chk *Chk) ClockSetCusB(f string)

ClockSetCusB defines the format string used for {{clkCusB#}} substitutions. The format must follow Go’s time layout conventions.

func (chk *Chk) ClockSetCusC(f string)

ClockSetCusC defines the format string used for {{clkCusC#}} substitutions. The format must follow Go’s time layout conventions.

The time (and increments used between successive timestamps) can be set with:

func (chk *Chk) ClockSet(newTime time.Time, inc ...time.Duration) func()

ClockSet assigns a new base time for the test clock and, if provided, updates the sequence of increments. When multiple increments are supplied, they are applied in order and wrap around once exhausted.

It returns a reset function that restores the clock to its previous state, intended for use with defer. Internally, the last time recorded is initialized to newTime minus the final increment.

or

func (chk *Chk) ClockOffsetDay(dayOffset int, inc ...time.Duration) func()

ClockOffsetDay shifts the test clock by the specified number of days. Negative values move the clock into the past. Optional increments may also be supplied, applied in the same cycling manner as ClockSet.

It returns a reset function that restores the clock to its prior state, intended for use with defer. Internally, the last time recorded is initialized to newTime minus the final increment.

or the clock can be adjusted with:

func (chk *Chk) ClockOffset(d time.Duration, inc ...time.Duration) func()

ClockOffset shifts the test clock by the specified duration. Optional increments may also be supplied, applied in the same cycling manner as ClockSet.

It returns a reset function that restores the clock to its prior state, intended for use with defer. Internally, the last time recorded is initialized to newTime minus the final increment.

while the last time returned can e retrieved with:

func (chk *Chk) ClockLast() time.Time

ClockLast returns the most recent timestamp generated by the test clock.

or the formatting convenience methods:

func (chk *Chk) ClockLastFmtTime() string
func (chk *Chk) ClockLastFmtDate() string
func (chk *Chk) ClockLastFmtTS() string
func (chk *Chk) ClockLastFmtNano() string
func (chk *Chk) ClockLastFmtCusA() string
func (chk *Chk) ClockLastFmtCusB() string
func (chk *Chk) ClockLastFmtCusC() string

Contents

Appendices

Appendix A: List of sztest.Capture* Create Functions

func CaptureNothing(t testingT) *Chk

CaptureNothing returns a *Chk that performs no output capturing.

Use this when a test needs the sztest helper object but does not need to capture stdout, stderr, or the package logger. The supplied t must be a testing helper (*testing.T).

Always defer chk.Release() to ensure any modified global state is restored and temporary resources are cleaned up.

func CaptureStdout(t testingT) *Chk

CaptureStdout returns a *Chk that captures os.Stdout.

Call (*Chk).Stdout(wantLines...) to assert the captured stdout before calling chk.Release(). After Release the captured data is no longer available.

func CaptureLog(t testingT) *Chk

CaptureLog returns a *Chk that captures the package logger (log.Writer()).

Call (*Chk).Log(wantLines...) to assert captured log output before calling chk.Release().

func CaptureLogAndStdout(t testingT) *Chk

CaptureLogAndStdout returns a *Chk that captures both log.Writer() and os.Stdout.

Use (*Chk).Log(...) to assert the logger output and (*Chk).Stdout(...) to assert stdout. Perform these checks before calling chk.Release().

func CaptureLogAndStderr(t testingT) *Chk

CaptureLogAndStderr returns a *Chk that captures log.Writer() and os.Stderr.

Use (*Chk).Log(...) to assert the logger output and (*Chk).Stderr(...) to assert stderr. Perform these checks before calling chk.Release().

func CaptureLogAndStderrAndStdout(t testingT) *Chk

CaptureLogAndStderrAndStdout returns a *Chk that captures the package logger, os.Stderr and os.Stdout.

Assert the captured streams with the corresponding methods ((*Chk).Log(...), (*Chk).Stdout(...) and (*Chk).Stderr(...)) before calling chk.Release().

func CaptureLogWithStderr(t testingT) *Chk

CaptureLogWithStderr returns a *Chk that combines the package logger output and os.Stderr into a single capture buffer.

In this combined mode the same underlying data may be inspected by either (*Chk).Log(...) or (*Chk).Stderr(...). Call exactly one of those two methods to assert the combined contents, and do so before calling chk.Release().

func CaptureLogWithStderrAndStdout(t testingT) *Chk

CaptureLogWithStderrAndStdout returns a *Chk that combines the package logger and os.Stderr into one capture buffer and also captures os.Stdout.

Assert the combined logger/stderr with either (*Chk).Log(...) or (*Chk).Stderr(...), and assert stdout with (*Chk).Stdout(...). Do all assertions before calling chk.Release().

func CaptureStderr(t testingT) *Chk

CaptureStderr returns a *Chk that captures os.Stderr.

Call (*Chk).Stderr(wantLines...) to assert the captured stderr before invoking chk.Release().

func CaptureStderrAndStdout(t testingT) *Chk

CaptureStderrAndStdout returns a *Chk that captures both stderr and stdout.

Call the corresponding assertion helpers ((*Chk).Stdout(...) and (*Chk).Stderr(...)) before calling chk.Release().

Contents

Appendix B: List of got/wnt test methods

Unformatted

func (chk *Chk) Bool(got, want bool, msg ...any) bool
func (chk *Chk) False(got bool, msg ...any) bool
func (chk *Chk) True(got bool, msg ...any) bool
func (chk *Chk) Byte(got, want byte, msg ...any) bool
func (chk *Chk) Complex64(got, want complex64, msg ...any) bool
func (chk *Chk) Complex128(got, want complex128, msg ...any) bool
func (chk *Chk) Float32(got, want, tolerance float32, msg ...any) bool
func (chk *Chk) Float64(got, want, tolerance float64, msg ...any) bool
func (chk *Chk) Int(got, want int, msg ...any) bool
func (chk *Chk) Int8(got, want int8, msg ...any) bool
func (chk *Chk) Int16(got, want int16, msg ...any) bool
func (chk *Chk) Int32(got, want int32, msg ...any) bool
func (chk *Chk) Int64(got, want int64, msg ...any) bool
func (chk *Chk) Rune(got, want rune, msg ...any) bool
func (chk *Chk) Str(got, want string, msg ...any) bool
func (chk *Chk) Uint(got, want uint, msg ...any) bool
func (chk *Chk) Uint8(got, want uint8, msg ...any) bool
func (chk *Chk) Uint16(got, want uint16, msg ...any) bool
func (chk *Chk) Uint32(got, want uint32, msg ...any) bool
func (chk *Chk) Uint64(got, want uint64, msg ...any) bool
func (chk *Chk) Uintptr(got, want uintptr, msg ...any) bool
func (chk *Chk) Dur(got, want time.Duration, msg ...any) bool

Formatted

func (chk *Chk) Boolf(got, want bool, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Falsef(got bool, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Truef(got bool, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Bytef(got, want byte, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Complex64f(got, want complex64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Complex128f(got, want complex128, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float32f(got, want, tolerance float32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float64f(got, want, tolerance float64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Intf(got, want int, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int8f(got, want int8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int16f(got, want int16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int32f(got, want int32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int64f(got, want int64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Runef(got, want rune, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Strf(got, want string, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uintf(got, want uint, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint8f(got, want uint8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint16f(got, want uint16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint32f(got, want uint32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint64f(got, want uint64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uintptrf(got, want uintptr, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Durf(got, want time.Duration, msgFmt string, msgArgs ...any) bool

Pointers and References Unformatted

func (chk *Chk) Nil(got any, msg ...any) bool
func (chk *Chk) NotNil(got any, msg ...any) bool

Pointers and References Formatted

func (chk *Chk) Nilf(got any, msgFmt string, msgArgs ...any) bool
func (chk *Chk) NotNilf(got any, msgFmt string, msgArgs ...any) bool

Contents

Appendix C: List of got/wnt slice test methods

Unformatted Slice

func (chk *Chk) BoolSlice(got, want []bool, msg ...any) bool
func (chk *Chk) ByteSlice(got, want []byte, msg ...any) bool
func (chk *Chk) Complex64Slice(got, want []complex64, msg ...any) bool
func (chk *Chk) Complex128Slice(got, want []complex128, msg ...any) bool
func (chk *Chk) Float32Slice(got, want []float32, tolerance float32, msg ...any) bool
func (chk *Chk) Float64Slice(got, want []float64, tolerance float64, msg ...any) bool
func (chk *Chk) IntSlice(got, want []int, msg ...any) bool
func (chk *Chk) Int8Slice(got, want []int8, msg ...any) bool
func (chk *Chk) Int16Slice(got, want []int16, msg ...any) bool
func (chk *Chk) Int32Slice(got, want []int32, msg ...any) bool
func (chk *Chk) Int64Slice(got, want []int64, msg ...any) bool
func (chk *Chk) RuneSlice(got, want []rune, msg ...any) bool
func (chk *Chk) StrSlice(got, want []string, msg ...any) bool
func (chk *Chk) UintSlice(got, want []uint, msg ...any) bool
func (chk *Chk) Uint8Slice(got, want []uint8, msg ...any) bool
func (chk *Chk) Uint16Slice(got, want []uint16, msg ...any) bool
func (chk *Chk) Uint32Slice(got, want []uint32, msg ...any) bool
func (chk *Chk) Uint64Slice(got, want []uint64, msg ...any) bool
func (chk *Chk) UintptrSlice(got, want []uintptr, msg ...any) bool
func (chk *Chk) DurSlice(got, want []time.Duration, msg ...any) bool
func (chk *Chk) ErrSlice(got []error, want []string, msg ...any) bool

Formatted Slice

func (chk *Chk) BoolSlicef(got, want []bool, msgFmt string, msgArgs ...any) bool
func (chk *Chk) ByteSlicef(got, want []byte, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Complex64Slicef(got, want []complex64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Complex128Slicef(got, want []complex128, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float32Slicef(got, want []float32, tolerance float32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float64Slicef(got, want []float64, tolerance float64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) IntSlicef(got, want []int, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int8Slicef(got, want []int8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int16Slicef(got, want []int16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int32Slicef(got, want []int32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int64Slicef(got, want []int64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) RuneSlicef(got, want []rune, msgFmt string, msgArgs ...any) bool
func (chk *Chk) StrSlicef(got, want []string, msgFmt string, msgArgs ...any) bool
func (chk *Chk) UintSlicef(got, want []uint, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint8Slicef(got, want []uint8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint16Slicef(got, want []uint16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint32Slicef(got, want []uint32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint64Slicef(got, want []uint64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) UintptrSlicef(got, want []uintptr, msgFmt string, msgArgs ...any) bool
func (chk *Chk) DurSlicef(got, want []time.Duration, msgFmt string, msgArgs ...any) bool
func (chk *Chk) ErrSlicef(got []error, want []string, msgFmt string, msgArgs ...any) bool

Contents

Appendix D: List of Bounded and Unbounded Interval tests

Bounded Unformatted

func (chk *Chk) ByteBounded(got byte, option BoundedOption, minV, maxV byte, msg ...any) bool
func (chk *Chk) Float32Bounded(got float32, option BoundedOption, minV, maxV float32, msg ...any) bool
func (chk *Chk) Float64Bounded(got float64, option BoundedOption, minV, maxV float64, msg ...any) bool
func (chk *Chk) IntBounded(got int, option BoundedOption, minV, maxV int, msg ...any) bool
func (chk *Chk) Int8Bounded(got int8, option BoundedOption, minV, maxV int8, msg ...any) bool
func (chk *Chk) Int16Bounded(got int16, option BoundedOption, minV, maxV int16, msg ...any) bool
func (chk *Chk) Int32Bounded(got int32, option BoundedOption, minV, maxV int32, msg ...any) bool
func (chk *Chk) Int64Bounded(got int64, option BoundedOption, minV, maxV int64, msg ...any) bool
func (chk *Chk) RuneBounded(got rune, option BoundedOption, minV, maxV rune, msg ...any) bool
func (chk *Chk) StrBounded(got string, option BoundedOption, minV, maxV string, msg ...any) bool
func (chk *Chk) UintBounded(got uint, option BoundedOption, minV, maxV uint, msg ...any) bool
func (chk *Chk) Uint8Bounded(got uint8, option BoundedOption, minV, maxV uint8, msg ...any) bool
func (chk *Chk) Uint16Bounded(got uint16, option BoundedOption, minV, maxV uint16, msg ...any) bool
func (chk *Chk) Uint32Bounded(got uint32, option BoundedOption, minV, maxV uint32, msg ...any) bool
func (chk *Chk) Uint64Bounded(got uint64, option BoundedOption, minV, maxV uint64, msg ...any) bool
func (chk *Chk) DurBounded(got time.Duration, option BoundedOption, minV, maxV time.Duration, msg ...any) bool

Bounded Formatted

func (chk *Chk) ByteBoundedf(got byte, option BoundedOption, minV, maxV byte, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float32Boundedf(got float32, option BoundedOption, minV, maxV float32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float64Boundedf(got float64, option BoundedOption, minV, maxV float64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) IntBoundedf(got int, option BoundedOption, minV, maxV int, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int8Boundedf(got int8, option BoundedOption, minV, maxV int8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int16Boundedf(got int16, option BoundedOption, minV, maxV int16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int32Boundedf(got int32, option BoundedOption, minV, maxV int32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int64Boundedf(got int64, option BoundedOption, minV, maxV int64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) RuneBoundedf(got rune, option BoundedOption, minV, maxV rune, msgFmt string, msgArgs ...any) bool
func (chk *Chk) StrBoundedf(got string, option BoundedOption, minV, maxV string, msgFmt string, msgArgs ...any) bool
func (chk *Chk) UintBoundedf(got uint, option BoundedOption, minV, maxV uint, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint8Boundedf(got uint8, option BoundedOption, minV, maxV uint8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint16Boundedf(got uint16, option BoundedOption, minV, maxV uint16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint32Boundedf(got uint32, option BoundedOption, minV, maxV uint32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint64Boundedf(got uint64, option BoundedOption, minV, maxV uint64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) DurBoundedf(got time.Duration, option BoundedOption, minV, maxV time.Duration, msgFmt string, msgArgs ...any) bool

Unbounded Unformatted

func (chk *Chk) ByteUnbounded(got byte, option UnboundedOption, bound byte, msg ...any) bool
func (chk *Chk) Float32Unbounded(got float32, option UnboundedOption, bound float32, msg ...any) bool
func (chk *Chk) Float64Unbounded(got float64, option UnboundedOption, bound float64, msg ...any) bool
func (chk *Chk) IntUnbounded(got int, option UnboundedOption, bound int, msg ...any) bool
func (chk *Chk) Int8Unbounded(got int8, option UnboundedOption, bound int8, msg ...any) bool
func (chk *Chk) Int16Unbounded(got int16, option UnboundedOption, bound int16, msg ...any) bool
func (chk *Chk) Int32Unbounded(got int32, option UnboundedOption, bound int32, msg ...any) bool
func (chk *Chk) Int64Unbounded(got int64, option UnboundedOption, bound int64, msg ...any) bool
func (chk *Chk) RuneUnbounded(got rune, option UnboundedOption, bound rune, msg ...any) bool
func (chk *Chk) StrUnbounded(got string, option UnboundedOption, bound string, msg ...any) bool
func (chk *Chk) UintUnbounded(got uint, option UnboundedOption, bound uint, msg ...any) bool
func (chk *Chk) Uint8Unbounded(got uint8, option UnboundedOption, bound uint8, msg ...any) bool
func (chk *Chk) Uint16Unbounded(got uint16, option UnboundedOption, bound uint16, msg ...any) bool
func (chk *Chk) Uint32Unbounded(got uint32, option UnboundedOption, bound uint32, msg ...any) bool
func (chk *Chk) Uint64Unbounded(got uint64, option UnboundedOption, bound uint64, msg ...any) bool
func (chk *Chk) DurUnbounded(got time.Duration, option UnboundedOption, bound time.Duration, msg ...any) bool

Unbounded Formatted

func (chk *Chk) ByteUnboundedf(got byte, option UnboundedOption, bound byte, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float32Unboundedf(got float32, option UnboundedOption, bound float32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Float64Unboundedf(got float64, option UnboundedOption, bound float64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) IntUnboundedf(got int, option UnboundedOption, bound int, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int8Unboundedf(got int8, option UnboundedOption, bound int8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int16Unboundedf(got int16, option UnboundedOption, bound int16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int32Unboundedf(got int32, option UnboundedOption, bound int32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Int64Unboundedf(got int64, option UnboundedOption, bound int64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) RuneUnboundedf(got rune, option UnboundedOption, bound rune, msgFmt string, msgArgs ...any) bool
func (chk *Chk) StrUnboundedf(got string, option UnboundedOption, bound string, msgFmt string, msgArgs ...any) bool
func (chk *Chk) UintUnboundedf(got uint, option UnboundedOption, bound uint, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint8Unboundedf(got uint8, option UnboundedOption, bound uint8, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint16Unboundedf(got uint16, option UnboundedOption, bound uint16, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint32Unboundedf(got uint32, option UnboundedOption, bound uint32, msgFmt string, msgArgs ...any) bool
func (chk *Chk) Uint64Unboundedf(got uint64, option UnboundedOption, bound uint64, msgFmt string, msgArgs ...any) bool
func (chk *Chk) DurUnboundedf(got time.Duration, option UnboundedOption, bound time.Duration, msgFmt string, msgArgs ...any) bool

Contents

Appendix E: Builtin Ansi Terminal Markup

See CONFIGURE.md Appendix E: Builtin Ansi Terminal Markup

Contents

Appendix F: Large Example Function

See Appendix F Example: Large Example Function

Contents

Appendix G: Large Example Main Function

See Appendix G: Large Example Main Function

Contents

Appendix H: License

/* Golang testing utility. Copyright (C) 2023-2025 Leslie Dancsecs

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. */

Contents