vendor: gotest.tools/v3 v3.0.3

https://github.com/gotestyourself/gotest.tools/compare/v3.0.2...v3.0.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2022-03-01 15:50:32 +01:00
parent 20b5dfa591
commit 8a3e3b22a7
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
13 changed files with 295 additions and 264 deletions

View File

@ -68,5 +68,4 @@ replace (
github.com/prometheus/common => github.com/prometheus/common v0.9.1 github.com/prometheus/common => github.com/prometheus/common v0.9.1
github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.11 github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.11
github.com/theupdateframework/notary => github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a github.com/theupdateframework/notary => github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
gotest.tools/v3 => gotest.tools/v3 v3.0.2
) )

View File

@ -911,8 +911,9 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -49,7 +49,7 @@ The example below shows assert used with some common types.
Comparisons Comparisons
Package http://gotest.tools/assert/cmp provides Package http://pkg.go.dev/gotest.tools/v3/assert/cmp provides
many common comparisons. Additional comparisons can be written to compare many common comparisons. Additional comparisons can be written to compare
values in other ways. See the example Assert (CustomComparison). values in other ways. See the example Assert (CustomComparison).
@ -58,22 +58,16 @@ Automated migration from testify
gty-migrate-from-testify is a command which translates Go source code from gty-migrate-from-testify is a command which translates Go source code from
testify assertions to the assertions provided by this package. testify assertions to the assertions provided by this package.
See http://gotest.tools/assert/cmd/gty-migrate-from-testify. See http://pkg.go.dev/gotest.tools/v3/assert/cmd/gty-migrate-from-testify.
*/ */
package assert // import "gotest.tools/v3/assert" package assert // import "gotest.tools/v3/assert"
import ( import (
"fmt"
"go/ast"
"go/token"
"reflect"
gocmp "github.com/google/go-cmp/cmp" gocmp "github.com/google/go-cmp/cmp"
"gotest.tools/v3/assert/cmp" "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/internal/format" "gotest.tools/v3/internal/assert"
"gotest.tools/v3/internal/source"
) )
// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage. // BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
@ -90,128 +84,6 @@ type helperT interface {
Helper() 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 := 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))
}
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 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 && 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 // Assert performs a comparison. If the comparison fails, the test is marked as
// failed, a failure message is logged, and execution is stopped immediately. // failed, a failure message is logged, and execution is stopped immediately.
// //
@ -222,7 +94,7 @@ func boolFailureMessage(expr ast.Expr) (string, error) {
// cmp.Comparison // cmp.Comparison
// Uses cmp.Result.Success() to check for success of failure. // Uses cmp.Result.Success() to check for success of failure.
// The comparison is responsible for producing a helpful failure message. // The comparison is responsible for producing a helpful failure message.
// http://gotest.tools/assert/cmp provides many common comparisons. // http://pkg.go.dev/gotest.tools/v3/assert/cmp provides many common comparisons.
// error // error
// A nil value is considered success. // A nil value is considered success.
// A non-nil error is a failure, err.Error() is used as the failure message. // A non-nil error is a failure, err.Error() is used as the failure message.
@ -230,7 +102,9 @@ func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{})
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
assert(t, t.FailNow, argsFromComparisonCall, comparison, msgAndArgs...) if !assert.Eval(t, assert.ArgsFromComparisonCall, comparison, msgAndArgs...) {
t.FailNow()
}
} }
// Check performs a comparison. If the comparison fails the test is marked as // Check performs a comparison. If the comparison fails the test is marked as
@ -242,7 +116,11 @@ func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) b
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
return assert(t, t.Fail, argsFromComparisonCall, comparison, msgAndArgs...) if !assert.Eval(t, assert.ArgsFromComparisonCall, comparison, msgAndArgs...) {
t.Fail()
return false
}
return true
} }
// NilError fails the test immediately if err is not nil. // NilError fails the test immediately if err is not nil.
@ -251,7 +129,9 @@ func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
assert(t, t.FailNow, argsAfterT, err, msgAndArgs...) if !assert.Eval(t, assert.ArgsAfterT, err, msgAndArgs...) {
t.FailNow()
}
} }
// Equal uses the == operator to assert two values are equal and fails the test // Equal uses the == operator to assert two values are equal and fails the test
@ -270,13 +150,15 @@ func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
assert(t, t.FailNow, argsAfterT, cmp.Equal(x, y), msgAndArgs...) if !assert.Eval(t, assert.ArgsAfterT, cmp.Equal(x, y), msgAndArgs...) {
t.FailNow()
}
} }
// DeepEqual uses google/go-cmp (https://godoc.org/github.com/google/go-cmp/cmp) // DeepEqual uses google/go-cmp (https://godoc.org/github.com/google/go-cmp/cmp)
// to assert two values are equal and fails the test if they are not equal. // to assert two values are equal and fails the test if they are not equal.
// //
// Package http://gotest.tools/assert/opt provides some additional // Package http://pkg.go.dev/gotest.tools/v3/assert/opt provides some additional
// commonly used Options. // commonly used Options.
// //
// This is equivalent to Assert(t, cmp.DeepEqual(x, y)). // This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
@ -284,7 +166,9 @@ func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
assert(t, t.FailNow, argsAfterT, cmp.DeepEqual(x, y, opts...)) if !assert.Eval(t, assert.ArgsAfterT, cmp.DeepEqual(x, y, opts...)) {
t.FailNow()
}
} }
// Error fails the test if err is nil, or the error message is not the expected // Error fails the test if err is nil, or the error message is not the expected
@ -294,7 +178,9 @@ func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
assert(t, t.FailNow, argsAfterT, cmp.Error(err, message), msgAndArgs...) if !assert.Eval(t, assert.ArgsAfterT, cmp.Error(err, message), msgAndArgs...) {
t.FailNow()
}
} }
// ErrorContains fails the test if err is nil, or the error message does not // ErrorContains fails the test if err is nil, or the error message does not
@ -304,7 +190,9 @@ func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interf
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
assert(t, t.FailNow, argsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...) if !assert.Eval(t, assert.ArgsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...) {
t.FailNow()
}
} }
// ErrorType fails the test if err is nil, or err is not the expected type. // ErrorType fails the test if err is nil, or err is not the expected type.
@ -325,5 +213,7 @@ func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interf
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }
assert(t, t.FailNow, argsAfterT, cmp.ErrorType(err, expected), msgAndArgs...) if !assert.Eval(t, assert.ArgsAfterT, cmp.ErrorType(err, expected), msgAndArgs...) {
t.FailNow()
}
} }

View File

@ -21,7 +21,7 @@ type Comparison func() Result
// and succeeds if the values are equal. // and succeeds if the values are equal.
// //
// The comparison can be customized using comparison Options. // The comparison can be customized using comparison Options.
// Package http://gotest.tools/assert/opt provides some additional // Package http://pkg.go.dev/gotest.tools/v3/assert/opt provides some additional
// commonly used Options. // commonly used Options.
func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison { func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
return func() (result Result) { return func() (result Result) {

View File

@ -52,13 +52,12 @@ func ResultFromError(err error) Result {
} }
type templatedResult struct { type templatedResult struct {
success bool
template string template string
data map[string]interface{} data map[string]interface{}
} }
func (r templatedResult) Success() bool { func (r templatedResult) Success() bool {
return r.success return false
} }
func (r templatedResult) FailureMessage(args []ast.Expr) string { func (r templatedResult) FailureMessage(args []ast.Expr) string {

View File

@ -26,6 +26,24 @@ type helperT interface {
Helper() Helper()
} }
// NormalizeCRLFToLF enables end-of-line normalization for actual values passed
// to Assert and String, as well as the values saved to golden files with
// -test.update-golden.
//
// Defaults to true. If you use the core.autocrlf=true git setting on windows
// you will need to set this to false.
//
// The value may be set to false by setting GOTESTTOOLS_GOLDEN_NormalizeCRLFToLF=false
// in the environment before running tests.
//
// The default value may change in a future major release.
var NormalizeCRLFToLF = os.Getenv("GOTESTTOOLS_GOLDEN_NormalizeCRLFToLF") != "false"
// FlagUpdate returns true when the -test.update-golden flag has been set.
func FlagUpdate() bool {
return *flagUpdate
}
// Open opens the file in ./testdata // Open opens the file in ./testdata
func Open(t assert.TestingT, filename string) *os.File { func Open(t assert.TestingT, filename string) *os.File {
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
@ -54,23 +72,13 @@ func Path(filename string) string {
return filepath.Join("testdata", filename) return filepath.Join("testdata", filename)
} }
func update(filename string, actual []byte, normalize normalize) error {
if *flagUpdate {
return ioutil.WriteFile(Path(filename), normalize(actual), 0644)
}
return nil
}
type normalize func([]byte) []byte
func removeCarriageReturn(in []byte) []byte { func removeCarriageReturn(in []byte) []byte {
if !NormalizeCRLFToLF {
return in
}
return bytes.Replace(in, []byte("\r\n"), []byte("\n"), -1) return bytes.Replace(in, []byte("\r\n"), []byte("\n"), -1)
} }
func exactBytes(in []byte) []byte {
return in
}
// Assert compares actual to the expected value in the golden file. // Assert compares actual to the expected value in the golden file.
// //
// Running `go test pkgname -test.update-golden` will write the value of actual // Running `go test pkgname -test.update-golden` will write the value of actual
@ -97,7 +105,7 @@ func Assert(t assert.TestingT, actual string, filename string, msgAndArgs ...int
func String(actual string, filename string) cmp.Comparison { func String(actual string, filename string) cmp.Comparison {
return func() cmp.Result { return func() cmp.Result {
actualBytes := removeCarriageReturn([]byte(actual)) actualBytes := removeCarriageReturn([]byte(actual))
result, expected := compare(actualBytes, filename, removeCarriageReturn) result, expected := compare(actualBytes, filename)
if result != nil { if result != nil {
return result return result
} }
@ -143,7 +151,7 @@ func AssertBytes(
// to the golden file. // to the golden file.
func Bytes(actual []byte, filename string) cmp.Comparison { func Bytes(actual []byte, filename string) cmp.Comparison {
return func() cmp.Result { return func() cmp.Result {
result, expected := compare(actual, filename, exactBytes) result, expected := compare(actual, filename)
if result != nil { if result != nil {
return result return result
} }
@ -152,8 +160,8 @@ func Bytes(actual []byte, filename string) cmp.Comparison {
} }
} }
func compare(actual []byte, filename string, normalize normalize) (cmp.Result, []byte) { func compare(actual []byte, filename string) (cmp.Result, []byte) {
if err := update(filename, actual, normalize); err != nil { if err := update(filename, actual); err != nil {
return cmp.ResultFromError(err), nil return cmp.ResultFromError(err), nil
} }
expected, err := ioutil.ReadFile(Path(filename)) expected, err := ioutil.ReadFile(Path(filename))
@ -165,3 +173,15 @@ func compare(actual []byte, filename string, normalize normalize) (cmp.Result, [
} }
return nil, expected return nil, expected
} }
func update(filename string, actual []byte) error {
if dir := filepath.Dir(filename); dir != "." {
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
}
if *flagUpdate {
return ioutil.WriteFile(Path(filename), actual, 0644)
}
return nil
}

View File

@ -0,0 +1,143 @@
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.
// nolint: gocyclo
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 && 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
}

View File

@ -9,8 +9,10 @@ import (
"gotest.tools/v3/internal/source" "gotest.tools/v3/internal/source"
) )
func runComparison( // RunComparison and return Comparison.Success. If the comparison fails a messages
t TestingT, // will be printed using t.Log.
func RunComparison(
t LogT,
argSelector argSelector, argSelector argSelector,
f cmp.Comparison, f cmp.Comparison,
msgAndArgs ...interface{}, msgAndArgs ...interface{},
@ -26,7 +28,7 @@ func runComparison(
var message string var message string
switch typed := result.(type) { switch typed := result.(type) {
case resultWithComparisonArgs: case resultWithComparisonArgs:
const stackIndex = 3 // Assert/Check, assert, runComparison const stackIndex = 3 // Assert/Check, assert, RunComparison
args, err := source.CallExprArgs(stackIndex) args, err := source.CallExprArgs(stackIndex)
if err != nil { if err != nil {
t.Log(err.Error()) t.Log(err.Error())
@ -88,15 +90,20 @@ func isShortPrintableExpr(expr ast.Expr) bool {
type argSelector func([]ast.Expr) []ast.Expr type argSelector func([]ast.Expr) []ast.Expr
func argsAfterT(args []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 { if len(args) < 1 {
return nil return nil
} }
return args[1:] return args[1:]
} }
func argsFromComparisonCall(args []ast.Expr) []ast.Expr { // ArgsFromComparisonCall selects args from the CallExpression at position 1.
if len(args) < 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 return nil
} }
if callExpr, ok := args[1].(*ast.CallExpr); ok { if callExpr, ok := args[1].(*ast.CallExpr); ok {
@ -104,3 +111,15 @@ func argsFromComparisonCall(args []ast.Expr) []ast.Expr {
} }
return nil 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
}

View File

@ -6,14 +6,17 @@ package cleanup
import ( import (
"os" "os"
"strings" "strings"
"gotest.tools/v3/x/subtest"
) )
type cleanupT interface { type cleanupT interface {
Cleanup(f func()) Cleanup(f func())
} }
// implemented by gotest.tools/x/subtest.TestContext
type addCleanupT interface {
AddCleanup(f func())
}
type logT interface { type logT interface {
Log(...interface{}) Log(...interface{})
} }
@ -39,7 +42,7 @@ func Cleanup(t logT, f func()) {
ct.Cleanup(f) ct.Cleanup(f)
return return
} }
if tc, ok := t.(subtest.TestContext); ok { if tc, ok := t.(addCleanupT); ok {
tc.AddCleanup(f) tc.AddCleanup(f)
} }
} }

View File

@ -93,8 +93,9 @@ func nodePosition(fileset *token.FileSet, node ast.Node) token.Position {
} }
// GoVersionLessThan returns true if runtime.Version() is semantically less than // GoVersionLessThan returns true if runtime.Version() is semantically less than
// version 1.minor. // version major.minor. Returns false if a release version can not be parsed from
func GoVersionLessThan(minor int64) bool { // runtime.Version().
func GoVersionLessThan(major, minor int64) bool {
version := runtime.Version() version := runtime.Version()
// not a release version // not a release version
if !strings.HasPrefix(version, "go") { if !strings.HasPrefix(version, "go") {
@ -105,11 +106,21 @@ func GoVersionLessThan(minor int64) bool {
if len(parts) < 2 { if len(parts) < 2 {
return false return false
} }
actual, err := strconv.ParseInt(parts[1], 10, 32) rMajor, err := strconv.ParseInt(parts[0], 10, 32)
return err == nil && parts[0] == "1" && actual < minor if err != nil {
return false
}
if rMajor != major {
return rMajor < major
}
rMinor, err := strconv.ParseInt(parts[1], 10, 32)
if err != nil {
return false
}
return rMinor < minor
} }
var goVersionBefore19 = GoVersionLessThan(9) var goVersionBefore19 = GoVersionLessThan(1, 9)
func getCallExprArgs(node ast.Node) ([]ast.Expr, error) { func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
visitor := &callExprVisitor{} visitor := &callExprVisitor{}

View File

@ -4,7 +4,11 @@ package poll // import "gotest.tools/v3/poll"
import ( import (
"fmt" "fmt"
"strings"
"time" "time"
"gotest.tools/v3/assert/cmp"
"gotest.tools/v3/internal/assert"
) )
// TestingT is the subset of testing.T used by WaitOn // TestingT is the subset of testing.T used by WaitOn
@ -138,3 +142,30 @@ func WaitOn(t TestingT, check Check, pollOps ...SettingOp) {
} }
} }
} }
// Compare values using the cmp.Comparison. If the comparison fails return a
// result which indicates to WaitOn that it should continue waiting.
// If the comparison is successful then WaitOn stops polling.
func Compare(compare cmp.Comparison) Result {
buf := new(logBuffer)
if assert.RunComparison(buf, assert.ArgsAtZeroIndex, compare) {
return Success()
}
return Continue(buf.String())
}
type logBuffer struct {
log [][]interface{}
}
func (c *logBuffer) Log(args ...interface{}) {
c.log = append(c.log, args)
}
func (c *logBuffer) String() string {
b := new(strings.Builder)
for _, item := range c.log {
b.WriteString(fmt.Sprint(item...) + " ")
}
return b.String()
}

View File

@ -1,84 +0,0 @@
/*Package subtest provides a TestContext to subtests which handles cleanup, and
provides a testing.TB, and context.Context.
This package was inspired by github.com/frankban/quicktest.
*/
package subtest // import "gotest.tools/v3/x/subtest"
import (
"context"
"testing"
)
type testcase struct {
testing.TB
ctx context.Context
cleanupFuncs []cleanupFunc
}
type cleanupFunc func()
func (tc *testcase) Ctx() context.Context {
if tc.ctx == nil {
var cancel func()
tc.ctx, cancel = context.WithCancel(context.Background())
tc.AddCleanup(cancel)
}
return tc.ctx
}
// cleanup runs all cleanup functions. Functions are run in the opposite order
// in which they were added. Cleanup is called automatically before Run exits.
func (tc *testcase) cleanup() {
for _, f := range tc.cleanupFuncs {
// Defer all cleanup functions so they all run even if one calls
// t.FailNow() or panics. Deferring them also runs them in reverse order.
defer f()
}
tc.cleanupFuncs = nil
}
func (tc *testcase) AddCleanup(f func()) {
tc.cleanupFuncs = append(tc.cleanupFuncs, f)
}
func (tc *testcase) Parallel() {
tp, ok := tc.TB.(parallel)
if !ok {
panic("Parallel called with a testing.B")
}
tp.Parallel()
}
type parallel interface {
Parallel()
}
// Run a subtest. When subtest exits, every cleanup function added with
// TestContext.AddCleanup will be run.
func Run(t *testing.T, name string, subtest func(t TestContext)) bool {
return t.Run(name, func(t *testing.T) {
tc := &testcase{TB: t}
defer tc.cleanup()
subtest(tc)
})
}
// TestContext provides a testing.TB and a context.Context for a test case.
type TestContext interface {
testing.TB
// AddCleanup function which will be run when before Run returns.
//
// Deprecated: Go 1.14+ now includes a testing.TB.Cleanup(func()) which
// should be used instead. AddCleanup will be removed in a future release.
AddCleanup(f func())
// Ctx returns a context for the test case. Multiple calls from the same subtest
// will return the same context. The context is cancelled when Run
// returns.
Ctx() context.Context
// Parallel calls t.Parallel on the testing.TB. Panics if testing.TB does
// not implement Parallel.
Parallel()
}
var _ TestContext = &testcase{}

5
vendor/modules.txt vendored
View File

@ -339,7 +339,7 @@ google.golang.org/protobuf/types/known/timestamppb
# gopkg.in/yaml.v2 v2.4.0 # gopkg.in/yaml.v2 v2.4.0
## explicit ## explicit
gopkg.in/yaml.v2 gopkg.in/yaml.v2
# gotest.tools/v3 v3.0.3 => gotest.tools/v3 v3.0.2 # gotest.tools/v3 v3.0.3
## explicit ## explicit
gotest.tools/v3/assert gotest.tools/v3/assert
gotest.tools/v3/assert/cmp gotest.tools/v3/assert/cmp
@ -347,13 +347,13 @@ gotest.tools/v3/env
gotest.tools/v3/fs gotest.tools/v3/fs
gotest.tools/v3/golden gotest.tools/v3/golden
gotest.tools/v3/icmd gotest.tools/v3/icmd
gotest.tools/v3/internal/assert
gotest.tools/v3/internal/cleanup gotest.tools/v3/internal/cleanup
gotest.tools/v3/internal/difflib gotest.tools/v3/internal/difflib
gotest.tools/v3/internal/format gotest.tools/v3/internal/format
gotest.tools/v3/internal/source gotest.tools/v3/internal/source
gotest.tools/v3/poll gotest.tools/v3/poll
gotest.tools/v3/skip gotest.tools/v3/skip
gotest.tools/v3/x/subtest
# cloud.google.com/go => cloud.google.com/go v0.44.3 # cloud.google.com/go => cloud.google.com/go v0.44.3
# github.com/docker/distribution => github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible # github.com/docker/distribution => github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
# github.com/docker/docker => github.com/docker/docker v20.10.3-0.20210811141259-343665850e3a+incompatible # github.com/docker/docker => github.com/docker/docker v20.10.3-0.20210811141259-343665850e3a+incompatible
@ -375,4 +375,3 @@ gotest.tools/v3/x/subtest
# github.com/prometheus/common => github.com/prometheus/common v0.9.1 # github.com/prometheus/common => github.com/prometheus/common v0.9.1
# github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.11 # github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.11
# github.com/theupdateframework/notary => github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a # github.com/theupdateframework/notary => github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
# gotest.tools/v3 => gotest.tools/v3 v3.0.2