verify

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 6, 2024 License: MIT Imports: 7 Imported by: 0

README

fluentassert

Extensible, type-safe, fluent assertion Go library.

Go Reference Keep a Changelog GitHub Release go.mod LICENSE

Build Status Go Report Card Codecov Mentioned in Awesome Go

Please ⭐ Star this repository if you find it valuable and worth maintaining.

Description

The fluent API makes the assertion code easier to read and write (more).

The generics (type parameters) make the usage type-safe.

The library is extensible by design.

In general, avoid using assertion libraries. Use this library if you still have a preference to use one. Consider using github.com/google/go-cmp and writing custom helpers instead.

Quick start
package test

import (
	"testing"

	"github.com/fluentassert/verify"
)

func Foo() (string, error) {
	return "wrong", nil
}

func TestFoo(t *testing.T) {
	got, err := Foo()

	verify.NoError(err).Require(t)           // Require(f) uses t.Fatal(f), stops execution if fails
	verify.String(got).Equal("ok").Assert(t) // Assert(f) uses t.Error(f), continues execution if fails
}
$ go test
--- FAIL: TestFoo (0.00s)
    basic_test.go:17:
        the objects are not equal
        got: "wrong"
        want: "ok"

⚠ Do not forget calling Assert(t) or Require(t) which executes the actual assertion.

Supported types

Out-of-the-box the package provides fluent assertions for the following types. The more specific function you use, the more assertions you get.

Go type Assertion entry point
interface{} (any) verify.Any()
comparable verify.Obj()
constraints.Ordered verify.Ordered()
constraints.Number verify.Number()
string verify.String()
error verify.Error()
[]T (slice) verify.Slice()
map[K]V (map) verify.Map()

Below you can find some convenience functions.

Deep equality

For testing deep equality use DeepEqual() or NotDeepEqual().

package test

import (
	"testing"

	"github.com/fluentassert/verify"
)

type A struct {
	Str   string
	Bool  bool
	Slice []int
}

func TestDeepEqual(t *testing.T) {
	got := A{Str: "wrong", Slice: []int{1, 4}}

	verify.Any(got).DeepEqual(
		A{Str: "string", Bool: true, Slice: []int{1, 2}},
	).Assert(t)
}
$ go test
--- FAIL: TestDeepEqual (0.00s)
    deepeq_test.go:20:
        mismatch (-want +got):
          test.A{
        -       Str:  "string",
        +       Str:  "wrong",
        -       Bool: true,
        +       Bool: false,
                Slice: []int{
                        1,
        -               2,
        +               4,
                },
          }
Collection assertions

The library contains many collection assertion. Below is an example of checking unordered equality.

package test

import (
	"testing"

	"github.com/fluentassert/verify"
)

func TestSlice(t *testing.T) {
	got := []int { 3, 1, 2 }

	verify.Slice(got).Equivalent([]int { 2, 3, 4 }).Assert(t)
}
$ go test
--- FAIL: TestSlice (0.00s)
    slice_test.go:12:
        not equivalent
        got: [3 1 2]
        want: [2 3 4]
        extra got: [1]
        extra want: [4]
Periodic polling

For asynchronous testing you can use verify.Eventually() or verify.EventuallyChan().

package test

import (
	"net/http"
	"testing"
	"time"

	"github.com/fluentassert/verify"
)

func TestPeriodic(t *testing.T) {
	verify.Eventually(10*time.Second, time.Second, func() verify.FailureMessage {
		client := http.Client{Timeout: time.Second}
		resp, err := client.Get("http://not-existing:1234")
		if err != nil {
			return verify.NoError(err)
		}
		return verify.Number(resp.StatusCode).Lesser(300)
	}).Assert(t)
}
$ go test
--- FAIL: TestPeriodic (10.00s)
    async_test.go:19:
        function never passed, last failure message:
        Get "http://not-existing:1234": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
Custom predicates

For the most basic scenarios, you can use one of the Check(), Should(), ShouldNot() assertions.

package test

import (
	"strings"
	"testing"

	"github.com/fluentassert/verify"
)

func TestShould(t *testing.T) {
	got := "wrong"

	chars := "abc"
	verify.Any(got).Should(func(got string) bool {
		return strings.ContainsAny(got, chars)
	}).Assertf(t, "does not contain any of: %s", chars)
}
$ go test
--- FAIL: TestShould (0.00s)
    should_test.go:16: does not contain any of: abc
        object does not meet the predicate criteria
        got: "wrong"
Panics

For testing panics use verify.Panics() and verify.NotPanics().

Custom assertion function

You can create a function that returns FailureMessage. Use verify.And() and verify.Or() functions together with Prefix() method to create complex assertions.

package test

import (
	"testing"

	"github.com/fluentassert/verify"
)

type A struct {
	Str string
	Ok  bool
}

func TestCustom(t *testing.T) {
	got := A{Str: "something was wrong"}

	verifyA(got).Assert(t)
}

func verifyA(got A) verify.FailureMessage {
	return verify.And(
		verify.String(got.Str).Contain("ok").Prefix("got.String: "),
		verify.True(got.Ok).Prefix("got.Ok: "),
	)
}
$ go test
--- FAIL: TestCustom (0.00s)
    custom_test.go:17:
        got.String: the value does not contain the substring
        got: "something was wrong"
        substr: "ok"

        got.Ok: the value is false

Extensibility

You can take advantage of the FailureMessage and Fluent* types to create your own fluent assertions for a given type.

For reference, take a look at the implementation of existing fluent assertions in this repository (for example comparable.go).

Supported Go versions

Minimal supported Go version is 1.18.

Contributing

See CONTRIBUTING.md if you want to help.

License

fluentassert is licensed under the terms of the MIT license.

github.com/google/go-cmp (license: BSD-3-Clause) is the only third-party dependency.

Documentation

Overview

Package verify contains the most useful type-safe fluent assertion functions.

It also provides the FailureMessage type which you can use for creating your own fluent assertions.

At last, you may embed a Fluent* type to extend it with additional assertion functions.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FailureMessage

type FailureMessage string

FailureMessage encapsulates a failure message that can by emitted using objects compatible with the testing.TB interface.

func And

func And(assertions ...FailureMessage) FailureMessage

And accumalates non-empty failure messages.

func Eventually

func Eventually(timeout, interval time.Duration, fn func() FailureMessage) FailureMessage

Eventually executes the test function until it returns an empty FailureMessage or timeout elapses.

func EventuallyChan

func EventuallyChan[TTimerPayload, TTickPayload any](timeout <-chan (TTimerPayload), ticker <-chan (TTickPayload), fn func() FailureMessage) FailureMessage

EventuallyChan executes the test function until it returns an empty FailureMessage or timeout elapses.

func False

func False[T ~bool](got T) FailureMessage

False tests if the object is a false value.

func IsError

func IsError(err error) FailureMessage

IsError tests if the error is non-nil.

func Nil

func Nil(v any) FailureMessage

Nil tests if provided interface value is nil. Use it only for interfaces. For structs and pointers use Obj(got).Zero().

func NoError

func NoError(err error) FailureMessage

NoError tests if the error is nil.

func NotNil

func NotNil(v any) FailureMessage

NotNil tests if provided interface is not nil. Use it only for interfaces. For structs and pointers use Obj(got).NonZero().

func NotPanics

func NotPanics(fn func()) (msg FailureMessage)

NotPanics tests if the function does not panic when executed.

func Or

func Or(assertions ...FailureMessage) FailureMessage

Or accumalates failure messages if all are not empty.

func Panics

func Panics(fn func()) (msg FailureMessage)

Panics tests if the function panics when executed.

func True

func True[T ~bool](got T) FailureMessage

True tests if the object is a true value.

func (FailureMessage) Assert

func (msg FailureMessage) Assert(t interface {
	Error(args ...any)
}, args ...any,
) bool

Assert calls t.Error if the failure message is not empty. Calling Error on *testing.T marks the the function as having failed and continues its execution. Returns true when the failure message is empty.

func (FailureMessage) Assertf

func (msg FailureMessage) Assertf(t interface {
	Errorf(format string, args ...any)
}, format string, args ...any,
) bool

Assertf calls t.Errorf if the failure message is not empty. Calling Errorf on *testing.T marks the the function as having failed and continues its execution. Returns true when the failure message is empty

func (FailureMessage) Prefix

func (msg FailureMessage) Prefix(s string) FailureMessage

Prefix adds prefix if the failure message is not empty.

func (FailureMessage) Require

func (msg FailureMessage) Require(t interface {
	Fatal(args ...any)
}, args ...any,
) bool

Require calls t.Fatal if the failure message is not empty. Calling Fatal on *testing.T stops the test function execution. Returns true when the failure message is empty.

func (FailureMessage) Requiref

func (msg FailureMessage) Requiref(t interface {
	Fatalf(format string, args ...any)
}, format string, args ...any,
) bool

Requiref calls t.Fatalf if the failure message is not empty. Calling Fatalf on *testing.T stops the test function execution. Returns true when the failure message is empty.

type FluentAny

type FluentAny[T any] struct {
	Got T
}

FluentAny encapsulates assertions for any object.

func Any

func Any[T any](got T) FluentAny[T]

Any is used for testing any object.

func (FluentAny[T]) Check

func (x FluentAny[T]) Check(fn func(got T) FailureMessage) FailureMessage

Check tests the object using the provided function.

func (FluentAny[T]) DeepEqual

func (x FluentAny[T]) DeepEqual(want T, opts ...cmp.Option) FailureMessage

DeepEqual tests if the objects are deep equal using github.com/google/go-cmp/cmp.

func (FluentAny[T]) NotDeepEqual

func (x FluentAny[T]) NotDeepEqual(obj T, opts ...cmp.Option) FailureMessage

NotDeepEqual tests if the objects are not deep equal using github.com/google/go-cmp/cmp.

func (FluentAny[T]) Should

func (x FluentAny[T]) Should(pred func(got T) bool) FailureMessage

Should tests if the object meets the predicate criteria.

func (FluentAny[T]) ShouldNot

func (x FluentAny[T]) ShouldNot(fn func(got T) bool) FailureMessage

ShouldNot tests if the object does not meet the predicate criteria.

type FluentError

type FluentError struct {
	FluentAny[error]
	FluentString[string]
}

FluentError encapsulates assertions for error object.

func Error

func Error(got error) FluentError

Error is used for testing error object.

func (FluentError) As

func (x FluentError) As(target any) FailureMessage

As finds the first error in err's chain that matches target, and if one is found, sets target to that error value. In such case it is a success..

func (FluentError) AsNot

func (x FluentError) AsNot(target any) FailureMessage

AsNot finds the first error in err's chain that matches target, and if one is found, sets target to that error value. In such case it is a failure.

func (FluentError) Is

func (x FluentError) Is(target error) FailureMessage

Is tests whether any error in err's chain matches target.

func (FluentError) IsNot

func (x FluentError) IsNot(target error) FailureMessage

IsNot tests whether no error in err's chain matches target.

type FluentMap

type FluentMap[K comparable, V any] struct {
	FluentAny[map[K]V]
}

FluentMap encapsulates assertions for a map.

func Map

func Map[K comparable, V any](got map[K]V) FluentMap[K, V]

Map is used for testing a map.

func (FluentMap[K, V]) All

func (x FluentMap[K, V]) All(predicate func(K, V) bool) FailureMessage

All tests if all of the map's pairs meet the predicate criteria.

func (FluentMap[K, V]) Any

func (x FluentMap[K, V]) Any(predicate func(K, V) bool) FailureMessage

Any tests if any of the map's pairs meets the predicate criteria.

func (FluentMap[K, V]) Contain

func (x FluentMap[K, V]) Contain(want map[K]V, opts ...cmp.Option) FailureMessage

Contain tests if the map contains all pairs from want.

func (FluentMap[K, V]) ContainPair

func (x FluentMap[K, V]) ContainPair(k K, v V, opts ...cmp.Option) FailureMessage

ContainPair tests if the map contains the pair.

func (FluentMap[K, V]) Empty

func (x FluentMap[K, V]) Empty() FailureMessage

Empty tests if the slice is empty.

func (FluentMap[K, V]) Len added in v1.1.0

func (x FluentMap[K, V]) Len(want int) FailureMessage

Len tests the length of the map.

func (FluentMap[K, V]) None

func (x FluentMap[K, V]) None(predicate func(K, V) bool) FailureMessage

None tests if none of the map's pairs meets the predicate criteria.

func (FluentMap[K, V]) NotContain

func (x FluentMap[K, V]) NotContain(want map[K]V, opts ...cmp.Option) FailureMessage

NotContain tests if the map does not contains all pairs from want.

func (FluentMap[K, V]) NotContainPair

func (x FluentMap[K, V]) NotContainPair(k K, v V, opts ...cmp.Option) FailureMessage

NotContainPair tests if the map does not contain the pair.

func (FluentMap[K, V]) NotEmpty

func (x FluentMap[K, V]) NotEmpty() FailureMessage

NotEmpty tests if the slice is not empty.

type FluentNumber

type FluentNumber[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64] struct {
	FluentOrdered[T]
}

FluentNumber encapsulates assertions for numbers that supports the operators < <= >= > + - * /.

func Number

func Number[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64](got T) FluentNumber[T]

Number is used for testing numbers that supports the operators < <= >= > + - * /.

func (FluentNumber[T]) InDelta

func (x FluentNumber[T]) InDelta(want T, delta float64) FailureMessage

InDelta tests that the numbers have an absolute error (distance) less or equal than delta.

func (FluentNumber[T]) InEpsilon

func (x FluentNumber[T]) InEpsilon(want T, epsilon float64) FailureMessage

InEpsilon tests that the numbers have a relative error less or equal than epsilon.

func (FluentNumber[T]) NotInDelta

func (x FluentNumber[T]) NotInDelta(want T, delta float64) FailureMessage

NotInDelta tests that the numbers have an absolute error (distance) greater than delta.

func (FluentNumber[T]) NotInEpsilon

func (x FluentNumber[T]) NotInEpsilon(want T, epsilon float64) FailureMessage

NotInEpsilon tests that the numbers have a relative error greater than epsilon.

type FluentObj

type FluentObj[T comparable] struct {
	FluentAny[T]
}

FluentObj encapsulates assertions for comparable object.

func Obj

func Obj[T comparable](got T) FluentObj[T]

Obj is used for testing a comparable object.

func (FluentObj[T]) Equal

func (x FluentObj[T]) Equal(want T) FailureMessage

Equal tests the objects using == operator.

func (FluentObj[T]) NonZero

func (x FluentObj[T]) NonZero() FailureMessage

NonZero tests if the object is a non-zero value.

func (FluentObj[T]) NotEqual

func (x FluentObj[T]) NotEqual(obj T) FailureMessage

NotEqual tests the objects using != operator.

func (FluentObj[T]) Zero

func (x FluentObj[T]) Zero() FailureMessage

Zero tests if the object is a zero value.

type FluentOrdered

type FluentOrdered[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string] struct {
	FluentObj[T]
}

FluentOrdered encapsulates assertions for ordered object that supports the operators < <= >= >.

func Ordered

func Ordered[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string](got T) FluentOrdered[T]

Ordered is used for testing a ordered object that supports the operators < <= >= >.

func (FluentOrdered[T]) Greater

func (x FluentOrdered[T]) Greater(than T) FailureMessage

Greater tests the objects using > operator.

func (FluentOrdered[T]) GreaterOrEqual

func (x FluentOrdered[T]) GreaterOrEqual(than T) FailureMessage

GreaterOrEqual tests the objects using >= operator.

func (FluentOrdered[T]) Lesser

func (x FluentOrdered[T]) Lesser(than T) FailureMessage

Lesser tests the objects using < operator.

func (FluentOrdered[T]) LesserOrEqual

func (x FluentOrdered[T]) LesserOrEqual(than T) FailureMessage

LesserOrEqual tests the objects using <= operator.

type FluentSlice

type FluentSlice[T any] struct {
	FluentAny[[]T]
}

FluentSlice encapsulates assertions for a slice.

func Slice

func Slice[T any](got []T) FluentSlice[T]

Slice is used for testing a slice.

func (FluentSlice[T]) All

func (x FluentSlice[T]) All(predicate func(T) bool) FailureMessage

All tests if all of the slice's items meet the predicate criteria.

func (FluentSlice[T]) Any

func (x FluentSlice[T]) Any(predicate func(T) bool) FailureMessage

Any tests if any of the slice's items meets the predicate criteria.

func (FluentSlice[T]) Contain

func (x FluentSlice[T]) Contain(item T, opts ...cmp.Option) FailureMessage

Contain tests if the slice contains the item.

func (FluentSlice[T]) Empty

func (x FluentSlice[T]) Empty() FailureMessage

Empty tests if the slice is empty.

func (FluentSlice[T]) Equivalent

func (x FluentSlice[T]) Equivalent(want []T, opts ...cmp.Option) FailureMessage

Equivalent tests if the slice has the same items as want in any order.

func (FluentSlice[T]) Len added in v1.1.0

func (x FluentSlice[T]) Len(want int) FailureMessage

Len tests the length of the slice.

func (FluentSlice[T]) None

func (x FluentSlice[T]) None(predicate func(T) bool) FailureMessage

None tests if none of the slice's items meets the predicate criteria.

func (FluentSlice[T]) NotContain

func (x FluentSlice[T]) NotContain(item T, opts ...cmp.Option) FailureMessage

NotContain tests if the slice does not contain the item.

func (FluentSlice[T]) NotEmpty

func (x FluentSlice[T]) NotEmpty() FailureMessage

NotEmpty tests if the slice is not empty.

func (FluentSlice[T]) NotEquivalent

func (x FluentSlice[T]) NotEquivalent(want []T, opts ...cmp.Option) FailureMessage

NotEquivalent tests if the slice does not have the same items as want in any order.

type FluentString

type FluentString[T ~string] struct {
	FluentOrdered[T]
}

FluentString encapsulates assertions for string object.

func String

func String[T ~string](got T) FluentString[T]

String is used for testing a string object.

func (FluentString[T]) Contain

func (x FluentString[T]) Contain(substr string) FailureMessage

Contain tests if the string contains the substring.

func (FluentString[T]) Empty

func (x FluentString[T]) Empty() FailureMessage

Empty tests if the string is not empty.

func (FluentString[T]) EqualFold

func (x FluentString[T]) EqualFold(want string) FailureMessage

EqualFold tests if the values interpreted as UTF-8 strings, are equal under simple Unicode case-folding, which is a more general form of case-insensitivity.

func (FluentString[T]) Len added in v1.1.0

func (x FluentString[T]) Len(want int) FailureMessage

Len tests the length of the string.

func (FluentString[T]) MatchRegex

func (x FluentString[T]) MatchRegex(regex *regexp.Regexp) FailureMessage

MatchRegex tests if the string matches the regular expression.

func (FluentString[T]) NoPrefix

func (x FluentString[T]) NoPrefix(prefix string) FailureMessage

NoPrefix tests if the string does not start with the prefix.

func (FluentString[T]) NoSufix

func (x FluentString[T]) NoSufix(sufix string) FailureMessage

NoSufix tests if the string does not end with the sufix.

func (FluentString[T]) NotContain

func (x FluentString[T]) NotContain(substr string) FailureMessage

NotContain tests if the string does not contain the substring.

func (FluentString[T]) NotEmpty

func (x FluentString[T]) NotEmpty() FailureMessage

NotEmpty tests if the string is not empty.

func (FluentString[T]) NotEqualFold

func (x FluentString[T]) NotEqualFold(want string) FailureMessage

NotEqualFold tests if the values interpreted as UTF-8 strings, are not equal under simple Unicode case-folding, which is a more general form of case-insensitivity.

func (FluentString[T]) NotMatchRegex

func (x FluentString[T]) NotMatchRegex(regex *regexp.Regexp) FailureMessage

NotMatchRegex tests if the string does not match the regular expression.

func (FluentString[T]) Prefix

func (x FluentString[T]) Prefix(prefix string) FailureMessage

Prefix tests if the string starts with the prefix.

func (FluentString[T]) Sufix

func (x FluentString[T]) Sufix(sufix string) FailureMessage

Sufix tests if the string ends with the sufix.

Directories

Path Synopsis
build module

Jump to

Keyboard shortcuts

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