vendor: gotest.tools v3.0.3

- assert: fixes a bug that would cause a panic if there were any
  function calls before `assert.Check` on the same line
- golden: create the directory if it does not exist, when run with
  `-test.update-golden`

full diff: 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 2020-11-23 12:33:57 +01:00
parent 6c0a036dce
commit 776cadc7db
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
12 changed files with 264 additions and 252 deletions

View File

@ -24,7 +24,7 @@ golang.org/x/sys eeed37f84f13f52d35e095e8023b
github.com/docker/go-units 519db1ee28dcc9fd2474ae59fca29a810482bfb1 # v0.4.0
github.com/docker/go-connections 7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0
golang.org/x/text 23ae387dee1f90d29a23c0e87ee0b46038fbed0e # v0.3.3
gotest.tools/v3 bb0d8a963040ea5048dcef1a14d8f8b58a33d4b3 # v3.0.2
gotest.tools/v3 568bc57cc5c19a2ef85e5749870b49a4cc2ab54d # v3.0.3
github.com/google/go-cmp 3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0
github.com/syndtr/gocapability 42c35b4376354fd554efc7ad35e0b7f94e3a0ffb

View File

@ -2,7 +2,7 @@
A collection of packages to augment `testing` and support common patterns.
[![GoDoc](https://godoc.org/gotest.tools?status.svg)](http://gotest.tools)
[![GoDoc](https://godoc.org/gotest.tools?status.svg)](https://pkg.go.dev/gotest.tools/v3/?tab=subdirectories)
[![CircleCI](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master.svg?style=shield)](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master)
[![Go Reportcard](https://goreportcard.com/badge/gotest.tools)](https://goreportcard.com/report/gotest.tools)
@ -24,19 +24,19 @@ module paths pin to version `v2.3.0`.
## Packages
* [assert](http://gotest.tools/assert) -
* [assert](http://pkg.go.dev/gotest.tools/v3/assert) -
compare values and fail the test when a comparison fails
* [env](http://gotest.tools/env) -
* [env](http://pkg.go.dev/gotest.tools/v3/env) -
test code which uses environment variables
* [fs](http://gotest.tools/fs) -
* [fs](http://pkg.go.dev/gotest.tools/v3/fs) -
create temporary files and compare a filesystem tree to an expected value
* [golden](http://gotest.tools/golden) -
* [golden](http://pkg.go.dev/gotest.tools/v3/golden) -
compare large multi-line strings against values frozen in golden files
* [icmd](http://gotest.tools/icmd) -
* [icmd](http://pkg.go.dev/gotest.tools/v3/icmd) -
execute binaries and test the output
* [poll](http://gotest.tools/poll) -
* [poll](http://pkg.go.dev/gotest.tools/v3/poll) -
test asynchronous code by polling until a desired state is reached
* [skip](http://gotest.tools/skip) -
* [skip](http://pkg.go.dev/gotest.tools/v3/skip) -
skip a test and print the source code of the condition used to skip the test
## Related

View File

@ -49,7 +49,7 @@ The example below shows assert used with some common types.
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
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
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"
import (
"fmt"
"go/ast"
"go/token"
"reflect"
gocmp "github.com/google/go-cmp/cmp"
"gotest.tools/v3/assert/cmp"
"gotest.tools/v3/internal/format"
"gotest.tools/v3/internal/source"
"gotest.tools/v3/internal/assert"
)
// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
@ -90,128 +84,6 @@ 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 := 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
// failed, a failure message is logged, and execution is stopped immediately.
//
@ -222,7 +94,7 @@ func boolFailureMessage(expr ast.Expr) (string, error) {
// cmp.Comparison
// Uses cmp.Result.Success() to check for success of failure.
// 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
// A nil value is considered success.
// 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 {
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
@ -242,7 +116,11 @@ func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) b
if ht, ok := t.(helperT); ok {
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.
@ -251,7 +129,9 @@ func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
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
@ -270,13 +150,15 @@ 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...)
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)
// 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.
//
// 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 {
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
@ -294,7 +178,9 @@ 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...)
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
@ -304,7 +190,9 @@ func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interf
if ht, ok := t.(helperT); ok {
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.
@ -325,5 +213,7 @@ func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interf
if ht, ok := t.(helperT); ok {
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.
//
// 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.
func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
return func() (result Result) {

View File

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

View File

@ -1,7 +1,7 @@
module gotest.tools/v3
require (
github.com/google/go-cmp v0.3.0
github.com/google/go-cmp v0.4.0
github.com/pkg/errors v0.8.1
github.com/spf13/pflag v1.0.3
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4

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"
)
func runComparison(
t TestingT,
// 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{},
@ -26,7 +28,7 @@ func runComparison(
var message string
switch typed := result.(type) {
case resultWithComparisonArgs:
const stackIndex = 3 // Assert/Check, assert, runComparison
const stackIndex = 3 // Assert/Check, assert, RunComparison
args, err := source.CallExprArgs(stackIndex)
if err != nil {
t.Log(err.Error())
@ -88,15 +90,20 @@ func isShortPrintableExpr(expr ast.Expr) bool {
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 {
return nil
}
return args[1:]
}
func argsFromComparisonCall(args []ast.Expr) []ast.Expr {
if len(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 {
@ -104,3 +111,15 @@ func argsFromComparisonCall(args []ast.Expr) []ast.Expr {
}
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 (
"os"
"strings"
"gotest.tools/v3/x/subtest"
)
type cleanupT interface {
Cleanup(f func())
}
// implemented by gotest.tools/x/subtest.TestContext
type addCleanupT interface {
AddCleanup(f func())
}
type logT interface {
Log(...interface{})
}
@ -39,7 +42,7 @@ func Cleanup(t logT, f func()) {
ct.Cleanup(f)
return
}
if tc, ok := t.(subtest.TestContext); ok {
if tc, ok := t.(addCleanupT); ok {
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
// version 1.minor.
func GoVersionLessThan(minor int64) bool {
// version major.minor. Returns false if a release version can not be parsed from
// runtime.Version().
func GoVersionLessThan(major, minor int64) bool {
version := runtime.Version()
// not a release version
if !strings.HasPrefix(version, "go") {
@ -105,11 +106,21 @@ func GoVersionLessThan(minor int64) bool {
if len(parts) < 2 {
return false
}
actual, err := strconv.ParseInt(parts[1], 10, 32)
return err == nil && parts[0] == "1" && actual < minor
rMajor, err := strconv.ParseInt(parts[0], 10, 32)
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) {
visitor := &callExprVisitor{}

View File

@ -4,7 +4,11 @@ package poll // import "gotest.tools/v3/poll"
import (
"fmt"
"strings"
"time"
"gotest.tools/v3/assert/cmp"
"gotest.tools/v3/internal/assert"
)
// 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{}