package assertimport (// Wrapper around gopkg.in/yaml.v3)//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"// TestingT is an interface wrapper around *testing.TtypeTestingTinterface {Errorf(format string, args ...interface{})}// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful// for table driven tests.typeComparisonAssertionFuncfunc(TestingT, interface{}, interface{}, ...interface{}) bool// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful// for table driven tests.typeValueAssertionFuncfunc(TestingT, interface{}, ...interface{}) bool// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful// for table driven tests.typeBoolAssertionFuncfunc(TestingT, bool, ...interface{}) bool// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful// for table driven tests.typeErrorAssertionFuncfunc(TestingT, error, ...interface{}) bool// PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful// for table driven tests.typePanicAssertionFunc = func(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool// Comparison is a custom function that returns true on success and false on failuretypeComparisonfunc() (success bool)/* Helper functions*/// ObjectsAreEqual determines if two objects are considered equal.//// This function does no assertion of any kind.func (, interface{}) bool {if == nil || == nil {return == } , := .([]byte)if ! {returnreflect.DeepEqual(, ) } , := .([]byte)if ! {returnfalse }if == nil || == nil {return == nil && == nil }returnbytes.Equal(, )}// copyExportedFields iterates downward through nested data structures and creates a copy// that only contains the exported struct fields.func copyExportedFields( interface{}) interface{} {ifisNil() {return } := reflect.TypeOf() := .Kind() := reflect.ValueOf()switch {casereflect.Struct: := reflect.New().Elem()for := 0; < .NumField(); ++ { := .Field() := .IsExported()if { := .Field()ifisNil() || isNil(.Interface()) {continue } := (.Interface()) .Field().Set(reflect.ValueOf()) } }return .Interface()casereflect.Ptr: := reflect.New(.Elem()) := (.Elem().Interface()) .Elem().Set(reflect.ValueOf())return .Interface()casereflect.Array, reflect.Slice:varreflect.Valueif == reflect.Array { = reflect.New(reflect.ArrayOf(.Len(), .Elem())).Elem() } else { = reflect.MakeSlice(, .Len(), .Len()) }for := 0; < .Len(); ++ { := .Index()ifisNil() {continue } := (.Interface()) .Index().Set(reflect.ValueOf()) }return .Interface()casereflect.Map: := reflect.MakeMap()for , := range .MapKeys() { := .MapIndex() := (.Interface()) .SetMapIndex(, reflect.ValueOf()) }return .Interface()default:return }}// ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are// considered equal. This comparison of only exported fields is applied recursively to nested data// structures.//// This function does no assertion of any kind.//// Deprecated: Use [EqualExportedValues] instead.func (, interface{}) bool { := copyExportedFields() := copyExportedFields()returnObjectsAreEqualValues(, )}// ObjectsAreEqualValues gets whether two objects are equal, or if their// values are equal.func (, interface{}) bool {ifObjectsAreEqual(, ) {returntrue } := reflect.ValueOf() := reflect.ValueOf()if !.IsValid() || !.IsValid() {returnfalse } := .Type() := .Type()if !.ConvertibleTo() {returnfalse }if !isNumericType() || !isNumericType() {// Attempt comparison after type conversionreturnreflect.DeepEqual( .Convert().Interface(), , ) }// If BOTH values are numeric, there are chances of false positives due // to overflow or underflow. So, we need to make sure to always convert // the smaller type to a larger type before comparing.if .Size() >= .Size() {return .Convert().Interface() == }return .Convert().Interface() == }// isNumericType returns true if the type is one of:// int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64,// float32, float64, complex64, complex128func isNumericType( reflect.Type) bool {return .Kind() >= reflect.Int && .Kind() <= reflect.Complex128}/* CallerInfo is necessary because the assert functions use the testing objectinternally, causing it to print the file:line of the assert method, rather than wherethe problem actually occurred in calling code.*/// CallerInfo returns an array of strings containing the file and line number// of each stack frame leading from the current test to the assert call that// failed.func () []string {varuintptrvarstringvarintvarstringconst = 10 := make([]uintptr, ) := []string{} := 1for { := runtime.Callers(, )if == 0 {break } := runtime.CallersFrames([:])for { , := .Next() = .PC = .File = .Line// This is a huge edge case, but it will panic if this is the case, see #180if == "<autogenerated>" {break } := runtime.FuncForPC()if == nil {break } = .Name()// testing.tRunner is the standard library function that calls // tests. Subtests are called directly by tRunner, without going through // the Test/Benchmark/Example function that contains the t.Run calls, so // with subtests we should break when we hit tRunner, without adding it // to the list of callers.if == "testing.tRunner" {break } := strings.Split(, "/")iflen() > 1 { := [len()-1] := [len()-2]if ( != "assert" && != "mock" && != "require") || == "mock_test.go" { = append(, fmt.Sprintf("%s:%d", , )) } }// Drop the package := strings.LastIndexByte(, '.') = [+1:]ifisTest(, "Test") ||isTest(, "Benchmark") ||isTest(, "Example") {break }if ! {break } }// Next batch += cap() }return}// Stolen from the `go test` tool.// isTest tells whether name looks like a test (or benchmark, according to prefix).// It is a Test (say) if there is a character after Test that is not a lower-case letter.// We don't want TesticularCancer.func isTest(, string) bool {if !strings.HasPrefix(, ) {returnfalse }iflen() == len() { // "Test" is okreturntrue } , := utf8.DecodeRuneInString([len():])return !unicode.IsLower()}func messageFromMsgAndArgs( ...interface{}) string {iflen() == 0 || == nil {return"" }iflen() == 1 { := [0]if , := .(string); {return }returnfmt.Sprintf("%+v", ) }iflen() > 1 {returnfmt.Sprintf([0].(string), [1:]...) }return""}// Aligns the provided message so that all lines after the first line start at the same location as the first line.// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).// The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the// basis on which the alignment occurs).func indentMessageLines( string, int) string { := new(bytes.Buffer)for , := 0, bufio.NewScanner(strings.NewReader()); .Scan(); ++ {// no need to align first line because it starts at the correct location (after the label)if != 0 {// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab .WriteString("\n\t" + strings.Repeat(" ", +1) + "\t") } .WriteString(.Text()) }return .String()}type failNower interface { FailNow()}// FailNow fails testfunc ( TestingT, string, ...interface{}) bool {if , := .(tHelper); { .Helper() }Fail(, , ...)// We cannot extend TestingT with FailNow() and // maintain backwards compatibility, so we fallback // to panicking when FailNow is not available in // TestingT. // See issue #263if , := .(failNower); { .FailNow() } else {panic("test failed and t is missing `FailNow()`") }returnfalse}// Fail reports a failure throughfunc ( TestingT, string, ...interface{}) bool {if , := .(tHelper); { .Helper() } := []labeledContent{ {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")}, {"Error", }, }// Add test name if the Go version supports itif , := .(interface { () string }); { = append(, labeledContent{"Test", .()}) } := messageFromMsgAndArgs(...)iflen() > 0 { = append(, labeledContent{"Messages", }) } .Errorf("\n%s", ""+labeledOutput(...))returnfalse}type labeledContent struct { label string content string}// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner://// \t{{label}}:{{align_spaces}}\t{{content}}\n//// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this// alignment is achieved, "\t{{content}}\n" is added for the output.//// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line.func labeledOutput( ...labeledContent) string { := 0for , := range {iflen(.label) > { = len(.label) } }varstringfor , := range { += "\t" + .label + ":" + strings.Repeat(" ", -len(.label)) + "\t" + indentMessageLines(.content, ) + "\n" }return}// Implements asserts that an object is implemented by the specified interface.//// assert.Implements(t, (*MyInterface)(nil), new(MyObject))func ( TestingT, interface{}, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } := reflect.TypeOf().Elem()if == nil {returnFail(, fmt.Sprintf("Cannot check if nil implements %v", ), ...) }if !reflect.TypeOf().Implements() {returnFail(, fmt.Sprintf("%T must implement %v", , ), ...) }returntrue}// NotImplements asserts that an object does not implement the specified interface.//// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject))func ( TestingT, interface{}, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } := reflect.TypeOf().Elem()if == nil {returnFail(, fmt.Sprintf("Cannot check if nil does not implement %v", ), ...) }ifreflect.TypeOf().Implements() {returnFail(, fmt.Sprintf("%T implements %v", , ), ...) }returntrue}func isType(, interface{}) bool {returnObjectsAreEqual(reflect.TypeOf(), reflect.TypeOf())}// IsType asserts that the specified objects are of the same type.//// assert.IsType(t, &MyStruct{}, &MyStruct{})func ( TestingT, , interface{}, ...interface{}) bool {ifisType(, ) {returntrue }if , := .(tHelper); { .Helper() }returnFail(, fmt.Sprintf("Object expected to be of type %T, but was %T", , ), ...)}// IsNotType asserts that the specified objects are not of the same type.//// assert.IsNotType(t, &NotMyStruct{}, &MyStruct{})func ( TestingT, , interface{}, ...interface{}) bool {if !isType(, ) {returntrue }if , := .(tHelper); { .Helper() }returnFail(, fmt.Sprintf("Object type expected to be different than %T", ), ...)}// Equal asserts that two objects are equal.//// assert.Equal(t, 123, 123)//// Pointer variable equality is determined based on the equality of the// referenced values (as opposed to the memory addresses). Function equality// cannot be determined and will always fail.func ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }if := validateEqualArgs(, ); != nil {returnFail(, fmt.Sprintf("Invalid operation: %#v == %#v (%s)", , , ), ...) }if !ObjectsAreEqual(, ) { := diff(, ) , = formatUnequalValues(, )returnFail(, fmt.Sprintf("Not equal: \n"+"expected: %s\n"+"actual : %s%s", , , ), ...) }returntrue}// validateEqualArgs checks whether provided arguments can be safely used in the// Equal/NotEqual functions.func validateEqualArgs(, interface{}) error {if == nil && == nil {returnnil }ifisFunction() || isFunction() {returnerrors.New("cannot take func type as argument") }returnnil}// 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 ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := samePointers(, )if ! {returnFail(, "Both arguments must be pointers", ...) }if ! {// both are pointers but not the same type & pointing to the same addressreturnFail(, fmt.Sprintf("Not same: \n"+"expected: %p %#[1]v\n"+"actual : %p %#[2]v", , ), ...) }returntrue}// 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 ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := samePointers(, )if ! {// fails when the arguments are not pointersreturn !(Fail(, "Both arguments must be pointers", ...)) }if {returnFail(, fmt.Sprintf("Expected and actual point to the same object: %p %#[1]v", ), ...) }returntrue}// samePointers checks if two generic interface objects are pointers of the same// type pointing to the same object. It returns two values: same indicating if// they are the same type and point to the same object, and ok indicating that// both inputs are pointers.func samePointers(, interface{}) ( bool, bool) { , := reflect.ValueOf(), reflect.ValueOf()if .Kind() != reflect.Ptr || .Kind() != reflect.Ptr {returnfalse, false// not both are pointers } , := reflect.TypeOf(), reflect.TypeOf()if != {returnfalse, true// both are pointers, but of different types }// compare pointer addressesreturn == , true}// formatUnequalValues takes two values of arbitrary types and returns string// representations appropriate to be presented to the user.//// If the values are not of like type, the returned strings will be prefixed// with the type name, and the value will be enclosed in parentheses similar// to a type conversion in the Go grammar.func formatUnequalValues(, interface{}) ( string, string) {ifreflect.TypeOf() != reflect.TypeOf() {returnfmt.Sprintf("%T(%s)", , truncatingFormat()),fmt.Sprintf("%T(%s)", , truncatingFormat()) }switch .(type) {casetime.Duration:returnfmt.Sprintf("%v", ), fmt.Sprintf("%v", ) }returntruncatingFormat(), truncatingFormat()}// truncatingFormat formats the data and truncates it if it's too long.//// This helps keep formatted error messages lines from exceeding the// bufio.MaxScanTokenSize max line length that the go testing framework imposes.func truncatingFormat( interface{}) string { := fmt.Sprintf("%#v", ) := bufio.MaxScanTokenSize - 100// Give us some space the type info too if needed.iflen() > { = [0:] + "<... truncated>" }return}// EqualValues asserts that two objects are equal or convertible to the larger// type and equal.//// assert.EqualValues(t, uint32(123), int32(123))func ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }if !ObjectsAreEqualValues(, ) { := diff(, ) , = formatUnequalValues(, )returnFail(, fmt.Sprintf("Not equal: \n"+"expected: %s\n"+"actual : %s%s", , , ), ...) }returntrue}// EqualExportedValues asserts that the types of two objects are equal and their public// fields are also equal. This is useful for comparing structs that have private fields// that could potentially differ.//// type S struct {// Exported int// notExported int// }// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => falsefunc ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } := reflect.TypeOf() := reflect.TypeOf()if != {returnFail(, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", , ), ...) } = copyExportedFields() = copyExportedFields()if !ObjectsAreEqualValues(, ) { := diff(, ) , = formatUnequalValues(, )returnFail(, fmt.Sprintf("Not equal (comparing only exported fields): \n"+"expected: %s\n"+"actual : %s%s", , , ), ...) }returntrue}// Exactly asserts that two objects are equal in value and type.//// assert.Exactly(t, int32(123), int64(123))func ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } := reflect.TypeOf() := reflect.TypeOf()if != {returnFail(, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", , ), ...) }returnEqual(, , , ...)}// NotNil asserts that the specified object is not nil.//// assert.NotNil(t, err)func ( TestingT, interface{}, ...interface{}) bool {if !isNil() {returntrue }if , := .(tHelper); { .Helper() }returnFail(, "Expected value not to be nil.", ...)}// isNil checks if a specified object is nil or not, without Failing.func isNil( interface{}) bool {if == nil {returntrue } := reflect.ValueOf()switch .Kind() {casereflect.Chan, reflect.Func,reflect.Interface, reflect.Map,reflect.Ptr, reflect.Slice, reflect.UnsafePointer:return .IsNil() }returnfalse}// Nil asserts that the specified object is nil.//// assert.Nil(t, err)func ( TestingT, interface{}, ...interface{}) bool {ifisNil() {returntrue }if , := .(tHelper); { .Helper() }returnFail(, fmt.Sprintf("Expected nil, but got: %#v", ), ...)}// isEmpty gets whether the specified object is considered empty or not.func isEmpty( interface{}) bool {// get nil case out of the wayif == nil {returntrue }returnisEmptyValue(reflect.ValueOf())}// isEmptyValue gets whether the specified reflect.Value is considered empty or not.func isEmptyValue( reflect.Value) bool {if .IsZero() {returntrue }// Special cases of non-zero values that we consider emptyswitch .Kind() {// collection types are empty when they have no element // Note: array types are empty when they match their zero-initialized state.casereflect.Chan, reflect.Map, reflect.Slice:return .Len() == 0// non-nil pointers are empty if the value they point to is emptycasereflect.Ptr:return (.Elem()) }returnfalse}// Empty asserts that the given value is "empty".//// [Zero values] are "empty".//// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").//// Slices, maps and channels with zero length are "empty".//// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".//// assert.Empty(t, obj)//// [Zero values]: https://go.dev/ref/spec#The_zero_valuefunc ( TestingT, interface{}, ...interface{}) bool { := isEmpty()if ! {if , := .(tHelper); { .Helper() }Fail(, fmt.Sprintf("Should be empty, but was %v", ), ...) }return}// NotEmpty asserts that the specified object is NOT [Empty].//// if assert.NotEmpty(t, obj) {// assert.Equal(t, "two", obj[1])// }func ( TestingT, interface{}, ...interface{}) bool { := !isEmpty()if ! {if , := .(tHelper); { .Helper() }Fail(, fmt.Sprintf("Should NOT be empty, but was %v", ), ...) }return}// getLen tries to get the length of an object.// It returns (0, false) if impossible.func getLen( interface{}) ( int, bool) { := reflect.ValueOf()deferfunc() { = recover() == nil }()return .Len(), true}// Len asserts that the specified object has specific length.// Len also fails if the object has a type that len() not accept.//// assert.Len(t, mySlice, 3)func ( TestingT, interface{}, int, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := getLen()if ! {returnFail(, fmt.Sprintf("\"%v\" could not be applied builtin len()", ), ...) }if != {returnFail(, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", , , ), ...) }returntrue}// True asserts that the specified value is true.//// assert.True(t, myBool)func ( TestingT, bool, ...interface{}) bool {if ! {if , := .(tHelper); { .Helper() }returnFail(, "Should be true", ...) }returntrue}// False asserts that the specified value is false.//// assert.False(t, myBool)func ( TestingT, bool, ...interface{}) bool {if {if , := .(tHelper); { .Helper() }returnFail(, "Should be false", ...) }returntrue}// NotEqual asserts that the specified values are NOT equal.//// assert.NotEqual(t, obj1, obj2)//// Pointer variable equality is determined based on the equality of the// referenced values (as opposed to the memory addresses).func ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }if := validateEqualArgs(, ); != nil {returnFail(, fmt.Sprintf("Invalid operation: %#v != %#v (%s)", , , ), ...) }ifObjectsAreEqual(, ) {returnFail(, fmt.Sprintf("Should not be: %#v\n", ), ...) }returntrue}// NotEqualValues asserts that two objects are not equal even when converted to the same type//// assert.NotEqualValues(t, obj1, obj2)func ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }ifObjectsAreEqualValues(, ) {returnFail(, fmt.Sprintf("Should not be: %#v\n", ), ...) }returntrue}// containsElement try loop over the list check if the list includes the element.// return (false, false) if impossible.// return (true, false) if element was not found.// return (true, true) if element was found.func containsElement( interface{}, interface{}) (, bool) { := reflect.ValueOf() := reflect.TypeOf()if == nil {returnfalse, false } := .Kind()deferfunc() {if := recover(); != nil { = false = false } }()if == reflect.String { := reflect.ValueOf()returntrue, strings.Contains(.String(), .String()) }if == reflect.Map { := .MapKeys()for := 0; < len(); ++ {ifObjectsAreEqual([].Interface(), ) {returntrue, true } }returntrue, false }for := 0; < .Len(); ++ {ifObjectsAreEqual(.Index().Interface(), ) {returntrue, true } }returntrue, false}// Contains asserts that the specified string, list(array, slice...) or map contains the// specified substring or element.//// assert.Contains(t, "Hello World", "World")// assert.Contains(t, ["Hello", "World"], "World")// assert.Contains(t, {"Hello": "World"}, "Hello")func ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := containsElement(, )if ! {returnFail(, fmt.Sprintf("%#v could not be applied builtin len()", ), ...) }if ! {returnFail(, fmt.Sprintf("%#v does not contain %#v", , ), ...) }returntrue}// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the// specified substring or element.//// assert.NotContains(t, "Hello World", "Earth")// assert.NotContains(t, ["Hello", "World"], "Earth")// assert.NotContains(t, {"Hello": "World"}, "Earth")func ( TestingT, , interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := containsElement(, )if ! {returnFail(, fmt.Sprintf("%#v could not be applied builtin len()", ), ...) }if {returnFail(, fmt.Sprintf("%#v should not contain %#v", , ), ...) }returntrue}// Subset asserts that the list (array, slice, or map) contains all elements// given in the subset (array, slice, or map).// Map elements are key-value pairs unless compared with an array or slice where// only the map key is evaluated.//// assert.Subset(t, [1, 2, 3], [1, 2])// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})// assert.Subset(t, [1, 2, 3], {1: "one", 2: "two"})// assert.Subset(t, {"x": 1, "y": 2}, ["x"])func ( TestingT, , interface{}, ...interface{}) ( bool) {if , := .(tHelper); { .Helper() }if == nil {returntrue// we consider nil to be equal to the nil set } := reflect.TypeOf().Kind()if != reflect.Array && != reflect.Slice && != reflect.Map {returnFail(, fmt.Sprintf("%q has an unsupported type %s", , ), ...) } := reflect.TypeOf().Kind()if != reflect.Array && != reflect.Slice && != reflect.Map {returnFail(, fmt.Sprintf("%q has an unsupported type %s", , ), ...) }if == reflect.Map && == reflect.Map { := reflect.ValueOf() := reflect.ValueOf()for , := range .MapKeys() { := .MapIndex() := .MapIndex()if !.IsValid() {returnFail(, fmt.Sprintf("%#v does not contain %#v", , ), ...) }if !ObjectsAreEqual(.Interface(), .Interface()) {returnFail(, fmt.Sprintf("%#v does not contain %#v", , ), ...) } }returntrue } := reflect.ValueOf()if == reflect.Map { := make([]interface{}, .Len())for , := range .MapKeys() { [] = .Interface() } = reflect.ValueOf() }for := 0; < .Len(); ++ { := .Index().Interface() , := containsElement(, )if ! {returnFail(, fmt.Sprintf("%#v could not be applied builtin len()", ), ...) }if ! {returnFail(, fmt.Sprintf("%#v does not contain %#v", , ), ...) } }returntrue}// NotSubset asserts that the list (array, slice, or map) does NOT contain all// elements given in the subset (array, slice, or map).// Map elements are key-value pairs unless compared with an array or slice where// only the map key is evaluated.//// assert.NotSubset(t, [1, 3, 4], [1, 2])// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})// assert.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"})// assert.NotSubset(t, {"x": 1, "y": 2}, ["z"])func ( TestingT, , interface{}, ...interface{}) ( bool) {if , := .(tHelper); { .Helper() }if == nil {returnFail(, "nil is the empty set which is a subset of every set", ...) } := reflect.TypeOf().Kind()if != reflect.Array && != reflect.Slice && != reflect.Map {returnFail(, fmt.Sprintf("%q has an unsupported type %s", , ), ...) } := reflect.TypeOf().Kind()if != reflect.Array && != reflect.Slice && != reflect.Map {returnFail(, fmt.Sprintf("%q has an unsupported type %s", , ), ...) }if == reflect.Map && == reflect.Map { := reflect.ValueOf() := reflect.ValueOf()for , := range .MapKeys() { := .MapIndex() := .MapIndex()if !.IsValid() {returntrue }if !ObjectsAreEqual(.Interface(), .Interface()) {returntrue } }returnFail(, fmt.Sprintf("%q is a subset of %q", , ), ...) } := reflect.ValueOf()if == reflect.Map { := make([]interface{}, .Len())for , := range .MapKeys() { [] = .Interface() } = reflect.ValueOf() }for := 0; < .Len(); ++ { := .Index().Interface() , := containsElement(, )if ! {returnFail(, fmt.Sprintf("%q could not be applied builtin len()", ), ...) }if ! {returntrue } }returnFail(, fmt.Sprintf("%q is a subset of %q", , ), ...)}// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,// the number of appearances of each of them in both lists should match.//// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])func ( TestingT, , interface{}, ...interface{}) ( bool) {if , := .(tHelper); { .Helper() }ifisEmpty() && isEmpty() {returntrue }if !isList(, , ...) || !isList(, , ...) {returnfalse } , := diffLists(, )iflen() == 0 && len() == 0 {returntrue }returnFail(, formatListDiff(, , , ), ...)}// isList checks that the provided value is array or slice.func isList( TestingT, interface{}, ...interface{}) ( bool) { := reflect.TypeOf().Kind()if != reflect.Array && != reflect.Slice {returnFail(, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", , ), ...) }returntrue}// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B.// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored.func diffLists(, interface{}) (, []interface{}) { := reflect.ValueOf() := reflect.ValueOf() := .Len() := .Len()// Mark indexes in bValue that we already used := make([]bool, )for := 0; < ; ++ { := .Index().Interface() := falsefor := 0; < ; ++ {if [] {continue }ifObjectsAreEqual(.Index().Interface(), ) { [] = true = truebreak } }if ! { = append(, ) } }for := 0; < ; ++ {if [] {continue } = append(, .Index().Interface()) }return}func formatListDiff(, interface{}, , []interface{}) string {varbytes.Buffer .WriteString("elements differ")iflen() > 0 { .WriteString("\n\nextra elements in list A:\n") .WriteString(spewConfig.Sdump()) }iflen() > 0 { .WriteString("\n\nextra elements in list B:\n") .WriteString(spewConfig.Sdump()) } .WriteString("\n\nlistA:\n") .WriteString(spewConfig.Sdump()) .WriteString("\n\nlistB:\n") .WriteString(spewConfig.Sdump())return .String()}// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,// the number of appearances of each of them in both lists should not match.// This is an inverse of ElementsMatch.//// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false//// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true//// assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> truefunc ( TestingT, , interface{}, ...interface{}) ( bool) {if , := .(tHelper); { .Helper() }ifisEmpty() && isEmpty() {returnFail(, "listA and listB contain the same elements", ) }if !isList(, , ...) {returnFail(, "listA is not a list type", ...) }if !isList(, , ...) {returnFail(, "listB is not a list type", ...) } , := diffLists(, )iflen() == 0 && len() == 0 {returnFail(, "listA and listB contain the same elements", ) }returntrue}// Condition uses a Comparison to assert a complex condition.func ( TestingT, Comparison, ...interface{}) bool {if , := .(tHelper); { .Helper() } := ()if ! {Fail(, "Condition failed!", ...) }return}// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics// methods, and represents a simple func that takes no arguments, and returns nothing.typePanicTestFuncfunc()// didPanic returns true if the function passed to it panics. Otherwise, it returns false.func didPanic( PanicTestFunc) ( bool, interface{}, string) { = truedeferfunc() { = recover()if { = string(debug.Stack()) } }()// call the target function () = falsereturn}// Panics asserts that the code inside the specified PanicTestFunc panics.//// assert.Panics(t, func(){ GoCrazy() })func ( TestingT, PanicTestFunc, ...interface{}) bool {if , := .(tHelper); { .Helper() }if , , := didPanic(); ! {returnFail(, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", , ), ...) }returntrue}// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that// the recovered panic value equals the expected panic value.//// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })func ( TestingT, interface{}, PanicTestFunc, ...interface{}) bool {if , := .(tHelper); { .Helper() } , , := didPanic()if ! {returnFail(, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", , ), ...) }if != {returnFail(, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", , , , ), ...) }returntrue}// PanicsWithError asserts that the code inside the specified PanicTestFunc// panics, and that the recovered panic value is an error that satisfies the// EqualError comparison.//// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })func ( TestingT, string, PanicTestFunc, ...interface{}) bool {if , := .(tHelper); { .Helper() } , , := didPanic()if ! {returnFail(, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", , ), ...) } , := .(error)if ! || .Error() != {returnFail(, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", , , , ), ...) }returntrue}// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.//// assert.NotPanics(t, func(){ RemainCalm() })func ( TestingT, PanicTestFunc, ...interface{}) bool {if , := .(tHelper); { .Helper() }if , , := didPanic(); {returnFail(, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", , , ), ...) }returntrue}// WithinDuration asserts that the two times are within duration delta of each other.//// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)func ( TestingT, , time.Time, time.Duration, ...interface{}) bool {if , := .(tHelper); { .Helper() } := .Sub()if < - || > {returnFail(, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", , , , ), ...) }returntrue}// WithinRange asserts that a time is within a time range (inclusive).//// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))func ( TestingT, , , time.Time, ...interface{}) bool {if , := .(tHelper); { .Helper() }if .Before() {returnFail(, "Start should be before end", ...) }if .Before() {returnFail(, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", , , ), ...) } elseif .After() {returnFail(, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", , , ), ...) }returntrue}func toFloat( interface{}) (float64, bool) {varfloat64 := trueswitch xn := .(type) {caseuint: = float64()caseuint8: = float64()caseuint16: = float64()caseuint32: = float64()caseuint64: = float64()caseint: = float64()caseint8: = float64()caseint16: = float64()caseint32: = float64()caseint64: = float64()casefloat32: = float64()casefloat64: = casetime.Duration: = float64()default: = false }return , }// InDelta asserts that the two numerals are within delta of each other.//// assert.InDelta(t, math.Pi, 22/7.0, 0.01)func ( TestingT, , interface{}, float64, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := toFloat() , := toFloat()if ! || ! {returnFail(, "Parameters must be numerical", ...) }ifmath.IsNaN() && math.IsNaN() {returntrue }ifmath.IsNaN() {returnFail(, "Expected must not be NaN", ...) }ifmath.IsNaN() {returnFail(, fmt.Sprintf("Expected %v with delta %v, but was NaN", , ), ...) } := - if < - || > {returnFail(, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", , , , ), ...) }returntrue}// InDeltaSlice is the same as InDelta, except it compares two slices.func ( TestingT, , interface{}, float64, ...interface{}) bool {if , := .(tHelper); { .Helper() }if == nil || == nil ||reflect.TypeOf().Kind() != reflect.Slice ||reflect.TypeOf().Kind() != reflect.Slice {returnFail(, "Parameters must be slice", ...) } := reflect.ValueOf() := reflect.ValueOf()for := 0; < .Len(); ++ { := InDelta(, .Index().Interface(), .Index().Interface(), , ...)if ! {return } }returntrue}// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.func ( TestingT, , interface{}, float64, ...interface{}) bool {if , := .(tHelper); { .Helper() }if == nil || == nil ||reflect.TypeOf().Kind() != reflect.Map ||reflect.TypeOf().Kind() != reflect.Map {returnFail(, "Arguments must be maps", ...) } := reflect.ValueOf() := reflect.ValueOf()if .Len() != .Len() {returnFail(, "Arguments must have the same number of keys", ...) }for , := range .MapKeys() { := .MapIndex() := .MapIndex()if !.IsValid() {returnFail(, fmt.Sprintf("missing key %q in expected map", ), ...) }if !.IsValid() {returnFail(, fmt.Sprintf("missing key %q in actual map", ), ...) }if !InDelta( , .Interface(), .Interface(), , ..., ) {returnfalse } }returntrue}func calcRelativeError(, interface{}) (float64, error) { , := toFloat() , := toFloat()if ! || ! {return0, fmt.Errorf("Parameters must be numerical") }ifmath.IsNaN() && math.IsNaN() {return0, nil }ifmath.IsNaN() {return0, errors.New("expected value must not be NaN") }if == 0 {return0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") }ifmath.IsNaN() {return0, errors.New("actual value must not be NaN") }returnmath.Abs(-) / math.Abs(), nil}// InEpsilon asserts that expected and actual have a relative error less than epsilonfunc ( TestingT, , interface{}, float64, ...interface{}) bool {if , := .(tHelper); { .Helper() }ifmath.IsNaN() {returnFail(, "epsilon must not be NaN", ...) } , := calcRelativeError(, )if != nil {returnFail(, .Error(), ...) }ifmath.IsNaN() {returnFail(, "relative error is NaN", ...) }if > {returnFail(, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+" < %#v (actual)", , ), ...) }returntrue}// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.func ( TestingT, , interface{}, float64, ...interface{}) bool {if , := .(tHelper); { .Helper() }if == nil || == nil {returnFail(, "Parameters must be slice", ...) } := reflect.ValueOf() := reflect.ValueOf()if .Type().Kind() != reflect.Slice {returnFail(, "Expected value must be slice", ...) } := .Len()if !IsType(, , ) || !Len(, , ) {returnfalse }for := 0; < ; ++ {if !InEpsilon(, .Index().Interface(), .Index().Interface(), , "at index %d", ) {returnfalse } }returntrue}/* Errors*/// NoError asserts that a function returned no error (i.e. `nil`).//// actualObj, err := SomeFunction()// if assert.NoError(t, err) {// assert.Equal(t, expectedObj, actualObj)// }func ( TestingT, error, ...interface{}) bool {if != nil {if , := .(tHelper); { .Helper() }returnFail(, fmt.Sprintf("Received unexpected error:\n%+v", ), ...) }returntrue}// Error asserts that a function returned an error (i.e. not `nil`).//// actualObj, err := SomeFunction()// assert.Error(t, err)func ( TestingT, error, ...interface{}) bool {if == nil {if , := .(tHelper); { .Helper() }returnFail(, "An error is expected but got nil.", ...) }returntrue}// EqualError asserts that a function returned an error (i.e. not `nil`)// and that it is equal to the provided error.//// actualObj, err := SomeFunction()// assert.EqualError(t, err, expectedErrorString)func ( TestingT, error, string, ...interface{}) bool {if , := .(tHelper); { .Helper() }if !Error(, , ...) {returnfalse } := := .Error()// don't need to use deep equals here, we know they are both stringsif != {returnFail(, fmt.Sprintf("Error message not equal:\n"+"expected: %q\n"+"actual : %q", , ), ...) }returntrue}// ErrorContains asserts that a function returned an error (i.e. not `nil`)// and that the error contains the specified substring.//// actualObj, err := SomeFunction()// assert.ErrorContains(t, err, expectedErrorSubString)func ( TestingT, error, string, ...interface{}) bool {if , := .(tHelper); { .Helper() }if !Error(, , ...) {returnfalse } := .Error()if !strings.Contains(, ) {returnFail(, fmt.Sprintf("Error %#v does not contain %#v", , ), ...) }returntrue}// matchRegexp return true if a specified regexp matches a string.func matchRegexp( interface{}, interface{}) bool {var *regexp.Regexpif , := .(*regexp.Regexp); { = } else { = regexp.MustCompile(fmt.Sprint()) }switch v := .(type) {case []byte:return .Match()casestring:return .MatchString()default:return .MatchString(fmt.Sprint()) }}// Regexp asserts that a specified regexp matches a string.//// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")// assert.Regexp(t, "start...$", "it's not starting")func ( TestingT, interface{}, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } := matchRegexp(, )if ! {Fail(, fmt.Sprintf("Expect \"%v\" to match \"%v\"", , ), ...) }return}// NotRegexp asserts that a specified regexp does not match a string.//// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")// assert.NotRegexp(t, "^start", "it's not starting")func ( TestingT, interface{}, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() } := matchRegexp(, )if {Fail(, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", , ), ...) }return !}// Zero asserts that i is the zero value for its type.func ( TestingT, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }if != nil && !reflect.DeepEqual(, reflect.Zero(reflect.TypeOf()).Interface()) {returnFail(, fmt.Sprintf("Should be zero, but was %v", ), ...) }returntrue}// NotZero asserts that i is not the zero value for its type.func ( TestingT, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }if == nil || reflect.DeepEqual(, reflect.Zero(reflect.TypeOf()).Interface()) {returnFail(, fmt.Sprintf("Should not be zero, but was %v", ), ...) }returntrue}// FileExists checks whether a file exists in the given path. It also fails if// the path points to a directory or there is an error when trying to check the file.func ( TestingT, string, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := os.Lstat()if != nil {ifos.IsNotExist() {returnFail(, fmt.Sprintf("unable to find file %q", ), ...) }returnFail(, fmt.Sprintf("error when running os.Lstat(%q): %s", , ), ...) }if .IsDir() {returnFail(, fmt.Sprintf("%q is a directory", ), ...) }returntrue}// NoFileExists checks whether a file does not exist in a given path. It fails// if the path points to an existing _file_ only.func ( TestingT, string, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := os.Lstat()if != nil {returntrue }if .IsDir() {returntrue }returnFail(, fmt.Sprintf("file %q exists", ), ...)}// DirExists checks whether a directory exists in the given path. It also fails// if the path is a file rather a directory or there is an error checking whether it exists.func ( TestingT, string, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := os.Lstat()if != nil {ifos.IsNotExist() {returnFail(, fmt.Sprintf("unable to find file %q", ), ...) }returnFail(, fmt.Sprintf("error when running os.Lstat(%q): %s", , ), ...) }if !.IsDir() {returnFail(, fmt.Sprintf("%q is a file", ), ...) }returntrue}// NoDirExists checks whether a directory does not exist in the given path.// It fails if the path points to an existing _directory_ only.func ( TestingT, string, ...interface{}) bool {if , := .(tHelper); { .Helper() } , := os.Lstat()if != nil {ifos.IsNotExist() {returntrue }returntrue }if !.IsDir() {returntrue }returnFail(, fmt.Sprintf("directory %q exists", ), ...)}// JSONEq asserts that two JSON strings are equivalent.//// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)func ( TestingT, string, string, ...interface{}) bool {if , := .(tHelper); { .Helper() }var , interface{}if := json.Unmarshal([]byte(), &); != nil {returnFail(, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", , .Error()), ...) }// Shortcut if same bytesif == {returntrue }if := json.Unmarshal([]byte(), &); != nil {returnFail(, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", , .Error()), ...) }returnEqual(, , , ...)}// YAMLEq asserts that two YAML strings are equivalent.func ( TestingT, string, string, ...interface{}) bool {if , := .(tHelper); { .Helper() }var , interface{}if := yaml.Unmarshal([]byte(), &); != nil {returnFail(, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", , .Error()), ...) }// Shortcut if same bytesif == {returntrue }if := yaml.Unmarshal([]byte(), &); != nil {returnFail(, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", , .Error()), ...) }returnEqual(, , , ...)}func typeAndKind( interface{}) (reflect.Type, reflect.Kind) { := reflect.TypeOf() := .Kind()if == reflect.Ptr { = .Elem() = .Kind() }return , }// diff returns a diff of both values as long as both are of the same type and// are a struct, map, slice, array or string. Otherwise it returns an empty string.func diff( interface{}, interface{}) string {if == nil || == nil {return"" } , := typeAndKind() , := typeAndKind()if != {return"" }if != reflect.Struct && != reflect.Map && != reflect.Slice && != reflect.Array && != reflect.String {return"" }var , stringswitch {casereflect.TypeOf(""): = reflect.ValueOf().String() = reflect.ValueOf().String()casereflect.TypeOf(time.Time{}): = spewConfigStringerEnabled.Sdump() = spewConfigStringerEnabled.Sdump()default: = spewConfig.Sdump() = spewConfig.Sdump() } , := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{A: difflib.SplitLines(),B: difflib.SplitLines(),FromFile: "Expected",FromDate: "",ToFile: "Actual",ToDate: "",Context: 1, })return"\n\nDiff:\n" + }func isFunction( interface{}) bool {if == nil {returnfalse }returnreflect.TypeOf().Kind() == reflect.Func}var spewConfig = spew.ConfigState{Indent: " ",DisablePointerAddresses: true,DisableCapacities: true,SortKeys: true,DisableMethods: true,MaxDepth: 10,}var spewConfigStringerEnabled = spew.ConfigState{Indent: " ",DisablePointerAddresses: true,DisableCapacities: true,SortKeys: true,MaxDepth: 10,}type tHelper = interface { Helper()}// Eventually asserts that given condition will be met in waitFor time,// periodically checking target function each tick.//// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)func ( TestingT, func() bool, time.Duration, time.Duration, ...interface{}) bool {if , := .(tHelper); { .Helper() } := make(chanbool, 1) := func() { <- () } := time.NewTimer()defer .Stop() := time.NewTicker()defer .Stop()var <-chantime.Time// Check the condition once first on the initial call.go ()for {select {case<-.C:returnFail(, "Condition never satisfied", ...)case<-: = nilgo ()case := <-:if {returntrue } = .C } }}// CollectT implements the TestingT interface and collects all errors.typeCollectTstruct {// A slice of errors. Non-nil slice denotes a failure. // If it's non-nil but len(c.errors) == 0, this is also a failure // obtained by direct c.FailNow() call. errors []error}// Helper is like [testing.T.Helper] but does nothing.func (CollectT) () {}// Errorf collects the error.func ( *CollectT) ( string, ...interface{}) { .errors = append(.errors, fmt.Errorf(, ...))}// FailNow stops execution by calling runtime.Goexit.func ( *CollectT) () { .fail()runtime.Goexit()}// Deprecated: That was a method for internal usage that should not have been published. Now just panics.func (*CollectT) () {panic("Reset() is deprecated")}// Deprecated: That was a method for internal usage that should not have been published. Now just panics.func (*CollectT) (TestingT) {panic("Copy() is deprecated")}func ( *CollectT) () {if !.failed() { .errors = []error{} // Make it non-nil to mark a failure. }}func ( *CollectT) () bool {return .errors != nil}// EventuallyWithT asserts that given condition will be met in waitFor time,// periodically checking target function each tick. In contrast to Eventually,// it supplies a CollectT to the condition function, so that the condition// function can use the CollectT to call other assertions.// The condition is considered "met" if no errors are raised in a tick.// The supplied CollectT collects all errors from one tick (if there are any).// If the condition is not met before waitFor, the collected errors of// the last tick are copied to t.//// externalValue := false// go func() {// time.Sleep(8*time.Second)// externalValue = true// }()// assert.EventuallyWithT(t, func(c *assert.CollectT) {// // add assertions as needed; any assertion failure will fail the current tick// assert.True(c, externalValue, "expected 'externalValue' to be true")// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")func ( TestingT, func( *CollectT), time.Duration, time.Duration, ...interface{}) bool {if , := .(tHelper); { .Helper() }var []error := make(chan *CollectT, 1) := func() { := new(CollectT)deferfunc() { <- }() () } := time.NewTimer()defer .Stop() := time.NewTicker()defer .Stop()var <-chantime.Time// Check the condition once first on the initial call.go ()for {select {case<-.C:for , := range { .Errorf("%v", ) }returnFail(, "Condition never satisfied", ...)case<-: = nilgo ()case := <-:if !.failed() {returntrue }// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached. = .errors = .C } }}// Never asserts that the given condition doesn't satisfy in waitFor time,// periodically checking the target function each tick.//// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)func ( TestingT, func() bool, time.Duration, time.Duration, ...interface{}) bool {if , := .(tHelper); { .Helper() } := make(chanbool, 1) := func() { <- () } := time.NewTimer()defer .Stop() := time.NewTicker()defer .Stop()var <-chantime.Time// Check the condition once first on the initial call.go ()for {select {case<-.C:returntruecase<-: = nilgo ()case := <-:if {returnFail(, "Condition satisfied", ...) } = .C } }}// ErrorIs asserts that at least one of the errors in err's chain matches target.// This is a wrapper for errors.Is.func ( TestingT, , error, ...interface{}) bool {if , := .(tHelper); { .Helper() }iferrors.Is(, ) {returntrue }varstringif != nil { = .Error()if == nil {returnFail(, fmt.Sprintf("Expected error with %q in chain but got nil.", ), ...) } } := buildErrorChainString(, false)returnFail(, fmt.Sprintf("Target error should be in err chain:\n"+"expected: %q\n"+"in chain: %s", , , ), ...)}// NotErrorIs asserts that none of the errors in err's chain matches target.// This is a wrapper for errors.Is.func ( TestingT, , error, ...interface{}) bool {if , := .(tHelper); { .Helper() }if !errors.Is(, ) {returntrue }varstringif != nil { = .Error() } := buildErrorChainString(, false)returnFail(, fmt.Sprintf("Target error should not be in err chain:\n"+"found: %q\n"+"in chain: %s", , , ), ...)}// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.// This is a wrapper for errors.As.func ( TestingT, error, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }iferrors.As(, ) {returntrue } := reflect.TypeOf().Elem().String()if == nil {returnFail(, fmt.Sprintf("An error is expected but got nil.\n"+"expected: %s", ), ...) } := buildErrorChainString(, true)returnFail(, fmt.Sprintf("Should be in error chain:\n"+"expected: %s\n"+"in chain: %s", , , ), ...)}// NotErrorAs asserts that none of the errors in err's chain matches target,// but if so, sets target to that error value.func ( TestingT, error, interface{}, ...interface{}) bool {if , := .(tHelper); { .Helper() }if !errors.As(, ) {returntrue } := buildErrorChainString(, true)returnFail(, fmt.Sprintf("Target error should not be in err chain:\n"+"found: %s\n"+"in chain: %s", reflect.TypeOf().Elem().String(), , ), ...)}func unwrapAll( error) ( []error) { = append(, )switch x := .(type) {caseinterface{ () error }: = .()if == nil {return } = append(, ()...)caseinterface{ () []error }:for , := range .() { = append(, ()...) } }return}func buildErrorChainString( error, bool) string {if == nil {return"" }varstring := unwrapAll()for := range {if != 0 { += "\n\t" } += fmt.Sprintf("%q", [].Error())if { += fmt.Sprintf(" (%T)", []) } }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.