exp

package module
v1.1.0 Latest Latest
Warning

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

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

README

Exp -- test fixture assertions

Exp was motivated by the wish to have

  • more self consistent testing
  • have assertions as compact as possible
  • have well thought through and powerful assertions cross package available

The compactness comes from the observation that most of the time a test execution can be terminated if an assertion fails; and having the test name, the line of the failing assertion and a generic failure message typically suffices to know where to look to fix things:

func Test(t *testing.T) {
    bb, err := os.Read("a-file")
    exp := exp.ErrIs(t, err, nil)
    ProductionDoesSomethingWith(bb)
    exp.Contains(bb, []byte("the answer is 42"))
}

If above test fails in its second or fourth line there is typically not more information needed to get started to fix what's broken. In the cases where a user-defined failure message is wanted or a test should continue to run after a failed assertion the methods/constructors exp/Exp.Msg and exp/Exp.Err can be used to setup a specific message and change the failure behavior for the next assertion but only for the next assertion.

For the last point a hand full of assertions is defined which make up typically more than 90% of the done assertions. Exp.Contains asserts not only strings like strings.Contains but string representations which may be also types implementing the fmt.Stringer interface or which are simply converted to their respective string representation. Exp.Eq investigates the typing of its arguments, considers pointers and otherwise investigates again string representations resulting in a human readable diff in case of non equality. Exp.Matches takes again the string representation of its first argument and matches it against a dynamically build regex which joins the variadic strings by the .*? regex while escaping special runes which have semantic in regexp and taking care of new-lines. Eventually finally lets us execute an assertion several times over time until either the assertion passes or a set timeout is reached.

func Test(t *testing.T) {
    // ... closure arg and closure strings ...
    exp.Eventually(t, func(exp *ExpBool) bool {
        return exp.Matches(closureArg, closureStrings...)
    }, time.Millisecond)
    // ...
}

See exp_test.go and the './testdata/test'-package for examples of how to make use of the Exp-type respectively of the exp package.

Documentation

Overview

Package exp was motivated by the wish to have

  • more self consistent testing
  • have assertions as compact as possible
  • have well thought through and powerful assertions cross package available

The compactness comes from the observation that most of the time a test execution can be terminated if an assertion fails; and having the test name, the line of the failing assertion and a generic failure message typically suffices to know where to look to fix things:

func Test(t *testing.T) {
	bb, err := os.Read("a-file")
	exp := exp.ErrIs(err, nil)
	ProductionDoesSomethingWith(bb)
	exp.Contains(bb, []byte("the answer is 42"))
}

If above test fails in its second or fourth line there is typically not more information needed to get started to fix what's broken. In the cases where a user-defined failure message is wanted or a test should continue to run after a failed assertion the methods/constructors exp/Exp.Msg and exp/Exp.Err can be used to setup a specific message and change the failure behavior for the next assertion but only for the next assertion.

For the last point a hand full of assertions is defined which make up typically more than 90% of the done assertions and which can be found here and there in various implementations. Exp.Contains asserts not only strings like strings.Contains but string representations which may be also types implementing the fmt.Stringer interface or which are simple converted to their respective string representation. Exp.Eq investigates the typing of its arguments, considers pointers and otherwise investigates again string representations resulting in a human readable diff in case of non equality. Exp.Matches takes again the string representation of its first argument and matches it against a dynamically build regex which joins the variadic strings by the `.*?` regex while escaping special runes which have semantic in regexp and taking care of new-lines. Eventually finally lets us execute a assertion several times over time until either the assertion passes or a set timeout is reached.

func Test(t *testing.T) {
	// ... closure arg and closure strings ...
	exp.Eventually(t, func(exp *ExpBool) bool {
		return exp.Matches(closureArg, closureStrings...)
	}, time.Millisecond)
	// ...
}

See exp_test.go and the './testdata/test'-package for examples of how to make use of the Exp-type respectively of the exp package.

Index

Constants

View Source
const (
	// FailMust is the generic failure message for the 'Must'-assertion
	FailMust = "expected given argument to be true"

	// FailMust is the generic failure message for the 'MustNot'-assertion
	FailMustNot = "expected given argument to be not true"

	// FailPanics is the generic failure message for the 'Panics'-assertion
	FailPanics = "expected given function to panic"

	// FailErrIs is the generic failure message for the 'ErrIs'-assertion
	FailErrIs = "expected given error of target '%v'"

	// FailContains is the generic failure message for the
	// 'Contains'-assertion
	FailContains = "expected following string (representation)%s" +
		">>>>>> to be in >>>>>>%s"

	// FailContainsNot is the generic failure message for the
	// 'ContainsNot'-assertion
	FailContainsNot = "expected following string (representation)%s" +
		">>>>>> NOT to be in >>>>>>%s"

	// FailEqTypes is the generic failure message for the 'Eq'-assertion
	// in case of type mismatch
	FailEqTypes = "expected given values of same type; got %T != %T"

	// FailEqPointer is the generic failure message for the
	// 'Eq'-assertion in case of pointer inequality
	FailEqPointer = "expected equal pointers; got %p != %p"

	// FailEqDiff is the generic failure message for the 'Eq'-assertion
	// in case not-equal values/string representations
	FailEqDiff = "expected equal string representations; got\n%s"

	// FailEqNot is the generic failure message for the
	// 'EqNot'-assertion
	FailEqNot = "expected different values; got '%s' == '%s'"

	// FailMatches is the generic failure message for the
	// 'Matches'-assertion
	FailMatches = "Regexp%s>>>>>> doesn't match >>>>>>%s"

	// FailMatchesNot is the generic failure message for the
	// 'MatchesNot'-assertion
	FailMatchesNot = "Regexp%s>>>>>> matches >>>>>>%s"

	// FailEventually is the generic failure message for the
	// 'MatchesEventually'-assertion in case no ExpBool assertion was
	// used to fail.
	FailEventually = "expected eventually condition evaluate to true"

	// ZeroString replaces in the Contains failure message an zero value
	ZeroString = "ZERO-STRING"
)

Variables

View Source
var EventuallyTimeoutDflt = 500 * time.Millisecond

EventuallyTimeoutDflt is the default duration the Exp.Eventually assertion waits for its condition to evaluate to true

Functions

func Errors added in v1.1.0

func Errors(e *Exp) bool

Errors informs if given expectations instance should rather error than fatale.

func Message added in v1.1.0

func Message(e *Exp) string

Message extracts of given expectations instance e a potentially set message.

Types

type Exp

type Exp struct {
	T                 T
	EventuallyTimeout time.Duration
	LastPanic         any
	// contains filtered or unexported fields
}

Exp provides assertions for the test associated by set Exp.T implementation.

func Contains

func Contains(t T, value, sub StringRepresentation) *Exp

Contains returns a new Exp-instance having given values already asserted, i.e. it fatales the test if value's string representation doesn't contain sub's string representation.

func ContainsNot

func ContainsNot(t T, value, sub StringRepresentation) *Exp

ContainsNot returns a new Exp-instance having given values already asserted, i.e. it fatales the test if value's string representation contains sub's string representation.

func Eq

func Eq(t T, a, b any) *Exp

Eq returns a new Exp-instance having given values already asserted, i.e. it fatales the test if a and b a are not considered equal (see Exp.Eq).

func EqNot

func EqNot(t T, a, b any) *Exp

EqNot returns a new Exp-instance having given values already asserted, i.e. it fatales the test if a and b a are considered equal (see Exp.Eq).

func Err

func Err(t T) *Exp

Err returns a new Exp-instance having the error-flag set (instead of failing a test fatal).

func ErrIs

func ErrIs(t T, err, target error) *Exp

ErrIs returns a new Exp-instance having given error err already asserted, i.e. it fatales the test if err does not match target.

func Eventually

func Eventually(
	t T, cond func(*ExpBool) bool, timeout ...time.Duration,
) *Exp

Eventually returns a new Exp-instance having given value already asserted, i.e. it fatales the test if given condition cond doesn't return true within set Exp.EventuallyTimeout.

func Matches

func Matches(t T, value StringRepresentation, ss ...string) *Exp

Matches returns a new Exp-instance having given values already asserted, i.e. it fatales the test if value's string representation is not matched by the joined variadic `.*?`-regex (see Exp.Matches).

func MatchesNot

func MatchesNot(t T, value StringRepresentation, ss ...string) *Exp

MatchesNot returns a new Exp-instance having given values already asserted, i.e. it fatales the test if value's string representation is matched by the joined variadic `.*?`-regex (see Exp.Matches).

func Msg

func Msg(t T, msg string, args ...any) *Exp

Msg return a new Exp-instance having given message msg set as the failure message for the next assertion.

func Must

func Must(t T, value bool) *Exp

Must returns a new Exp-instance having given value already asserted, i.e. it fatales the test if given value is not true.

func MustNot

func MustNot(t T, value bool) *Exp

MustNot returns a new Exp-instance having given value already asserted, i.e. it fatales the test if given value is not false.

func Panics

func Panics(t T, value func()) *Exp

MustNot returns a new Exp-instance having given value already asserted, i.e. it fatales the test if given value does not panic.

func (*Exp) Contains

func (e *Exp) Contains(value, sub StringRepresentation, args ...any)

Contains fails the test if given value's string representation doesn't contain given sub-value's string representation. In case of given variadic arguments sub is interpreted as a format string, i.e.: sub = fmt.Sprintf(sub, args...).

func (*Exp) ContainsNot

func (e *Exp) ContainsNot(value, sub StringRepresentation, args ...any)

Contains fails the test if given value's string representation contains given sub-value's string representation. In case of given variadic arguments sub is interpreted as a format string, i.e.: sub = fmt.Sprintf(sub, args...).

func (*Exp) Eq

func (e *Exp) Eq(a, b any)

Eq fails associated test if given values a, b are not considered equal, i.e.: - if they are not of the same type and a && b are no stringers - if a != b in case of two pointers - if toString(a) != toString(b)

func (*Exp) EqNot

func (e *Exp) EqNot(a, b any)

EqNot fails associated test if given values a, b are considered equal, i.e.: - if a == b in case of two pointers - if toString(a) == toString(b) otherwise

func (*Exp) Err

func (e *Exp) Err() *Exp

Err fails the next assertion with an error instead of fatal, i.e. doesn't stop the test execution on failing.

func (*Exp) ErrIs

func (e *Exp) ErrIs(err, target error)

ErrIs fails associated test if given error is not of target error. NOTE this assertion may also be used to ensure that no error occurred:

Exp.ErrIs(errors.New("err"), nil)

will fail the test.

func (*Exp) Eventually

func (e *Exp) Eventually(cond func(*ExpBool) bool, timeout ...time.Duration)

Eventually fails associated test if given condition cond not returns true within set Exp.EventuallyTimeout. Note if Exp.EventuallyTimeout is not set it defaults to EventuallyTimeoutDflt which may be overwritten by providing an optional timeout argument. The condition is provided wit an ExpBool instance providing assertions that evaluate to true or false, i.e. may be called repeatedly and set on failing a generic fail message like the Exp assertions. The last such message set before Eventually fails is reported as failure message (if Eventually fails).

func (*Exp) Matches

func (e *Exp) Matches(value StringRepresentation, ss ...string)

Matches escapes given variadic-strings before it joins them with the `.*?`-separator and matches the result against given value's string representation, e.g. a string str:

<p>
   some text
</p>

would be matched by

exp.Matches(str, "p", "me", "x", "/p").

Matches fails associated test if the matching fails.

func (*Exp) MatchesNot

func (e *Exp) MatchesNot(value StringRepresentation, ss ...string)

MatchesNot fails associated test if the regex build from given variadic strings ss matches given value.

func (*Exp) Msg

func (e *Exp) Msg(fmtMessage string, args ...any) *Exp

Msg sets a user defined failure message for the next assertion.

func (*Exp) Must

func (e *Exp) Must(truthy bool)

Must fails associated test if given bool truthy is not true.

func (*Exp) MustNot

func (e *Exp) MustNot(falsy bool)

MustNot fails associated test if given bool falsy is not false.

func (*Exp) Panics

func (e *Exp) Panics(f func()) (pncValue any)

Panics fails associated test if given function f's execution doesn't panic.

type ExpBool

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

ExpBool provides the assertions as boolean functions which can be used inside the condition of an Eventually assertion which provides to the conditional-callback an ExpBool instance.

func (*ExpBool) Contains

func (e *ExpBool) Contains(value, sub StringRepresentation) bool

Contains return true if value's string representation contains given sub string representation; otherwise false.

func (*ExpBool) ContainsNot

func (e *ExpBool) ContainsNot(value, sub StringRepresentation) bool

ContainsNot return true if value's string representation contains not give sub string representation; otherwise false

func (*ExpBool) Eq

func (e *ExpBool) Eq(a, b any) bool

Eq returns true if given values a and b are considered equal; otherwise false (see Exp.Eq).

func (*ExpBool) EqNot

func (e *ExpBool) EqNot(a, b any) bool

EqNot returns true if given values a and b are considered not equal; otherwise false (see Exp.Eq).

func (*ExpBool) ErrIs

func (e *ExpBool) ErrIs(err, target error) bool

ErrIs return true if given error err matches target; otherwise false.

func (*ExpBool) Matches

func (e *ExpBool) Matches(value StringRepresentation, ss ...string) bool

Matches returns true if given values string representation is matched by the variadic `.*?`-regex joined from given strings ss; false otherwise (see [Exp.Match]).

func (*ExpBool) MatchesNot

func (e *ExpBool) MatchesNot(value StringRepresentation, ss ...string) bool

Matches returns true if given values string representation is *not* matched by the variadic `.*?`-regex joined from given strings ss; false otherwise (see [Exp.Match]).

func (*ExpBool) Must

func (e *ExpBool) Must(value bool) bool

Must returns true if given bool value is true; otherwise false.

func (*ExpBool) MustNot

func (e *ExpBool) MustNot(value bool) bool

MustNot return true if given bool value is false; otherwise false.

func (*ExpBool) Panics

func (e *ExpBool) Panics(f func()) (exp bool)

Panics returns true if given function f panics; otherwise false.

type StringRepresentation

type StringRepresentation interface{}

StringRepresentation documents what a string representation of any type is:

  • the string if it is of type string,
  • the return value of String if the Stringer interface is implemented,
  • fmt.Sprintf("%v", value) in all other cases.

type T

type T interface {
	Fatal(args ...any)
	Helper()
	Error(args ...any)
}

T interface implementations associate a test with an Exp-instance whose *testing.T instance implements this interface.

Jump to

Keyboard shortcuts

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