Explorar o código

vendor: gotest.tools v3.3.0

full diff: https://github.com/gotestyourself/gotest.tools/compare/v3.2.0...v3.3.0

- golden: accept -update for updating files
- assert: golden variables

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn %!s(int64=2) %!d(string=hai) anos
pai
achega
3e1601a980

+ 1 - 1
vendor.mod

@@ -85,7 +85,7 @@ require (
 	golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
 	google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
 	google.golang.org/grpc v1.45.0
-	gotest.tools/v3 v3.2.0
+	gotest.tools/v3 v3.3.0
 )
 
 require (

+ 2 - 2
vendor.sum

@@ -1700,8 +1700,8 @@ gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
 gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
-gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I=
-gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
+gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
+gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 4 - 4
vendor/gotest.tools/v3/assert/cmp/compare.go

@@ -35,7 +35,7 @@ func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
 		if diff == "" {
 			return ResultSuccess
 		}
-		return multiLineDiffResult(diff)
+		return multiLineDiffResult(diff, x, y)
 	}
 }
 
@@ -102,7 +102,7 @@ func Equal(x, y interface{}) Comparison {
 			return ResultSuccess
 		case isMultiLineStringCompare(x, y):
 			diff := format.UnifiedDiff(format.DiffConfig{A: x.(string), B: y.(string)})
-			return multiLineDiffResult(diff)
+			return multiLineDiffResult(diff, x, y)
 		}
 		return ResultFailureTemplate(`
 			{{- printf "%v" .Data.x}} (
@@ -128,12 +128,12 @@ func isMultiLineStringCompare(x, y interface{}) bool {
 	return strings.Contains(strX, "\n") || strings.Contains(strY, "\n")
 }
 
-func multiLineDiffResult(diff string) Result {
+func multiLineDiffResult(diff string, x, y interface{}) Result {
 	return ResultFailureTemplate(`
 --- {{ with callArg 0 }}{{ formatNode . }}{{else}}←{{end}}
 +++ {{ with callArg 1 }}{{ formatNode . }}{{else}}→{{end}}
 {{ .Data.diff }}`,
-		map[string]interface{}{"diff": diff})
+		map[string]interface{}{"diff": diff, "x": x, "y": y})
 }
 
 // Len succeeds if the sequence has the expected length.

+ 5 - 0
vendor/gotest.tools/v3/assert/cmp/result.go

@@ -69,6 +69,11 @@ func (r templatedResult) FailureMessage(args []ast.Expr) string {
 	return msg
 }
 
+func (r templatedResult) UpdatedExpected(stackIndex int) error {
+	// TODO: would be nice to have structured data instead of a map
+	return source.UpdateExpectedValue(stackIndex+1, r.data["x"], r.data["y"])
+}
+
 // 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

+ 14 - 11
vendor/gotest.tools/v3/golden/golden.go

@@ -2,7 +2,7 @@
 
 Golden files are files in the ./testdata/ subdirectory of the package under test.
 Golden files can be automatically updated to match new values by running
-`go test pkgname -test.update-golden`. To ensure the update is correct
+`go test pkgname -update`. To ensure the update is correct
 compare the diff of the old expected value to the new expected value.
 */
 package golden // import "gotest.tools/v3/golden"
@@ -18,9 +18,12 @@ import (
 	"gotest.tools/v3/assert"
 	"gotest.tools/v3/assert/cmp"
 	"gotest.tools/v3/internal/format"
+	"gotest.tools/v3/internal/source"
 )
 
-var flagUpdate = flag.Bool("test.update-golden", false, "update golden file")
+func init() {
+	flag.BoolVar(&source.Update, "test.update-golden", false, "deprecated flag")
+}
 
 type helperT interface {
 	Helper()
@@ -28,7 +31,7 @@ type helperT interface {
 
 // 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.
+// -update.
 //
 // Defaults to true. If you use the core.autocrlf=true git setting on windows
 // you will need to set this to false.
@@ -39,9 +42,9 @@ type helperT interface {
 // 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.
+// FlagUpdate returns true when the -update flag has been set.
 func FlagUpdate() bool {
-	return *flagUpdate
+	return source.Update
 }
 
 // Open opens the file in ./testdata
@@ -81,7 +84,7 @@ func removeCarriageReturn(in []byte) []byte {
 
 // 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 -update` will write the value of actual
 // to the golden file.
 //
 // This is equivalent to assert.Assert(t, String(actual, filename))
@@ -95,7 +98,7 @@ func Assert(t assert.TestingT, actual string, filename string, msgAndArgs ...int
 // String compares actual to the contents of filename and returns success
 // if the strings are equal.
 //
-// Running `go test pkgname -test.update-golden` will write the value of actual
+// Running `go test pkgname -update` will write the value of actual
 // to the golden file.
 //
 // Any \r\n substrings in actual are converted to a single \n character
@@ -122,13 +125,13 @@ func String(actual string, filename string) cmp.Comparison {
 func failurePostamble(filename string) string {
 	return fmt.Sprintf(`
 
-You can run 'go test . -test.update-golden' to automatically update %s to the new expected value.'
+You can run 'go test . -update' to automatically update %s to the new expected value.'
 `, Path(filename))
 }
 
 // AssertBytes compares actual to the expected value in the golden.
 //
-// Running `go test pkgname -test.update-golden` will write the value of actual
+// Running `go test pkgname -update` will write the value of actual
 // to the golden file.
 //
 // This is equivalent to assert.Assert(t, Bytes(actual, filename))
@@ -147,7 +150,7 @@ func AssertBytes(
 // Bytes compares actual to the contents of filename and returns success
 // if the bytes are equal.
 //
-// Running `go test pkgname -test.update-golden` will write the value of actual
+// Running `go test pkgname -update` will write the value of actual
 // to the golden file.
 func Bytes(actual []byte, filename string) cmp.Comparison {
 	return func() cmp.Result {
@@ -175,7 +178,7 @@ func compare(actual []byte, filename string) (cmp.Result, []byte) {
 }
 
 func update(filename string, actual []byte) error {
-	if !*flagUpdate {
+	if !source.Update {
 		return nil
 	}
 	if dir := filepath.Dir(Path(filename)); dir != "." {

+ 21 - 0
vendor/gotest.tools/v3/internal/assert/result.go

@@ -1,6 +1,7 @@
 package assert
 
 import (
+	"errors"
 	"fmt"
 	"go/ast"
 
@@ -25,6 +26,22 @@ func RunComparison(
 		return true
 	}
 
+	if source.Update {
+		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:
@@ -52,6 +69,10 @@ 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.
 //

+ 1 - 1
vendor/gotest.tools/v3/internal/source/defers.go

@@ -28,7 +28,7 @@ func guessDefer(node ast.Node) (ast.Node, error) {
 	defers := collectDefers(node)
 	switch len(defers) {
 	case 0:
-		return nil, fmt.Errorf("failed to expression in defer")
+		return nil, fmt.Errorf("failed to find expression in defer")
 	case 1:
 		return defers[0].Call, nil
 	default:

+ 23 - 56
vendor/gotest.tools/v3/internal/source/source.go

@@ -10,12 +10,8 @@ import (
 	"go/token"
 	"os"
 	"runtime"
-	"strconv"
-	"strings"
 )
 
-const baseStackIndex = 1
-
 // FormattedCallExprArg returns the argument from an ast.CallExpr at the
 // index in the call stack. The argument is formatted using FormatNode.
 func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
@@ -32,28 +28,26 @@ func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
 // CallExprArgs returns the ast.Expr slice for the args of an ast.CallExpr at
 // the index in the call stack.
 func CallExprArgs(stackIndex int) ([]ast.Expr, error) {
-	_, filename, lineNum, ok := runtime.Caller(baseStackIndex + stackIndex)
+	_, filename, line, ok := runtime.Caller(stackIndex + 1)
 	if !ok {
 		return nil, errors.New("failed to get call stack")
 	}
-	debug("call stack position: %s:%d", filename, lineNum)
+	debug("call stack position: %s:%d", filename, line)
 
-	node, err := getNodeAtLine(filename, lineNum)
-	if err != nil {
-		return nil, err
-	}
-	debug("found node: %s", debugFormatNode{node})
-
-	return getCallExprArgs(node)
-}
-
-func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
 	fileset := token.NewFileSet()
 	astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
 	if err != nil {
 		return nil, fmt.Errorf("failed to parse source file %s: %w", filename, err)
 	}
 
+	expr, err := getCallExprArgs(fileset, astFile, line)
+	if err != nil {
+		return nil, fmt.Errorf("call from %s:%d: %w", filename, line, err)
+	}
+	return expr, nil
+}
+
+func getNodeAtLine(fileset *token.FileSet, astFile ast.Node, lineNum int) (ast.Node, error) {
 	if node := scanToLine(fileset, astFile, lineNum); node != nil {
 		return node, nil
 	}
@@ -63,8 +57,7 @@ func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
 			return node, err
 		}
 	}
-	return nil, fmt.Errorf(
-		"failed to find an expression on line %d in %s", lineNum, filename)
+	return nil, nil
 }
 
 func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
@@ -73,7 +66,7 @@ func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
 		switch {
 		case node == nil || matchedNode != nil:
 			return false
-		case nodePosition(fileset, node).Line == lineNum:
+		case fileset.Position(node.Pos()).Line == lineNum:
 			matchedNode = node
 			return false
 		}
@@ -82,46 +75,17 @@ func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
 	return matchedNode
 }
 
-// In golang 1.9 the line number changed from being the line where the statement
-// ended to the line where the statement began.
-func nodePosition(fileset *token.FileSet, node ast.Node) token.Position {
-	if goVersionBefore19 {
-		return fileset.Position(node.End())
-	}
-	return fileset.Position(node.Pos())
-}
-
-// GoVersionLessThan returns true if runtime.Version() is semantically less than
-// 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") {
-		return false
-	}
-	version = strings.TrimPrefix(version, "go")
-	parts := strings.Split(version, ".")
-	if len(parts) < 2 {
-		return false
-	}
-	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
+func getCallExprArgs(fileset *token.FileSet, astFile ast.Node, line int) ([]ast.Expr, error) {
+	node, err := getNodeAtLine(fileset, astFile, line)
+	switch {
+	case err != nil:
+		return nil, err
+	case node == nil:
+		return nil, fmt.Errorf("failed to find an expression")
 	}
-	return rMinor < minor
-}
 
-var goVersionBefore19 = GoVersionLessThan(1, 9)
+	debug("found node: %s", debugFormatNode{node})
 
-func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
 	visitor := &callExprVisitor{}
 	ast.Walk(visitor, node)
 	if visitor.expr == nil {
@@ -172,6 +136,9 @@ type debugFormatNode struct {
 }
 
 func (n debugFormatNode) String() string {
+	if n.Node == nil {
+		return "none"
+	}
 	out, err := FormatNode(n.Node)
 	if err != nil {
 		return fmt.Sprintf("failed to format %s: %s", n.Node, err)

+ 138 - 0
vendor/gotest.tools/v3/internal/source/update.go

@@ -0,0 +1,138 @@
+package source
+
+import (
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"os"
+	"runtime"
+	"strings"
+)
+
+// Update is set by the -update flag. It indicates the user running the tests
+// would like to update any golden values.
+var Update bool
+
+func init() {
+	flag.BoolVar(&Update, "update", false, "update golden values")
+}
+
+// ErrNotFound indicates that UpdateExpectedValue failed to find the
+// variable to update, likely because it is not a package level variable.
+var ErrNotFound = fmt.Errorf("failed to find variable for update of golden value")
+
+// UpdateExpectedValue looks for a package-level variable with a name that
+// starts with expected in the arguments to the caller. If the variable is
+// found, the value of the variable will be updated to value of the other
+// argument to the caller.
+func UpdateExpectedValue(stackIndex int, x, y interface{}) error {
+	_, filename, line, ok := runtime.Caller(stackIndex + 1)
+	if !ok {
+		return errors.New("failed to get call stack")
+	}
+	debug("call stack position: %s:%d", filename, line)
+
+	fileset := token.NewFileSet()
+	astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors|parser.ParseComments)
+	if err != nil {
+		return fmt.Errorf("failed to parse source file %s: %w", filename, err)
+	}
+
+	expr, err := getCallExprArgs(fileset, astFile, line)
+	if err != nil {
+		return fmt.Errorf("call from %s:%d: %w", filename, line, err)
+	}
+
+	if len(expr) < 3 {
+		debug("not enough arguments %d: %v",
+			len(expr), debugFormatNode{Node: &ast.CallExpr{Args: expr}})
+		return ErrNotFound
+	}
+
+	argIndex, varName := getVarNameForExpectedValueArg(expr)
+	if argIndex < 0 || varName == "" {
+		debug("no arguments started with the word 'expected': %v",
+			debugFormatNode{Node: &ast.CallExpr{Args: expr}})
+		return ErrNotFound
+	}
+
+	value := x
+	if argIndex == 1 {
+		value = y
+	}
+
+	strValue, ok := value.(string)
+	if !ok {
+		debug("value must be type string, got %T", value)
+		return ErrNotFound
+	}
+	return UpdateVariable(filename, fileset, astFile, varName, strValue)
+}
+
+// UpdateVariable writes to filename the contents of astFile with the value of
+// the variable updated to value.
+func UpdateVariable(
+	filename string,
+	fileset *token.FileSet,
+	astFile *ast.File,
+	varName string,
+	value string,
+) error {
+	obj := astFile.Scope.Objects[varName]
+	if obj == nil {
+		return ErrNotFound
+	}
+	if obj.Kind != ast.Con && obj.Kind != ast.Var {
+		debug("can only update var and const, found %v", obj.Kind)
+		return ErrNotFound
+	}
+
+	spec, ok := obj.Decl.(*ast.ValueSpec)
+	if !ok {
+		debug("can only update *ast.ValueSpec, found %T", obj.Decl)
+		return ErrNotFound
+	}
+	if len(spec.Names) != 1 {
+		debug("more than one name in ast.ValueSpec")
+		return ErrNotFound
+	}
+
+	spec.Values[0] = &ast.BasicLit{
+		Kind:  token.STRING,
+		Value: "`" + value + "`",
+	}
+
+	var buf bytes.Buffer
+	if err := format.Node(&buf, fileset, astFile); err != nil {
+		return fmt.Errorf("failed to format file after update: %w", err)
+	}
+
+	fh, err := os.Create(filename)
+	if err != nil {
+		return fmt.Errorf("failed to open file %v: %w", filename, err)
+	}
+	if _, err = fh.Write(buf.Bytes()); err != nil {
+		return fmt.Errorf("failed to write file %v: %w", filename, err)
+	}
+	if err := fh.Sync(); err != nil {
+		return fmt.Errorf("failed to sync file %v: %w", filename, err)
+	}
+	return nil
+}
+
+func getVarNameForExpectedValueArg(expr []ast.Expr) (int, string) {
+	for i := 1; i < 3; i++ {
+		switch e := expr[i].(type) {
+		case *ast.Ident:
+			if strings.HasPrefix(strings.ToLower(e.Name), "expected") {
+				return i, e.Name
+			}
+		}
+	}
+	return -1, ""
+}

+ 35 - 0
vendor/gotest.tools/v3/internal/source/version.go

@@ -0,0 +1,35 @@
+package source
+
+import (
+	"runtime"
+	"strconv"
+	"strings"
+)
+
+// GoVersionLessThan returns true if runtime.Version() is semantically less than
+// 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") {
+		return false
+	}
+	version = strings.TrimPrefix(version, "go")
+	parts := strings.Split(version, ".")
+	if len(parts) < 2 {
+		return false
+	}
+	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
+}

+ 1 - 1
vendor/modules.txt

@@ -1105,7 +1105,7 @@ google.golang.org/protobuf/types/known/fieldmaskpb
 google.golang.org/protobuf/types/known/structpb
 google.golang.org/protobuf/types/known/timestamppb
 google.golang.org/protobuf/types/known/wrapperspb
-# gotest.tools/v3 v3.2.0
+# gotest.tools/v3 v3.3.0
 ## explicit; go 1.13
 gotest.tools/v3/assert
 gotest.tools/v3/assert/cmp