qt

package module
v1.101.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2023 License: MIT Imports: 19 Imported by: 3

README

qt: quicker Go tests

go get github.com/go-quicktest/qt

Package qt provides a collection of Go helpers for writing tests. It uses generics, so requires Go 1.18 at least.

For a complete API reference, see the package documentation.

Quicktest helpers can be easily integrated inside regular Go tests, for instance:

    import "github.com/go-quicktest/qt"

    func TestFoo(t *testing.T) {
        t.Run("numbers", func(t *testing.T) {
            numbers, err := somepackage.Numbers()
            qt.Assert(t, qt.DeepEquals(numbers, []int{42, 47})
            qt.Assert(t, qt.ErrorMatches(err, "bad wolf"))
        })
        t.Run("nil", func(t *testing.T) {
            got := somepackage.MaybeNil()
            qt.Assert(t, qt.IsNil(got), qt.Commentf("value: %v", somepackage.Value))
        })
    }
Assertions

An assertion looks like this, where qt.Equals could be replaced by any available checker. If the assertion fails, the underlying t.Fatal method is called to describe the error and abort the test.

qt.Assert(t, qt.Equals(someValue, wantValue))

If you don’t want to abort on failure, use Check instead, which calls Error instead of Fatal:

qt.Check(t, qt.Equals(someValue, wantValue))

The library provides some base checkers like Equals, DeepEquals, Matches, ErrorMatches, IsNil and others. More can be added by implementing the Checker interface.

Other helpers

The Patch helper makes it a little more convenient to change a global or other variable for the duration of a test.

Documentation

Overview

Package qt implements assertions and other helpers wrapped around the standard library's testing types.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrSilent = fmt.Errorf("silent failure")

ErrSilent is the error used when there is no need to include in the failure output the "error" and "check" keys and all the keys automatically added for args. This helper can be used when implementing checkers.

Functions

func Assert

func Assert(t testing.TB, checker Checker, comments ...Comment) bool

Assert checks that the provided argument passes the given check and calls tb.Fatal otherwise, including any Comment arguments in the failure.

func BadCheckf

func BadCheckf(format string, a ...any) error

BadCheckf returns an error used to report a problem with the checker invocation or testing execution itself (like wrong number or type of arguments) rather than a real Check or Assert failure. This helper can be used when implementing checkers.

func Check

func Check(t testing.TB, checker Checker, comments ...Comment) bool

Check checks that the provided argument passes the given check and calls tb.Error otherwise, including any Comment arguments in the failure.

func F2

func F2[Got, Want any](cf func(got Got, want Want) Checker, want Want) func(got Got) Checker

F2 factors a 2-argument checker function into a single argument function suitable for passing to an *Any or *All checker. Whenever the returned function is called, cf is called with arguments (got, want).

func Format

func Format(v any) string

Format formats the given value as a string. It is used to print values in test failures.

func IsBadCheck

func IsBadCheck(err error) bool

IsBadCheck reports whether the given error has been created by BadCheckf. This helper can be used when implementing checkers.

func Patch

func Patch[T any](tb testing.TB, dest *T, value T)

Patch sets a variable to a temporary value for the duration of the test.

It sets the value pointed to by the given destination to the given value, which must be assignable to the element type of the destination.

At the end of the test (see "Deferred execution" in the package docs), the destination is set back to its original value.

Types

type Arg

type Arg struct {
	Name  string
	Value any
}

Arg holds a single argument to a checker.

type Checker

type Checker interface {
	// Check runs the check for this checker.
	// On failure, the returned error is printed along with
	// the checker arguments (obtained by calling Args)
	// and key-value pairs added by calling the note function.
	//
	// If Check returns ErrSilent, neither the checker arguments nor
	// the error are printed; values with note are still printed.
	Check(note func(key string, value any)) error

	// Args returns a slice of all the arguments passed
	// to the checker. The first argument should always be
	// the "got" value being checked.
	Args() []Arg
}

Checker is implemented by types used as part of Check/Assert invocations.

func CmpEquals

func CmpEquals[T any](got, want T, opts ...cmp.Option) Checker

CmpEquals is like DeepEquals but allows custom compare options to be passed too, to allow unexported fields to be compared.

It can be useful to define your own version that uses a custom set of compare options. See example for details.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
	"github.com/google/go-cmp/cmp/cmpopts"
)

func main() {
	runExampleTest(func(t testing.TB) {
		list := []int{42, 47}
		qt.Assert(t, qt.CmpEquals(list, []int{47, 42}, cmpopts.SortSlices(func(i, j int) bool {
			return i < j
		})))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS
Example (Customfunc)
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
	"github.com/google/go-cmp/cmp"
)

type myStruct struct {
	a int
}

func customDeepEquals[T any](got, want T) qt.Checker {
	return qt.CmpEquals(got, want, cmp.AllowUnexported(myStruct{}))
}

func main() {
	runExampleTest(func(t testing.TB) {
		got := &myStruct{
			a: 1234,
		}
		qt.Assert(t, customDeepEquals(got, &myStruct{
			a: 1234,
		}))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func CodecEquals

func CodecEquals[T []byte | string](
	got T,
	want any,
	marshal func(any) ([]byte, error),
	unmarshal func([]byte, any) error,
	opts ...cmp.Option,
) Checker

CodecEquals returns a Checker that checks for codec value equivalence.

It expects two arguments: a byte slice or a string containing some codec-marshaled data, and a Go value.

It uses unmarshal to unmarshal the data into an interface{} value. It marshals the Go value using marshal, then unmarshals the result into an any value.

It then checks that the two interface{} values are deep-equal to one another, using CmpEquals(opts) to perform the check.

See JSONEquals for an example of this in use.

func ContentEquals

func ContentEquals[T any](got, want T) Checker

ContentEquals is like DeepEquals but any slices in the compared values will be sorted before being compared.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		got := []int{1, 23, 4, 5}
		qt.Assert(t, qt.ContentEquals(got, []int{1, 4, 5, 23}))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func DeepEquals

func DeepEquals[T any](got, want T) Checker

DeepEquals returns a Checker checking equality of two values using cmp.DeepEqual.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		list := []int{42, 47}
		qt.Assert(t, qt.DeepEquals(list, []int{42, 47}))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func Equals

func Equals[T any](got, want T) Checker

Equals returns a Checker checking equality of two comparable values.

Note that T is not constrained to be comparable because we also allow comparing interface values which currently do not satisfy that constraint.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		answer := int64(42)
		qt.Assert(t, qt.Equals(answer, 42))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func ErrorAs

func ErrorAs[T any](got error, want *T) Checker

ErrorAs retruns a Checker checking that the error is or wraps a specific error type. If so, it assigns it to the provided pointer. This is analogous to calling errors.As.

Example
package main

import (
	"errors"
	"fmt"
	"os"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		_, err := os.Open("/non-existent-file")

		// Checking for a specific error type.
		qt.Assert(t, qt.ErrorAs(err, new(*os.PathError)))
		qt.Assert(t, qt.ErrorAs[*os.PathError](err, nil))

		// Checking fields on a specific error type.
		var pathError *os.PathError
		if qt.Check(t, qt.ErrorAs(err, &pathError)) {
			qt.Assert(t, qt.Equals(pathError.Path, "/non-existent-file"))
		}
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func ErrorIs

func ErrorIs(got, want error) Checker

ErrorIs returns a Checker that checks that the error is or wraps a specific error value. This is analogous to calling errors.Is.

Example
package main

import (
	"errors"
	"fmt"
	"os"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		_, err := os.Open("/non-existent-file")

		qt.Assert(t, qt.ErrorIs(err, os.ErrNotExist))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func ErrorMatches

func ErrorMatches[StringOrRegexp string | *regexp.Regexp](got error, want StringOrRegexp) Checker

ErrorMatches returns a Checker checking that the provided value is an error whose message matches the provided regular expression pattern.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		err := errors.New("bad wolf at the door")
		qt.Assert(t, qt.ErrorMatches(err, "bad wolf .*"))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func HasLen

func HasLen[T any](got T, n int) Checker

HasLen returns a Checker checking that the provided value has the given length. The value may be a slice, array, channel, map or string.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.HasLen([]int{42, 47}, 2))

		myMap := map[string]int{
			"a": 13,
			"b": 4,
			"c": 10,
		}
		qt.Assert(t, qt.HasLen(myMap, 3))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func Implements

func Implements[I any](got any) Checker

Implements returns a Checker checking that the provided value implements the interface specified by the type parameter.

Example
package main

import (
	"errors"
	"fmt"
	"io"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		var myReader struct {
			io.ReadCloser
		}
		qt.Assert(t, qt.Implements[io.ReadCloser](myReader))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func IsFalse

func IsFalse[T ~bool](got T) Checker

IsFalse returns a Checker checking that the provided value is false.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		isValid := func() bool {
			return false
		}
		qt.Assert(t, qt.IsFalse(1 == 0))
		qt.Assert(t, qt.IsFalse(isValid()))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func IsNil

func IsNil[T any](got T) Checker

IsNil returns a Checker checking that the provided value is equal to nil.

Note that an interface value containing a nil concrete type is not considered to be nil.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		got := (*int)(nil)
		qt.Assert(t, qt.IsNil(got))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func IsNotNil

func IsNotNil[T any](got T) Checker

IsNotNil returns a Checker checking that the provided value is not nil. IsNotNil(v) is the equivalent of qt.Not(qt.IsNil(v)).

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		got := new(int)

		qt.Assert(t, qt.IsNotNil(got))

		// Note that unlike reflection-based APIs, a nil
		// value inside an interface still counts as non-nil,
		// just as if we were comparing the actual interface
		// value against nil.
		nilValueInInterface := any((*int)(nil))
		qt.Assert(t, qt.IsNotNil(nilValueInInterface))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func IsTrue

func IsTrue[T ~bool](got T) Checker

IsTrue returns a Checker checking that the provided value is true.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		isValid := func() bool {
			return true
		}
		qt.Assert(t, qt.IsTrue(1 == 1))
		qt.Assert(t, qt.IsTrue(isValid()))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func JSONEquals

func JSONEquals[T []byte | string](got T, want any) Checker

JSONEquals returns a Checker that checks whether a string or byte slice is JSON-equivalent to a Go value. See CodecEquals for more information.

It uses DeepEquals to do the comparison. If a more sophisticated comparison is required, use CodecEquals directly.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		data := `[1, 2, 3]`
		qt.Assert(t, qt.JSONEquals(data, []uint{1, 2, 3}))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func MapAll

func MapAll[K comparable, V any](container map[K]V, f func(elem V) Checker) Checker

MapAll returns a Checker that uses checkers returned by f to check values of a map. It succeeds if f(v) passes the check for all values v in the map.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.MapAll(map[string]int{
			"x": 2,
			"y": 2,
		}, qt.F2(qt.Equals[int], 2)))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func MapAny

func MapAny[K comparable, V any](container map[K]V, f func(elem V) Checker) Checker

MapAny returns a Checker that uses checkers returned by f to check values of a map. It succeeds if f(v) passes the check for any value v in the map.

See the F2 function for a way to adapt a regular checker function to the type expected for the f argument here.

See also MapAll and MapContains.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.MapAny(map[string]int{"x": 2, "y": 3}, qt.F2(qt.Equals[int], 3)))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func MapContains

func MapContains[K comparable, V any](container map[K]V, elem V) Checker

MapContains returns a Checker that succeeds if the given value is contained in the values of the given map, by comparing for equality.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.MapContains(map[string]int{
			"hello": 1234,
		}, 1234))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func Matches

func Matches[StringOrRegexp string | *regexp.Regexp](got string, want StringOrRegexp) Checker

Matches returns a Checker checking that the provided string matches the provided regular expression pattern.

Example
package main

import (
	"errors"
	"fmt"
	"net"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.Matches("these are the voyages", "these are .*"))
		qt.Assert(t, qt.Matches(net.ParseIP("1.2.3.4").String(), "1.*"))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func Not

func Not(c Checker) Checker

Not returns a Checker negating the given Checker.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {

		got := []int{1, 2}
		qt.Assert(t, qt.Not(qt.IsNil(got)))

		answer := 13
		qt.Assert(t, qt.Not(qt.Equals(answer, 42)))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func PanicMatches

func PanicMatches[StringOrRegexp string | *regexp.Regexp](f func(), want StringOrRegexp) Checker

PanicMatches returns a Checker checking that the provided function panics with a message matching the provided regular expression pattern.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		divide := func(a, b int) int {
			return a / b
		}
		qt.Assert(t, qt.PanicMatches(func() {
			divide(5, 0)
		}, "runtime error: .*"))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func Satisfies

func Satisfies[T any](got T, f func(T) bool) Checker

Satisfies returns a Checker checking that the provided value, when used as argument of the provided predicate function, causes the function to return true.

Example
package main

import (
	"errors"
	"fmt"
	"math"
	"os"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		// Check that an error from os.Open satisfies os.IsNotExist.
		_, err := os.Open("/non-existent-file")
		qt.Assert(t, qt.Satisfies(err, os.IsNotExist))

		// Check that a floating point number is a not-a-number.
		f := math.NaN()
		qt.Assert(t, qt.Satisfies(f, math.IsNaN))

	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func SliceAll

func SliceAll[T any](container []T, f func(elem T) Checker) Checker

SliceAll returns a Checker that uses checkers returned by f to check elements of a slice. It succeeds if all elements of the slice pass the check. On failure it prints the error from the first index that failed.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.SliceAll([]int{3, 5, 8}, func(e int) qt.Checker {
			return qt.Not(qt.Equals(e, 0))
		}))
		qt.Assert(t, qt.SliceAll([][]string{{"a", "b"}, {"a", "b"}}, qt.F2(qt.DeepEquals[[]string], []string{"a", "b"})))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func SliceAny

func SliceAny[T any](container []T, f func(elem T) Checker) Checker

SliceAny returns a Checker that uses the given checker to check elements of a slice. It succeeds if f(v) passes the check for any v in the slice.

See the F2 function for a way to adapt a regular checker function to the type expected for the f argument here.

See also SliceAll and SliceContains.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.SliceAny([]int{3, 5, 7, 99}, qt.F2(qt.Equals[int], 7)))
		qt.Assert(t, qt.SliceAny([][]string{{"a", "b"}, {"c", "d"}}, qt.F2(qt.DeepEquals[[]string], []string{"c", "d"})))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func SliceContains

func SliceContains[T any](container []T, elem T) Checker

SliceContains returns a Checker that succeeds if the given slice contains the given element, by comparing for equality.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.SliceContains([]int{3, 5, 7, 99}, 99))
		qt.Assert(t, qt.SliceContains([]string{"a", "cd", "e"}, "cd"))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func StringContains

func StringContains[T ~string](got, substr T) Checker

StringContains returns a Checker checking that the given string contains the given substring.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		qt.Assert(t, qt.StringContains("hello world", "hello"))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

type Comment

type Comment struct {
	// contains filtered or unexported fields
}

Comment represents additional information on a check or an assertion which is displayed when the check or assertion fails.

Example
package main

import (
	"errors"
	"fmt"
	"testing"

	"github.com/go-quicktest/qt"
)

func main() {
	runExampleTest(func(t testing.TB) {
		a := 42
		qt.Assert(t, qt.Equals(a, 42), qt.Commentf("no answer to life, the universe, and everything"))
	})
}

func runExampleTest(f func(t testing.TB)) {
	defer func() {
		if err := recover(); err != nil && err != exampleTestFatal {
			panic(err)
		}
	}()
	var t exampleTestingT
	f(&t)
	if t.failed {
		fmt.Println("FAIL")
	} else {
		fmt.Println("PASS")
	}
}

type exampleTestingT struct {
	testing.TB
	failed bool
}

var exampleTestFatal = errors.New("example test fatal error")

func (t *exampleTestingT) Helper() {}

func (t *exampleTestingT) Error(args ...any) {
	fmt.Printf("ERROR: %s\n", fmt.Sprint(args...))
	t.failed = true
}

func (t *exampleTestingT) Fatal(args ...any) {
	fmt.Printf("FATAL: %s\n", fmt.Sprint(args...))
	t.failed = true
	panic(exampleTestFatal)
}
Output:

PASS

func Commentf

func Commentf(format string, args ...any) Comment

Commentf returns a test comment whose output is formatted according to the given format specifier and args. It may be provided as the last argument to any check or assertion and will be displayed if the check or assertion fails.

func (Comment) String

func (c Comment) String() string

String outputs a string formatted according to the stored format specifier and args.

type SuppressedIfLong added in v1.100.0

type SuppressedIfLong struct {
	// Value holds the original annotated value.
	Value any
}

SuppressedIfLong indicates that the value must be suppressed if verbose testing is off and the pretty printed version of the value is long. This is useful when a checker calls note and does not want the provided value to be printed in non-verbose test runs if the value is too long.

type Unquoted

type Unquoted string

Unquoted indicates that the string must not be pretty printed in the failure output. This is useful when a checker calls note and does not want the provided value to be quoted.

Directories

Path Synopsis
Package qtsuite allows quicktest to run test suites.
Package qtsuite allows quicktest to run test suites.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL