mirror of https://github.com/docker/cli.git
Merge pull request #3852 from thaJeztah/update_gotest
vendor: gotest.tools/v3 v3.4.0, github.com/google/go-cmp v0.5.9, remove golang.org/x/xerrors
This commit is contained in:
commit
86502f73aa
|
@ -16,7 +16,7 @@ require (
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/fvbommel/sortorder v1.0.2
|
github.com/fvbommel/sortorder v1.0.2
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/google/go-cmp v0.5.7
|
github.com/google/go-cmp v0.5.9
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/imdario/mergo v0.3.12
|
github.com/imdario/mergo v0.3.12
|
||||||
github.com/mattn/go-runewidth v0.0.13
|
github.com/mattn/go-runewidth v0.0.13
|
||||||
|
@ -41,7 +41,7 @@ require (
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gotest.tools/v3 v3.3.0
|
gotest.tools/v3 v3.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -71,7 +71,6 @@ require (
|
||||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
|
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
|
||||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect; updated for CVE-2022-27664
|
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect; updated for CVE-2022-27664
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||||
google.golang.org/grpc v1.45.0 // indirect
|
google.golang.org/grpc v1.45.0 // indirect
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
|
|
@ -198,8 +198,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
@ -635,7 +635,6 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
@ -752,8 +751,8 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
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.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
|
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||||
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
|
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
|
||||||
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-20190106161140-3f1c8253044a/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=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package cmpopts
|
package cmpopts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
@ -41,6 +42,7 @@ func isEmpty(x, y interface{}) bool {
|
||||||
// The fraction and margin must be non-negative.
|
// The fraction and margin must be non-negative.
|
||||||
//
|
//
|
||||||
// The mathematical expression used is equivalent to:
|
// The mathematical expression used is equivalent to:
|
||||||
|
//
|
||||||
// |x-y| ≤ max(fraction*min(|x|, |y|), margin)
|
// |x-y| ≤ max(fraction*min(|x|, |y|), margin)
|
||||||
//
|
//
|
||||||
// EquateApprox can be used in conjunction with EquateNaNs.
|
// EquateApprox can be used in conjunction with EquateNaNs.
|
||||||
|
@ -146,3 +148,9 @@ func areConcreteErrors(x, y interface{}) bool {
|
||||||
_, ok2 := y.(error)
|
_, ok2 := y.(error)
|
||||||
return ok1 && ok2
|
return ok1 && ok2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compareErrors(x, y interface{}) bool {
|
||||||
|
xe := x.(error)
|
||||||
|
ye := y.(error)
|
||||||
|
return errors.Is(xe, ye) || errors.Is(ye, xe)
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright 2021, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build go1.13
|
|
||||||
// +build go1.13
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func compareErrors(x, y interface{}) bool {
|
|
||||||
xe := x.(error)
|
|
||||||
ye := y.(error)
|
|
||||||
return errors.Is(xe, ye) || errors.Is(ye, xe)
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright 2021, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build !go1.13
|
|
||||||
// +build !go1.13
|
|
||||||
|
|
||||||
// TODO(≥go1.13): For support on <go1.13, we use the xerrors package.
|
|
||||||
// Drop this file when we no longer support older Go versions.
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import "golang.org/x/xerrors"
|
|
||||||
|
|
||||||
func compareErrors(x, y interface{}) bool {
|
|
||||||
xe := x.(error)
|
|
||||||
ye := y.(error)
|
|
||||||
return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
|
|
||||||
}
|
|
|
@ -18,9 +18,9 @@ import (
|
||||||
// sort any slice with element type V that is assignable to T.
|
// sort any slice with element type V that is assignable to T.
|
||||||
//
|
//
|
||||||
// The less function must be:
|
// The less function must be:
|
||||||
// • Deterministic: less(x, y) == less(x, y)
|
// - Deterministic: less(x, y) == less(x, y)
|
||||||
// • Irreflexive: !less(x, x)
|
// - Irreflexive: !less(x, x)
|
||||||
// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
|
// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
|
||||||
//
|
//
|
||||||
// The less function does not have to be "total". That is, if !less(x, y) and
|
// The less function does not have to be "total". That is, if !less(x, y) and
|
||||||
// !less(y, x) for two elements x and y, their relative order is maintained.
|
// !less(y, x) for two elements x and y, their relative order is maintained.
|
||||||
|
@ -91,10 +91,10 @@ func (ss sliceSorter) less(v reflect.Value, i, j int) bool {
|
||||||
// use Comparers on K or the K.Equal method if it exists.
|
// use Comparers on K or the K.Equal method if it exists.
|
||||||
//
|
//
|
||||||
// The less function must be:
|
// The less function must be:
|
||||||
// • Deterministic: less(x, y) == less(x, y)
|
// - Deterministic: less(x, y) == less(x, y)
|
||||||
// • Irreflexive: !less(x, x)
|
// - Irreflexive: !less(x, x)
|
||||||
// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
|
// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
|
||||||
// • Total: if x != y, then either less(x, y) or less(y, x)
|
// - Total: if x != y, then either less(x, y) or less(y, x)
|
||||||
//
|
//
|
||||||
// SortMaps can be used in conjunction with EquateEmpty.
|
// SortMaps can be used in conjunction with EquateEmpty.
|
||||||
func SortMaps(lessFunc interface{}) cmp.Option {
|
func SortMaps(lessFunc interface{}) cmp.Option {
|
||||||
|
|
|
@ -67,12 +67,14 @@ func (sf structFilter) filter(p cmp.Path) bool {
|
||||||
// fieldTree represents a set of dot-separated identifiers.
|
// fieldTree represents a set of dot-separated identifiers.
|
||||||
//
|
//
|
||||||
// For example, inserting the following selectors:
|
// For example, inserting the following selectors:
|
||||||
|
//
|
||||||
// Foo
|
// Foo
|
||||||
// Foo.Bar.Baz
|
// Foo.Bar.Baz
|
||||||
// Foo.Buzz
|
// Foo.Buzz
|
||||||
// Nuka.Cola.Quantum
|
// Nuka.Cola.Quantum
|
||||||
//
|
//
|
||||||
// Results in a tree of the form:
|
// Results in a tree of the form:
|
||||||
|
//
|
||||||
// {sub: {
|
// {sub: {
|
||||||
// "Foo": {ok: true, sub: {
|
// "Foo": {ok: true, sub: {
|
||||||
// "Bar": {sub: {
|
// "Bar": {sub: {
|
||||||
|
|
|
@ -23,6 +23,7 @@ func (xf xformFilter) filter(p cmp.Path) bool {
|
||||||
// that the transformer cannot be recursively applied upon its own output.
|
// that the transformer cannot be recursively applied upon its own output.
|
||||||
//
|
//
|
||||||
// An example use case is a transformer that splits a string by lines:
|
// An example use case is a transformer that splits a string by lines:
|
||||||
|
//
|
||||||
// AcyclicTransformer("SplitLines", func(s string) []string{
|
// AcyclicTransformer("SplitLines", func(s string) []string{
|
||||||
// return strings.Split(s, "\n")
|
// return strings.Split(s, "\n")
|
||||||
// })
|
// })
|
||||||
|
|
|
@ -13,21 +13,21 @@
|
||||||
//
|
//
|
||||||
// The primary features of cmp are:
|
// The primary features of cmp are:
|
||||||
//
|
//
|
||||||
// • When the default behavior of equality does not suit the needs of the test,
|
// - When the default behavior of equality does not suit the test's needs,
|
||||||
// custom equality functions can override the equality operation.
|
// custom equality functions can override the equality operation.
|
||||||
// For example, an equality function may report floats as equal so long as they
|
// For example, an equality function may report floats as equal so long as
|
||||||
// are within some tolerance of each other.
|
// they are within some tolerance of each other.
|
||||||
//
|
//
|
||||||
// • Types that have an Equal method may use that method to determine equality.
|
// - Types with an Equal method may use that method to determine equality.
|
||||||
// This allows package authors to determine the equality operation for the types
|
// This allows package authors to determine the equality operation
|
||||||
// that they define.
|
// for the types that they define.
|
||||||
//
|
//
|
||||||
// • If no custom equality functions are used and no Equal method is defined,
|
// - If no custom equality functions are used and no Equal method is defined,
|
||||||
// equality is determined by recursively comparing the primitive kinds on both
|
// equality is determined by recursively comparing the primitive kinds on
|
||||||
// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
|
// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual,
|
||||||
// fields are not compared by default; they result in panics unless suppressed
|
// unexported fields are not compared by default; they result in panics
|
||||||
// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly
|
// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported)
|
||||||
// compared using the Exporter option.
|
// or explicitly compared using the Exporter option.
|
||||||
package cmp
|
package cmp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -40,27 +40,29 @@ import (
|
||||||
"github.com/google/go-cmp/cmp/internal/value"
|
"github.com/google/go-cmp/cmp/internal/value"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO(≥go1.18): Use any instead of interface{}.
|
||||||
|
|
||||||
// Equal reports whether x and y are equal by recursively applying the
|
// Equal reports whether x and y are equal by recursively applying the
|
||||||
// following rules in the given order to x and y and all of their sub-values:
|
// following rules in the given order to x and y and all of their sub-values:
|
||||||
//
|
//
|
||||||
// • Let S be the set of all Ignore, Transformer, and Comparer options that
|
// - Let S be the set of all Ignore, Transformer, and Comparer options that
|
||||||
// remain after applying all path filters, value filters, and type filters.
|
// remain after applying all path filters, value filters, and type filters.
|
||||||
// If at least one Ignore exists in S, then the comparison is ignored.
|
// If at least one Ignore exists in S, then the comparison is ignored.
|
||||||
// If the number of Transformer and Comparer options in S is greater than one,
|
// If the number of Transformer and Comparer options in S is non-zero,
|
||||||
// then Equal panics because it is ambiguous which option to use.
|
// then Equal panics because it is ambiguous which option to use.
|
||||||
// If S contains a single Transformer, then use that to transform the current
|
// If S contains a single Transformer, then use that to transform
|
||||||
// values and recursively call Equal on the output values.
|
// the current values and recursively call Equal on the output values.
|
||||||
// If S contains a single Comparer, then use that to compare the current values.
|
// If S contains a single Comparer, then use that to compare the current values.
|
||||||
// Otherwise, evaluation proceeds to the next rule.
|
// Otherwise, evaluation proceeds to the next rule.
|
||||||
//
|
//
|
||||||
// • If the values have an Equal method of the form "(T) Equal(T) bool" or
|
// - If the values have an Equal method of the form "(T) Equal(T) bool" or
|
||||||
// "(T) Equal(I) bool" where T is assignable to I, then use the result of
|
// "(T) Equal(I) bool" where T is assignable to I, then use the result of
|
||||||
// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
|
// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
|
||||||
// evaluation proceeds to the next rule.
|
// evaluation proceeds to the next rule.
|
||||||
//
|
//
|
||||||
// • Lastly, try to compare x and y based on their basic kinds.
|
// - Lastly, try to compare x and y based on their basic kinds.
|
||||||
// Simple kinds like booleans, integers, floats, complex numbers, strings, and
|
// Simple kinds like booleans, integers, floats, complex numbers, strings,
|
||||||
// channels are compared using the equivalent of the == operator in Go.
|
// and channels are compared using the equivalent of the == operator in Go.
|
||||||
// Functions are only equal if they are both nil, otherwise they are unequal.
|
// Functions are only equal if they are both nil, otherwise they are unequal.
|
||||||
//
|
//
|
||||||
// Structs are equal if recursively calling Equal on all fields report equal.
|
// Structs are equal if recursively calling Equal on all fields report equal.
|
||||||
|
@ -142,7 +144,7 @@ func rootStep(x, y interface{}) PathStep {
|
||||||
// so that they have the same parent type.
|
// so that they have the same parent type.
|
||||||
var t reflect.Type
|
var t reflect.Type
|
||||||
if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() {
|
if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() {
|
||||||
t = reflect.TypeOf((*interface{})(nil)).Elem()
|
t = anyType
|
||||||
if vx.IsValid() {
|
if vx.IsValid() {
|
||||||
vvx := reflect.New(t).Elem()
|
vvx := reflect.New(t).Elem()
|
||||||
vvx.Set(vx)
|
vvx.Set(vx)
|
||||||
|
@ -637,7 +639,9 @@ type dynChecker struct{ curr, next int }
|
||||||
// Next increments the state and reports whether a check should be performed.
|
// Next increments the state and reports whether a check should be performed.
|
||||||
//
|
//
|
||||||
// Checks occur every Nth function call, where N is a triangular number:
|
// Checks occur every Nth function call, where N is a triangular number:
|
||||||
|
//
|
||||||
// 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ...
|
// 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ...
|
||||||
|
//
|
||||||
// See https://en.wikipedia.org/wiki/Triangular_number
|
// See https://en.wikipedia.org/wiki/Triangular_number
|
||||||
//
|
//
|
||||||
// This sequence ensures that the cost of checks drops significantly as
|
// This sequence ensures that the cost of checks drops significantly as
|
||||||
|
|
|
@ -127,9 +127,9 @@ var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
|
||||||
// This function returns an edit-script, which is a sequence of operations
|
// This function returns an edit-script, which is a sequence of operations
|
||||||
// needed to convert one list into the other. The following invariants for
|
// needed to convert one list into the other. The following invariants for
|
||||||
// the edit-script are maintained:
|
// the edit-script are maintained:
|
||||||
// • eq == (es.Dist()==0)
|
// - eq == (es.Dist()==0)
|
||||||
// • nx == es.LenX()
|
// - nx == es.LenX()
|
||||||
// • ny == es.LenY()
|
// - ny == es.LenY()
|
||||||
//
|
//
|
||||||
// This algorithm is not guaranteed to be an optimal solution (i.e., one that
|
// This algorithm is not guaranteed to be an optimal solution (i.e., one that
|
||||||
// produces an edit-script with a minimal Levenshtein distance). This algorithm
|
// produces an edit-script with a minimal Levenshtein distance). This algorithm
|
||||||
|
@ -169,12 +169,13 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
|
||||||
// A diagonal edge is equivalent to a matching symbol between both X and Y.
|
// A diagonal edge is equivalent to a matching symbol between both X and Y.
|
||||||
|
|
||||||
// Invariants:
|
// Invariants:
|
||||||
// • 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx
|
// - 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx
|
||||||
// • 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny
|
// - 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny
|
||||||
//
|
//
|
||||||
// In general:
|
// In general:
|
||||||
// • fwdFrontier.X < revFrontier.X
|
// - fwdFrontier.X < revFrontier.X
|
||||||
// • fwdFrontier.Y < revFrontier.Y
|
// - fwdFrontier.Y < revFrontier.Y
|
||||||
|
//
|
||||||
// Unless, it is time for the algorithm to terminate.
|
// Unless, it is time for the algorithm to terminate.
|
||||||
fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)}
|
fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)}
|
||||||
revPath := path{-1, point{nx, ny}, make(EditScript, 0)}
|
revPath := path{-1, point{nx, ny}, make(EditScript, 0)}
|
||||||
|
@ -195,18 +196,20 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
|
||||||
// computing sub-optimal edit-scripts between two lists.
|
// computing sub-optimal edit-scripts between two lists.
|
||||||
//
|
//
|
||||||
// The algorithm is approximately as follows:
|
// The algorithm is approximately as follows:
|
||||||
// • Searching for differences switches back-and-forth between
|
// - Searching for differences switches back-and-forth between
|
||||||
// a search that starts at the beginning (the top-left corner), and
|
// a search that starts at the beginning (the top-left corner), and
|
||||||
// a search that starts at the end (the bottom-right corner). The goal of
|
// a search that starts at the end (the bottom-right corner).
|
||||||
// the search is connect with the search from the opposite corner.
|
// The goal of the search is connect with the search
|
||||||
// • As we search, we build a path in a greedy manner, where the first
|
// from the opposite corner.
|
||||||
// match seen is added to the path (this is sub-optimal, but provides a
|
// - As we search, we build a path in a greedy manner,
|
||||||
// decent result in practice). When matches are found, we try the next pair
|
// where the first match seen is added to the path (this is sub-optimal,
|
||||||
// of symbols in the lists and follow all matches as far as possible.
|
// but provides a decent result in practice). When matches are found,
|
||||||
// • When searching for matches, we search along a diagonal going through
|
// we try the next pair of symbols in the lists and follow all matches
|
||||||
// through the "frontier" point. If no matches are found, we advance the
|
// as far as possible.
|
||||||
// frontier towards the opposite corner.
|
// - When searching for matches, we search along a diagonal going through
|
||||||
// • This algorithm terminates when either the X coordinates or the
|
// through the "frontier" point. If no matches are found,
|
||||||
|
// we advance the frontier towards the opposite corner.
|
||||||
|
// - This algorithm terminates when either the X coordinates or the
|
||||||
// Y coordinates of the forward and reverse frontier points ever intersect.
|
// Y coordinates of the forward and reverse frontier points ever intersect.
|
||||||
|
|
||||||
// This algorithm is correct even if searching only in the forward direction
|
// This algorithm is correct even if searching only in the forward direction
|
||||||
|
@ -389,6 +392,7 @@ type point struct{ X, Y int }
|
||||||
func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy }
|
func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy }
|
||||||
|
|
||||||
// zigzag maps a consecutive sequence of integers to a zig-zag sequence.
|
// zigzag maps a consecutive sequence of integers to a zig-zag sequence.
|
||||||
|
//
|
||||||
// [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...]
|
// [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...]
|
||||||
func zigzag(x int) int {
|
func zigzag(x int) int {
|
||||||
if x&1 != 0 {
|
if x&1 != 0 {
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright 2017, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package value
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsZero reports whether v is the zero value.
|
|
||||||
// This does not rely on Interface and so can be used on unexported fields.
|
|
||||||
func IsZero(v reflect.Value) bool {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return v.Bool() == false
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return v.Int() == 0
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return v.Uint() == 0
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return math.Float64bits(v.Float()) == 0
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0
|
|
||||||
case reflect.String:
|
|
||||||
return v.String() == ""
|
|
||||||
case reflect.UnsafePointer:
|
|
||||||
return v.Pointer() == 0
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
|
|
||||||
return v.IsNil()
|
|
||||||
case reflect.Array:
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
if !IsZero(v.Index(i)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Struct:
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
if !IsZero(v.Field(i)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -33,6 +33,7 @@ type Option interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// applicableOption represents the following types:
|
// applicableOption represents the following types:
|
||||||
|
//
|
||||||
// Fundamental: ignore | validator | *comparer | *transformer
|
// Fundamental: ignore | validator | *comparer | *transformer
|
||||||
// Grouping: Options
|
// Grouping: Options
|
||||||
type applicableOption interface {
|
type applicableOption interface {
|
||||||
|
@ -43,6 +44,7 @@ type applicableOption interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// coreOption represents the following types:
|
// coreOption represents the following types:
|
||||||
|
//
|
||||||
// Fundamental: ignore | validator | *comparer | *transformer
|
// Fundamental: ignore | validator | *comparer | *transformer
|
||||||
// Filters: *pathFilter | *valuesFilter
|
// Filters: *pathFilter | *valuesFilter
|
||||||
type coreOption interface {
|
type coreOption interface {
|
||||||
|
@ -336,9 +338,9 @@ func (tr transformer) String() string {
|
||||||
// both implement T.
|
// both implement T.
|
||||||
//
|
//
|
||||||
// The equality function must be:
|
// The equality function must be:
|
||||||
// • Symmetric: equal(x, y) == equal(y, x)
|
// - Symmetric: equal(x, y) == equal(y, x)
|
||||||
// • Deterministic: equal(x, y) == equal(x, y)
|
// - Deterministic: equal(x, y) == equal(x, y)
|
||||||
// • Pure: equal(x, y) does not modify x or y
|
// - Pure: equal(x, y) does not modify x or y
|
||||||
func Comparer(f interface{}) Option {
|
func Comparer(f interface{}) Option {
|
||||||
v := reflect.ValueOf(f)
|
v := reflect.ValueOf(f)
|
||||||
if !function.IsType(v.Type(), function.Equal) || v.IsNil() {
|
if !function.IsType(v.Type(), function.Equal) || v.IsNil() {
|
||||||
|
@ -430,7 +432,7 @@ func AllowUnexported(types ...interface{}) Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result represents the comparison result for a single node and
|
// Result represents the comparison result for a single node and
|
||||||
// is provided by cmp when calling Result (see Reporter).
|
// is provided by cmp when calling Report (see Reporter).
|
||||||
type Result struct {
|
type Result struct {
|
||||||
_ [0]func() // Make Result incomparable
|
_ [0]func() // Make Result incomparable
|
||||||
flags resultFlags
|
flags resultFlags
|
||||||
|
|
|
@ -41,12 +41,12 @@ type PathStep interface {
|
||||||
// The type of each valid value is guaranteed to be identical to Type.
|
// The type of each valid value is guaranteed to be identical to Type.
|
||||||
//
|
//
|
||||||
// In some cases, one or both may be invalid or have restrictions:
|
// In some cases, one or both may be invalid or have restrictions:
|
||||||
// • For StructField, both are not interface-able if the current field
|
// - For StructField, both are not interface-able if the current field
|
||||||
// is unexported and the struct type is not explicitly permitted by
|
// is unexported and the struct type is not explicitly permitted by
|
||||||
// an Exporter to traverse unexported fields.
|
// an Exporter to traverse unexported fields.
|
||||||
// • For SliceIndex, one may be invalid if an element is missing from
|
// - For SliceIndex, one may be invalid if an element is missing from
|
||||||
// either the x or y slice.
|
// either the x or y slice.
|
||||||
// • For MapIndex, one may be invalid if an entry is missing from
|
// - For MapIndex, one may be invalid if an entry is missing from
|
||||||
// either the x or y map.
|
// either the x or y map.
|
||||||
//
|
//
|
||||||
// The provided values must not be mutated.
|
// The provided values must not be mutated.
|
||||||
|
@ -94,6 +94,7 @@ func (pa Path) Index(i int) PathStep {
|
||||||
// The simplified path only contains struct field accesses.
|
// The simplified path only contains struct field accesses.
|
||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
|
//
|
||||||
// MyMap.MySlices.MyField
|
// MyMap.MySlices.MyField
|
||||||
func (pa Path) String() string {
|
func (pa Path) String() string {
|
||||||
var ss []string
|
var ss []string
|
||||||
|
@ -108,6 +109,7 @@ func (pa Path) String() string {
|
||||||
// GoString returns the path to a specific node using Go syntax.
|
// GoString returns the path to a specific node using Go syntax.
|
||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
|
//
|
||||||
// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
|
// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
|
||||||
func (pa Path) GoString() string {
|
func (pa Path) GoString() string {
|
||||||
var ssPre, ssPost []string
|
var ssPre, ssPost []string
|
||||||
|
@ -159,7 +161,7 @@ func (ps pathStep) String() string {
|
||||||
if ps.typ == nil {
|
if ps.typ == nil {
|
||||||
return "<nil>"
|
return "<nil>"
|
||||||
}
|
}
|
||||||
s := ps.typ.String()
|
s := value.TypeString(ps.typ, false)
|
||||||
if s == "" || strings.ContainsAny(s, "{}\n") {
|
if s == "" || strings.ContainsAny(s, "{}\n") {
|
||||||
return "root" // Type too simple or complex to print
|
return "root" // Type too simple or complex to print
|
||||||
}
|
}
|
||||||
|
@ -282,7 +284,7 @@ type typeAssertion struct {
|
||||||
|
|
||||||
func (ta TypeAssertion) Type() reflect.Type { return ta.typ }
|
func (ta TypeAssertion) Type() reflect.Type { return ta.typ }
|
||||||
func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
|
func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
|
||||||
func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
|
func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) }
|
||||||
|
|
||||||
// Transform is a transformation from the parent type to the current type.
|
// Transform is a transformation from the parent type to the current type.
|
||||||
type Transform struct{ *transform }
|
type Transform struct{ *transform }
|
||||||
|
|
|
@ -7,8 +7,6 @@ package cmp
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp/internal/value"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// numContextRecords is the number of surrounding equal records to print.
|
// numContextRecords is the number of surrounding equal records to print.
|
||||||
|
@ -116,7 +114,10 @@ func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out
|
||||||
}
|
}
|
||||||
|
|
||||||
// For leaf nodes, format the value based on the reflect.Values alone.
|
// For leaf nodes, format the value based on the reflect.Values alone.
|
||||||
if v.MaxDepth == 0 {
|
// As a special case, treat equal []byte as a leaf nodes.
|
||||||
|
isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == byteType
|
||||||
|
isEqualBytes := isBytes && v.NumDiff+v.NumIgnored+v.NumTransformed == 0
|
||||||
|
if v.MaxDepth == 0 || isEqualBytes {
|
||||||
switch opts.DiffMode {
|
switch opts.DiffMode {
|
||||||
case diffUnknown, diffIdentical:
|
case diffUnknown, diffIdentical:
|
||||||
// Format Equal.
|
// Format Equal.
|
||||||
|
@ -245,11 +246,11 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, pt
|
||||||
var isZero bool
|
var isZero bool
|
||||||
switch opts.DiffMode {
|
switch opts.DiffMode {
|
||||||
case diffIdentical:
|
case diffIdentical:
|
||||||
isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY)
|
isZero = r.Value.ValueX.IsZero() || r.Value.ValueY.IsZero()
|
||||||
case diffRemoved:
|
case diffRemoved:
|
||||||
isZero = value.IsZero(r.Value.ValueX)
|
isZero = r.Value.ValueX.IsZero()
|
||||||
case diffInserted:
|
case diffInserted:
|
||||||
isZero = value.IsZero(r.Value.ValueY)
|
isZero = r.Value.ValueY.IsZero()
|
||||||
}
|
}
|
||||||
if isZero {
|
if isZero {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -16,6 +16,13 @@ import (
|
||||||
"github.com/google/go-cmp/cmp/internal/value"
|
"github.com/google/go-cmp/cmp/internal/value"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
anyType = reflect.TypeOf((*interface{})(nil)).Elem()
|
||||||
|
stringType = reflect.TypeOf((*string)(nil)).Elem()
|
||||||
|
bytesType = reflect.TypeOf((*[]byte)(nil)).Elem()
|
||||||
|
byteType = reflect.TypeOf((*byte)(nil)).Elem()
|
||||||
|
)
|
||||||
|
|
||||||
type formatValueOptions struct {
|
type formatValueOptions struct {
|
||||||
// AvoidStringer controls whether to avoid calling custom stringer
|
// AvoidStringer controls whether to avoid calling custom stringer
|
||||||
// methods like error.Error or fmt.Stringer.String.
|
// methods like error.Error or fmt.Stringer.String.
|
||||||
|
@ -184,7 +191,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind,
|
||||||
}
|
}
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
vv := v.Field(i)
|
vv := v.Field(i)
|
||||||
if value.IsZero(vv) {
|
if vv.IsZero() {
|
||||||
continue // Elide fields with zero values
|
continue // Elide fields with zero values
|
||||||
}
|
}
|
||||||
if len(list) == maxLen {
|
if len(list) == maxLen {
|
||||||
|
@ -205,13 +212,13 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether this is a []byte of text data.
|
// Check whether this is a []byte of text data.
|
||||||
if t.Elem() == reflect.TypeOf(byte(0)) {
|
if t.Elem() == byteType {
|
||||||
b := v.Bytes()
|
b := v.Bytes()
|
||||||
isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) || unicode.IsSpace(r) }
|
isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) || unicode.IsSpace(r) }
|
||||||
if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 {
|
if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 {
|
||||||
out = opts.formatString("", string(b))
|
out = opts.formatString("", string(b))
|
||||||
skipType = true
|
skipType = true
|
||||||
return opts.WithTypeMode(emitType).FormatType(t, out)
|
return opts.FormatType(t, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +289,12 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind,
|
||||||
}
|
}
|
||||||
defer ptrs.Pop()
|
defer ptrs.Pop()
|
||||||
|
|
||||||
|
// Skip the name only if this is an unnamed pointer type.
|
||||||
|
// Otherwise taking the address of a value does not reproduce
|
||||||
|
// the named pointer type.
|
||||||
|
if v.Type().Name() == "" {
|
||||||
skipType = true // Let the underlying value print the type instead
|
skipType = true // Let the underlying value print the type instead
|
||||||
|
}
|
||||||
out = opts.FormatValue(v.Elem(), t.Kind(), ptrs)
|
out = opts.FormatValue(v.Elem(), t.Kind(), ptrs)
|
||||||
out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
|
out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
|
||||||
out = &textWrap{Prefix: "&", Value: out}
|
out = &textWrap{Prefix: "&", Value: out}
|
||||||
|
@ -293,7 +305,6 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind,
|
||||||
}
|
}
|
||||||
// Interfaces accept different concrete types,
|
// Interfaces accept different concrete types,
|
||||||
// so configure the underlying value to explicitly print the type.
|
// so configure the underlying value to explicitly print the type.
|
||||||
skipType = true // Print the concrete type instead
|
|
||||||
return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs)
|
return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("%v kind not handled", v.Kind()))
|
panic(fmt.Sprintf("%v kind not handled", v.Kind()))
|
||||||
|
|
|
@ -104,7 +104,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
|
||||||
case t.Kind() == reflect.String:
|
case t.Kind() == reflect.String:
|
||||||
sx, sy = vx.String(), vy.String()
|
sx, sy = vx.String(), vy.String()
|
||||||
isString = true
|
isString = true
|
||||||
case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)):
|
case t.Kind() == reflect.Slice && t.Elem() == byteType:
|
||||||
sx, sy = string(vx.Bytes()), string(vy.Bytes())
|
sx, sy = string(vx.Bytes()), string(vy.Bytes())
|
||||||
isString = true
|
isString = true
|
||||||
case t.Kind() == reflect.Array:
|
case t.Kind() == reflect.Array:
|
||||||
|
@ -147,7 +147,10 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
|
||||||
})
|
})
|
||||||
efficiencyLines := float64(esLines.Dist()) / float64(len(esLines))
|
efficiencyLines := float64(esLines.Dist()) / float64(len(esLines))
|
||||||
efficiencyBytes := float64(esBytes.Dist()) / float64(len(esBytes))
|
efficiencyBytes := float64(esBytes.Dist()) / float64(len(esBytes))
|
||||||
isPureLinedText = efficiencyLines < 4*efficiencyBytes
|
quotedLength := len(strconv.Quote(sx + sy))
|
||||||
|
unquotedLength := len(sx) + len(sy)
|
||||||
|
escapeExpansionRatio := float64(quotedLength) / float64(unquotedLength)
|
||||||
|
isPureLinedText = efficiencyLines < 4*efficiencyBytes || escapeExpansionRatio > 1.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,12 +174,13 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
|
||||||
// differences in a string literal. This format is more readable,
|
// differences in a string literal. This format is more readable,
|
||||||
// but has edge-cases where differences are visually indistinguishable.
|
// but has edge-cases where differences are visually indistinguishable.
|
||||||
// This format is avoided under the following conditions:
|
// This format is avoided under the following conditions:
|
||||||
// • A line starts with `"""`
|
// - A line starts with `"""`
|
||||||
// • A line starts with "..."
|
// - A line starts with "..."
|
||||||
// • A line contains non-printable characters
|
// - A line contains non-printable characters
|
||||||
// • Adjacent different lines differ only by whitespace
|
// - Adjacent different lines differ only by whitespace
|
||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
|
//
|
||||||
// """
|
// """
|
||||||
// ... // 3 identical lines
|
// ... // 3 identical lines
|
||||||
// foo
|
// foo
|
||||||
|
@ -231,7 +235,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
|
||||||
var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"}
|
var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"}
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if t != reflect.TypeOf(string("")) {
|
if t != stringType {
|
||||||
out = opts.FormatType(t, out)
|
out = opts.FormatType(t, out)
|
||||||
}
|
}
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
|
@ -326,12 +330,12 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
|
out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
|
||||||
if t != reflect.TypeOf(string("")) {
|
if t != stringType {
|
||||||
out = opts.FormatType(t, out)
|
out = opts.FormatType(t, out)
|
||||||
}
|
}
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
|
out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
|
||||||
if t != reflect.TypeOf([]byte(nil)) {
|
if t != bytesType {
|
||||||
out = opts.FormatType(t, out)
|
out = opts.FormatType(t, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,7 +450,6 @@ func (opts formatOptions) formatDiffSlice(
|
||||||
// {NumIdentical: 3},
|
// {NumIdentical: 3},
|
||||||
// {NumInserted: 1},
|
// {NumInserted: 1},
|
||||||
// ]
|
// ]
|
||||||
//
|
|
||||||
func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) {
|
func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) {
|
||||||
var prevMode byte
|
var prevMode byte
|
||||||
lastStats := func(mode byte) *diffStats {
|
lastStats := func(mode byte) *diffStats {
|
||||||
|
@ -503,7 +506,6 @@ func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats)
|
||||||
// {NumIdentical: 8, NumRemoved: 12, NumInserted: 3},
|
// {NumIdentical: 8, NumRemoved: 12, NumInserted: 3},
|
||||||
// {NumIdentical: 63},
|
// {NumIdentical: 63},
|
||||||
// ]
|
// ]
|
||||||
//
|
|
||||||
func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats {
|
func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats {
|
||||||
groups, groupsOrig := groups[:0], groups
|
groups, groupsOrig := groups[:0], groups
|
||||||
for i, ds := range groupsOrig {
|
for i, ds := range groupsOrig {
|
||||||
|
@ -548,7 +550,6 @@ func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStat
|
||||||
// {NumRemoved: 9},
|
// {NumRemoved: 9},
|
||||||
// {NumIdentical: 64}, // incremented by 10
|
// {NumIdentical: 64}, // incremented by 10
|
||||||
// ]
|
// ]
|
||||||
//
|
|
||||||
func cleanupSurroundingIdentical(groups []diffStats, eq func(i, j int) bool) []diffStats {
|
func cleanupSurroundingIdentical(groups []diffStats, eq func(i, j int) bool) []diffStats {
|
||||||
var ix, iy int // indexes into sequence x and y
|
var ix, iy int // indexes into sequence x and y
|
||||||
for i, ds := range groups {
|
for i, ds := range groups {
|
||||||
|
|
|
@ -393,6 +393,7 @@ func (s diffStats) Append(ds diffStats) diffStats {
|
||||||
// String prints a humanly-readable summary of coalesced records.
|
// String prints a humanly-readable summary of coalesced records.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
//
|
||||||
// diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields"
|
// diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields"
|
||||||
func (s diffStats) String() string {
|
func (s diffStats) String() string {
|
||||||
var ss []string
|
var ss []string
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2019 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,22 +0,0 @@
|
||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
|
@ -1,2 +0,0 @@
|
||||||
This repository holds the transition packages for the new Go 1.13 error values.
|
|
||||||
See golang.org/design/29934-error-values.
|
|
|
@ -1,193 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FormatError calls the FormatError method of f with an errors.Printer
|
|
||||||
// configured according to s and verb, and writes the result to s.
|
|
||||||
func FormatError(f Formatter, s fmt.State, verb rune) {
|
|
||||||
// Assuming this function is only called from the Format method, and given
|
|
||||||
// that FormatError takes precedence over Format, it cannot be called from
|
|
||||||
// any package that supports errors.Formatter. It is therefore safe to
|
|
||||||
// disregard that State may be a specific printer implementation and use one
|
|
||||||
// of our choice instead.
|
|
||||||
|
|
||||||
// limitations: does not support printing error as Go struct.
|
|
||||||
|
|
||||||
var (
|
|
||||||
sep = " " // separator before next error
|
|
||||||
p = &state{State: s}
|
|
||||||
direct = true
|
|
||||||
)
|
|
||||||
|
|
||||||
var err error = f
|
|
||||||
|
|
||||||
switch verb {
|
|
||||||
// Note that this switch must match the preference order
|
|
||||||
// for ordinary string printing (%#v before %+v, and so on).
|
|
||||||
|
|
||||||
case 'v':
|
|
||||||
if s.Flag('#') {
|
|
||||||
if stringer, ok := err.(fmt.GoStringer); ok {
|
|
||||||
io.WriteString(&p.buf, stringer.GoString())
|
|
||||||
goto exit
|
|
||||||
}
|
|
||||||
// proceed as if it were %v
|
|
||||||
} else if s.Flag('+') {
|
|
||||||
p.printDetail = true
|
|
||||||
sep = "\n - "
|
|
||||||
}
|
|
||||||
case 's':
|
|
||||||
case 'q', 'x', 'X':
|
|
||||||
// Use an intermediate buffer in the rare cases that precision,
|
|
||||||
// truncation, or one of the alternative verbs (q, x, and X) are
|
|
||||||
// specified.
|
|
||||||
direct = false
|
|
||||||
|
|
||||||
default:
|
|
||||||
p.buf.WriteString("%!")
|
|
||||||
p.buf.WriteRune(verb)
|
|
||||||
p.buf.WriteByte('(')
|
|
||||||
switch {
|
|
||||||
case err != nil:
|
|
||||||
p.buf.WriteString(reflect.TypeOf(f).String())
|
|
||||||
default:
|
|
||||||
p.buf.WriteString("<nil>")
|
|
||||||
}
|
|
||||||
p.buf.WriteByte(')')
|
|
||||||
io.Copy(s, &p.buf)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
switch v := err.(type) {
|
|
||||||
case Formatter:
|
|
||||||
err = v.FormatError((*printer)(p))
|
|
||||||
case fmt.Formatter:
|
|
||||||
v.Format(p, 'v')
|
|
||||||
break loop
|
|
||||||
default:
|
|
||||||
io.WriteString(&p.buf, v.Error())
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if p.needColon || !p.printDetail {
|
|
||||||
p.buf.WriteByte(':')
|
|
||||||
p.needColon = false
|
|
||||||
}
|
|
||||||
p.buf.WriteString(sep)
|
|
||||||
p.inDetail = false
|
|
||||||
p.needNewline = false
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
width, okW := s.Width()
|
|
||||||
prec, okP := s.Precision()
|
|
||||||
|
|
||||||
if !direct || (okW && width > 0) || okP {
|
|
||||||
// Construct format string from State s.
|
|
||||||
format := []byte{'%'}
|
|
||||||
if s.Flag('-') {
|
|
||||||
format = append(format, '-')
|
|
||||||
}
|
|
||||||
if s.Flag('+') {
|
|
||||||
format = append(format, '+')
|
|
||||||
}
|
|
||||||
if s.Flag(' ') {
|
|
||||||
format = append(format, ' ')
|
|
||||||
}
|
|
||||||
if okW {
|
|
||||||
format = strconv.AppendInt(format, int64(width), 10)
|
|
||||||
}
|
|
||||||
if okP {
|
|
||||||
format = append(format, '.')
|
|
||||||
format = strconv.AppendInt(format, int64(prec), 10)
|
|
||||||
}
|
|
||||||
format = append(format, string(verb)...)
|
|
||||||
fmt.Fprintf(s, string(format), p.buf.String())
|
|
||||||
} else {
|
|
||||||
io.Copy(s, &p.buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var detailSep = []byte("\n ")
|
|
||||||
|
|
||||||
// state tracks error printing state. It implements fmt.State.
|
|
||||||
type state struct {
|
|
||||||
fmt.State
|
|
||||||
buf bytes.Buffer
|
|
||||||
|
|
||||||
printDetail bool
|
|
||||||
inDetail bool
|
|
||||||
needColon bool
|
|
||||||
needNewline bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) Write(b []byte) (n int, err error) {
|
|
||||||
if s.printDetail {
|
|
||||||
if len(b) == 0 {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
if s.inDetail && s.needColon {
|
|
||||||
s.needNewline = true
|
|
||||||
if b[0] == '\n' {
|
|
||||||
b = b[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
k := 0
|
|
||||||
for i, c := range b {
|
|
||||||
if s.needNewline {
|
|
||||||
if s.inDetail && s.needColon {
|
|
||||||
s.buf.WriteByte(':')
|
|
||||||
s.needColon = false
|
|
||||||
}
|
|
||||||
s.buf.Write(detailSep)
|
|
||||||
s.needNewline = false
|
|
||||||
}
|
|
||||||
if c == '\n' {
|
|
||||||
s.buf.Write(b[k:i])
|
|
||||||
k = i + 1
|
|
||||||
s.needNewline = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.buf.Write(b[k:])
|
|
||||||
if !s.inDetail {
|
|
||||||
s.needColon = true
|
|
||||||
}
|
|
||||||
} else if !s.inDetail {
|
|
||||||
s.buf.Write(b)
|
|
||||||
}
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// printer wraps a state to implement an xerrors.Printer.
|
|
||||||
type printer state
|
|
||||||
|
|
||||||
func (s *printer) Print(args ...interface{}) {
|
|
||||||
if !s.inDetail || s.printDetail {
|
|
||||||
fmt.Fprint((*state)(s), args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *printer) Printf(format string, args ...interface{}) {
|
|
||||||
if !s.inDetail || s.printDetail {
|
|
||||||
fmt.Fprintf((*state)(s), format, args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *printer) Detail() bool {
|
|
||||||
s.inDetail = true
|
|
||||||
return s.printDetail
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
issuerepo: golang/go
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package xerrors implements functions to manipulate errors.
|
|
||||||
//
|
|
||||||
// This package is based on the Go 2 proposal for error values:
|
|
||||||
// https://golang.org/design/29934-error-values
|
|
||||||
//
|
|
||||||
// These functions were incorporated into the standard library's errors package
|
|
||||||
// in Go 1.13:
|
|
||||||
// - Is
|
|
||||||
// - As
|
|
||||||
// - Unwrap
|
|
||||||
//
|
|
||||||
// Also, Errorf's %w verb was incorporated into fmt.Errorf.
|
|
||||||
//
|
|
||||||
// Use this package to get equivalent behavior in all supported Go versions.
|
|
||||||
//
|
|
||||||
// No other features of this package were included in Go 1.13, and at present
|
|
||||||
// there are no plans to include any of them.
|
|
||||||
package xerrors // import "golang.org/x/xerrors"
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// errorString is a trivial implementation of error.
|
|
||||||
type errorString struct {
|
|
||||||
s string
|
|
||||||
frame Frame
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns an error that formats as the given text.
|
|
||||||
//
|
|
||||||
// The returned error contains a Frame set to the caller's location and
|
|
||||||
// implements Formatter to show this information when printed with details.
|
|
||||||
func New(text string) error {
|
|
||||||
return &errorString{text, Caller(1)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *errorString) Error() string {
|
|
||||||
return e.s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) }
|
|
||||||
|
|
||||||
func (e *errorString) FormatError(p Printer) (next error) {
|
|
||||||
p.Print(e.s)
|
|
||||||
e.frame.Format(p)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,187 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
const percentBangString = "%!"
|
|
||||||
|
|
||||||
// Errorf formats according to a format specifier and returns the string as a
|
|
||||||
// value that satisfies error.
|
|
||||||
//
|
|
||||||
// The returned error includes the file and line number of the caller when
|
|
||||||
// formatted with additional detail enabled. If the last argument is an error
|
|
||||||
// the returned error's Format method will return it if the format string ends
|
|
||||||
// with ": %s", ": %v", or ": %w". If the last argument is an error and the
|
|
||||||
// format string ends with ": %w", the returned error implements an Unwrap
|
|
||||||
// method returning it.
|
|
||||||
//
|
|
||||||
// If the format specifier includes a %w verb with an error operand in a
|
|
||||||
// position other than at the end, the returned error will still implement an
|
|
||||||
// Unwrap method returning the operand, but the error's Format method will not
|
|
||||||
// return the wrapped error.
|
|
||||||
//
|
|
||||||
// It is invalid to include more than one %w verb or to supply it with an
|
|
||||||
// operand that does not implement the error interface. The %w verb is otherwise
|
|
||||||
// a synonym for %v.
|
|
||||||
func Errorf(format string, a ...interface{}) error {
|
|
||||||
format = formatPlusW(format)
|
|
||||||
// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
|
|
||||||
wrap := strings.HasSuffix(format, ": %w")
|
|
||||||
idx, format2, ok := parsePercentW(format)
|
|
||||||
percentWElsewhere := !wrap && idx >= 0
|
|
||||||
if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) {
|
|
||||||
err := errorAt(a, len(a)-1)
|
|
||||||
if err == nil {
|
|
||||||
return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
|
|
||||||
}
|
|
||||||
// TODO: this is not entirely correct. The error value could be
|
|
||||||
// printed elsewhere in format if it mixes numbered with unnumbered
|
|
||||||
// substitutions. With relatively small changes to doPrintf we can
|
|
||||||
// have it optionally ignore extra arguments and pass the argument
|
|
||||||
// list in its entirety.
|
|
||||||
msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
|
|
||||||
frame := Frame{}
|
|
||||||
if internal.EnableTrace {
|
|
||||||
frame = Caller(1)
|
|
||||||
}
|
|
||||||
if wrap {
|
|
||||||
return &wrapError{msg, err, frame}
|
|
||||||
}
|
|
||||||
return &noWrapError{msg, err, frame}
|
|
||||||
}
|
|
||||||
// Support %w anywhere.
|
|
||||||
// TODO: don't repeat the wrapped error's message when %w occurs in the middle.
|
|
||||||
msg := fmt.Sprintf(format2, a...)
|
|
||||||
if idx < 0 {
|
|
||||||
return &noWrapError{msg, nil, Caller(1)}
|
|
||||||
}
|
|
||||||
err := errorAt(a, idx)
|
|
||||||
if !ok || err == nil {
|
|
||||||
// Too many %ws or argument of %w is not an error. Approximate the Go
|
|
||||||
// 1.13 fmt.Errorf message.
|
|
||||||
return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)}
|
|
||||||
}
|
|
||||||
frame := Frame{}
|
|
||||||
if internal.EnableTrace {
|
|
||||||
frame = Caller(1)
|
|
||||||
}
|
|
||||||
return &wrapError{msg, err, frame}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorAt(args []interface{}, i int) error {
|
|
||||||
if i < 0 || i >= len(args) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err, ok := args[i].(error)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatPlusW is used to avoid the vet check that will barf at %w.
|
|
||||||
func formatPlusW(s string) string {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the index of the only %w in format, or -1 if none.
|
|
||||||
// Also return a rewritten format string with %w replaced by %v, and
|
|
||||||
// false if there is more than one %w.
|
|
||||||
// TODO: handle "%[N]w".
|
|
||||||
func parsePercentW(format string) (idx int, newFormat string, ok bool) {
|
|
||||||
// Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go.
|
|
||||||
idx = -1
|
|
||||||
ok = true
|
|
||||||
n := 0
|
|
||||||
sz := 0
|
|
||||||
var isW bool
|
|
||||||
for i := 0; i < len(format); i += sz {
|
|
||||||
if format[i] != '%' {
|
|
||||||
sz = 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// "%%" is not a format directive.
|
|
||||||
if i+1 < len(format) && format[i+1] == '%' {
|
|
||||||
sz = 2
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sz, isW = parsePrintfVerb(format[i:])
|
|
||||||
if isW {
|
|
||||||
if idx >= 0 {
|
|
||||||
ok = false
|
|
||||||
} else {
|
|
||||||
idx = n
|
|
||||||
}
|
|
||||||
// "Replace" the last character, the 'w', with a 'v'.
|
|
||||||
p := i + sz - 1
|
|
||||||
format = format[:p] + "v" + format[p+1:]
|
|
||||||
}
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
return idx, format, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the printf verb starting with a % at s[0].
|
|
||||||
// Return how many bytes it occupies and whether the verb is 'w'.
|
|
||||||
func parsePrintfVerb(s string) (int, bool) {
|
|
||||||
// Assume only that the directive is a sequence of non-letters followed by a single letter.
|
|
||||||
sz := 0
|
|
||||||
var r rune
|
|
||||||
for i := 1; i < len(s); i += sz {
|
|
||||||
r, sz = utf8.DecodeRuneInString(s[i:])
|
|
||||||
if unicode.IsLetter(r) {
|
|
||||||
return i + sz, r == 'w'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(s), false
|
|
||||||
}
|
|
||||||
|
|
||||||
type noWrapError struct {
|
|
||||||
msg string
|
|
||||||
err error
|
|
||||||
frame Frame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *noWrapError) Error() string {
|
|
||||||
return fmt.Sprint(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
|
|
||||||
|
|
||||||
func (e *noWrapError) FormatError(p Printer) (next error) {
|
|
||||||
p.Print(e.msg)
|
|
||||||
e.frame.Format(p)
|
|
||||||
return e.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrapError struct {
|
|
||||||
msg string
|
|
||||||
err error
|
|
||||||
frame Frame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *wrapError) Error() string {
|
|
||||||
return fmt.Sprint(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
|
|
||||||
|
|
||||||
func (e *wrapError) FormatError(p Printer) (next error) {
|
|
||||||
p.Print(e.msg)
|
|
||||||
e.frame.Format(p)
|
|
||||||
return e.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *wrapError) Unwrap() error {
|
|
||||||
return e.err
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
// A Formatter formats error messages.
|
|
||||||
type Formatter interface {
|
|
||||||
error
|
|
||||||
|
|
||||||
// FormatError prints the receiver's first error and returns the next error in
|
|
||||||
// the error chain, if any.
|
|
||||||
FormatError(p Printer) (next error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Printer formats error messages.
|
|
||||||
//
|
|
||||||
// The most common implementation of Printer is the one provided by package fmt
|
|
||||||
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
|
|
||||||
// typically provide their own implementations.
|
|
||||||
type Printer interface {
|
|
||||||
// Print appends args to the message output.
|
|
||||||
Print(args ...interface{})
|
|
||||||
|
|
||||||
// Printf writes a formatted string.
|
|
||||||
Printf(format string, args ...interface{})
|
|
||||||
|
|
||||||
// Detail reports whether error detail is requested.
|
|
||||||
// After the first call to Detail, all text written to the Printer
|
|
||||||
// is formatted as additional detail, or ignored when
|
|
||||||
// detail has not been requested.
|
|
||||||
// If Detail returns false, the caller can avoid printing the detail at all.
|
|
||||||
Detail() bool
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Frame contains part of a call stack.
|
|
||||||
type Frame struct {
|
|
||||||
// Make room for three PCs: the one we were asked for, what it called,
|
|
||||||
// and possibly a PC for skipPleaseUseCallersFrames. See:
|
|
||||||
// https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169
|
|
||||||
frames [3]uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caller returns a Frame that describes a frame on the caller's stack.
|
|
||||||
// The argument skip is the number of frames to skip over.
|
|
||||||
// Caller(0) returns the frame for the caller of Caller.
|
|
||||||
func Caller(skip int) Frame {
|
|
||||||
var s Frame
|
|
||||||
runtime.Callers(skip+1, s.frames[:])
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// location reports the file, line, and function of a frame.
|
|
||||||
//
|
|
||||||
// The returned function may be "" even if file and line are not.
|
|
||||||
func (f Frame) location() (function, file string, line int) {
|
|
||||||
frames := runtime.CallersFrames(f.frames[:])
|
|
||||||
if _, ok := frames.Next(); !ok {
|
|
||||||
return "", "", 0
|
|
||||||
}
|
|
||||||
fr, ok := frames.Next()
|
|
||||||
if !ok {
|
|
||||||
return "", "", 0
|
|
||||||
}
|
|
||||||
return fr.Function, fr.File, fr.Line
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format prints the stack as error detail.
|
|
||||||
// It should be called from an error's Format implementation
|
|
||||||
// after printing any other error detail.
|
|
||||||
func (f Frame) Format(p Printer) {
|
|
||||||
if p.Detail() {
|
|
||||||
function, file, line := f.location()
|
|
||||||
if function != "" {
|
|
||||||
p.Printf("%s\n ", function)
|
|
||||||
}
|
|
||||||
if file != "" {
|
|
||||||
p.Printf("%s:%d\n", file, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
// EnableTrace indicates whether stack information should be recorded in errors.
|
|
||||||
var EnableTrace = true
|
|
|
@ -1,106 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Wrapper provides context around another error.
|
|
||||||
type Wrapper interface {
|
|
||||||
// Unwrap returns the next error in the error chain.
|
|
||||||
// If there is no next error, Unwrap returns nil.
|
|
||||||
Unwrap() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opaque returns an error with the same error formatting as err
|
|
||||||
// but that does not match err and cannot be unwrapped.
|
|
||||||
func Opaque(err error) error {
|
|
||||||
return noWrapper{err}
|
|
||||||
}
|
|
||||||
|
|
||||||
type noWrapper struct {
|
|
||||||
error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e noWrapper) FormatError(p Printer) (next error) {
|
|
||||||
if f, ok := e.error.(Formatter); ok {
|
|
||||||
return f.FormatError(p)
|
|
||||||
}
|
|
||||||
p.Print(e.error)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the result of calling the Unwrap method on err, if err implements
|
|
||||||
// Unwrap. Otherwise, Unwrap returns nil.
|
|
||||||
func Unwrap(err error) error {
|
|
||||||
u, ok := err.(Wrapper)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return u.Unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is reports whether any error in err's chain matches target.
|
|
||||||
//
|
|
||||||
// An error is considered to match a target if it is equal to that target or if
|
|
||||||
// it implements a method Is(error) bool such that Is(target) returns true.
|
|
||||||
func Is(err, target error) bool {
|
|
||||||
if target == nil {
|
|
||||||
return err == target
|
|
||||||
}
|
|
||||||
|
|
||||||
isComparable := reflect.TypeOf(target).Comparable()
|
|
||||||
for {
|
|
||||||
if isComparable && err == target {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// TODO: consider supporing target.Is(err). This would allow
|
|
||||||
// user-definable predicates, but also may allow for coping with sloppy
|
|
||||||
// APIs, thereby making it easier to get away with them.
|
|
||||||
if err = Unwrap(err); err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// As finds the first error in err's chain that matches the type to which target
|
|
||||||
// points, and if so, sets the target to its value and returns true. An error
|
|
||||||
// matches a type if it is assignable to the target type, or if it has a method
|
|
||||||
// As(interface{}) bool such that As(target) returns true. As will panic if target
|
|
||||||
// is not a non-nil pointer to a type which implements error or is of interface type.
|
|
||||||
//
|
|
||||||
// The As method should set the target to its value and return true if err
|
|
||||||
// matches the type to which target points.
|
|
||||||
func As(err error, target interface{}) bool {
|
|
||||||
if target == nil {
|
|
||||||
panic("errors: target cannot be nil")
|
|
||||||
}
|
|
||||||
val := reflect.ValueOf(target)
|
|
||||||
typ := val.Type()
|
|
||||||
if typ.Kind() != reflect.Ptr || val.IsNil() {
|
|
||||||
panic("errors: target must be a non-nil pointer")
|
|
||||||
}
|
|
||||||
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
|
|
||||||
panic("errors: *target must be interface or implement error")
|
|
||||||
}
|
|
||||||
targetType := typ.Elem()
|
|
||||||
for err != nil {
|
|
||||||
if reflect.TypeOf(err).AssignableTo(targetType) {
|
|
||||||
val.Elem().Set(reflect.ValueOf(err))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
err = Unwrap(err)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
|
|
@ -1,7 +1,8 @@
|
||||||
/*Package assert provides assertions for comparing expected values to actual
|
/*
|
||||||
|
Package assert provides assertions for comparing expected values to actual
|
||||||
values in tests. When an assertion fails a helpful error message is printed.
|
values in tests. When an assertion fails a helpful error message is printed.
|
||||||
|
|
||||||
Example usage
|
# Example usage
|
||||||
|
|
||||||
All the assertions in this package use testing.T.Helper to mark themselves as
|
All the assertions in this package use testing.T.Helper to mark themselves as
|
||||||
test helpers. This allows the testing package to print the filename and line
|
test helpers. This allows the testing package to print the filename and line
|
||||||
|
@ -64,7 +65,7 @@ message is omitted from these examples for brevity.
|
||||||
assert.Assert(t, ref != nil) // use Assert for NotNil
|
assert.Assert(t, ref != nil) // use Assert for NotNil
|
||||||
// assertion failed: ref is nil
|
// assertion failed: ref is nil
|
||||||
|
|
||||||
Assert and Check
|
# Assert and Check
|
||||||
|
|
||||||
Assert and Check are very similar, they both accept a Comparison, and fail
|
Assert and Check are very similar, they both accept a Comparison, and fail
|
||||||
the test when the comparison fails. The one difference is that Assert uses
|
the test when the comparison fails. The one difference is that Assert uses
|
||||||
|
@ -76,20 +77,18 @@ Like testing.T.FailNow, Assert must be called from the goroutine running the tes
|
||||||
not from other goroutines created during the test. Check is safe to use from any
|
not from other goroutines created during the test. Check is safe to use from any
|
||||||
goroutine.
|
goroutine.
|
||||||
|
|
||||||
Comparisons
|
# Comparisons
|
||||||
|
|
||||||
Package http://pkg.go.dev/gotest.tools/v3/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).
|
||||||
|
|
||||||
Automated migration from testify
|
# 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://pkg.go.dev/gotest.tools/v3/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"
|
||||||
|
|
||||||
|
@ -132,7 +131,6 @@ type helperT interface {
|
||||||
// A nil value is considered success, and a non-nil error is a failure.
|
// A nil value is considered success, and a non-nil error is a failure.
|
||||||
// The return value of error.Error is used as the failure message.
|
// The return value of error.Error is used as the failure message.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Extra details can be added to the failure message using msgAndArgs. msgAndArgs
|
// Extra details can be added to the failure message using msgAndArgs. msgAndArgs
|
||||||
// may be either a single string, or a format string and args that will be
|
// may be either a single string, or a format string and args that will be
|
||||||
// passed to fmt.Sprintf.
|
// passed to fmt.Sprintf.
|
||||||
|
|
|
@ -68,6 +68,7 @@ type RegexOrPattern interface{}
|
||||||
// Regexp succeeds if value v matches regular expression re.
|
// Regexp succeeds if value v matches regular expression re.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
//
|
||||||
// assert.Assert(t, cmp.Regexp("^[0-9a-f]{32}$", str))
|
// assert.Assert(t, cmp.Regexp("^[0-9a-f]{32}$", str))
|
||||||
// r := regexp.MustCompile("^[0-9a-f]{32}$")
|
// r := regexp.MustCompile("^[0-9a-f]{32}$")
|
||||||
// assert.Assert(t, cmp.Regexp(r, str))
|
// assert.Assert(t, cmp.Regexp(r, str))
|
||||||
|
@ -248,7 +249,7 @@ type causer interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatErrorMessage(err error) string {
|
func formatErrorMessage(err error) string {
|
||||||
// nolint: errorlint // unwrapping is not appropriate here
|
//nolint:errorlint // unwrapping is not appropriate here
|
||||||
if _, ok := err.(causer); ok {
|
if _, ok := err.(causer); ok {
|
||||||
return fmt.Sprintf("%q\n%+v", err, err)
|
return fmt.Sprintf("%q\n%+v", err, err)
|
||||||
}
|
}
|
||||||
|
@ -288,15 +289,23 @@ func isNil(obj interface{}, msgFunc func(reflect.Value) string) Comparison {
|
||||||
// ErrorType succeeds if err is not nil and is of the expected type.
|
// ErrorType succeeds if err is not nil and is of the expected type.
|
||||||
//
|
//
|
||||||
// Expected can be one of:
|
// Expected can be one of:
|
||||||
|
//
|
||||||
// func(error) bool
|
// func(error) bool
|
||||||
|
//
|
||||||
// Function should return true if the error is the expected type.
|
// Function should return true if the error is the expected type.
|
||||||
|
//
|
||||||
// type struct{}, type &struct{}
|
// type struct{}, type &struct{}
|
||||||
|
//
|
||||||
// A struct or a pointer to a struct.
|
// A struct or a pointer to a struct.
|
||||||
// Fails if the error is not of the same type as expected.
|
// Fails if the error is not of the same type as expected.
|
||||||
|
//
|
||||||
// type &interface{}
|
// type &interface{}
|
||||||
|
//
|
||||||
// A pointer to an interface type.
|
// A pointer to an interface type.
|
||||||
// Fails if err does not implement the interface.
|
// Fails if err does not implement the interface.
|
||||||
|
//
|
||||||
// reflect.Type
|
// reflect.Type
|
||||||
|
//
|
||||||
// Fails if err does not implement the reflect.Type
|
// Fails if err does not implement the reflect.Type
|
||||||
func ErrorType(err error, expected interface{}) Comparison {
|
func ErrorType(err error, expected interface{}) Comparison {
|
||||||
return func() Result {
|
return func() Result {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*Package env provides functions to test code that read environment variables
|
/*
|
||||||
|
Package env provides functions to test code that read environment variables
|
||||||
or the current working directory.
|
or the current working directory.
|
||||||
*/
|
*/
|
||||||
package env // import "gotest.tools/v3/env"
|
package env // import "gotest.tools/v3/env"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*Package fs provides tools for creating temporary files, and testing the
|
/*
|
||||||
|
Package fs provides tools for creating temporary files, and testing the
|
||||||
contents and structure of a directory.
|
contents and structure of a directory.
|
||||||
*/
|
*/
|
||||||
package fs // import "gotest.tools/v3/fs"
|
package fs // import "gotest.tools/v3/fs"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -45,7 +45,7 @@ func NewFile(t assert.TestingT, prefix string, ops ...PathOp) *File {
|
||||||
if ht, ok := t.(helperT); ok {
|
if ht, ok := t.(helperT); ok {
|
||||||
ht.Helper()
|
ht.Helper()
|
||||||
}
|
}
|
||||||
tempfile, err := ioutil.TempFile("", cleanPrefix(prefix)+"-")
|
tempfile, err := os.CreateTemp("", cleanPrefix(prefix)+"-")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
file := &File{path: tempfile.Name()}
|
file := &File{path: tempfile.Name()}
|
||||||
|
@ -71,8 +71,7 @@ func (f *File) Path() string {
|
||||||
|
|
||||||
// Remove the file
|
// Remove the file
|
||||||
func (f *File) Remove() {
|
func (f *File) Remove() {
|
||||||
// nolint: errcheck
|
_ = os.Remove(f.path)
|
||||||
os.Remove(f.path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dir is a temporary directory
|
// Dir is a temporary directory
|
||||||
|
@ -89,7 +88,7 @@ func NewDir(t assert.TestingT, prefix string, ops ...PathOp) *Dir {
|
||||||
if ht, ok := t.(helperT); ok {
|
if ht, ok := t.(helperT); ok {
|
||||||
ht.Helper()
|
ht.Helper()
|
||||||
}
|
}
|
||||||
path, err := ioutil.TempDir("", cleanPrefix(prefix)+"-")
|
path, err := os.MkdirTemp("", cleanPrefix(prefix)+"-")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
dir := &Dir{path: path}
|
dir := &Dir{path: path}
|
||||||
cleanup.Cleanup(t, dir.Remove)
|
cleanup.Cleanup(t, dir.Remove)
|
||||||
|
@ -105,8 +104,7 @@ func (d *Dir) Path() string {
|
||||||
|
|
||||||
// Remove the directory
|
// Remove the directory
|
||||||
func (d *Dir) Remove() {
|
func (d *Dir) Remove() {
|
||||||
// nolint: errcheck
|
_ = os.RemoveAll(d.path)
|
||||||
os.RemoveAll(d.path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join returns a new path with this directory as the base of the path
|
// Join returns a new path with this directory as the base of the path
|
||||||
|
|
|
@ -3,7 +3,6 @@ package fs
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ func manifestFromDir(path string) (Manifest, error) {
|
||||||
|
|
||||||
func newDirectory(path string, info os.FileInfo) (*directory, error) {
|
func newDirectory(path string, info os.FileInfo) (*directory, error) {
|
||||||
items := make(map[string]dirEntry)
|
items := make(map[string]dirEntry)
|
||||||
children, err := ioutil.ReadDir(path)
|
children, err := os.ReadDir(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -103,7 +102,11 @@ func newDirectory(path string, info os.FileInfo) (*directory, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTypedResource(path string, info os.FileInfo) (dirEntry, error) {
|
func getTypedResource(path string, entry os.DirEntry) (dirEntry, error) {
|
||||||
|
info, err := entry.Info()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case info.IsDir():
|
case info.IsDir():
|
||||||
return newDirectory(path, info)
|
return newDirectory(path, info)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -43,10 +42,10 @@ type manifestDirectory interface {
|
||||||
func WithContent(content string) PathOp {
|
func WithContent(content string) PathOp {
|
||||||
return func(path Path) error {
|
return func(path Path) error {
|
||||||
if m, ok := path.(manifestFile); ok {
|
if m, ok := path.(manifestFile); ok {
|
||||||
m.SetContent(ioutil.NopCloser(strings.NewReader(content)))
|
m.SetContent(io.NopCloser(strings.NewReader(content)))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ioutil.WriteFile(path.Path(), []byte(content), defaultFileMode)
|
return os.WriteFile(path.Path(), []byte(content), defaultFileMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,10 +53,10 @@ func WithContent(content string) PathOp {
|
||||||
func WithBytes(raw []byte) PathOp {
|
func WithBytes(raw []byte) PathOp {
|
||||||
return func(path Path) error {
|
return func(path Path) error {
|
||||||
if m, ok := path.(manifestFile); ok {
|
if m, ok := path.(manifestFile); ok {
|
||||||
m.SetContent(ioutil.NopCloser(bytes.NewReader(raw)))
|
m.SetContent(io.NopCloser(bytes.NewReader(raw)))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ioutil.WriteFile(path.Path(), raw, defaultFileMode)
|
return os.WriteFile(path.Path(), raw, defaultFileMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +64,7 @@ func WithBytes(raw []byte) PathOp {
|
||||||
func WithReaderContent(r io.Reader) PathOp {
|
func WithReaderContent(r io.Reader) PathOp {
|
||||||
return func(path Path) error {
|
return func(path Path) error {
|
||||||
if m, ok := path.(manifestFile); ok {
|
if m, ok := path.(manifestFile); ok {
|
||||||
m.SetContent(ioutil.NopCloser(r))
|
m.SetContent(io.NopCloser(r))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
f, err := os.OpenFile(path.Path(), os.O_WRONLY, defaultFileMode)
|
f, err := os.OpenFile(path.Path(), os.O_WRONLY, defaultFileMode)
|
||||||
|
@ -107,7 +106,7 @@ func WithFile(filename, content string, ops ...PathOp) PathOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFile(fullpath string, content string) error {
|
func createFile(fullpath string, content string) error {
|
||||||
return ioutil.WriteFile(fullpath, []byte(content), defaultFileMode)
|
return os.WriteFile(fullpath, []byte(content), defaultFileMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithFiles creates all the files in the directory at path with their content
|
// WithFiles creates all the files in the directory at path with their content
|
||||||
|
@ -191,34 +190,38 @@ func WithMode(mode os.FileMode) PathOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyDirectory(source, dest string) error {
|
func copyDirectory(source, dest string) error {
|
||||||
entries, err := ioutil.ReadDir(source)
|
entries, err := os.ReadDir(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
sourcePath := filepath.Join(source, entry.Name())
|
sourcePath := filepath.Join(source, entry.Name())
|
||||||
destPath := filepath.Join(dest, entry.Name())
|
destPath := filepath.Join(dest, entry.Name())
|
||||||
switch {
|
err = copyEntry(entry, destPath, sourcePath)
|
||||||
case entry.IsDir():
|
if err != nil {
|
||||||
if err := os.Mkdir(destPath, 0755); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := copyDirectory(sourcePath, destPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case entry.Mode()&os.ModeSymlink != 0:
|
|
||||||
if err := copySymLink(sourcePath, destPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if err := copyFile(sourcePath, destPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyEntry(entry os.DirEntry, destPath string, sourcePath string) error {
|
||||||
|
if entry.IsDir() {
|
||||||
|
if err := os.Mkdir(destPath, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return copyDirectory(sourcePath, destPath)
|
||||||
|
}
|
||||||
|
info, err := entry.Info()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.Mode()&os.ModeSymlink != 0 {
|
||||||
|
return copySymLink(sourcePath, destPath)
|
||||||
|
}
|
||||||
|
return copyFile(sourcePath, destPath)
|
||||||
|
}
|
||||||
|
|
||||||
func copySymLink(source, dest string) error {
|
func copySymLink(source, dest string) error {
|
||||||
link, err := os.Readlink(source)
|
link, err := os.Readlink(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -228,11 +231,11 @@ func copySymLink(source, dest string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFile(source, dest string) error {
|
func copyFile(source, dest string) error {
|
||||||
content, err := ioutil.ReadFile(source)
|
content, err := os.ReadFile(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ioutil.WriteFile(dest, content, 0644)
|
return os.WriteFile(dest, content, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSymlink creates a symlink in the directory which links to target.
|
// WithSymlink creates a symlink in the directory which links to target.
|
||||||
|
|
|
@ -3,7 +3,6 @@ package fs
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
@ -124,7 +123,7 @@ func normalizeID(id int) uint32 {
|
||||||
return uint32(id)
|
return uint32(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
var anyFileContent = ioutil.NopCloser(bytes.NewReader(nil))
|
var anyFileContent = io.NopCloser(bytes.NewReader(nil))
|
||||||
|
|
||||||
// MatchAnyFileContent is a PathOp that updates a Manifest so that the file
|
// MatchAnyFileContent is a PathOp that updates a Manifest so that the file
|
||||||
// at path may contain any content.
|
// at path may contain any content.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package fs
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -86,9 +86,9 @@ func eqFile(x, y *file) []problem {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
xContent, xErr := ioutil.ReadAll(x.content)
|
xContent, xErr := io.ReadAll(x.content)
|
||||||
defer x.content.Close()
|
defer x.content.Close()
|
||||||
yContent, yErr := ioutil.ReadAll(y.content)
|
yContent, yErr := io.ReadAll(y.content)
|
||||||
defer y.content.Close()
|
defer y.content.Close()
|
||||||
|
|
||||||
if xErr != nil {
|
if xErr != nil {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*Package golden provides tools for comparing large mutli-line strings.
|
/*
|
||||||
|
Package golden provides tools for comparing large mutli-line strings.
|
||||||
|
|
||||||
Golden files are files in the ./testdata/ subdirectory of the package under test.
|
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
|
Golden files can be automatically updated to match new values by running
|
||||||
|
@ -11,7 +12,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func Get(t assert.TestingT, filename string) []byte {
|
||||||
if ht, ok := t.(helperT); ok {
|
if ht, ok := t.(helperT); ok {
|
||||||
ht.Helper()
|
ht.Helper()
|
||||||
}
|
}
|
||||||
expected, err := ioutil.ReadFile(Path(filename))
|
expected, err := os.ReadFile(Path(filename))
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
return expected
|
return expected
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ func compare(actual []byte, filename string) (cmp.Result, []byte) {
|
||||||
if err := update(filename, actual); 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 := os.ReadFile(Path(filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmp.ResultFromError(err), nil
|
return cmp.ResultFromError(err), nil
|
||||||
}
|
}
|
||||||
|
@ -186,5 +186,5 @@ func update(filename string, actual []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ioutil.WriteFile(Path(filename), actual, 0644)
|
return os.WriteFile(Path(filename), actual, 0644)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
exec "golang.org/x/sys/execabs"
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
"gotest.tools/v3/assert/cmp"
|
"gotest.tools/v3/assert/cmp"
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,8 +2,7 @@ package icmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"os/exec"
|
||||||
exec "golang.org/x/sys/execabs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func processExitCode(err error) int {
|
func processExitCode(err error) int {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package assert provides internal utilties for assertions.
|
||||||
package assert
|
package assert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*Package cleanup handles migration to and support for the Go 1.14+
|
/*
|
||||||
|
Package cleanup handles migration to and support for the Go 1.14+
|
||||||
testing.TB.Cleanup() function.
|
testing.TB.Cleanup() function.
|
||||||
*/
|
*/
|
||||||
package cleanup
|
package cleanup
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package format provides utilities for formatting diffs and messages.
|
||||||
package format
|
package format
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package source provides utilities for handling source-code.
|
||||||
package source // import "gotest.tools/v3/internal/source"
|
package source // import "gotest.tools/v3/internal/source"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -54,8 +54,8 @@ func UpdateExpectedValue(stackIndex int, x, y interface{}) error {
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
argIndex, varName := getVarNameForExpectedValueArg(expr)
|
argIndex, ident := getIdentForExpectedValueArg(expr)
|
||||||
if argIndex < 0 || varName == "" {
|
if argIndex < 0 || ident == nil {
|
||||||
debug("no arguments started with the word 'expected': %v",
|
debug("no arguments started with the word 'expected': %v",
|
||||||
debugFormatNode{Node: &ast.CallExpr{Args: expr}})
|
debugFormatNode{Node: &ast.CallExpr{Args: expr}})
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
|
@ -71,7 +71,7 @@ func UpdateExpectedValue(stackIndex int, x, y interface{}) error {
|
||||||
debug("value must be type string, got %T", value)
|
debug("value must be type string, got %T", value)
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
return UpdateVariable(filename, fileset, astFile, varName, strValue)
|
return UpdateVariable(filename, fileset, astFile, ident, strValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateVariable writes to filename the contents of astFile with the value of
|
// UpdateVariable writes to filename the contents of astFile with the value of
|
||||||
|
@ -80,10 +80,10 @@ func UpdateVariable(
|
||||||
filename string,
|
filename string,
|
||||||
fileset *token.FileSet,
|
fileset *token.FileSet,
|
||||||
astFile *ast.File,
|
astFile *ast.File,
|
||||||
varName string,
|
ident *ast.Ident,
|
||||||
value string,
|
value string,
|
||||||
) error {
|
) error {
|
||||||
obj := astFile.Scope.Objects[varName]
|
obj := ident.Obj
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
|
@ -92,21 +92,34 @@ func UpdateVariable(
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
spec, ok := obj.Decl.(*ast.ValueSpec)
|
switch decl := obj.Decl.(type) {
|
||||||
if !ok {
|
case *ast.ValueSpec:
|
||||||
debug("can only update *ast.ValueSpec, found %T", obj.Decl)
|
if len(decl.Names) != 1 {
|
||||||
return ErrNotFound
|
|
||||||
}
|
|
||||||
if len(spec.Names) != 1 {
|
|
||||||
debug("more than one name in ast.ValueSpec")
|
debug("more than one name in ast.ValueSpec")
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
spec.Values[0] = &ast.BasicLit{
|
decl.Values[0] = &ast.BasicLit{
|
||||||
Kind: token.STRING,
|
Kind: token.STRING,
|
||||||
Value: "`" + value + "`",
|
Value: "`" + value + "`",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case *ast.AssignStmt:
|
||||||
|
if len(decl.Lhs) != 1 {
|
||||||
|
debug("more than one name in ast.AssignStmt")
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
decl.Rhs[0] = &ast.BasicLit{
|
||||||
|
Kind: token.STRING,
|
||||||
|
Value: "`" + value + "`",
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
debug("can only update *ast.ValueSpec, found %T", obj.Decl)
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := format.Node(&buf, fileset, astFile); err != nil {
|
if err := format.Node(&buf, fileset, astFile); err != nil {
|
||||||
return fmt.Errorf("failed to format file after update: %w", err)
|
return fmt.Errorf("failed to format file after update: %w", err)
|
||||||
|
@ -125,14 +138,14 @@ func UpdateVariable(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getVarNameForExpectedValueArg(expr []ast.Expr) (int, string) {
|
func getIdentForExpectedValueArg(expr []ast.Expr) (int, *ast.Ident) {
|
||||||
for i := 1; i < 3; i++ {
|
for i := 1; i < 3; i++ {
|
||||||
switch e := expr[i].(type) {
|
switch e := expr[i].(type) {
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
if strings.HasPrefix(strings.ToLower(e.Name), "expected") {
|
if strings.HasPrefix(strings.ToLower(e.Name), "expected") {
|
||||||
return i, e.Name
|
return i, e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1, ""
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*Package skip provides functions for skipping a test and printing the source code
|
/*
|
||||||
|
Package skip provides functions for skipping a test and printing the source code
|
||||||
of the condition used to skip the test.
|
of the condition used to skip the test.
|
||||||
*/
|
*/
|
||||||
package skip // import "gotest.tools/v3/skip"
|
package skip // import "gotest.tools/v3/skip"
|
||||||
|
|
|
@ -112,8 +112,8 @@ github.com/golang/protobuf/ptypes
|
||||||
github.com/golang/protobuf/ptypes/any
|
github.com/golang/protobuf/ptypes/any
|
||||||
github.com/golang/protobuf/ptypes/duration
|
github.com/golang/protobuf/ptypes/duration
|
||||||
github.com/golang/protobuf/ptypes/timestamp
|
github.com/golang/protobuf/ptypes/timestamp
|
||||||
# github.com/google/go-cmp v0.5.7
|
# github.com/google/go-cmp v0.5.9
|
||||||
## explicit; go 1.11
|
## explicit; go 1.13
|
||||||
github.com/google/go-cmp/cmp
|
github.com/google/go-cmp/cmp
|
||||||
github.com/google/go-cmp/cmp/cmpopts
|
github.com/google/go-cmp/cmp/cmpopts
|
||||||
github.com/google/go-cmp/cmp/internal/diff
|
github.com/google/go-cmp/cmp/internal/diff
|
||||||
|
@ -292,10 +292,6 @@ golang.org/x/text/width
|
||||||
# golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
# golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/time/rate
|
golang.org/x/time/rate
|
||||||
# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
|
||||||
## explicit; go 1.11
|
|
||||||
golang.org/x/xerrors
|
|
||||||
golang.org/x/xerrors/internal
|
|
||||||
# google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
|
# google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
google.golang.org/genproto/googleapis/rpc/status
|
google.golang.org/genproto/googleapis/rpc/status
|
||||||
|
@ -381,7 +377,7 @@ google.golang.org/protobuf/types/known/timestamppb
|
||||||
# gopkg.in/yaml.v2 v2.4.0
|
# gopkg.in/yaml.v2 v2.4.0
|
||||||
## explicit; go 1.15
|
## explicit; go 1.15
|
||||||
gopkg.in/yaml.v2
|
gopkg.in/yaml.v2
|
||||||
# gotest.tools/v3 v3.3.0
|
# gotest.tools/v3 v3.4.0
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
gotest.tools/v3/assert
|
gotest.tools/v3/assert
|
||||||
gotest.tools/v3/assert/cmp
|
gotest.tools/v3/assert/cmp
|
||||||
|
|
Loading…
Reference in New Issue