forked from toolshed/abra
chore: vendor
This commit is contained in:
161
vendor/gotest.tools/v3/internal/assert/assert.go
vendored
Normal file
161
vendor/gotest.tools/v3/internal/assert/assert.go
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
// Package assert provides internal utilties for assertions.
|
||||
package assert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"reflect"
|
||||
|
||||
"gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/internal/format"
|
||||
"gotest.tools/v3/internal/source"
|
||||
)
|
||||
|
||||
// LogT is the subset of testing.T used by the assert package.
|
||||
type LogT interface {
|
||||
Log(args ...interface{})
|
||||
}
|
||||
|
||||
type helperT interface {
|
||||
Helper()
|
||||
}
|
||||
|
||||
const failureMessage = "assertion failed: "
|
||||
|
||||
// Eval the comparison and print a failure messages if the comparison has failed.
|
||||
func Eval(
|
||||
t LogT,
|
||||
argSelector argSelector,
|
||||
comparison interface{},
|
||||
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 := failureMsgFromError(check)
|
||||
t.Log(format.WithCustomMessage(failureMessage+msg, 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))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func runCompareFunc(
|
||||
t LogT,
|
||||
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 LogT, msgAndArgs ...interface{}) {
|
||||
if ht, ok := t.(helperT); ok {
|
||||
ht.Helper()
|
||||
}
|
||||
const stackIndex = 3 // Assert()/Check(), assert(), logFailureFromBool()
|
||||
args, err := source.CallExprArgs(stackIndex)
|
||||
if err != nil {
|
||||
t.Log(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
const comparisonArgIndex = 1 // Assert(t, comparison)
|
||||
if len(args) <= comparisonArgIndex {
|
||||
t.Log(failureMessage + "but assert failed to find the expression to print")
|
||||
return
|
||||
}
|
||||
|
||||
msg, err := boolFailureMessage(args[comparisonArgIndex])
|
||||
if err != nil {
|
||||
t.Log(err.Error())
|
||||
msg = "expression is false"
|
||||
}
|
||||
|
||||
t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
|
||||
}
|
||||
|
||||
func failureMsgFromError(err error) string {
|
||||
// Handle errors with non-nil types
|
||||
v := reflect.ValueOf(err)
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return fmt.Sprintf("error is not nil: error has type %T", err)
|
||||
}
|
||||
return "error is not nil: " + err.Error()
|
||||
}
|
||||
|
||||
func boolFailureMessage(expr ast.Expr) (string, error) {
|
||||
if binaryExpr, ok := expr.(*ast.BinaryExpr); ok {
|
||||
x, err := source.FormatNode(binaryExpr.X)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
y, err := source.FormatNode(binaryExpr.Y)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch binaryExpr.Op {
|
||||
case token.NEQ:
|
||||
return x + " is " + y, nil
|
||||
case token.EQL:
|
||||
return x + " is not " + y, nil
|
||||
case token.GTR:
|
||||
return x + " is <= " + y, nil
|
||||
case token.LSS:
|
||||
return x + " is >= " + y, nil
|
||||
case token.GEQ:
|
||||
return x + " is less than " + y, nil
|
||||
case token.LEQ:
|
||||
return x + " is greater than " + 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
|
||||
}
|
||||
|
||||
if ident, ok := expr.(*ast.Ident); ok {
|
||||
return ident.Name + " is false", nil
|
||||
}
|
||||
|
||||
formatted, err := source.FormatNode(expr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "expression is false: " + formatted, nil
|
||||
}
|
146
vendor/gotest.tools/v3/internal/assert/result.go
vendored
Normal file
146
vendor/gotest.tools/v3/internal/assert/result.go
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
package assert
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
|
||||
"gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/internal/format"
|
||||
"gotest.tools/v3/internal/source"
|
||||
)
|
||||
|
||||
// RunComparison and return Comparison.Success. If the comparison fails a messages
|
||||
// will be printed using t.Log.
|
||||
func RunComparison(
|
||||
t LogT,
|
||||
argSelector argSelector,
|
||||
f cmp.Comparison,
|
||||
msgAndArgs ...interface{},
|
||||
) bool {
|
||||
if ht, ok := t.(helperT); ok {
|
||||
ht.Helper()
|
||||
}
|
||||
result := f()
|
||||
if result.Success() {
|
||||
return true
|
||||
}
|
||||
|
||||
if source.IsUpdate() {
|
||||
if updater, ok := result.(updateExpected); ok {
|
||||
const stackIndex = 3 // Assert/Check, assert, RunComparison
|
||||
err := updater.UpdatedExpected(stackIndex)
|
||||
switch {
|
||||
case err == nil:
|
||||
return true
|
||||
case errors.Is(err, source.ErrNotFound):
|
||||
// do nothing, fallthrough to regular failure message
|
||||
default:
|
||||
t.Log("failed to update source", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type updateExpected interface {
|
||||
UpdatedExpected(stackIndex int) error
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
// ArgsAfterT selects args starting at position 1. Used when the caller has a
|
||||
// testing.T as the first argument, and the args to select should follow it.
|
||||
func ArgsAfterT(args []ast.Expr) []ast.Expr {
|
||||
if len(args) < 1 {
|
||||
return nil
|
||||
}
|
||||
return args[1:]
|
||||
}
|
||||
|
||||
// ArgsFromComparisonCall selects args from the CallExpression at position 1.
|
||||
// Used when the caller has a testing.T as the first argument, and the args to
|
||||
// select are passed to the cmp.Comparison at position 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
|
||||
}
|
||||
|
||||
// ArgsAtZeroIndex selects args from the CallExpression at position 1.
|
||||
// Used when the caller accepts a single cmp.Comparison argument.
|
||||
func ArgsAtZeroIndex(args []ast.Expr) []ast.Expr {
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
if callExpr, ok := args[0].(*ast.CallExpr); ok {
|
||||
return callExpr.Args
|
||||
}
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user