You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
731 lines
18 KiB
Go
731 lines
18 KiB
Go
package assert
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"git.noahlan.cn/noahlan/ntool/narr"
|
|
"git.noahlan.cn/noahlan/ntool/nmap"
|
|
"git.noahlan.cn/noahlan/ntool/nmath"
|
|
"git.noahlan.cn/noahlan/ntool/nreflect"
|
|
"git.noahlan.cn/noahlan/ntool/nstd"
|
|
"github.com/gookit/color"
|
|
"reflect"
|
|
"runtime/debug"
|
|
"strings"
|
|
)
|
|
|
|
// Nil asserts that the given is a nil value
|
|
func Nil(t TestingT, give any, fmtAndArgs ...any) bool {
|
|
if nstd.IsNil(give) {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Expected nil, but got: %#v", give), fmtAndArgs)
|
|
}
|
|
|
|
// NotNil asserts that the given is a not nil value
|
|
func NotNil(t TestingT, give any, fmtAndArgs ...any) bool {
|
|
if !nstd.IsNil(give) {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t, "Should not nil value", fmtAndArgs)
|
|
}
|
|
|
|
// True asserts that the given is a bool true
|
|
func True(t TestingT, give bool, fmtAndArgs ...any) bool {
|
|
if !give {
|
|
t.Helper()
|
|
return fail(t, "Result should be True", fmtAndArgs)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// False asserts that the given is a bool false
|
|
func False(t TestingT, give bool, fmtAndArgs ...any) bool {
|
|
if give {
|
|
t.Helper()
|
|
return fail(t, "Result should be False", fmtAndArgs)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Empty asserts that the give should be empty
|
|
func Empty(t TestingT, give any, fmtAndArgs ...any) bool {
|
|
empty := isEmpty(give)
|
|
if !empty {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Should be empty, but was:\n%#v", give), fmtAndArgs)
|
|
}
|
|
|
|
return empty
|
|
}
|
|
|
|
// NotEmpty asserts that the give should not be empty
|
|
func NotEmpty(t TestingT, give any, fmtAndArgs ...any) bool {
|
|
nEmpty := !isEmpty(give)
|
|
if !nEmpty {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Should not be empty, but was:\n%#v", give), fmtAndArgs)
|
|
}
|
|
|
|
return nEmpty
|
|
}
|
|
|
|
// PanicRunFunc define
|
|
type PanicRunFunc func()
|
|
|
|
// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
|
|
func runPanicFunc(f PanicRunFunc) (didPanic bool, message any, stack string) {
|
|
didPanic = true
|
|
defer func() {
|
|
message = recover()
|
|
if didPanic {
|
|
stack = string(debug.Stack())
|
|
}
|
|
}()
|
|
|
|
// call the target function
|
|
f()
|
|
didPanic = false
|
|
|
|
return
|
|
}
|
|
|
|
// Panics asserts that the code inside the specified func panics.
|
|
func Panics(t TestingT, fn PanicRunFunc, fmtAndArgs ...any) bool {
|
|
if hasPanic, panicVal, _ := runPanicFunc(fn); !hasPanic {
|
|
t.Helper()
|
|
|
|
return fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", fn, panicVal), fmtAndArgs)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// NotPanics asserts that the code inside the specified func NOT panics.
|
|
func NotPanics(t TestingT, fn PanicRunFunc, fmtAndArgs ...any) bool {
|
|
if hasPanic, panicVal, stackMsg := runPanicFunc(fn); hasPanic {
|
|
t.Helper()
|
|
|
|
return fail(t, fmt.Sprintf(
|
|
"func %#v should not panic\n\tPanic value:\t%#v\n\tPanic stack:\t%s",
|
|
fn, panicVal, stackMsg,
|
|
), fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// PanicsMsg should panic and with a value
|
|
func PanicsMsg(t TestingT, fn PanicRunFunc, wantVal any, fmtAndArgs ...any) bool {
|
|
hasPanic, panicVal, stackMsg := runPanicFunc(fn)
|
|
if !hasPanic {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", fn, panicVal), fmtAndArgs)
|
|
}
|
|
|
|
if panicVal != wantVal {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf(
|
|
"func %#v should panic.\n\tWant value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s",
|
|
fn, wantVal, panicVal, stackMsg),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// PanicsErrMsg should panic and with error message
|
|
func PanicsErrMsg(t TestingT, fn PanicRunFunc, errMsg string, fmtAndArgs ...any) bool {
|
|
hasPanic, panicVal, stackMsg := runPanicFunc(fn)
|
|
if !hasPanic {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", fn, panicVal), fmtAndArgs)
|
|
}
|
|
|
|
err, ok := panicVal.(error)
|
|
if !ok {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("func %#v should panic and is error type,\nbut type was: %T", fn, panicVal), fmtAndArgs)
|
|
}
|
|
|
|
if err.Error() != errMsg {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf(
|
|
"func %#v should panic.\n\tWant error:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s",
|
|
fn, errMsg, panicVal, stackMsg),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Contains asserts that the given data(string,slice,map) should contain element
|
|
//
|
|
// TIP: only support types: string, map, array, slice
|
|
//
|
|
// map - check key exists
|
|
// string - check sub-string exists
|
|
// array,slice - check sub-element exists
|
|
func Contains(t TestingT, src, elem any, fmtAndArgs ...any) bool {
|
|
valid, found := nstd.CheckContains(src, elem)
|
|
if valid && found {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
|
|
// src invalid
|
|
if !valid {
|
|
return fail(t, fmt.Sprintf("%#v could not be applied builtin len()", src), fmtAndArgs)
|
|
}
|
|
|
|
// not found
|
|
return fail(t, fmt.Sprintf("%#v\nShould contain: %#v", src, elem), fmtAndArgs)
|
|
}
|
|
|
|
// NotContains asserts that the given data(string,slice,map) should not contain element
|
|
//
|
|
// TIP: only support types: string, map, array, slice
|
|
//
|
|
// map - check key exists
|
|
// string - check sub-string exists
|
|
// array,slice - check sub-element exists
|
|
func NotContains(t TestingT, src, elem any, fmtAndArgs ...any) bool {
|
|
valid, found := nstd.CheckContains(src, elem)
|
|
if valid && !found {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
|
|
// src invalid
|
|
if !valid {
|
|
return fail(t, fmt.Sprintf("%#v could not be applied builtin len()", src), fmtAndArgs)
|
|
}
|
|
|
|
// found
|
|
return fail(t, fmt.Sprintf("%#v\nShould not contain: %#v", src, elem), fmtAndArgs)
|
|
}
|
|
|
|
// ContainsKey asserts that the given map is contains key
|
|
func ContainsKey(t TestingT, mp, key any, fmtAndArgs ...any) bool {
|
|
if !nmap.HasKey(mp, key) {
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf(
|
|
"Map should contains the key: %#v\nMap data:\n%v",
|
|
key,
|
|
nmap.FormatIndent(mp, " "),
|
|
),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// NotContainsKey asserts that the given map is not contains key
|
|
func NotContainsKey(t TestingT, mp, key any, fmtAndArgs ...any) bool {
|
|
if nmap.HasKey(mp, key) {
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf(
|
|
"Map should not contains the key: %#v\nMap data:\n%v",
|
|
key,
|
|
nmap.FormatIndent(mp, " "),
|
|
),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// ContainsKeys asserts that the map is contains all given keys
|
|
//
|
|
// Usage:
|
|
//
|
|
// ContainsKeys(t, map[string]any{...}, []string{"key1", "key2"})
|
|
func ContainsKeys(t TestingT, mp any, keys any, fmtAndArgs ...any) bool {
|
|
anyKeys, err := narr.AnyToSlice(keys)
|
|
if err != nil {
|
|
t.Helper()
|
|
return fail(t, err.Error(), fmtAndArgs)
|
|
}
|
|
|
|
ok, noKey := nmap.HasAllKeys(mp, anyKeys...)
|
|
if !ok {
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf(
|
|
"Map should contains the key: %#v\nMap data:\n%v",
|
|
noKey,
|
|
nmap.FormatIndent(mp, " "),
|
|
),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// NotContainsKeys asserts that the map is not contains all given keys
|
|
//
|
|
// Usage:
|
|
//
|
|
// NotContainsKeys(t, map[string]any{...}, []string{"key1", "key2"})
|
|
func NotContainsKeys(t TestingT, mp any, keys any, fmtAndArgs ...any) bool {
|
|
anyKeys, err := narr.AnyToSlice(keys)
|
|
if err != nil {
|
|
t.Helper()
|
|
return fail(t, err.Error(), fmtAndArgs)
|
|
}
|
|
|
|
ok, hasKey := nmap.HasOneKey(mp, anyKeys...)
|
|
if ok {
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf(
|
|
"Map should not contains the key: %#v\nMap data:\n%v",
|
|
hasKey,
|
|
nmap.FormatIndent(mp, " "),
|
|
),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// StrContains asserts that the given strings is contains sub-string
|
|
func StrContains(t TestingT, s, sub string, fmtAndArgs ...any) bool {
|
|
if strings.Contains(s, sub) {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf("String check fail:\nGiven string: %#v\nNot contains: %#v", s, sub),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
// StrCount asserts that the given strings is contains sub-string and count
|
|
func StrCount(t TestingT, s, sub string, count int, fmtAndArgs ...any) bool {
|
|
if strings.Count(s, sub) == count {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf("String check fail:\nGiven string: %s\nNot contains %q count: %d", s, sub, count),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
//
|
|
// -------------------- error --------------------
|
|
//
|
|
|
|
// NoError asserts that the given is a nil error. alias of NoError()
|
|
func NoError(t TestingT, err error, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
return NoErr(t, err, fmtAndArgs...)
|
|
}
|
|
|
|
// NoErr asserts that the given is a nil error
|
|
func NoErr(t TestingT, err error, fmtAndArgs ...any) bool {
|
|
if err != nil {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), fmtAndArgs)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Error asserts that the given is a not nil error. alias of Error()
|
|
func Error(t TestingT, err error, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
return Err(t, err, fmtAndArgs...)
|
|
}
|
|
|
|
// Err asserts that the given is a not nil error
|
|
func Err(t TestingT, err error, fmtAndArgs ...any) bool {
|
|
if err == nil {
|
|
t.Helper()
|
|
return fail(t, "An error is expected but got nil.", fmtAndArgs)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// ErrIs asserts that the given error is equals wantErr
|
|
func ErrIs(t TestingT, err, wantErr error, fmtAndArgs ...any) bool {
|
|
if err == nil {
|
|
t.Helper()
|
|
return fail(t, "An error is expected but got nil.", fmtAndArgs)
|
|
}
|
|
|
|
if !errors.Is(err, wantErr) {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Expect given err is equals %#v.", wantErr), fmtAndArgs)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// ErrMsg asserts that the given is a not nil error and error message equals wantMsg
|
|
func ErrMsg(t TestingT, err error, wantMsg string, fmtAndArgs ...any) bool {
|
|
if err == nil {
|
|
t.Helper()
|
|
return fail(t, "An error is expected but got nil.", fmtAndArgs)
|
|
}
|
|
|
|
errMsg := err.Error()
|
|
if errMsg != wantMsg {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Error message not equal:\n"+
|
|
"expect: %q\n"+
|
|
"actual: %q", wantMsg, errMsg), fmtAndArgs)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// ErrSubMsg asserts that the given is a not nil error and the error message contains subMsg
|
|
func ErrSubMsg(t TestingT, err error, subMsg string, fmtAndArgs ...any) bool {
|
|
if err == nil {
|
|
t.Helper()
|
|
return fail(t, "An error is expected but got nil.", fmtAndArgs)
|
|
}
|
|
|
|
errMsg := err.Error()
|
|
if !strings.Contains(errMsg, subMsg) {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Error message check fail:\n"+
|
|
"error message : %q\n"+
|
|
"should contains: %q", errMsg, subMsg), fmtAndArgs)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
//
|
|
// -------------------- Len --------------------
|
|
//
|
|
|
|
// Len assert given length is equals to wantLn
|
|
func Len(t TestingT, give any, wantLn int, fmtAndArgs ...any) bool {
|
|
gln := nreflect.Len(reflect.ValueOf(give))
|
|
if gln < 0 {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("\"%s\" could not be calc length", give), fmtAndArgs)
|
|
}
|
|
|
|
if gln != wantLn {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", give, wantLn, gln), fmtAndArgs)
|
|
}
|
|
return false
|
|
}
|
|
|
|
// LenGt assert given length is greater than to minLn
|
|
func LenGt(t TestingT, give any, minLn int, fmtAndArgs ...any) bool {
|
|
gln := nreflect.Len(reflect.ValueOf(give))
|
|
if gln < 0 {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("\"%s\" could not be calc length", give), fmtAndArgs)
|
|
}
|
|
|
|
if gln < minLn {
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("\"%s\" should less have %d item(s), but has %d", give, minLn, gln), fmtAndArgs)
|
|
}
|
|
return false
|
|
}
|
|
|
|
//
|
|
// -------------------- compare --------------------
|
|
//
|
|
|
|
// Equal asserts that the want should equal to the given.
|
|
//
|
|
// alias of Eq()
|
|
func Equal(t TestingT, want, give any, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
return Eq(t, want, give, fmtAndArgs...)
|
|
}
|
|
|
|
// Eq asserts that the want should equal to the given
|
|
func Eq(t TestingT, want, give any, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
|
|
if err := checkEqualArgs(want, give); err != nil {
|
|
return fail(t,
|
|
fmt.Sprintf("Cannot compare: %#v == %#v (%s)", want, give, err),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
if !nreflect.IsEqual(want, give) {
|
|
// TODO diff := diff(want, give)
|
|
want, give = formatUnequalValues(want, give)
|
|
return fail(t, fmt.Sprintf("Not equal: \n"+
|
|
"expect: %s\n"+
|
|
"actual: %s", want, give), fmtAndArgs)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Neq asserts that the want should not be equal to the given.
|
|
//
|
|
// alias of NotEq()
|
|
func Neq(t TestingT, want, give any, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
return NotEq(t, want, give, fmtAndArgs...)
|
|
}
|
|
|
|
// NotEqual asserts that the want should not be equal to the given.
|
|
//
|
|
// alias of NotEq()
|
|
func NotEqual(t TestingT, want, give any, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
return NotEq(t, want, give, fmtAndArgs...)
|
|
}
|
|
|
|
// NotEq asserts that the want should not be equal to the given
|
|
func NotEq(t TestingT, want, give any, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
|
|
if err := checkEqualArgs(want, give); err != nil {
|
|
return fail(t,
|
|
fmt.Sprintf("Cannot compare: %#v == %#v (%s)", want, give, err),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
if nreflect.IsEqual(want, give) {
|
|
return fail(t, fmt.Sprintf("Given should not be: %#v\n", give), fmtAndArgs)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// EqualValues asserts that two objects are equal or convertable to the same types
|
|
// and equal.
|
|
//
|
|
// assert.EqualValues(t, uint32(123), int32(123))
|
|
func EqualValues(t TestingT, expected, actual any, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
|
|
if !nreflect.IsEqualValues(expected, actual) {
|
|
//diff := diff(expected, actual)
|
|
expected, actual = formatUnequalValues(expected, actual)
|
|
return fail(t, fmt.Sprintf("Not equal: \n"+
|
|
"expected: %s\n"+
|
|
"actual : %s", expected, actual), fmtAndArgs)
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
// Lt asserts that the give(intX,uintX,floatX) should not be less than max
|
|
func Lt(t TestingT, give, max any, fmtAndArgs ...any) bool {
|
|
if nmath.Compare(give, max, "lt") {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Given %v should later than %v", give, max), fmtAndArgs)
|
|
}
|
|
|
|
// Lte asserts that the give(intX,uintX,floatX) should not be less than or equals to max
|
|
func Lte(t TestingT, give, max any, fmtAndArgs ...any) bool {
|
|
if nmath.Compare(give, max, "lte") {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Given %v should later than %v", give, max), fmtAndArgs)
|
|
}
|
|
|
|
// Gt asserts that the give(intX,uintX,floatX) should not be greater than min
|
|
func Gt(t TestingT, give, min any, fmtAndArgs ...any) bool {
|
|
if nmath.Compare(give, min, "gt") {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Given %v should gater than %v", give, min), fmtAndArgs)
|
|
}
|
|
|
|
// Gte asserts that the give(intX,uintX,floatX) should not be greater than or equals to min
|
|
func Gte(t TestingT, give, min any, fmtAndArgs ...any) bool {
|
|
if nmath.Compare(give, min, "gte") {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Given %v should gater than or equal %v", give, min), fmtAndArgs)
|
|
}
|
|
|
|
// IsType assert data type equals
|
|
//
|
|
// Usage:
|
|
//
|
|
// assert.IsType(t, 0, val) // assert type is int
|
|
func IsType(t TestingT, wantType, give any, fmtAndArgs ...any) bool {
|
|
if nreflect.IsEqual(reflect.TypeOf(wantType), reflect.TypeOf(give)) {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf("Expected to be of type %v, but was %v", reflect.TypeOf(wantType), reflect.TypeOf(give)),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
// IsKind assert data reflect.Kind equals.
|
|
// If `give` is ptr or interface, will get real kind.
|
|
//
|
|
// Usage:
|
|
//
|
|
// assert.IsKind(t, reflect.Int, val) // assert type is int kind.
|
|
func IsKind(t TestingT, wantKind reflect.Kind, give any, fmtAndArgs ...any) bool {
|
|
giveKind := nreflect.Elem(reflect.ValueOf(give)).Kind()
|
|
if wantKind == giveKind {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t,
|
|
fmt.Sprintf("Expected to be of kind %v, but was %v", wantKind, giveKind),
|
|
fmtAndArgs,
|
|
)
|
|
}
|
|
|
|
// Same asserts that two pointers reference the same object.
|
|
//
|
|
// assert.Same(t, ptr1, ptr2)
|
|
//
|
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
|
// determined based on the equality of both type and value.
|
|
func Same(t TestingT, wanted, actual any, fmtAndArgs ...any) bool {
|
|
if samePointers(wanted, actual) {
|
|
return true
|
|
}
|
|
|
|
return fail(t, fmt.Sprintf("Not same: \n"+
|
|
"wanted: %p %#v\n"+
|
|
"actual: %p %#v", wanted, wanted, actual, actual), fmtAndArgs)
|
|
}
|
|
|
|
// NotSame asserts that two pointers do not reference the same object.
|
|
//
|
|
// assert.NotSame(t, ptr1, ptr2)
|
|
//
|
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
|
// determined based on the equality of both type and value.
|
|
func NotSame(t TestingT, want, actual any, fmtAndArgs ...any) bool {
|
|
if !samePointers(want, actual) {
|
|
return true
|
|
}
|
|
|
|
t.Helper()
|
|
return fail(t, fmt.Sprintf("Expect and actual point to the same object: %p %#v", want, want), fmtAndArgs)
|
|
}
|
|
|
|
// samePointers compares two generic interface objects and returns whether
|
|
// they point to the same object
|
|
func samePointers(first, second any) bool {
|
|
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
|
|
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
|
|
return false
|
|
}
|
|
|
|
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
|
|
if firstType != secondType {
|
|
return false
|
|
}
|
|
|
|
// compare pointer addresses
|
|
return first == second
|
|
}
|
|
|
|
//
|
|
// -------------------- fail --------------------
|
|
//
|
|
|
|
// Fail reports a failure through
|
|
func Fail(t TestingT, failMsg string, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
return fail(t, failMsg, fmtAndArgs)
|
|
}
|
|
|
|
type failNower interface {
|
|
FailNow()
|
|
}
|
|
|
|
// FailNow fails test
|
|
func FailNow(t TestingT, failMsg string, fmtAndArgs ...any) bool {
|
|
t.Helper()
|
|
fail(t, failMsg, fmtAndArgs)
|
|
|
|
if fnr, ok := t.(failNower); ok {
|
|
fnr.FailNow()
|
|
}
|
|
return false
|
|
}
|
|
|
|
//
|
|
// -------------------- render error --------------------
|
|
//
|
|
|
|
var (
|
|
// ShowFullPath on show error trace
|
|
ShowFullPath = true
|
|
// EnableColor on show error trace
|
|
EnableColor = true
|
|
)
|
|
|
|
// DisableColor render
|
|
func DisableColor() {
|
|
EnableColor = false
|
|
}
|
|
|
|
// HideFullPath render
|
|
func HideFullPath() {
|
|
ShowFullPath = false
|
|
}
|
|
|
|
// fail reports a failure through
|
|
func fail(t TestingT, failMsg string, fmtAndArgs []any) bool {
|
|
t.Helper()
|
|
|
|
tName := t.Name()
|
|
if EnableColor {
|
|
tName = color.Red.Sprint(tName)
|
|
}
|
|
|
|
labeledTexts := []labeledText{
|
|
{"Test Name", tName},
|
|
{"Error At", strings.Join(callerInfos(), "\n")},
|
|
{"Error Msg", failMsg},
|
|
}
|
|
|
|
// user custom message
|
|
if userMsg := formatTplAndArgs(fmtAndArgs...); len(userMsg) > 0 {
|
|
labeledTexts = append(labeledTexts, labeledText{"User Msg", userMsg})
|
|
}
|
|
|
|
t.Error("\n" + formatLabeledTexts(labeledTexts))
|
|
return false
|
|
}
|