aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gotest.tools/assert
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gotest.tools/assert')
-rw-r--r--vendor/gotest.tools/assert/assert.go311
-rw-r--r--vendor/gotest.tools/assert/cmp/compare.go312
-rw-r--r--vendor/gotest.tools/assert/cmp/result.go94
-rw-r--r--vendor/gotest.tools/assert/result.go107
4 files changed, 824 insertions, 0 deletions
diff --git a/vendor/gotest.tools/assert/assert.go b/vendor/gotest.tools/assert/assert.go
new file mode 100644
index 00000000..05d66354
--- /dev/null
+++ b/vendor/gotest.tools/assert/assert.go
@@ -0,0 +1,311 @@
+/*Package assert provides assertions for comparing expected values to actual
+values. When an assertion fails a helpful error message is printed.
+
+Assert and Check
+
+Assert() and Check() both accept a Comparison, and fail the test when the
+comparison fails. The one difference is that Assert() will end the test execution
+immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
+return the value of the comparison, then proceed with the rest of the test case.
+
+Example usage
+
+The example below shows assert used with some common types.
+
+
+ import (
+ "testing"
+
+ "gotest.tools/assert"
+ is "gotest.tools/assert/cmp"
+ )
+
+ func TestEverything(t *testing.T) {
+ // booleans
+ assert.Assert(t, ok)
+ assert.Assert(t, !missing)
+
+ // primitives
+ assert.Equal(t, count, 1)
+ assert.Equal(t, msg, "the message")
+ assert.Assert(t, total != 10) // NotEqual
+
+ // errors
+ assert.NilError(t, closer.Close())
+ assert.Error(t, err, "the exact error message")
+ assert.ErrorContains(t, err, "includes this")
+ assert.ErrorType(t, err, os.IsNotExist)
+
+ // complex types
+ assert.DeepEqual(t, result, myStruct{Name: "title"})
+ assert.Assert(t, is.Len(items, 3))
+ assert.Assert(t, len(sequence) != 0) // NotEmpty
+ assert.Assert(t, is.Contains(mapping, "key"))
+
+ // pointers and interface
+ assert.Assert(t, is.Nil(ref))
+ assert.Assert(t, ref != nil) // NotNil
+ }
+
+Comparisons
+
+Package https://godoc.org/gotest.tools/assert/cmp provides
+many common comparisons. Additional comparisons can be written to compare
+values in other ways. See the example Assert (CustomComparison).
+
+Automated migration from testify
+
+gty-migrate-from-testify is a binary which can update source code which uses
+testify assertions to use the assertions provided by this package.
+
+See http://bit.do/cmd-gty-migrate-from-testify.
+
+
+*/
+package assert // import "gotest.tools/assert"
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ gocmp "github.com/google/go-cmp/cmp"
+ "gotest.tools/assert/cmp"
+ "gotest.tools/internal/format"
+ "gotest.tools/internal/source"
+)
+
+// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
+type BoolOrComparison interface{}
+
+// TestingT is the subset of testing.T used by the assert package.
+type TestingT interface {
+ FailNow()
+ Fail()
+ Log(args ...interface{})
+}
+
+type helperT interface {
+ Helper()
+}
+
+const failureMessage = "assertion failed: "
+
+// nolint: gocyclo
+func assert(
+ t TestingT,
+ failer func(),
+ argSelector argSelector,
+ comparison BoolOrComparison,
+ msgAndArgs ...interface{},
+) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ var success bool
+ switch check := comparison.(type) {
+ case bool:
+ if check {
+ return true
+ }
+ logFailureFromBool(t, msgAndArgs...)
+
+ // Undocumented legacy comparison without Result type
+ case func() (success bool, message string):
+ success = runCompareFunc(t, check, msgAndArgs...)
+
+ case nil:
+ return true
+
+ case error:
+ msg := "error is not nil: "
+ t.Log(format.WithCustomMessage(failureMessage+msg+check.Error(), msgAndArgs...))
+
+ case cmp.Comparison:
+ success = runComparison(t, argSelector, check, msgAndArgs...)
+
+ case func() cmp.Result:
+ success = runComparison(t, argSelector, check, msgAndArgs...)
+
+ default:
+ t.Log(fmt.Sprintf("invalid Comparison: %v (%T)", check, check))
+ }
+
+ if success {
+ return true
+ }
+ failer()
+ return false
+}
+
+func runCompareFunc(
+ t TestingT,
+ f func() (success bool, message string),
+ msgAndArgs ...interface{},
+) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ if success, message := f(); !success {
+ t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
+ return false
+ }
+ return true
+}
+
+func logFailureFromBool(t TestingT, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ const stackIndex = 3 // Assert()/Check(), assert(), formatFailureFromBool()
+ const comparisonArgPos = 1
+ args, err := source.CallExprArgs(stackIndex)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ msg, err := boolFailureMessage(args[comparisonArgPos])
+ if err != nil {
+ t.Log(err.Error())
+ msg = "expression is false"
+ }
+
+ t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
+}
+
+func boolFailureMessage(expr ast.Expr) (string, error) {
+ if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
+ x, err := source.FormatNode(binaryExpr.X)
+ if err != nil {
+ return "", err
+ }
+ y, err := source.FormatNode(binaryExpr.Y)
+ if err != nil {
+ return "", err
+ }
+ return x + " is " + y, nil
+ }
+
+ if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
+ x, err := source.FormatNode(unaryExpr.X)
+ if err != nil {
+ return "", err
+ }
+ return x + " is true", nil
+ }
+
+ formatted, err := source.FormatNode(expr)
+ if err != nil {
+ return "", err
+ }
+ return "expression is false: " + formatted, nil
+}
+
+// Assert performs a comparison. If the comparison fails the test is marked as
+// failed, a failure message is logged, and execution is stopped immediately.
+//
+// The comparison argument may be one of three types: bool, cmp.Comparison or
+// error.
+// When called with a bool the failure message will contain the literal source
+// code of the expression.
+// When called with a cmp.Comparison the comparison is responsible for producing
+// a helpful failure message.
+// When called with an error a nil value is considered success. A non-nil error
+// is a failure, and Error() is used as the failure message.
+func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsFromComparisonCall, comparison, msgAndArgs...)
+}
+
+// Check performs a comparison. If the comparison fails the test is marked as
+// failed, a failure message is logged, and Check returns false. Otherwise returns
+// true.
+//
+// See Assert for details about the comparison arg and failure messages.
+func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ return assert(t, t.Fail, argsFromComparisonCall, comparison, msgAndArgs...)
+}
+
+// NilError fails the test immediately if err is not nil.
+// This is equivalent to Assert(t, err)
+func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, err, msgAndArgs...)
+}
+
+// Equal uses the == operator to assert two values are equal and fails the test
+// if they are not equal.
+//
+// If the comparison fails Equal will use the variable names for x and y as part
+// of the failure message to identify the actual and expected values.
+//
+// If either x or y are a multi-line string the failure message will include a
+// unified diff of the two values. If the values only differ by whitespace
+// the unified diff will be augmented by replacing whitespace characters with
+// visible characters to identify the whitespace difference.
+//
+// This is equivalent to Assert(t, cmp.Equal(x, y)).
+func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.Equal(x, y), msgAndArgs...)
+}
+
+// DeepEqual uses google/go-cmp (http://bit.do/go-cmp) to assert two values are
+// equal and fails the test if they are not equal.
+//
+// Package https://godoc.org/gotest.tools/assert/opt provides some additional
+// commonly used Options.
+//
+// This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
+func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.DeepEqual(x, y, opts...))
+}
+
+// Error fails the test if err is nil, or the error message is not the expected
+// message.
+// Equivalent to Assert(t, cmp.Error(err, message)).
+func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.Error(err, message), msgAndArgs...)
+}
+
+// ErrorContains fails the test if err is nil, or the error message does not
+// contain the expected substring.
+// Equivalent to Assert(t, cmp.ErrorContains(err, substring)).
+func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...)
+}
+
+// ErrorType fails the test if err is nil, or err is not the expected type.
+//
+// Expected can be one of:
+// a func(error) bool which returns true if the error is the expected type,
+// an instance of (or a pointer to) a struct of the expected type,
+// a pointer to an interface the error is expected to implement,
+// a reflect.Type of the expected struct or interface.
+//
+// Equivalent to Assert(t, cmp.ErrorType(err, expected)).
+func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.ErrorType(err, expected), msgAndArgs...)
+}
diff --git a/vendor/gotest.tools/assert/cmp/compare.go b/vendor/gotest.tools/assert/cmp/compare.go
new file mode 100644
index 00000000..ae03749e
--- /dev/null
+++ b/vendor/gotest.tools/assert/cmp/compare.go
@@ -0,0 +1,312 @@
+/*Package cmp provides Comparisons for Assert and Check*/
+package cmp // import "gotest.tools/assert/cmp"
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/google/go-cmp/cmp"
+ "gotest.tools/internal/format"
+)
+
+// Comparison is a function which compares values and returns ResultSuccess if
+// the actual value matches the expected value. If the values do not match the
+// Result will contain a message about why it failed.
+type Comparison func() Result
+
+// DeepEqual compares two values using google/go-cmp (http://bit.do/go-cmp)
+// and succeeds if the values are equal.
+//
+// The comparison can be customized using comparison Options.
+// Package https://godoc.org/gotest.tools/assert/opt provides some additional
+// commonly used Options.
+func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
+ return func() (result Result) {
+ defer func() {
+ if panicmsg, handled := handleCmpPanic(recover()); handled {
+ result = ResultFailure(panicmsg)
+ }
+ }()
+ diff := cmp.Diff(x, y, opts...)
+ if diff == "" {
+ return ResultSuccess
+ }
+ return multiLineDiffResult(diff)
+ }
+}
+
+func handleCmpPanic(r interface{}) (string, bool) {
+ if r == nil {
+ return "", false
+ }
+ panicmsg, ok := r.(string)
+ if !ok {
+ panic(r)
+ }
+ switch {
+ case strings.HasPrefix(panicmsg, "cannot handle unexported field"):
+ return panicmsg, true
+ }
+ panic(r)
+}
+
+func toResult(success bool, msg string) Result {
+ if success {
+ return ResultSuccess
+ }
+ return ResultFailure(msg)
+}
+
+// Equal succeeds if x == y. See assert.Equal for full documentation.
+func Equal(x, y interface{}) Comparison {
+ return func() Result {
+ switch {
+ case x == y:
+ return ResultSuccess
+ case isMultiLineStringCompare(x, y):
+ diff := format.UnifiedDiff(format.DiffConfig{A: x.(string), B: y.(string)})
+ return multiLineDiffResult(diff)
+ }
+ return ResultFailureTemplate(`
+ {{- .Data.x}} (
+ {{- with callArg 0 }}{{ formatNode . }} {{end -}}
+ {{- printf "%T" .Data.x -}}
+ ) != {{ .Data.y}} (
+ {{- with callArg 1 }}{{ formatNode . }} {{end -}}
+ {{- printf "%T" .Data.y -}}
+ )`,
+ map[string]interface{}{"x": x, "y": y})
+ }
+}
+
+func isMultiLineStringCompare(x, y interface{}) bool {
+ strX, ok := x.(string)
+ if !ok {
+ return false
+ }
+ strY, ok := y.(string)
+ if !ok {
+ return false
+ }
+ return strings.Contains(strX, "\n") || strings.Contains(strY, "\n")
+}
+
+func multiLineDiffResult(diff string) Result {
+ return ResultFailureTemplate(`
+--- {{ with callArg 0 }}{{ formatNode . }}{{else}}←{{end}}
++++ {{ with callArg 1 }}{{ formatNode . }}{{else}}→{{end}}
+{{ .Data.diff }}`,
+ map[string]interface{}{"diff": diff})
+}
+
+// Len succeeds if the sequence has the expected length.
+func Len(seq interface{}, expected int) Comparison {
+ return func() (result Result) {
+ defer func() {
+ if e := recover(); e != nil {
+ result = ResultFailure(fmt.Sprintf("type %T does not have a length", seq))
+ }
+ }()
+ value := reflect.ValueOf(seq)
+ length := value.Len()
+ if length == expected {
+ return ResultSuccess
+ }
+ msg := fmt.Sprintf("expected %s (length %d) to have length %d", seq, length, expected)
+ return ResultFailure(msg)
+ }
+}
+
+// Contains succeeds if item is in collection. Collection may be a string, map,
+// slice, or array.
+//
+// If collection is a string, item must also be a string, and is compared using
+// strings.Contains().
+// If collection is a Map, contains will succeed if item is a key in the map.
+// If collection is a slice or array, item is compared to each item in the
+// sequence using reflect.DeepEqual().
+func Contains(collection interface{}, item interface{}) Comparison {
+ return func() Result {
+ colValue := reflect.ValueOf(collection)
+ if !colValue.IsValid() {
+ return ResultFailure(fmt.Sprintf("nil does not contain items"))
+ }
+ msg := fmt.Sprintf("%v does not contain %v", collection, item)
+
+ itemValue := reflect.ValueOf(item)
+ switch colValue.Type().Kind() {
+ case reflect.String:
+ if itemValue.Type().Kind() != reflect.String {
+ return ResultFailure("string may only contain strings")
+ }
+ return toResult(
+ strings.Contains(colValue.String(), itemValue.String()),
+ fmt.Sprintf("string %q does not contain %q", collection, item))
+
+ case reflect.Map:
+ if itemValue.Type() != colValue.Type().Key() {
+ return ResultFailure(fmt.Sprintf(
+ "%v can not contain a %v key", colValue.Type(), itemValue.Type()))
+ }
+ return toResult(colValue.MapIndex(itemValue).IsValid(), msg)
+
+ case reflect.Slice, reflect.Array:
+ for i := 0; i < colValue.Len(); i++ {
+ if reflect.DeepEqual(colValue.Index(i).Interface(), item) {
+ return ResultSuccess
+ }
+ }
+ return ResultFailure(msg)
+ default:
+ return ResultFailure(fmt.Sprintf("type %T does not contain items", collection))
+ }
+ }
+}
+
+// Panics succeeds if f() panics.
+func Panics(f func()) Comparison {
+ return func() (result Result) {
+ defer func() {
+ if err := recover(); err != nil {
+ result = ResultSuccess
+ }
+ }()
+ f()
+ return ResultFailure("did not panic")
+ }
+}
+
+// Error succeeds if err is a non-nil error, and the error message equals the
+// expected message.
+func Error(err error, message string) Comparison {
+ return func() Result {
+ switch {
+ case err == nil:
+ return ResultFailure("expected an error, got nil")
+ case err.Error() != message:
+ return ResultFailure(fmt.Sprintf(
+ "expected error %q, got %+v", message, err))
+ }
+ return ResultSuccess
+ }
+}
+
+// ErrorContains succeeds if err is a non-nil error, and the error message contains
+// the expected substring.
+func ErrorContains(err error, substring string) Comparison {
+ return func() Result {
+ switch {
+ case err == nil:
+ return ResultFailure("expected an error, got nil")
+ case !strings.Contains(err.Error(), substring):
+ return ResultFailure(fmt.Sprintf(
+ "expected error to contain %q, got %+v", substring, err))
+ }
+ return ResultSuccess
+ }
+}
+
+// Nil succeeds if obj is a nil interface, pointer, or function.
+//
+// Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,
+// maps, and channels.
+func Nil(obj interface{}) Comparison {
+ msgFunc := func(value reflect.Value) string {
+ return fmt.Sprintf("%v (type %s) is not nil", reflect.Indirect(value), value.Type())
+ }
+ return isNil(obj, msgFunc)
+}
+
+func isNil(obj interface{}, msgFunc func(reflect.Value) string) Comparison {
+ return func() Result {
+ if obj == nil {
+ return ResultSuccess
+ }
+ value := reflect.ValueOf(obj)
+ kind := value.Type().Kind()
+ if kind >= reflect.Chan && kind <= reflect.Slice {
+ if value.IsNil() {
+ return ResultSuccess
+ }
+ return ResultFailure(msgFunc(value))
+ }
+
+ return ResultFailure(fmt.Sprintf("%v (type %s) can not be nil", value, value.Type()))
+ }
+}
+
+// ErrorType succeeds if err is not nil and is of the expected type.
+//
+// Expected can be one of:
+// a func(error) bool which returns true if the error is the expected type,
+// an instance of (or a pointer to) a struct of the expected type,
+// a pointer to an interface the error is expected to implement,
+// a reflect.Type of the expected struct or interface.
+func ErrorType(err error, expected interface{}) Comparison {
+ return func() Result {
+ switch expectedType := expected.(type) {
+ case func(error) bool:
+ return cmpErrorTypeFunc(err, expectedType)
+ case reflect.Type:
+ if expectedType.Kind() == reflect.Interface {
+ return cmpErrorTypeImplementsType(err, expectedType)
+ }
+ return cmpErrorTypeEqualType(err, expectedType)
+ case nil:
+ return ResultFailure(fmt.Sprintf("invalid type for expected: nil"))
+ }
+
+ expectedType := reflect.TypeOf(expected)
+ switch {
+ case expectedType.Kind() == reflect.Struct, isPtrToStruct(expectedType):
+ return cmpErrorTypeEqualType(err, expectedType)
+ case isPtrToInterface(expectedType):
+ return cmpErrorTypeImplementsType(err, expectedType.Elem())
+ }
+ return ResultFailure(fmt.Sprintf("invalid type for expected: %T", expected))
+ }
+}
+
+func cmpErrorTypeFunc(err error, f func(error) bool) Result {
+ if f(err) {
+ return ResultSuccess
+ }
+ actual := "nil"
+ if err != nil {
+ actual = fmt.Sprintf("%s (%T)", err, err)
+ }
+ return ResultFailureTemplate(`error is {{ .Data.actual }}
+ {{- with callArg 1 }}, not {{ formatNode . }}{{end -}}`,
+ map[string]interface{}{"actual": actual})
+}
+
+func cmpErrorTypeEqualType(err error, expectedType reflect.Type) Result {
+ if err == nil {
+ return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
+ }
+ errValue := reflect.ValueOf(err)
+ if errValue.Type() == expectedType {
+ return ResultSuccess
+ }
+ return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
+}
+
+func cmpErrorTypeImplementsType(err error, expectedType reflect.Type) Result {
+ if err == nil {
+ return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
+ }
+ errValue := reflect.ValueOf(err)
+ if errValue.Type().Implements(expectedType) {
+ return ResultSuccess
+ }
+ return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
+}
+
+func isPtrToInterface(typ reflect.Type) bool {
+ return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Interface
+}
+
+func isPtrToStruct(typ reflect.Type) bool {
+ return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct
+}
diff --git a/vendor/gotest.tools/assert/cmp/result.go b/vendor/gotest.tools/assert/cmp/result.go
new file mode 100644
index 00000000..7c3c37dd
--- /dev/null
+++ b/vendor/gotest.tools/assert/cmp/result.go
@@ -0,0 +1,94 @@
+package cmp
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "text/template"
+
+ "gotest.tools/internal/source"
+)
+
+// Result of a Comparison.
+type Result interface {
+ Success() bool
+}
+
+type result struct {
+ success bool
+ message string
+}
+
+func (r result) Success() bool {
+ return r.success
+}
+
+func (r result) FailureMessage() string {
+ return r.message
+}
+
+// ResultSuccess is a constant which is returned by a ComparisonWithResult to
+// indicate success.
+var ResultSuccess = result{success: true}
+
+// ResultFailure returns a failed Result with a failure message.
+func ResultFailure(message string) Result {
+ return result{message: message}
+}
+
+// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
+// is returned with the error message as the failure message.
+func ResultFromError(err error) Result {
+ if err == nil {
+ return ResultSuccess
+ }
+ return ResultFailure(err.Error())
+}
+
+type templatedResult struct {
+ success bool
+ template string
+ data map[string]interface{}
+}
+
+func (r templatedResult) Success() bool {
+ return r.success
+}
+
+func (r templatedResult) FailureMessage(args []ast.Expr) string {
+ msg, err := renderMessage(r, args)
+ if err != nil {
+ return fmt.Sprintf("failed to render failure message: %s", err)
+ }
+ return msg
+}
+
+// ResultFailureTemplate returns a Result with a template string and data which
+// can be used to format a failure message. The template may access data from .Data,
+// the comparison args with the callArg function, and the formatNode function may
+// be used to format the call args.
+func ResultFailureTemplate(template string, data map[string]interface{}) Result {
+ return templatedResult{template: template, data: data}
+}
+
+func renderMessage(result templatedResult, args []ast.Expr) (string, error) {
+ tmpl := template.New("failure").Funcs(template.FuncMap{
+ "formatNode": source.FormatNode,
+ "callArg": func(index int) ast.Expr {
+ if index >= len(args) {
+ return nil
+ }
+ return args[index]
+ },
+ })
+ var err error
+ tmpl, err = tmpl.Parse(result.template)
+ if err != nil {
+ return "", err
+ }
+ buf := new(bytes.Buffer)
+ err = tmpl.Execute(buf, map[string]interface{}{
+ "Data": result.data,
+ })
+ return buf.String(), err
+}
diff --git a/vendor/gotest.tools/assert/result.go b/vendor/gotest.tools/assert/result.go
new file mode 100644
index 00000000..3900264d
--- /dev/null
+++ b/vendor/gotest.tools/assert/result.go
@@ -0,0 +1,107 @@
+package assert
+
+import (
+ "fmt"
+ "go/ast"
+
+ "gotest.tools/assert/cmp"
+ "gotest.tools/internal/format"
+ "gotest.tools/internal/source"
+)
+
+func runComparison(
+ t TestingT,
+ argSelector argSelector,
+ f cmp.Comparison,
+ msgAndArgs ...interface{},
+) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ result := f()
+ if result.Success() {
+ return true
+ }
+
+ var message string
+ switch typed := result.(type) {
+ case resultWithComparisonArgs:
+ const stackIndex = 3 // Assert/Check, assert, runComparison
+ args, err := source.CallExprArgs(stackIndex)
+ if err != nil {
+ t.Log(err.Error())
+ }
+ message = typed.FailureMessage(filterPrintableExpr(argSelector(args)))
+ case resultBasic:
+ message = typed.FailureMessage()
+ default:
+ message = fmt.Sprintf("comparison returned invalid Result type: %T", result)
+ }
+
+ t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
+ return false
+}
+
+type resultWithComparisonArgs interface {
+ FailureMessage(args []ast.Expr) string
+}
+
+type resultBasic interface {
+ FailureMessage() string
+}
+
+// filterPrintableExpr filters the ast.Expr slice to only include Expr that are
+// easy to read when printed and contain relevant information to an assertion.
+//
+// Ident and SelectorExpr are included because they print nicely and the variable
+// names may provide additional context to their values.
+// BasicLit and CompositeLit are excluded because their source is equivalent to
+// their value, which is already available.
+// Other types are ignored for now, but could be added if they are relevant.
+func filterPrintableExpr(args []ast.Expr) []ast.Expr {
+ result := make([]ast.Expr, len(args))
+ for i, arg := range args {
+ if isShortPrintableExpr(arg) {
+ result[i] = arg
+ continue
+ }
+
+ if starExpr, ok := arg.(*ast.StarExpr); ok {
+ result[i] = starExpr.X
+ continue
+ }
+ result[i] = nil
+ }
+ return result
+}
+
+func isShortPrintableExpr(expr ast.Expr) bool {
+ switch expr.(type) {
+ case *ast.Ident, *ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr:
+ return true
+ case *ast.BinaryExpr, *ast.UnaryExpr:
+ return true
+ default:
+ // CallExpr, ParenExpr, TypeAssertExpr, KeyValueExpr, StarExpr
+ return false
+ }
+}
+
+type argSelector func([]ast.Expr) []ast.Expr
+
+func argsAfterT(args []ast.Expr) []ast.Expr {
+ if len(args) < 1 {
+ return nil
+ }
+ return args[1:]
+}
+
+func argsFromComparisonCall(args []ast.Expr) []ast.Expr {
+ if len(args) < 1 {
+ return nil
+ }
+ if callExpr, ok := args[1].(*ast.CallExpr); ok {
+ return callExpr.Args
+ }
+ return nil
+}