test

package module
v1.8.0 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2024 License: MPL-2.0 Imports: 14 Imported by: 8

README

test

Go Reference MPL License Run CI Tests

test is a modern and generics oriented testing assertions library for Go.

There are five key packages,

  • must - assertions causing test failure and halt the test case immediately
  • test - assertions causing test failure and allow the test case to continue
  • wait - utilities for waiting on conditionals in tests
  • skip - utilities for skipping test cases in some situations
  • portal - utilities for allocating free ports for network listeners in tests
Changes

☑ v1.8.0 introduces the skip package for skipping tests!

  • New helper functions for skipping out tests based on some given criteria

☑ v1.7.0 marks the first stable release!

  • Going forward no breaking changes will be made without a v2 major version

☑ v0.6.0 adds support for custom cmp.Option values

  • Adds ability to customize cmp.Equal behavior via cmp.Option arguments
  • Adds assertions for existence of single map key
  • Fixes some error outputs
Requirements

Only depends on github.com/google/go-cmp.

The minimum Go version is go1.18.

Install

Use go get to grab the latest version of test.

go get -u github.com/shoenig/test@latest
Influence

This library was made after a ~decade of using testify, quite possibly the most used library in the whole Go ecosystem. All credit of inspiration belongs them.

Philosophy

Go has always lacked a strong definition of equivalency, and until recently lacked the language features necessary to make type-safe yet generic assertive statements based on the contents of values.

This test (and companion must) package aims to provide a test-case assertion library where the caller is in control of how types are compared, and to do so in a strongly typed way - avoiding erroneous comparisons in the first place.

Generally there are 4 ways of asserting equivalence between types.

the == operator

Functions like EqOp and ContainsOp work on types that are comparable, i.e. are compatible with Go's built-in == and != operators.

a comparator function

Functions like EqFunc and ContainsFunc work on any type, as the caller passes in a function that takes two arguments of that type, returning a boolean indicating equivalence.

an .Equal method

Functions like Equal and ContainsEqual work on types implementing the EqualFunc generic interface (i.e. implement an .Equal method). The .Equal method is called to determine equivalence.

the cmp.Equal or reflect.DeepEqual functions

Functions like Eq and Contains work on any type, using the cmp.Equal or reflect.DeepEqual functions to determine equivalence. Although this is the easiest / most compatible way to "just compare stuff", it the least deterministic way of comparing instances of a type. Changes to the underlying types may cause unexpected changes in their equivalence (e.g. the addition of unexported fields, function field types, etc.). Assertions that make use of cmp.Equal configured with custom cmp.Option values.

output

When possible, a nice diff output is created to show why an equivalence has failed. This is done via the cmp.Diff function. For incompatible types, their GoString values are printed instead.

All output is directed through t.Log functions, and is visible only if test verbosity is turned on (e.g. go test -v).

fail fast vs. fail later

The test and must packages are identical, except for how test cases behave when encountering a failure. Sometimes it is helpful for a test case to continue running even though a failure has occurred (e.g. contains cleanup logic not captured via a t.Cleanup function). Other times it make sense to fail immediately and stop the test case execution.

go-cmp Options

The test assertions that rely on cmp.Equal can be customized in how objects are compared by specifying custom cmp.Option values. These can be configured through test.Cmp and must.Cmp helpers. Google provides some common custom behaviors in the cmpopts package. The protocmp package is also particularly helpful when working with Protobuf types.

Here is an example of comparing two slices, but using a custom Option to sort the slices so that the order of elements does not matter.

a := []int{3, 5, 1, 6, 7}
b := []int{1, 7, 6, 3, 5}
must.Eq(t, a, b, must.Cmp(cmpopts.SortSlices(func(i, j int) bool {
  return i < j
})))
PostScripts

Some tests are large and complex (like e2e testing). It can be helpful to provide more context on test case failures beyond the actual assertion. Logging could do this, but often we want to only produce output on failure.

The test and must packages provide a PostScript interface which can be implemented to add more context in the output of failed tests. There are handy implementations of the PostScript interface provided - Sprint, Sprintf, Values, and Func.

By adding one or more PostScript to an assertion, on failure the error message will be appended with the additional context.

// Add a single Sprintf-string to the output of a failed test assertion.
must.Eq(t, exp, result, must.Sprintf("some more context: %v", value))
// Add a formatted key-value map to the output of a failed test assertion.
must.Eq(t, exp, result, must.Values(
  "one", 1,
  "two", 2,
  "fruit", "banana",
))
// Add the output from a closure to the output of a failed test assertion.
must.Eq(t, exp, result, must.Func(func() string {
  // ... something interesting
  return s
})
Skip

Sometimes it makes sense to just skip running a certain test case. Maybe the operating system is incompatible or a certain required command is not installed. The skip package provides utilities for skipping tests under some given conditions.

skip.OperatingSystem(t, "windows", "plan9", "dragonfly")
skip.NotArchitecture(t, "amd64", "arm64")
skip.CommandUnavailable(t, "java")
skip.EnvironmentVariableSet(t, "CI")
Wait

Sometimes a test needs to wait on a condition for a non-deterministic amount of time. For these cases, the wait package provides utilities for configuring conditionals that can assert some condition becomes true, or that some condition remains true - whether for a specified amount time, or a specific number of iterations.

A Constraint is created in one of two forms

  • InitialSuccess - assert a function eventually returns a positive result
  • ContinualSuccess - assert a function continually returns a positive result

A Constraint may be configured with a few Option functions.

  • Timeout - set a time bound on the constraint
  • Attempts - set an iteration bound on the constraint
  • Gap - set the iteration interval pace
  • BoolFunc - set a predicate function of type func() bool
  • ErrorFunc - set a predicate function of type func() error
  • TestFunc - set a predicate function of type func() (bool, error)
Assertions form

The test and must package implement an assertion helper for using the wait package.

must.Wait(t, wait.InitialSuccess(wait.ErrorFunc(f)))
must.Wait(t, wait.ContinualSuccess(
    wait.ErrorFunc(f),
    wait.Attempts(100),
    wait.Gap(10 * time.Millisecond),
))
Fundamental form

Although the 99% use case is via the test or must packages as described above, the wait package can also be used in isolation by calling Run() directly. An error is returned if the conditional failed, and nil otherwise.

c := wait.InitialSuccess(
    BoolFunc(f),
    Timeout(10 * time.Seconds),
    Gap(1 * time.Second),
)
err := c.Run()
Examples (equality)
import "github.com/shoenig/test/must"

// ... 

e1 := Employee{ID: 100, Name: "Alice"}
e2 := Employee{ID: 101, Name: "Bob"}

// using cmp.Equal (like magic!)
must.Eq(t, e1, e2)

// using == operator
must.EqOp(t, e1, e2)

// using a custom comparator
must.EqFunc(t, e1, e2, func(a, b *Employee) bool {
    return a.ID == b.ID
})

// using .Equal method
must.Equal(t, e1, e2)
Output

The test and must package attempt to create useful, readable output when an assertions goes awry. Some random examples below.

test_test.go:779: expected different file permissions
↪ name: find
↪ exp: -rw-rwx-wx
↪ got: -rwxr-xr-x
tests_test.go:569: expected maps of same values via 'eq' function
↪ difference:
map[int]test.Person{
0: {ID: 100, Name: "Alice"},
  	1: {
  		ID:   101,
-  		Name: "Bob",
+  		Name: "Bob B.",
    	},
    }
test_test.go:520: expected slice[1].Less(slice[2])
↪ slice[1]: &{200 Bob}
↪ slice[2]: &{150 Carl}
test_test.go:688: expected maps of same values via .Equal method
↪ differential ↷
  map[int]*test.Person{
  	0: &{ID: 100, Name: "Alice"},
  	1: &{
- 		ID:   101,
+ 		ID:   200,
  		Name: "Bob",
  	},
  }
test_test.go:801: expected regexp match
↪ s: abcX
↪ re: abc\d
License

Open source under the MPL

Documentation

Overview

Package test provides a modern generic testing assertions library.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Ascending added in v0.2.5

func Ascending[O constraints.Ordered](t T, slice []O, settings ...Setting)

Ascending asserts slice[n] ≤ slice[n+1] for each element.

Example
nums := []int{1, 3, 4, 4, 9}
Ascending(t, nums)
Output:

func AscendingCmp added in v0.6.3

func AscendingCmp[A any](t T, slice []A, compare func(A, A) int, settings ...Setting)

AscendingCmp asserts slice[n] is less than slice[n+1] for each element using the cmp comparator.

Example
labels := []string{"Fun", "great", "Happy", "joyous"}
AscendingCmp(t, labels, func(a, b string) int {
	A := strings.ToLower(a)
	B := strings.ToLower(b)
	switch {
	case A == B:
		return 0
	case A < B:
		return -1
	default:
		return 1
	}
})
Output:

func AscendingFunc added in v0.2.5

func AscendingFunc[A any](t T, slice []A, less func(A, A) bool, settings ...Setting)

AscendingFunc asserts slice[n] is less than slice[n+1] for each element using the less comparator.

Example
labels := []string{"Fun", "great", "Happy", "joyous"}
AscendingFunc(t, labels, func(a, b string) bool {
	A := strings.ToLower(a)
	B := strings.ToLower(b)
	return A < B
})
Output:

func AscendingLess added in v0.2.5

func AscendingLess[L interfaces.LessFunc[L]](t T, slice []L, settings ...Setting)

AscendingLess asserts slice[n].Less(slice[n+1]) for each element.

Example
nums := []score{4, 6, 7, 9}
AscendingLess(t, nums)
Output:

func Between added in v0.4.0

func Between[O constraints.Ordered](t T, lower, val, upper O, settings ...Setting)

Between asserts lower ≤ val ≤ upper.

Example
lower, upper := 3, 9
value := 5
Between(t, lower, value, upper)
Output:

func BetweenExclusive added in v0.4.0

func BetweenExclusive[O constraints.Ordered](t T, lower, val, upper O, settings ...Setting)

BetweenExclusive asserts lower < val < upper.

Example
lower, upper := 2, 8
value := 4
BetweenExclusive(t, lower, value, upper)
Output:

func Close added in v0.6.7

func Close(t T, c io.Closer)

Close asserts c.Close does not cause an error.

func Contains

func Contains[C any](t T, element C, container interfaces.ContainsFunc[C], settings ...Setting)

Contains asserts container.ContainsFunc(element) is true.

Example
// container implements .Contains method
container := newContainer(2, 4, 6, 8)
Contains[int](t, 4, container)
Output:

func ContainsSubset added in v0.6.1

func ContainsSubset[C any](t T, elements []C, container interfaces.ContainsFunc[C], settings ...Setting)

ContainsSubset asserts each element in elements exists in container, in no particular order. There may be elements in container beyond what is present in elements.

Example
// container implements .Contains method
container := newContainer(1, 2, 3, 4, 5, 6)
ContainsSubset[int](t, []int{2, 4, 6}, container)
Output:

func Descending added in v0.2.5

func Descending[O constraints.Ordered](t T, slice []O, settings ...Setting)

Descending asserts slice[n] ≥ slice[n+1] for each element.

Example
nums := []int{9, 6, 5, 4, 4, 2, 1}
Descending(t, nums)
Output:

func DescendingCmp added in v0.6.3

func DescendingCmp[A any](t T, slice []A, compare func(A, A) int, settings ...Setting)

DescendingCmp asserts slice[n+1] is ≤ slice[n] for each element.

Example
nums := []int{9, 5, 3, 3, 1, -2}
DescendingCmp(t, nums, func(a, b int) int {
	return a - b
})
Output:

func DescendingFunc added in v0.2.5

func DescendingFunc[A any](t T, slice []A, less func(A, A) bool, settings ...Setting)

DescendingFunc asserts slice[n+1] is less than slice[n] for each element using the less comparator.

Example
words := []string{"Foo", "baz", "Bar", "AND"}
DescendingFunc(t, words, func(a, b string) bool {
	lowerA := strings.ToLower(a)
	lowerB := strings.ToLower(b)
	return lowerA < lowerB
})
Output:

func DescendingLess added in v0.2.5

func DescendingLess[L interfaces.LessFunc[L]](t T, slice []L, settings ...Setting)

DescendingLess asserts slice[n+1].Less(slice[n]) for each element.

Example
nums := []score{9, 6, 3, 1, 0}
DescendingLess(t, nums)
Output:

func DirExists added in v0.2.5

func DirExists(t T, directory string, settings ...Setting)

DirExists asserts directory exists on the OS filesystem.

Example
DirExists(t, "/tmp")
Output:

func DirExistsFS added in v0.4.0

func DirExistsFS(t T, system fs.FS, directory string, settings ...Setting)

DirExistsFS asserts directory exists on the fs.FS filesystem.

Example, DirExistsFS(t, os.DirFS("/usr/local"), "bin")

Example
DirExistsFS(t, os.DirFS("/"), "tmp")
Output:

func DirMode added in v1.8.0

func DirMode(t T, path string, permissions fs.FileMode, settings ...Setting)

DirMode asserts the directory at path on the OS filesystem has exactly the given permission bits.

func DirModeFS added in v1.8.0

func DirModeFS(t T, system fs.FS, path string, permissions fs.FileMode, settings ...Setting)

DirModeFS asserts the directory at path on fs.FS has exactly the given permission bits.

Example, DirModeFS(t, os.DirFS("/"), "bin", 0655)

func DirNotExists added in v0.2.5

func DirNotExists(t T, directory string, settings ...Setting)

DirNotExists asserts directory does not exist on the OS filesystem.

Example
DirNotExists(t, "/does/not/exist")
Output:

func DirNotExistsFS added in v0.4.0

func DirNotExistsFS(t T, system fs.FS, directory string, settings ...Setting)

DirNotExistsFS asserts directory does not exist on the fs.FS filesystem.

Example, DirNotExistsFS(t, os.DirFS("/tmp"), "scratch")

Example
DirNotExistsFS(t, os.DirFS("/"), "does/not/exist")
Output:

func Empty

func Empty(t T, e interfaces.EmptyFunc, settings ...Setting)

Empty asserts e.Empty() is true.

Example
// container implements .Empty method
container := newContainer[string]()
Empty(t, container)
Output:

func Eq

func Eq[A any](t T, exp, val A, settings ...Setting)

Eq asserts exp and val are equal using cmp.Equal.

Example
actual := "hello"
Eq(t, "hello", actual)
Output:

func EqError added in v0.2.2

func EqError(t T, err error, msg string, settings ...Setting)

EqError asserts err contains message msg.

Example
err := errors.New("undefined error")
EqError(t, err, "undefined error")
Output:

func EqFunc added in v0.1.0

func EqFunc[A any](t T, exp, val A, eq func(a, b A) bool, settings ...Setting)

EqFunc asserts exp and val are equal using eq.

Example
EqFunc(t, "abcd", "dcba", func(a, b string) bool {
	if len(a) != len(b) {
		return false
	}
	l := len(a)
	for i := 0; i < l; i++ {
		if a[i] != b[l-1-i] {
			return false
		}
	}
	return true
})
Output:

func EqJSON

func EqJSON(t T, exp, val string, settings ...Setting)

EqJSON asserts exp and val are equivalent JSON.

Example
a := `{"foo":"bar","numbers":[1,2,3]}`
b := `{"numbers":[1,2,3],"foo":"bar"}`
EqJSON(t, a, b)
Output:

func EqOp added in v0.2.4

func EqOp[C comparable](t T, exp, val C, settings ...Setting)

EqOp asserts exp == val.

Example
EqOp(t, 123, 123)
Output:

func Equal added in v0.4.0

func Equal[E interfaces.EqualFunc[E]](t T, exp, val E, settings ...Setting)

Equal asserts val.Equal(exp).

Example
// score implements .Equal method
Equal(t, score(1000), score(1000))
Output:

func Error

func Error(t T, err error, settings ...Setting)

Error asserts err is a non-nil error.

Example
Error(t, errors.New("error"))
Output:

func ErrorContains added in v0.5.0

func ErrorContains(t T, err error, sub string, settings ...Setting)

ErrorContains asserts err contains sub.

Example
err := errors.New("error beer not found")
ErrorContains(t, err, "beer")
Output:

func ErrorIs

func ErrorIs(t T, err error, target error, settings ...Setting)

ErrorIs asserts err

Example
e1 := errors.New("e1")
e2 := errors.New("e2")
e3 := errors.New("e3")
errorChain := errors.Join(e1, e2, e3)
ErrorIs(t, errorChain, e2)
Output:

func False

func False(t T, condition bool, settings ...Setting)

False asserts condition is false.

Example
False(t, 1 == int('a'))
Output:

func FileContains added in v0.2.5

func FileContains(t T, file, content string, settings ...Setting)

FileContains asserts the file on the OS filesystem contains content as a substring.

Example
_ = os.WriteFile("/tmp/example", []byte("foo bar baz"), fs.FileMode(0600))
FileContains(t, "/tmp/example", "bar")
Output:

func FileContainsFS added in v0.4.0

func FileContainsFS(t T, system fs.FS, file, content string, settings ...Setting)

FileContainsFS asserts the file on fs.FS contains content as a substring.

Often os.DirFS is used to interact with the host filesystem. Example, FileContainsFS(t, os.DirFS("/etc"), "hosts", "localhost")

Example
_ = os.WriteFile("/tmp/example", []byte("foo bar baz"), fs.FileMode(0600))
FileContainsFS(t, os.DirFS("/tmp"), "example", "bar")
Output:

func FileExists added in v0.2.5

func FileExists(t T, file string, settings ...Setting)

FileExists asserts file exists on the OS filesystem.

Example
_ = os.WriteFile("/tmp/example", []byte{}, fs.FileMode(0600))
FileExists(t, "/tmp/example")
Output:

func FileExistsFS added in v0.4.0

func FileExistsFS(t T, system fs.FS, file string, settings ...Setting)

FileExistsFS asserts file exists on the fs.FS filesystem.

Example, FileExistsFS(t, os.DirFS("/etc"), "hosts")

Example
_ = os.WriteFile("/tmp/example", []byte{}, fs.FileMode(0600))
FileExistsFS(t, os.DirFS("/tmp"), "example")
Output:

func FileMode added in v0.2.5

func FileMode(t T, path string, permissions fs.FileMode, settings ...Setting)

FileMode asserts the file or directory at path on the OS filesystem has exactly the given permission bits.

Example
_ = os.WriteFile("/tmp/example_fm", []byte{}, fs.FileMode(0600))
FileMode(t, "/tmp/example_fm", fs.FileMode(0600))
Output:

func FileModeFS added in v0.4.0

func FileModeFS(t T, system fs.FS, path string, permissions fs.FileMode, settings ...Setting)

FileModeFS asserts the file or directory at path on fs.FS has exactly the given permission bits.

Example, FileModeFS(t, os.DirFS("/bin"), "find", 0655)

Example
_ = os.WriteFile("/tmp/example_fm", []byte{}, fs.FileMode(0600))
FileModeFS(t, os.DirFS("/tmp"), "example_fm", fs.FileMode(0600))
Output:

func FileNotExists added in v0.2.5

func FileNotExists(t T, file string, settings ...Setting)

FileNotExists asserts file does not exist on the OS filesystem.

Example
FileNotExists(t, "/tmp/not_existing_file")
Output:

func FileNotExistsFS added in v0.4.0

func FileNotExistsFS(t T, system fs.FS, file string, settings ...Setting)

FileNotExistsFS asserts file does not exist on the fs.FS filesystem.

Example, FileNotExist(t, os.DirFS("/bin"), "exploit.exe")

Example
FileNotExistsFS(t, os.DirFS("/tmp"), "not_existing_file")
Output:

func FilePathValid added in v0.2.5

func FilePathValid(t T, path string, settings ...Setting)

FilePathValid asserts path is a valid file path.

Example
FilePathValid(t, "foo/bar/baz")
Output:

func Greater

func Greater[O constraints.Ordered](t T, exp, val O, settings ...Setting)

Greater asserts val > exp.

Example
Greater(t, 30, 42)
Output:

func GreaterEq

func GreaterEq[O constraints.Ordered](t T, exp, val O, settings ...Setting)

GreaterEq asserts val ≥ exp.

Example
GreaterEq(t, 30.1, 30.3)
Output:

func InDelta

func InDelta[N interfaces.Number](t T, a, b, delta N, settings ...Setting)

InDelta asserts a and b are within delta of each other.

Example
InDelta(t, 30.5, 30.54, .1)
Output:

func InDeltaSlice

func InDeltaSlice[N interfaces.Number](t T, a, b []N, delta N, settings ...Setting)

InDeltaSlice asserts each element a[n] is within delta of b[n].

Example
nums := []int{51, 48, 55, 49, 52}
base := []int{52, 44, 51, 51, 47}
InDeltaSlice(t, nums, base, 5)
Output:

func Len

func Len[A any](t T, n int, slice []A, settings ...Setting)

Len asserts slice is of length n.

Shorthand function for SliceLen. For checking Len() of a struct, use the Length() assertion.

Example
nums := []int{1, 3, 5, 9}
Len(t, 4, nums)
Output:

func Length added in v0.4.0

func Length(t T, exp int, l interfaces.LengthFunc, settings ...Setting)

Length asserts l.Len() is equal to exp.

Example
s := scores{89, 93, 91, 99, 88}
Length(t, 5, s)
Output:

func Less

func Less[O constraints.Ordered](t T, exp, val O, settings ...Setting)

Less asserts val < exp.

Example
// compare using < operator
s := score(50)
Less(t, 66, s)
Output:

func LessEq

func LessEq[O constraints.Ordered](t T, exp, val O, settings ...Setting)

LessEq asserts val ≤ exp.

Example
s := score(50)
LessEq(t, 50, s)
Output:

func Lesser

func Lesser[L interfaces.LessFunc[L]](t T, exp, val L, settings ...Setting)

Lesser asserts val.Less(exp).

Example
// compare using .Less method
s := score(50)
Lesser(t, 66, s)
Output:

func MapContainsKey added in v0.6.0

func MapContainsKey[M ~map[K]V, K comparable, V any](t T, m M, key K, settings ...Setting)

MapContainsKey asserts m contains key.

Example
numbers := map[string]int{"one": 1, "two": 2, "three": 3}
MapContainsKey(t, numbers, "one")
Output:

func MapContainsKeys added in v0.2.5

func MapContainsKeys[M ~map[K]V, K comparable, V any](t T, m M, keys []K, settings ...Setting)

MapContainsKeys asserts m contains each key in keys.

Example
numbers := map[string]int{"one": 1, "two": 2, "three": 3}
keys := []string{"one", "two"}
MapContainsKeys(t, numbers, keys)
Output:

func MapContainsValue added in v1.7.2

func MapContainsValue[M ~map[K]V, K comparable, V any](t T, m M, val V, settings ...Setting)

MapContainsValue asserts m contains val.

func MapContainsValueEqual added in v1.7.2

func MapContainsValueEqual[M ~map[K]V, K comparable, V interfaces.EqualFunc[V]](t T, m M, val V, settings ...Setting)

MapContainsValueEqual asserts m contains val using the V.Equal method.

func MapContainsValueFunc added in v1.7.2

func MapContainsValueFunc[M ~map[K]V, K comparable, V any](t T, m M, val V, eq func(V, V) bool, settings ...Setting)

MapContainsValueFunc asserts m contains val using the eq function.

func MapContainsValues added in v0.2.5

func MapContainsValues[M ~map[K]V, K comparable, V any](t T, m M, vals []V, settings ...Setting)

MapContainsValues asserts m contains each val in vals.

Example
numbers := map[string]int{"one": 1, "two": 2, "three": 3}
values := []int{1, 2}
MapContainsValues(t, numbers, values)
Output:

func MapContainsValuesEqual added in v0.4.0

func MapContainsValuesEqual[M ~map[K]V, K comparable, V interfaces.EqualFunc[V]](t T, m M, vals []V, settings ...Setting)

MapContainsValuesEqual asserts m contains each val in vals using the V.Equal method.

Example
// employee implements .Equal
m := map[int]*employee{
	0: {first: "armon", id: 101},
	1: {first: "mitchell", id: 100},
	2: {first: "dave", id: 102},
}
expect := []*employee{
	{first: "armon", id: 101},
	{first: "dave", id: 102},
}
MapContainsValuesEqual(t, m, expect)
Output:

func MapContainsValuesFunc added in v0.2.5

func MapContainsValuesFunc[M ~map[K]V, K comparable, V any](t T, m M, vals []V, eq func(V, V) bool, settings ...Setting)

MapContainsValuesFunc asserts m contains each val in vals using the eq function.

Example
m := map[int]string{
	0: "Zero",
	1: "ONE",
	2: "two",
}
f := func(a, b string) bool {
	return strings.EqualFold(a, b)
}
MapContainsValuesFunc(t, m, []string{"one", "two"}, f)
Output:

func MapEmpty

func MapEmpty[M ~map[K]V, K comparable, V any](t T, m M, settings ...Setting)

MapEmpty asserts map is empty.

Example
m := make(map[int]int)
MapEmpty(t, m)
Output:

func MapEq

func MapEq[M1, M2 interfaces.Map[K, V], K comparable, V any](t T, exp M1, val M2, settings ...Setting)

MapEq asserts maps exp and val contain the same key/val pairs, using cmp.Equal function to compare vals.

Example
m1 := map[string]int{"one": 1, "two": 2, "three": 3}
m2 := map[string]int{"one": 1, "two": 2, "three": 3}
MapEq(t, m1, m2)
Output:

func MapEqFunc

func MapEqFunc[M1, M2 interfaces.Map[K, V], K comparable, V any](t T, exp M1, val M2, eq func(V, V) bool, settings ...Setting)

MapEqFunc asserts maps exp and val contain the same key/val pairs, using eq to compare vals.

Example
m1 := map[int]string{
	0: "Zero",
	1: "one",
	2: "TWO",
}
m2 := map[int]string{
	0: "ZERO",
	1: "ONE",
	2: "TWO",
}
MapEqFunc(t, m1, m2, func(a, b string) bool {
	return strings.EqualFold(a, b)
})
Output:

func MapEqual added in v0.4.0

func MapEqual[M interfaces.MapEqualFunc[K, V], K comparable, V interfaces.EqualFunc[V]](t T, exp, val M, settings ...Setting)

MapEqual asserts maps exp and val contain the same key/val pairs, using Equal method to compare vals

Example
armon := &employee{first: "armon", id: 101}
mitchell := &employee{first: "mitchell", id: 100}
m1 := map[int]*employee{
	0: mitchell,
	1: armon,
}
m2 := map[int]*employee{
	0: mitchell,
	1: armon,
}
MapEqual(t, m1, m2)
Output:

func MapLen

func MapLen[M ~map[K]V, K comparable, V any](t T, n int, m M, settings ...Setting)

MapLen asserts map is of size n.

Example
m := map[int]string{
	1: "one",
	2: "two",
}
MapLen(t, 2, m)
Output:

func MapNotContainsKey added in v0.6.0

func MapNotContainsKey[M ~map[K]V, K comparable, V any](t T, m M, key K, settings ...Setting)

MapNotContainsKey asserts m does not contain key.

Example
m := map[string]int{
	"one":   1,
	"two":   2,
	"three": 3,
}
MapNotContainsKey(t, m, "four")
Output:

func MapNotContainsKeys added in v0.4.6

func MapNotContainsKeys[M ~map[K]V, K comparable, V any](t T, m M, keys []K, settings ...Setting)

MapNotContainsKeys asserts m does not contain any key in keys.

Example
m := map[string]int{
	"one": 1,
	"two": 2,
}
MapNotContainsKeys(t, m, []string{"three", "four"})
Output:

func MapNotContainsValue added in v1.7.2

func MapNotContainsValue[M ~map[K]V, K comparable, V any](t T, m M, val V, settings ...Setting)

MapNotContainsValue asserts m does not contain val.

func MapNotContainsValueEqual added in v1.7.2

func MapNotContainsValueEqual[M ~map[K]V, K comparable, V interfaces.EqualFunc[V]](t T, m M, val V, settings ...Setting)

MapNotContainsValueEqual asserts m does not contain val using the V.Equal method.

func MapNotContainsValueFunc added in v1.7.2

func MapNotContainsValueFunc[M ~map[K]V, K comparable, V any](t T, m M, val V, eq func(V, V) bool, settings ...Setting)

MapNotContainsValueFunc asserts m does not contain val using the eq function.

func MapNotContainsValues added in v0.4.6

func MapNotContainsValues[M ~map[K]V, K comparable, V any](t T, m M, vals []V, settings ...Setting)

MapNotContainsValues asserts m does not contain any value in vals.

Example
m := map[int]string{
	1: "one",
	2: "two",
}
MapNotContainsValues(t, m, []string{"three", "four"})
Output:

func MapNotContainsValuesEqual added in v0.4.6

func MapNotContainsValuesEqual[M ~map[K]V, K comparable, V interfaces.EqualFunc[V]](t T, m M, vals []V, settings ...Setting)

MapNotContainsValuesEqual asserts m does not contain any value in vals using the V.Equal method.

Example
m := map[int]*employee{
	0: {first: "mitchell", id: 100},
	1: {first: "armon", id: 101},
}
MapNotContainsValuesEqual(t, m, []*employee{
	{first: "dave", id: 103},
})
Output:

func MapNotContainsValuesFunc added in v0.4.6

func MapNotContainsValuesFunc[M ~map[K]V, K comparable, V any](t T, m M, vals []V, eq func(V, V) bool, settings ...Setting)

MapNotContainsValuesFunc asserts m does not contain any value in vals using the eq function.

Example
m := map[int]string{
	1: "One",
	2: "TWO",
	3: "three",
}
f := func(a, b string) bool {
	return strings.EqualFold(a, b)
}
MapNotContainsValuesFunc(t, m, []string{"four", "five"}, f)
Output:

func MapNotEmpty added in v0.4.0

func MapNotEmpty[M ~map[K]V, K comparable, V any](t T, m M, settings ...Setting)

MapNotEmpty asserts map is not empty.

Example
m := map[string]int{
	"one": 1,
}
MapNotEmpty(t, m)
Output:

func Max added in v0.6.3

func Max[A any, C interfaces.MaxFunc[A]](t T, expect A, collection C, settings ...Setting)

Max asserts collection.Max() is equal to expect.

The equality method may be configured with Cmp options.

Example
s := scores{89, 88, 91, 90, 87}
Max[score](t, 91, s)
Output:

func Min added in v0.6.3

func Min[A any, C interfaces.MinFunc[A]](t T, expect A, collection C, settings ...Setting)

Min asserts collection.Min() is equal to expect.

The equality method may be configured with Cmp options.

Example
s := scores{89, 88, 90, 91}
Min[score](t, 88, s)
Output:

func Negative added in v0.2.5

func Negative[N interfaces.Number](t T, n N, settings ...Setting)

Negative asserts n < 0.

Example
Negative(t, -9)
Output:

func Nil

func Nil(t T, a any, settings ...Setting)

Nil asserts a is nil.

Example
var e *employee
Nil(t, e)
Output:

func NoError

func NoError(t T, err error, settings ...Setting)

NoError asserts err is a nil error.

Example
var err error
NoError(t, err)
Output:

func NonNegative added in v0.4.0

func NonNegative[N interfaces.Number](t T, n N, settings ...Setting)

NonNegative asserts n >= 0.

Example
NonNegative(t, 4)
Output:

func NonPositive added in v0.4.0

func NonPositive[N interfaces.Number](t T, n N, settings ...Setting)

NonPositive asserts n ≤ 0.

Example
NonPositive(t, -3)
Output:

func NonZero added in v0.2.5

func NonZero[N interfaces.Number](t T, n N, settings ...Setting)

NonZero asserts n != 0.

Example
NonZero(t, .001)
Output:

func NotContains added in v0.4.0

func NotContains[C any](t T, element C, container interfaces.ContainsFunc[C], settings ...Setting)

NotContains asserts container.ContainsFunc(element) is false.

Example
c := newContainer("mage", "warrior", "priest", "paladin", "hunter")
NotContains[string](t, "rogue", c)
Output:

func NotEmpty added in v0.4.0

func NotEmpty(t T, e interfaces.EmptyFunc, settings ...Setting)

NotEmpty asserts e.Empty() is false.

Example
c := newContainer("one", "two", "three")
NotEmpty(t, c)
Output:

func NotEq

func NotEq[A any](t T, exp, val A, settings ...Setting)

NotEq asserts exp and val are not equal using cmp.Equal.

Example
NotEq(t, "one", "two")
Output:

func NotEqFunc added in v0.1.0

func NotEqFunc[A any](t T, exp, val A, eq func(a, b A) bool, settings ...Setting)

NotEqFunc asserts exp and val are not equal using eq.

Example
NotEqFunc(t, 4.1, 5.2, func(a, b float64) bool {
	return math.Round(a) == math.Round(b)
})
Output:

func NotEqOp added in v0.2.5

func NotEqOp[C comparable](t T, exp, val C, settings ...Setting)

NotEqOp asserts exp != val.

Example
NotEqOp(t, 1, 2)
Output:

func NotEqual added in v0.4.0

func NotEqual[E interfaces.EqualFunc[E]](t T, exp, val E, settings ...Setting)

NotEqual asserts !val.Equal(exp).

Example
e1 := &employee{first: "alice"}
e2 := &employee{first: "bob"}
NotEqual(t, e1, e2)
Output:

func NotNil

func NotNil(t T, a any, settings ...Setting)

NotNil asserts a is not nil.

Example
e := &employee{first: "bob"}
NotNil(t, e)
Output:

func One added in v0.3.1

func One[N interfaces.Number](t T, n N, settings ...Setting)

One asserts n == 1.

Example
One(t, 1)
Output:

func Positive added in v0.2.5

func Positive[N interfaces.Number](t T, n N, settings ...Setting)

Positive asserts n > 0.

Example
Positive(t, 42)
Output:

func RegexCompiles added in v0.3.0

func RegexCompiles(t T, expr string, settings ...Setting)

RegexCompiles asserts expr compiles as a valid regular expression.

Example
RegexCompiles(t, `[a-z]{7}`)
Output:

func RegexCompilesPOSIX added in v0.3.0

func RegexCompilesPOSIX(t T, expr string, settings ...Setting)

RegexCompilesPOSIX asserts expr compiles as a valid POSIX regular expression.

Example
RegexCompilesPOSIX(t, `[a-z]{3}`)
Output:

func RegexMatch added in v0.2.5

func RegexMatch(t T, re *regexp.Regexp, s string, settings ...Setting)

RegexMatch asserts regular expression re matches string s.

Example
re := regexp.MustCompile(`[a-z]{6}`)
RegexMatch(t, re, "cookie")
Output:

func Size added in v0.4.0

func Size(t T, exp int, s interfaces.SizeFunc, settings ...Setting)

Size asserts s.Size() is equal to exp.

Example
c := newContainer("pie", "brownie", "cake", "cookie")
Size(t, 4, c)
Output:

func SliceContains added in v0.4.0

func SliceContains[A any](t T, slice []A, item A, settings ...Setting)

SliceContains asserts item exists in slice, using cmp.Equal to compare elements.

Example
drinks := []string{"ale", "lager", "cider", "wine"}
SliceContains(t, drinks, "cider")
Output:

func SliceContainsAll added in v0.4.0

func SliceContainsAll[A any](t T, slice, items []A, settings ...Setting)

SliceContainsAll asserts slice and items contain the same elements, but in no particular order. The number of elements in slice and items must be the same.

Example
nums := []int{2, 4, 6, 7, 8}
SliceContainsAll(t, nums, []int{7, 8, 2, 6, 4})
Output:

func SliceContainsEqual added in v0.4.0

func SliceContainsEqual[E interfaces.EqualFunc[E]](t T, slice []E, item E, settings ...Setting)

SliceContainsEqual asserts item exists in slice, using Equal to compare elements.

Example
dave := &employee{first: "dave", id: 8}
armon := &employee{first: "armon", id: 2}
mitchell := &employee{first: "mitchell", id: 1}
employees := []*employee{dave, armon, mitchell}
SliceContainsEqual(t, employees, &employee{first: "dave", id: 8})
Output:

func SliceContainsFunc added in v0.4.0

func SliceContainsFunc[A, B any](t T, slice []A, item B, eq func(a A, b B) bool, settings ...Setting)

SliceContainsFunc asserts item exists in slice, using eq to compare elements.

Example
// comparing slice to element of same type
words := []string{"UP", "DoWn", "LefT", "RiGHT"}
SliceContainsFunc(t, words, "left", func(a, b string) bool {
	return strings.EqualFold(a, b)
})

// comparing slice to element of different type
nums := []string{"2", "4", "6", "8"}
SliceContainsFunc(t, nums, 4, func(a string, b int) bool {
	return a == strconv.Itoa(b)
})
Output:

func SliceContainsOp added in v0.4.0

func SliceContainsOp[C comparable](t T, slice []C, item C, settings ...Setting)

SliceContainsOp asserts item exists in slice using == operator.

Example
nums := []int{1, 2, 3, 4, 5}
SliceContainsOp(t, nums, 3)
Output:

func SliceContainsSubset added in v0.4.1

func SliceContainsSubset[A any](t T, slice, items []A, settings ...Setting)

SliceContainsSubset asserts slice contains each item in items, in no particular order. There could be additional elements in slice not in items.

Example
nums := []int{10, 20, 30, 40, 50}
SliceContainsSubset(t, nums, []int{40, 10, 30})
Output:

func SliceEmpty added in v0.4.0

func SliceEmpty[A any](t T, slice []A, settings ...Setting)

SliceEmpty asserts slice is empty.

Example
var ints []int
SliceEmpty(t, ints)
Output:

func SliceEqFunc added in v0.4.0

func SliceEqFunc[A, B any](t T, exp []B, val []A, eq func(expectation A, value B) bool, settings ...Setting)

SliceEqFunc asserts elements of val satisfy eq for the corresponding element in exp.

Example
ints := []int{2, 4, 6}
strings := []string{"2", "4", "6"}
SliceEqFunc(t, ints, strings, func(exp string, value int) bool {
	return strconv.Itoa(value) == exp
})
Output:

func SliceEqual added in v0.4.0

func SliceEqual[E interfaces.EqualFunc[E]](t T, exp, val []E, settings ...Setting)

SliceEqual asserts val[n].Equal(exp[n]) for each element n.

Example
// type employee implements .Equal
dave := &employee{first: "dave"}
armon := &employee{first: "armon"}
mitchell := &employee{first: "mitchell"}
s1 := []*employee{dave, armon, mitchell}
s2 := []*employee{dave, armon, mitchell}
SliceEqual(t, s1, s2)
Output:

func SliceLen added in v0.4.0

func SliceLen[A any](t T, n int, slice []A, settings ...Setting)

SliceLen asserts slice is of length n.

Example
SliceLen(t, 4, []float64{32, 1.2, 0.01, 9e4})
Output:

func SliceNotContains added in v0.4.0

func SliceNotContains[A any](t T, slice []A, item A, settings ...Setting)

SliceNotContains asserts item does not exist in slice, using cmp.Equal to compare elements.

Example
SliceNotContains(t, []int{1, 2, 4, 5}, 3)
Output:

func SliceNotContainsFunc added in v0.6.3

func SliceNotContainsFunc[A, B any](t T, slice []A, item B, eq func(a A, b B) bool, settings ...Setting)

SliceNotContainsFunc asserts item does not exist inslice, using eq to compare elements.

Example
// comparing slice to element of same type
f := func(a, b int) bool {
	return a == b
}
SliceNotContainsFunc(t, []int{10, 20, 30}, 50, f)

// comparing slice to element of different type
g := func(s string, b int) bool {
	return strconv.Itoa(b) == s
}
SliceNotContainsFunc(t, []string{"1", "2", "3"}, 5, g)
Output:

func SliceNotEmpty added in v0.4.0

func SliceNotEmpty[A any](t T, slice []A, settings ...Setting)

SliceNotEmpty asserts slice is not empty.

Example
SliceNotEmpty(t, []int{2, 4, 6, 8})
Output:

func StrContains added in v0.3.0

func StrContains(t T, s, sub string, settings ...Setting)

StrContains asserts s contains substring sub.

Example
StrContains(t, "Visit https://github.com today!", "https://")
Output:

func StrContainsAny added in v0.3.0

func StrContainsAny(t T, s, chars string, settings ...Setting)

StrContainsAny asserts s contains at least one character in chars.

Example
StrContainsAny(t, "glyph", "aeiouy")
Output:

func StrContainsFields added in v0.3.0

func StrContainsFields(t T, s string, fields []string, settings ...Setting)

StrContainsFields asserts that fields is a subset of the result of strings.Fields(s).

Example
StrContainsFields(t, "apple banana cherry grape strawberry", []string{"banana", "grape"})
Output:

func StrContainsFold added in v0.3.0

func StrContainsFold(t T, s, sub string, settings ...Setting)

StrContainsFold asserts s contains substring sub, ignoring case.

Example
StrContainsFold(t, "one two three", "TWO")
Output:

func StrCount added in v0.3.0

func StrCount(t T, s, sub string, count int, settings ...Setting)

StrCount asserts s contains exactly count instances of substring sub.

Example
StrCount(t, "see sally sell sea shells by the sea shore", "se", 4)
Output:

func StrEqFold added in v0.3.0

func StrEqFold(t T, exp, val string, settings ...Setting)

StrEqFold asserts exp and val are equivalent, ignoring case.

Example
StrEqFold(t, "So MANY test Cases!", "so many test cases!")
Output:

func StrHasPrefix added in v0.3.0

func StrHasPrefix(t T, prefix, s string, settings ...Setting)

StrHasPrefix asserts that s starts with prefix.

Example
StrHasPrefix(t, "hello", "hello world!")
Output:

func StrHasSuffix added in v0.3.0

func StrHasSuffix(t T, suffix, s string, settings ...Setting)

StrHasSuffix asserts that s ends with suffix.

Example
StrHasSuffix(t, "world!", "hello world!")
Output:

func StrNotContains added in v0.3.0

func StrNotContains(t T, s, sub string, settings ...Setting)

StrNotContains asserts s does not contain substring sub.

Example
StrNotContains(t, "public static void main", "def")
Output:

func StrNotContainsAny added in v0.3.0

func StrNotContainsAny(t T, s, chars string, settings ...Setting)

StrNotContainsAny asserts s does not contain any character in chars.

Example
StrNotContainsAny(t, "The quick brown fox", "alyz")
Output:

func StrNotContainsFold added in v0.3.0

func StrNotContainsFold(t T, s, sub string, settings ...Setting)

StrNotContainsFold asserts s does not contain substring sub, ignoring case.

Example
StrNotContainsFold(t, "This is some text.", "Absent")
Output:

func StrNotEqFold added in v0.3.0

func StrNotEqFold(t T, exp, val string, settings ...Setting)

StrNotEqFold asserts exp and val are not equivalent, ignoring case.

Example
StrNotEqFold(t, "This Is SOME text.", "THIS is some TEXT!")
Output:

func StrNotHasPrefix added in v0.3.0

func StrNotHasPrefix(t T, prefix, s string, settings ...Setting)

StrNotHasPrefix asserts that s does not start with prefix.

Example
StrNotHasPrefix(t, "public static void main", "private")
Output:

func StrNotHasSuffix added in v0.3.0

func StrNotHasSuffix(t T, suffix, s string, settings ...Setting)

StrNotHasSuffix asserts that s does not end with suffix.

func StructEqual added in v0.6.2

func StructEqual[E interfaces.CopyEqual[E]](t T, original E, tweaks Tweaks[E], settings ...Setting)

StructEqual will apply each Tweak and assert E.Equal captures the modification.

Example
original := &employee{
	first: "mitchell",
	last:  "hashimoto",
	id:    1,
}
StructEqual(t, original, Tweaks[*employee]{{
	Field: "first",
	Apply: func(e *employee) { e.first = "modified" },
}, {
	Field: "last",
	Apply: func(e *employee) { e.last = "modified" },
}, {
	Field: "id",
	Apply: func(e *employee) { e.id = 999 },
}})
Output:

func True

func True(t T, condition bool, settings ...Setting)

True asserts that condition is true.

Example
True(t, true)
Output:

func UUIDv4 added in v0.3.1

func UUIDv4(t T, id string, settings ...Setting)

UUIDv4 asserts id meets the criteria of a v4 UUID.

Example
UUIDv4(t, "60bf6bb2-dceb-c986-2d47-07ac5d14f247")
Output:

func Unreachable added in v0.2.8

func Unreachable(t T, settings ...Setting)

Unreachable asserts a code path is not executed.

Example
if "foo" < "bar" {
	Unreachable(t)
}
Output:

func ValidJSON added in v0.6.1

func ValidJSON(t T, js string, settings ...Setting)

ValidJSON asserts js is valid JSON.

Example
js := `{"key": ["v1", "v2"]}`
ValidJSON(t, js)
Output:

func ValidJSONBytes added in v0.6.1

func ValidJSONBytes(t T, js []byte, settings ...Setting)

ValidJSONBytes asserts js is valid JSON.

Example
js := []byte(`{"key": ["v1", "v2"]}`)
ValidJSONBytes(t, js)
Output:

func Wait added in v0.5.0

func Wait(t T, wc *wait.Constraint, settings ...Setting)

Wait asserts wc.

Example (Continual_success)
Wait(t, wait.ContinualSuccess(
	wait.BoolFunc(func() bool {
		// will be retried until timeout expires
		// and will fail test if false is ever returned
		return true
	}),
	wait.Timeout(1*time.Second),
	wait.Gap(100*time.Millisecond),
))
Output:

Example (Initial_success)
Wait(t, wait.InitialSuccess(
	wait.BoolFunc(func() bool {
		// will be retried until returns true
		// or timeout is exceeded
		return true
	}),
	wait.Timeout(1*time.Second),
	wait.Gap(100*time.Millisecond),
))
Output:

func Zero added in v0.2.5

func Zero[N interfaces.Number](t T, n N, settings ...Setting)

Zero asserts n == 0.

Example
Zero(t, 0)
Zero(t, 0.0)
Output:

Types

type PostScript added in v0.3.0

type PostScript interface {
	// Label should categorize what is in Content.
	Label() string

	// Content contains extra contextual information for debugging a test failure.
	Content() string
}

A PostScript is used to annotate a test failure with additional information.

Can be useful in large e2e style test cases, where adding additional context beyond an assertion helps in debugging.

type Setting added in v0.6.0

type Setting func(s *Settings)

A Setting changes the behavior of a test case assertion.

func Cmp added in v0.6.0

func Cmp(options ...cmp.Option) Setting

Cmp enables configuring cmp.Option values for modifying the behavior of the cmp.Equal function. Custom cmp.Option values control how the cmp.Equal function determines equality between the two objects.

https://github.com/google/go-cmp/blob/master/cmp/options.go#L16

func Func added in v0.3.0

func Func(f func() string) Setting

Func adds the string produced by f as an annotation to the output of a test case failure.

func Sprint added in v0.3.0

func Sprint(args ...any) Setting

Sprint appends a Sprint-string as an annotation to the output of a test case failure.

func Sprintf added in v0.3.0

func Sprintf(msg string, args ...any) Setting

Sprintf appends a Sprintf-string as an annotation to the output of a test case failure.

func Values added in v0.3.0

func Values(vals ...any) Setting

Values adds formatted key-val mappings as an annotation to the output of a test case failure.

type Settings added in v0.6.0

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

Settings are used to manage a collection of Setting values used to modify the behavior of a test case assertion. Currently supports specifying custom error output content, and custom cmp.Option comparators / transforms.

Use Cmp for specifying custom cmp.Option values.

Use Sprint, Sprintf, Values, Func for specifying custom failure output messages.

type T

type T interface {
	Helper()
	Errorf(string, ...any)
}

T is the minimal set of functions to be implemented by any testing framework compatible with the test package.

type Tweak added in v0.6.2

type Tweak[E interfaces.CopyEqual[E]] struct {
	Field string
	Apply interfaces.TweakFunc[E]
}

Tweak is used to modify a struct and assert its Equal method captures the modification.

Field is the name of the struct field and is used only for error printing. Apply is a function that modifies E.

type Tweaks added in v0.6.3

type Tweaks[E interfaces.CopyEqual[E]] []Tweak[E]

Tweaks is a slice of Tweak.

Directories

Path Synopsis
internal
constraints
Package constraints defines a set of useful constraints to be used with type parameters.
Package constraints defines a set of useful constraints to be used with type parameters.
Package test provides a modern generic testing assertions library.
Package test provides a modern generic testing assertions library.
Package portal (Port Allocator) provides a helper for reserving free TCP ports across multiple processes on the same machine.
Package portal (Port Allocator) provides a helper for reserving free TCP ports across multiple processes on the same machine.
Package skip provides helper functions for skipping test cases.
Package skip provides helper functions for skipping test cases.
Package wait provides constructs for waiting on conditionals within specified constraints.
Package wait provides constructs for waiting on conditionals within specified constraints.

Jump to

Keyboard shortcuts

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