chore: vendor

This commit is contained in:
2024-08-04 11:06:58 +02:00
parent 2a5985e44e
commit 04aec8232f
3557 changed files with 981078 additions and 1 deletions

View 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
}

View 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
}