Browse code

vendor: gotest.tools v3.0.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2020/09/01 00:55:22
Showing 42 changed files
... ...
@@ -7,7 +7,7 @@ import (
7 7
 
8 8
 	"github.com/docker/libnetwork/options"
9 9
 	_ "github.com/docker/libnetwork/testutils"
10
-	"gotest.tools/assert"
10
+	"gotest.tools/v3/assert"
11 11
 )
12 12
 
13 13
 var dummyKey = "dummy"
... ...
@@ -11,8 +11,8 @@ import (
11 11
 	"github.com/docker/libnetwork/netlabel"
12 12
 	_ "github.com/docker/libnetwork/testutils"
13 13
 	"github.com/docker/libnetwork/types"
14
-	"gotest.tools/assert"
15
-	is "gotest.tools/assert/cmp"
14
+	"gotest.tools/v3/assert"
15
+	is "gotest.tools/v3/assert/cmp"
16 16
 )
17 17
 
18 18
 func newDriver(t *testing.T) *driver {
... ...
@@ -11,8 +11,8 @@ import (
11 11
 	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
12 12
 	nullIpam "github.com/docker/libnetwork/ipams/null"
13 13
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
14
-	"gotest.tools/assert"
15
-	is "gotest.tools/assert/cmp"
14
+	"gotest.tools/v3/assert"
15
+	is "gotest.tools/v3/assert/cmp"
16 16
 
17 17
 	// this takes care of the incontainer flag
18 18
 	_ "github.com/docker/libnetwork/testutils"
... ...
@@ -8,7 +8,7 @@ import (
8 8
 	"github.com/docker/libnetwork/iptables"
9 9
 	"github.com/docker/libnetwork/netlabel"
10 10
 	"github.com/docker/libnetwork/options"
11
-	"gotest.tools/assert"
11
+	"gotest.tools/v3/assert"
12 12
 )
13 13
 
14 14
 const (
... ...
@@ -19,8 +19,8 @@ import (
19 19
 	"github.com/docker/libnetwork/ipamapi"
20 20
 	_ "github.com/docker/libnetwork/testutils"
21 21
 	"github.com/docker/libnetwork/types"
22
-	"gotest.tools/assert"
23
-	is "gotest.tools/assert/cmp"
22
+	"gotest.tools/v3/assert"
23
+	is "gotest.tools/v3/assert/cmp"
24 24
 )
25 25
 
26 26
 const (
... ...
@@ -13,8 +13,8 @@ import (
13 13
 
14 14
 	"github.com/docker/libnetwork/ipamapi"
15 15
 	"golang.org/x/sync/semaphore"
16
-	"gotest.tools/assert"
17
-	is "gotest.tools/assert/cmp"
16
+	"gotest.tools/v3/assert"
17
+	is "gotest.tools/v3/assert/cmp"
18 18
 )
19 19
 
20 20
 const (
... ...
@@ -5,8 +5,8 @@ import (
5 5
 	"testing"
6 6
 
7 7
 	_ "github.com/docker/libnetwork/testutils"
8
-	"gotest.tools/assert"
9
-	is "gotest.tools/assert/cmp"
8
+	"gotest.tools/v3/assert"
9
+	is "gotest.tools/v3/assert/cmp"
10 10
 )
11 11
 
12 12
 func initBroadPredefinedNetworks() []*net.IPNet {
... ...
@@ -15,9 +15,9 @@ import (
15 15
 	"github.com/docker/go-events"
16 16
 	"github.com/hashicorp/memberlist"
17 17
 	"github.com/sirupsen/logrus"
18
-	"gotest.tools/assert"
19
-	is "gotest.tools/assert/cmp"
20
-	"gotest.tools/poll"
18
+	"gotest.tools/v3/assert"
19
+	is "gotest.tools/v3/assert/cmp"
20
+	"gotest.tools/v3/poll"
21 21
 
22 22
 	// this takes care of the incontainer flag
23 23
 	_ "github.com/docker/libnetwork/testutils"
... ...
@@ -4,8 +4,8 @@ import (
4 4
 	"testing"
5 5
 
6 6
 	"github.com/sirupsen/logrus"
7
-	"gotest.tools/assert"
8
-	is "gotest.tools/assert/cmp"
7
+	"gotest.tools/v3/assert"
8
+	is "gotest.tools/v3/assert/cmp"
9 9
 
10 10
 	_ "github.com/docker/libnetwork/testutils"
11 11
 )
... ...
@@ -5,8 +5,8 @@ import (
5 5
 	"testing"
6 6
 
7 7
 	"github.com/docker/libnetwork/resolvconf"
8
-	"gotest.tools/assert"
9
-	is "gotest.tools/assert/cmp"
8
+	"gotest.tools/v3/assert"
9
+	is "gotest.tools/v3/assert/cmp"
10 10
 )
11 11
 
12 12
 func TestCleanupServiceDiscovery(t *testing.T) {
... ...
@@ -5,8 +5,8 @@ import (
5 5
 	"testing"
6 6
 
7 7
 	_ "github.com/docker/libnetwork/testutils"
8
-	"gotest.tools/assert"
9
-	is "gotest.tools/assert/cmp"
8
+	"gotest.tools/v3/assert"
9
+	is "gotest.tools/v3/assert/cmp"
10 10
 )
11 11
 
12 12
 func TestTransportPortConv(t *testing.T) {
... ...
@@ -50,7 +50,7 @@ github.com/pkg/errors                               614d223910a179a466c1767a9854
50 50
 github.com/ishidawataru/sctp                        6e2cb1366111dcf547c13531e3a263a067715847
51 51
 go.opencensus.io                                    9c377598961b706d1542bd2d84d538b5094d596e # v0.22.0
52 52
 
53
-gotest.tools                                        1083505acf35a0bd8a696b26837e1fb3187a7a83 # v2.3.0
53
+gotest.tools/v3                                     bb0d8a963040ea5048dcef1a14d8f8b58a33d4b3 # v3.0.2
54 54
 github.com/google/go-cmp                            3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0
55 55
 
56 56
 github.com/moby/ipvs                                4566ccea0e08d68e9614c3e7a64a23b850c4bb35 # v1.0.1
57 57
deleted file mode 100644
... ...
@@ -1,13 +0,0 @@
1
-Copyright 2018 gotest.tools authors
2
-
3
-Licensed under the Apache License, Version 2.0 (the "License");
4
-you may not use this file except in compliance with the License.
5
-You may obtain a copy of the License at
6
-
7
-    http://www.apache.org/licenses/LICENSE-2.0
8
-
9
-Unless required by applicable law or agreed to in writing, software
10
-distributed under the License is distributed on an "AS IS" BASIS,
11
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
-See the License for the specific language governing permissions and
13
-limitations under the License.
14 1
deleted file mode 100644
... ...
@@ -1,35 +0,0 @@
1
-# gotest.tools
2
-
3
-A collection of packages to augment `testing` and support common patterns.
4
-
5
-[![GoDoc](https://godoc.org/gotest.tools?status.svg)](https://godoc.org/gotest.tools)
6
-[![CircleCI](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master.svg?style=shield)](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master)
7
-[![Go Reportcard](https://goreportcard.com/badge/gotest.tools)](https://goreportcard.com/report/gotest.tools)
8
-
9
-
10
-## Packages
11
-
12
-* [assert](http://godoc.org/gotest.tools/assert) -
13
-  compare values and fail the test when a comparison fails
14
-* [env](http://godoc.org/gotest.tools/env) -
15
-  test code which uses environment variables
16
-* [fs](http://godoc.org/gotest.tools/fs) -
17
-  create temporary files and compare a filesystem tree to an expected value
18
-* [golden](http://godoc.org/gotest.tools/golden) -
19
-  compare large multi-line strings against values frozen in golden files
20
-* [icmd](http://godoc.org/gotest.tools/icmd) -
21
-  execute binaries and test the output
22
-* [poll](http://godoc.org/gotest.tools/poll) -
23
-  test asynchronous code by polling until a desired state is reached
24
-* [skip](http://godoc.org/gotest.tools/skip) -
25
-  skip a test and print the source code of the condition used to skip the test
26
-
27
-## Related
28
-
29
-* [gotest.tools/gotestsum](https://github.com/gotestyourself/gotestsum) - go test runner with custom output
30
-* [maxbrunsfeld/counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) - generate fakes for interfaces
31
-* [jonboulle/clockwork](https://github.com/jonboulle/clockwork) - a fake clock for testing code that uses `time`
32
-
33
-## Contributing
34
-
35
-See [CONTRIBUTING.md](CONTRIBUTING.md).
36 1
deleted file mode 100644
... ...
@@ -1,311 +0,0 @@
1
-/*Package assert provides assertions for comparing expected values to actual
2
-values. When an assertion fails a helpful error message is printed.
3
-
4
-Assert and Check
5
-
6
-Assert() and Check() both accept a Comparison, and fail the test when the
7
-comparison fails. The one difference is that Assert() will end the test execution
8
-immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
9
-return the value of the comparison, then proceed with the rest of the test case.
10
-
11
-Example usage
12
-
13
-The example below shows assert used with some common types.
14
-
15
-
16
-	import (
17
-	    "testing"
18
-
19
-	    "gotest.tools/assert"
20
-	    is "gotest.tools/assert/cmp"
21
-	)
22
-
23
-	func TestEverything(t *testing.T) {
24
-	    // booleans
25
-	    assert.Assert(t, ok)
26
-	    assert.Assert(t, !missing)
27
-
28
-	    // primitives
29
-	    assert.Equal(t, count, 1)
30
-	    assert.Equal(t, msg, "the message")
31
-	    assert.Assert(t, total != 10) // NotEqual
32
-
33
-	    // errors
34
-	    assert.NilError(t, closer.Close())
35
-	    assert.Error(t, err, "the exact error message")
36
-	    assert.ErrorContains(t, err, "includes this")
37
-	    assert.ErrorType(t, err, os.IsNotExist)
38
-
39
-	    // complex types
40
-	    assert.DeepEqual(t, result, myStruct{Name: "title"})
41
-	    assert.Assert(t, is.Len(items, 3))
42
-	    assert.Assert(t, len(sequence) != 0) // NotEmpty
43
-	    assert.Assert(t, is.Contains(mapping, "key"))
44
-
45
-	    // pointers and interface
46
-	    assert.Assert(t, is.Nil(ref))
47
-	    assert.Assert(t, ref != nil) // NotNil
48
-	}
49
-
50
-Comparisons
51
-
52
-Package https://godoc.org/gotest.tools/assert/cmp provides
53
-many common comparisons. Additional comparisons can be written to compare
54
-values in other ways. See the example Assert (CustomComparison).
55
-
56
-Automated migration from testify
57
-
58
-gty-migrate-from-testify is a binary which can update source code which uses
59
-testify assertions to use the assertions provided by this package.
60
-
61
-See http://bit.do/cmd-gty-migrate-from-testify.
62
-
63
-
64
-*/
65
-package assert // import "gotest.tools/assert"
66
-
67
-import (
68
-	"fmt"
69
-	"go/ast"
70
-	"go/token"
71
-
72
-	gocmp "github.com/google/go-cmp/cmp"
73
-	"gotest.tools/assert/cmp"
74
-	"gotest.tools/internal/format"
75
-	"gotest.tools/internal/source"
76
-)
77
-
78
-// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
79
-type BoolOrComparison interface{}
80
-
81
-// TestingT is the subset of testing.T used by the assert package.
82
-type TestingT interface {
83
-	FailNow()
84
-	Fail()
85
-	Log(args ...interface{})
86
-}
87
-
88
-type helperT interface {
89
-	Helper()
90
-}
91
-
92
-const failureMessage = "assertion failed: "
93
-
94
-// nolint: gocyclo
95
-func assert(
96
-	t TestingT,
97
-	failer func(),
98
-	argSelector argSelector,
99
-	comparison BoolOrComparison,
100
-	msgAndArgs ...interface{},
101
-) bool {
102
-	if ht, ok := t.(helperT); ok {
103
-		ht.Helper()
104
-	}
105
-	var success bool
106
-	switch check := comparison.(type) {
107
-	case bool:
108
-		if check {
109
-			return true
110
-		}
111
-		logFailureFromBool(t, msgAndArgs...)
112
-
113
-	// Undocumented legacy comparison without Result type
114
-	case func() (success bool, message string):
115
-		success = runCompareFunc(t, check, msgAndArgs...)
116
-
117
-	case nil:
118
-		return true
119
-
120
-	case error:
121
-		msg := "error is not nil: "
122
-		t.Log(format.WithCustomMessage(failureMessage+msg+check.Error(), msgAndArgs...))
123
-
124
-	case cmp.Comparison:
125
-		success = runComparison(t, argSelector, check, msgAndArgs...)
126
-
127
-	case func() cmp.Result:
128
-		success = runComparison(t, argSelector, check, msgAndArgs...)
129
-
130
-	default:
131
-		t.Log(fmt.Sprintf("invalid Comparison: %v (%T)", check, check))
132
-	}
133
-
134
-	if success {
135
-		return true
136
-	}
137
-	failer()
138
-	return false
139
-}
140
-
141
-func runCompareFunc(
142
-	t TestingT,
143
-	f func() (success bool, message string),
144
-	msgAndArgs ...interface{},
145
-) bool {
146
-	if ht, ok := t.(helperT); ok {
147
-		ht.Helper()
148
-	}
149
-	if success, message := f(); !success {
150
-		t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
151
-		return false
152
-	}
153
-	return true
154
-}
155
-
156
-func logFailureFromBool(t TestingT, msgAndArgs ...interface{}) {
157
-	if ht, ok := t.(helperT); ok {
158
-		ht.Helper()
159
-	}
160
-	const stackIndex = 3 // Assert()/Check(), assert(), formatFailureFromBool()
161
-	const comparisonArgPos = 1
162
-	args, err := source.CallExprArgs(stackIndex)
163
-	if err != nil {
164
-		t.Log(err.Error())
165
-		return
166
-	}
167
-
168
-	msg, err := boolFailureMessage(args[comparisonArgPos])
169
-	if err != nil {
170
-		t.Log(err.Error())
171
-		msg = "expression is false"
172
-	}
173
-
174
-	t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
175
-}
176
-
177
-func boolFailureMessage(expr ast.Expr) (string, error) {
178
-	if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
179
-		x, err := source.FormatNode(binaryExpr.X)
180
-		if err != nil {
181
-			return "", err
182
-		}
183
-		y, err := source.FormatNode(binaryExpr.Y)
184
-		if err != nil {
185
-			return "", err
186
-		}
187
-		return x + " is " + y, nil
188
-	}
189
-
190
-	if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
191
-		x, err := source.FormatNode(unaryExpr.X)
192
-		if err != nil {
193
-			return "", err
194
-		}
195
-		return x + " is true", nil
196
-	}
197
-
198
-	formatted, err := source.FormatNode(expr)
199
-	if err != nil {
200
-		return "", err
201
-	}
202
-	return "expression is false: " + formatted, nil
203
-}
204
-
205
-// Assert performs a comparison. If the comparison fails the test is marked as
206
-// failed, a failure message is logged, and execution is stopped immediately.
207
-//
208
-// The comparison argument may be one of three types: bool, cmp.Comparison or
209
-// error.
210
-// When called with a bool the failure message will contain the literal source
211
-// code of the expression.
212
-// When called with a cmp.Comparison the comparison is responsible for producing
213
-// a helpful failure message.
214
-// When called with an error a nil value is considered success. A non-nil error
215
-// is a failure, and Error() is used as the failure message.
216
-func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) {
217
-	if ht, ok := t.(helperT); ok {
218
-		ht.Helper()
219
-	}
220
-	assert(t, t.FailNow, argsFromComparisonCall, comparison, msgAndArgs...)
221
-}
222
-
223
-// Check performs a comparison. If the comparison fails the test is marked as
224
-// failed, a failure message is logged, and Check returns false. Otherwise returns
225
-// true.
226
-//
227
-// See Assert for details about the comparison arg and failure messages.
228
-func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) bool {
229
-	if ht, ok := t.(helperT); ok {
230
-		ht.Helper()
231
-	}
232
-	return assert(t, t.Fail, argsFromComparisonCall, comparison, msgAndArgs...)
233
-}
234
-
235
-// NilError fails the test immediately if err is not nil.
236
-// This is equivalent to Assert(t, err)
237
-func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
238
-	if ht, ok := t.(helperT); ok {
239
-		ht.Helper()
240
-	}
241
-	assert(t, t.FailNow, argsAfterT, err, msgAndArgs...)
242
-}
243
-
244
-// Equal uses the == operator to assert two values are equal and fails the test
245
-// if they are not equal.
246
-//
247
-// If the comparison fails Equal will use the variable names for x and y as part
248
-// of the failure message to identify the actual and expected values.
249
-//
250
-// If either x or y are a multi-line string the failure message will include a
251
-// unified diff of the two values. If the values only differ by whitespace
252
-// the unified diff will be augmented by replacing whitespace characters with
253
-// visible characters to identify the whitespace difference.
254
-//
255
-// This is equivalent to Assert(t, cmp.Equal(x, y)).
256
-func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
257
-	if ht, ok := t.(helperT); ok {
258
-		ht.Helper()
259
-	}
260
-	assert(t, t.FailNow, argsAfterT, cmp.Equal(x, y), msgAndArgs...)
261
-}
262
-
263
-// DeepEqual uses google/go-cmp (http://bit.do/go-cmp) to assert two values are
264
-// equal and fails the test if they are not equal.
265
-//
266
-// Package https://godoc.org/gotest.tools/assert/opt provides some additional
267
-// commonly used Options.
268
-//
269
-// This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
270
-func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
271
-	if ht, ok := t.(helperT); ok {
272
-		ht.Helper()
273
-	}
274
-	assert(t, t.FailNow, argsAfterT, cmp.DeepEqual(x, y, opts...))
275
-}
276
-
277
-// Error fails the test if err is nil, or the error message is not the expected
278
-// message.
279
-// Equivalent to Assert(t, cmp.Error(err, message)).
280
-func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
281
-	if ht, ok := t.(helperT); ok {
282
-		ht.Helper()
283
-	}
284
-	assert(t, t.FailNow, argsAfterT, cmp.Error(err, message), msgAndArgs...)
285
-}
286
-
287
-// ErrorContains fails the test if err is nil, or the error message does not
288
-// contain the expected substring.
289
-// Equivalent to Assert(t, cmp.ErrorContains(err, substring)).
290
-func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interface{}) {
291
-	if ht, ok := t.(helperT); ok {
292
-		ht.Helper()
293
-	}
294
-	assert(t, t.FailNow, argsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...)
295
-}
296
-
297
-// ErrorType fails the test if err is nil, or err is not the expected type.
298
-//
299
-// Expected can be one of:
300
-// a func(error) bool which returns true if the error is the expected type,
301
-// an instance of (or a pointer to) a struct of the expected type,
302
-// a pointer to an interface the error is expected to implement,
303
-// a reflect.Type of the expected struct or interface.
304
-//
305
-// Equivalent to Assert(t, cmp.ErrorType(err, expected)).
306
-func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interface{}) {
307
-	if ht, ok := t.(helperT); ok {
308
-		ht.Helper()
309
-	}
310
-	assert(t, t.FailNow, argsAfterT, cmp.ErrorType(err, expected), msgAndArgs...)
311
-}
312 1
deleted file mode 100644
... ...
@@ -1,356 +0,0 @@
1
-/*Package cmp provides Comparisons for Assert and Check*/
2
-package cmp // import "gotest.tools/assert/cmp"
3
-
4
-import (
5
-	"fmt"
6
-	"reflect"
7
-	"regexp"
8
-	"strings"
9
-
10
-	"github.com/google/go-cmp/cmp"
11
-	"gotest.tools/internal/format"
12
-)
13
-
14
-// Comparison is a function which compares values and returns ResultSuccess if
15
-// the actual value matches the expected value. If the values do not match the
16
-// Result will contain a message about why it failed.
17
-type Comparison func() Result
18
-
19
-// DeepEqual compares two values using google/go-cmp (http://bit.do/go-cmp)
20
-// and succeeds if the values are equal.
21
-//
22
-// The comparison can be customized using comparison Options.
23
-// Package https://godoc.org/gotest.tools/assert/opt provides some additional
24
-// commonly used Options.
25
-func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
26
-	return func() (result Result) {
27
-		defer func() {
28
-			if panicmsg, handled := handleCmpPanic(recover()); handled {
29
-				result = ResultFailure(panicmsg)
30
-			}
31
-		}()
32
-		diff := cmp.Diff(x, y, opts...)
33
-		if diff == "" {
34
-			return ResultSuccess
35
-		}
36
-		return multiLineDiffResult(diff)
37
-	}
38
-}
39
-
40
-func handleCmpPanic(r interface{}) (string, bool) {
41
-	if r == nil {
42
-		return "", false
43
-	}
44
-	panicmsg, ok := r.(string)
45
-	if !ok {
46
-		panic(r)
47
-	}
48
-	switch {
49
-	case strings.HasPrefix(panicmsg, "cannot handle unexported field"):
50
-		return panicmsg, true
51
-	}
52
-	panic(r)
53
-}
54
-
55
-func toResult(success bool, msg string) Result {
56
-	if success {
57
-		return ResultSuccess
58
-	}
59
-	return ResultFailure(msg)
60
-}
61
-
62
-// RegexOrPattern may be either a *regexp.Regexp or a string that is a valid
63
-// regexp pattern.
64
-type RegexOrPattern interface{}
65
-
66
-// Regexp succeeds if value v matches regular expression re.
67
-//
68
-// Example:
69
-//   assert.Assert(t, cmp.Regexp("^[0-9a-f]{32}$", str))
70
-//   r := regexp.MustCompile("^[0-9a-f]{32}$")
71
-//   assert.Assert(t, cmp.Regexp(r, str))
72
-func Regexp(re RegexOrPattern, v string) Comparison {
73
-	match := func(re *regexp.Regexp) Result {
74
-		return toResult(
75
-			re.MatchString(v),
76
-			fmt.Sprintf("value %q does not match regexp %q", v, re.String()))
77
-	}
78
-
79
-	return func() Result {
80
-		switch regex := re.(type) {
81
-		case *regexp.Regexp:
82
-			return match(regex)
83
-		case string:
84
-			re, err := regexp.Compile(regex)
85
-			if err != nil {
86
-				return ResultFailure(err.Error())
87
-			}
88
-			return match(re)
89
-		default:
90
-			return ResultFailure(fmt.Sprintf("invalid type %T for regex pattern", regex))
91
-		}
92
-	}
93
-}
94
-
95
-// Equal succeeds if x == y. See assert.Equal for full documentation.
96
-func Equal(x, y interface{}) Comparison {
97
-	return func() Result {
98
-		switch {
99
-		case x == y:
100
-			return ResultSuccess
101
-		case isMultiLineStringCompare(x, y):
102
-			diff := format.UnifiedDiff(format.DiffConfig{A: x.(string), B: y.(string)})
103
-			return multiLineDiffResult(diff)
104
-		}
105
-		return ResultFailureTemplate(`
106
-			{{- .Data.x}} (
107
-				{{- with callArg 0 }}{{ formatNode . }} {{end -}}
108
-				{{- printf "%T" .Data.x -}}
109
-			) != {{ .Data.y}} (
110
-				{{- with callArg 1 }}{{ formatNode . }} {{end -}}
111
-				{{- printf "%T" .Data.y -}}
112
-			)`,
113
-			map[string]interface{}{"x": x, "y": y})
114
-	}
115
-}
116
-
117
-func isMultiLineStringCompare(x, y interface{}) bool {
118
-	strX, ok := x.(string)
119
-	if !ok {
120
-		return false
121
-	}
122
-	strY, ok := y.(string)
123
-	if !ok {
124
-		return false
125
-	}
126
-	return strings.Contains(strX, "\n") || strings.Contains(strY, "\n")
127
-}
128
-
129
-func multiLineDiffResult(diff string) Result {
130
-	return ResultFailureTemplate(`
131
-+++ {{ with callArg 1 }}{{ formatNode . }}{{else}}→{{end}}
132
-{{ .Data.diff }}`,
133
-		map[string]interface{}{"diff": diff})
134
-}
135
-
136
-// Len succeeds if the sequence has the expected length.
137
-func Len(seq interface{}, expected int) Comparison {
138
-	return func() (result Result) {
139
-		defer func() {
140
-			if e := recover(); e != nil {
141
-				result = ResultFailure(fmt.Sprintf("type %T does not have a length", seq))
142
-			}
143
-		}()
144
-		value := reflect.ValueOf(seq)
145
-		length := value.Len()
146
-		if length == expected {
147
-			return ResultSuccess
148
-		}
149
-		msg := fmt.Sprintf("expected %s (length %d) to have length %d", seq, length, expected)
150
-		return ResultFailure(msg)
151
-	}
152
-}
153
-
154
-// Contains succeeds if item is in collection. Collection may be a string, map,
155
-// slice, or array.
156
-//
157
-// If collection is a string, item must also be a string, and is compared using
158
-// strings.Contains().
159
-// If collection is a Map, contains will succeed if item is a key in the map.
160
-// If collection is a slice or array, item is compared to each item in the
161
-// sequence using reflect.DeepEqual().
162
-func Contains(collection interface{}, item interface{}) Comparison {
163
-	return func() Result {
164
-		colValue := reflect.ValueOf(collection)
165
-		if !colValue.IsValid() {
166
-			return ResultFailure(fmt.Sprintf("nil does not contain items"))
167
-		}
168
-		msg := fmt.Sprintf("%v does not contain %v", collection, item)
169
-
170
-		itemValue := reflect.ValueOf(item)
171
-		switch colValue.Type().Kind() {
172
-		case reflect.String:
173
-			if itemValue.Type().Kind() != reflect.String {
174
-				return ResultFailure("string may only contain strings")
175
-			}
176
-			return toResult(
177
-				strings.Contains(colValue.String(), itemValue.String()),
178
-				fmt.Sprintf("string %q does not contain %q", collection, item))
179
-
180
-		case reflect.Map:
181
-			if itemValue.Type() != colValue.Type().Key() {
182
-				return ResultFailure(fmt.Sprintf(
183
-					"%v can not contain a %v key", colValue.Type(), itemValue.Type()))
184
-			}
185
-			return toResult(colValue.MapIndex(itemValue).IsValid(), msg)
186
-
187
-		case reflect.Slice, reflect.Array:
188
-			for i := 0; i < colValue.Len(); i++ {
189
-				if reflect.DeepEqual(colValue.Index(i).Interface(), item) {
190
-					return ResultSuccess
191
-				}
192
-			}
193
-			return ResultFailure(msg)
194
-		default:
195
-			return ResultFailure(fmt.Sprintf("type %T does not contain items", collection))
196
-		}
197
-	}
198
-}
199
-
200
-// Panics succeeds if f() panics.
201
-func Panics(f func()) Comparison {
202
-	return func() (result Result) {
203
-		defer func() {
204
-			if err := recover(); err != nil {
205
-				result = ResultSuccess
206
-			}
207
-		}()
208
-		f()
209
-		return ResultFailure("did not panic")
210
-	}
211
-}
212
-
213
-// Error succeeds if err is a non-nil error, and the error message equals the
214
-// expected message.
215
-func Error(err error, message string) Comparison {
216
-	return func() Result {
217
-		switch {
218
-		case err == nil:
219
-			return ResultFailure("expected an error, got nil")
220
-		case err.Error() != message:
221
-			return ResultFailure(fmt.Sprintf(
222
-				"expected error %q, got %s", message, formatErrorMessage(err)))
223
-		}
224
-		return ResultSuccess
225
-	}
226
-}
227
-
228
-// ErrorContains succeeds if err is a non-nil error, and the error message contains
229
-// the expected substring.
230
-func ErrorContains(err error, substring string) Comparison {
231
-	return func() Result {
232
-		switch {
233
-		case err == nil:
234
-			return ResultFailure("expected an error, got nil")
235
-		case !strings.Contains(err.Error(), substring):
236
-			return ResultFailure(fmt.Sprintf(
237
-				"expected error to contain %q, got %s", substring, formatErrorMessage(err)))
238
-		}
239
-		return ResultSuccess
240
-	}
241
-}
242
-
243
-func formatErrorMessage(err error) string {
244
-	if _, ok := err.(interface {
245
-		Cause() error
246
-	}); ok {
247
-		return fmt.Sprintf("%q\n%+v", err, err)
248
-	}
249
-	// This error was not wrapped with github.com/pkg/errors
250
-	return fmt.Sprintf("%q", err)
251
-}
252
-
253
-// Nil succeeds if obj is a nil interface, pointer, or function.
254
-//
255
-// Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,
256
-// maps, and channels.
257
-func Nil(obj interface{}) Comparison {
258
-	msgFunc := func(value reflect.Value) string {
259
-		return fmt.Sprintf("%v (type %s) is not nil", reflect.Indirect(value), value.Type())
260
-	}
261
-	return isNil(obj, msgFunc)
262
-}
263
-
264
-func isNil(obj interface{}, msgFunc func(reflect.Value) string) Comparison {
265
-	return func() Result {
266
-		if obj == nil {
267
-			return ResultSuccess
268
-		}
269
-		value := reflect.ValueOf(obj)
270
-		kind := value.Type().Kind()
271
-		if kind >= reflect.Chan && kind <= reflect.Slice {
272
-			if value.IsNil() {
273
-				return ResultSuccess
274
-			}
275
-			return ResultFailure(msgFunc(value))
276
-		}
277
-
278
-		return ResultFailure(fmt.Sprintf("%v (type %s) can not be nil", value, value.Type()))
279
-	}
280
-}
281
-
282
-// ErrorType succeeds if err is not nil and is of the expected type.
283
-//
284
-// Expected can be one of:
285
-// a func(error) bool which returns true if the error is the expected type,
286
-// an instance of (or a pointer to) a struct of the expected type,
287
-// a pointer to an interface the error is expected to implement,
288
-// a reflect.Type of the expected struct or interface.
289
-func ErrorType(err error, expected interface{}) Comparison {
290
-	return func() Result {
291
-		switch expectedType := expected.(type) {
292
-		case func(error) bool:
293
-			return cmpErrorTypeFunc(err, expectedType)
294
-		case reflect.Type:
295
-			if expectedType.Kind() == reflect.Interface {
296
-				return cmpErrorTypeImplementsType(err, expectedType)
297
-			}
298
-			return cmpErrorTypeEqualType(err, expectedType)
299
-		case nil:
300
-			return ResultFailure(fmt.Sprintf("invalid type for expected: nil"))
301
-		}
302
-
303
-		expectedType := reflect.TypeOf(expected)
304
-		switch {
305
-		case expectedType.Kind() == reflect.Struct, isPtrToStruct(expectedType):
306
-			return cmpErrorTypeEqualType(err, expectedType)
307
-		case isPtrToInterface(expectedType):
308
-			return cmpErrorTypeImplementsType(err, expectedType.Elem())
309
-		}
310
-		return ResultFailure(fmt.Sprintf("invalid type for expected: %T", expected))
311
-	}
312
-}
313
-
314
-func cmpErrorTypeFunc(err error, f func(error) bool) Result {
315
-	if f(err) {
316
-		return ResultSuccess
317
-	}
318
-	actual := "nil"
319
-	if err != nil {
320
-		actual = fmt.Sprintf("%s (%T)", err, err)
321
-	}
322
-	return ResultFailureTemplate(`error is {{ .Data.actual }}
323
-		{{- with callArg 1 }}, not {{ formatNode . }}{{end -}}`,
324
-		map[string]interface{}{"actual": actual})
325
-}
326
-
327
-func cmpErrorTypeEqualType(err error, expectedType reflect.Type) Result {
328
-	if err == nil {
329
-		return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
330
-	}
331
-	errValue := reflect.ValueOf(err)
332
-	if errValue.Type() == expectedType {
333
-		return ResultSuccess
334
-	}
335
-	return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
336
-}
337
-
338
-func cmpErrorTypeImplementsType(err error, expectedType reflect.Type) Result {
339
-	if err == nil {
340
-		return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
341
-	}
342
-	errValue := reflect.ValueOf(err)
343
-	if errValue.Type().Implements(expectedType) {
344
-		return ResultSuccess
345
-	}
346
-	return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
347
-}
348
-
349
-func isPtrToInterface(typ reflect.Type) bool {
350
-	return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Interface
351
-}
352
-
353
-func isPtrToStruct(typ reflect.Type) bool {
354
-	return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct
355
-}
356 1
deleted file mode 100644
... ...
@@ -1,100 +0,0 @@
1
-package cmp
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"go/ast"
7
-	"text/template"
8
-
9
-	"gotest.tools/internal/source"
10
-)
11
-
12
-// A Result of a Comparison.
13
-type Result interface {
14
-	Success() bool
15
-}
16
-
17
-// StringResult is an implementation of Result that reports the error message
18
-// string verbatim and does not provide any templating or formatting of the
19
-// message.
20
-type StringResult struct {
21
-	success bool
22
-	message string
23
-}
24
-
25
-// Success returns true if the comparison was successful.
26
-func (r StringResult) Success() bool {
27
-	return r.success
28
-}
29
-
30
-// FailureMessage returns the message used to provide additional information
31
-// about the failure.
32
-func (r StringResult) FailureMessage() string {
33
-	return r.message
34
-}
35
-
36
-// ResultSuccess is a constant which is returned by a ComparisonWithResult to
37
-// indicate success.
38
-var ResultSuccess = StringResult{success: true}
39
-
40
-// ResultFailure returns a failed Result with a failure message.
41
-func ResultFailure(message string) StringResult {
42
-	return StringResult{message: message}
43
-}
44
-
45
-// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
46
-// is returned with the error message as the failure message.
47
-func ResultFromError(err error) Result {
48
-	if err == nil {
49
-		return ResultSuccess
50
-	}
51
-	return ResultFailure(err.Error())
52
-}
53
-
54
-type templatedResult struct {
55
-	success  bool
56
-	template string
57
-	data     map[string]interface{}
58
-}
59
-
60
-func (r templatedResult) Success() bool {
61
-	return r.success
62
-}
63
-
64
-func (r templatedResult) FailureMessage(args []ast.Expr) string {
65
-	msg, err := renderMessage(r, args)
66
-	if err != nil {
67
-		return fmt.Sprintf("failed to render failure message: %s", err)
68
-	}
69
-	return msg
70
-}
71
-
72
-// ResultFailureTemplate returns a Result with a template string and data which
73
-// can be used to format a failure message. The template may access data from .Data,
74
-// the comparison args with the callArg function, and the formatNode function may
75
-// be used to format the call args.
76
-func ResultFailureTemplate(template string, data map[string]interface{}) Result {
77
-	return templatedResult{template: template, data: data}
78
-}
79
-
80
-func renderMessage(result templatedResult, args []ast.Expr) (string, error) {
81
-	tmpl := template.New("failure").Funcs(template.FuncMap{
82
-		"formatNode": source.FormatNode,
83
-		"callArg": func(index int) ast.Expr {
84
-			if index >= len(args) {
85
-				return nil
86
-			}
87
-			return args[index]
88
-		},
89
-	})
90
-	var err error
91
-	tmpl, err = tmpl.Parse(result.template)
92
-	if err != nil {
93
-		return "", err
94
-	}
95
-	buf := new(bytes.Buffer)
96
-	err = tmpl.Execute(buf, map[string]interface{}{
97
-		"Data": result.data,
98
-	})
99
-	return buf.String(), err
100
-}
101 1
deleted file mode 100644
... ...
@@ -1,106 +0,0 @@
1
-package assert
2
-
3
-import (
4
-	"fmt"
5
-	"go/ast"
6
-
7
-	"gotest.tools/assert/cmp"
8
-	"gotest.tools/internal/format"
9
-	"gotest.tools/internal/source"
10
-)
11
-
12
-func runComparison(
13
-	t TestingT,
14
-	argSelector argSelector,
15
-	f cmp.Comparison,
16
-	msgAndArgs ...interface{},
17
-) bool {
18
-	if ht, ok := t.(helperT); ok {
19
-		ht.Helper()
20
-	}
21
-	result := f()
22
-	if result.Success() {
23
-		return true
24
-	}
25
-
26
-	var message string
27
-	switch typed := result.(type) {
28
-	case resultWithComparisonArgs:
29
-		const stackIndex = 3 // Assert/Check, assert, runComparison
30
-		args, err := source.CallExprArgs(stackIndex)
31
-		if err != nil {
32
-			t.Log(err.Error())
33
-		}
34
-		message = typed.FailureMessage(filterPrintableExpr(argSelector(args)))
35
-	case resultBasic:
36
-		message = typed.FailureMessage()
37
-	default:
38
-		message = fmt.Sprintf("comparison returned invalid Result type: %T", result)
39
-	}
40
-
41
-	t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
42
-	return false
43
-}
44
-
45
-type resultWithComparisonArgs interface {
46
-	FailureMessage(args []ast.Expr) string
47
-}
48
-
49
-type resultBasic interface {
50
-	FailureMessage() string
51
-}
52
-
53
-// filterPrintableExpr filters the ast.Expr slice to only include Expr that are
54
-// easy to read when printed and contain relevant information to an assertion.
55
-//
56
-// Ident and SelectorExpr are included because they print nicely and the variable
57
-// names may provide additional context to their values.
58
-// BasicLit and CompositeLit are excluded because their source is equivalent to
59
-// their value, which is already available.
60
-// Other types are ignored for now, but could be added if they are relevant.
61
-func filterPrintableExpr(args []ast.Expr) []ast.Expr {
62
-	result := make([]ast.Expr, len(args))
63
-	for i, arg := range args {
64
-		if isShortPrintableExpr(arg) {
65
-			result[i] = arg
66
-			continue
67
-		}
68
-
69
-		if starExpr, ok := arg.(*ast.StarExpr); ok {
70
-			result[i] = starExpr.X
71
-			continue
72
-		}
73
-	}
74
-	return result
75
-}
76
-
77
-func isShortPrintableExpr(expr ast.Expr) bool {
78
-	switch expr.(type) {
79
-	case *ast.Ident, *ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr:
80
-		return true
81
-	case *ast.BinaryExpr, *ast.UnaryExpr:
82
-		return true
83
-	default:
84
-		// CallExpr, ParenExpr, TypeAssertExpr, KeyValueExpr, StarExpr
85
-		return false
86
-	}
87
-}
88
-
89
-type argSelector func([]ast.Expr) []ast.Expr
90
-
91
-func argsAfterT(args []ast.Expr) []ast.Expr {
92
-	if len(args) < 1 {
93
-		return nil
94
-	}
95
-	return args[1:]
96
-}
97
-
98
-func argsFromComparisonCall(args []ast.Expr) []ast.Expr {
99
-	if len(args) < 1 {
100
-		return nil
101
-	}
102
-	if callExpr, ok := args[1].(*ast.CallExpr); ok {
103
-		return callExpr.Args
104
-	}
105
-	return nil
106
-}
107 1
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-module gotest.tools
2
-
3
-require (
4
-	github.com/google/go-cmp v0.2.0
5
-	github.com/pkg/errors v0.8.0
6
-	github.com/spf13/pflag v1.0.3
7
-	golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d
8
-)
9 1
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-Copyright (c) 2013, Patrick Mezard
2
-All rights reserved.
3
-
4
-Redistribution and use in source and binary forms, with or without
5
-modification, are permitted provided that the following conditions are
6
-met:
7
-
8
-    Redistributions of source code must retain the above copyright
9
-notice, this list of conditions and the following disclaimer.
10
-    Redistributions in binary form must reproduce the above copyright
11
-notice, this list of conditions and the following disclaimer in the
12
-documentation and/or other materials provided with the distribution.
13
-    The names of its contributors may not be used to endorse or promote
14
-products derived from this software without specific prior written
15
-permission.
16
-
17
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1
deleted file mode 100644
... ...
@@ -1,423 +0,0 @@
1
-/*Package difflib is a partial port of Python difflib module.
2
-
3
-Original source: https://github.com/pmezard/go-difflib
4
-
5
-This file is trimmed to only the parts used by this repository.
6
-*/
7
-package difflib // import "gotest.tools/internal/difflib"
8
-
9
-func min(a, b int) int {
10
-	if a < b {
11
-		return a
12
-	}
13
-	return b
14
-}
15
-
16
-func max(a, b int) int {
17
-	if a > b {
18
-		return a
19
-	}
20
-	return b
21
-}
22
-
23
-// Match stores line numbers of size of match
24
-type Match struct {
25
-	A    int
26
-	B    int
27
-	Size int
28
-}
29
-
30
-// OpCode identifies the type of diff
31
-type OpCode struct {
32
-	Tag byte
33
-	I1  int
34
-	I2  int
35
-	J1  int
36
-	J2  int
37
-}
38
-
39
-// SequenceMatcher compares sequence of strings. The basic
40
-// algorithm predates, and is a little fancier than, an algorithm
41
-// published in the late 1980's by Ratcliff and Obershelp under the
42
-// hyperbolic name "gestalt pattern matching".  The basic idea is to find
43
-// the longest contiguous matching subsequence that contains no "junk"
44
-// elements (R-O doesn't address junk).  The same idea is then applied
45
-// recursively to the pieces of the sequences to the left and to the right
46
-// of the matching subsequence.  This does not yield minimal edit
47
-// sequences, but does tend to yield matches that "look right" to people.
48
-//
49
-// SequenceMatcher tries to compute a "human-friendly diff" between two
50
-// sequences.  Unlike e.g. UNIX(tm) diff, the fundamental notion is the
51
-// longest *contiguous* & junk-free matching subsequence.  That's what
52
-// catches peoples' eyes.  The Windows(tm) windiff has another interesting
53
-// notion, pairing up elements that appear uniquely in each sequence.
54
-// That, and the method here, appear to yield more intuitive difference
55
-// reports than does diff.  This method appears to be the least vulnerable
56
-// to synching up on blocks of "junk lines", though (like blank lines in
57
-// ordinary text files, or maybe "<P>" lines in HTML files).  That may be
58
-// because this is the only method of the 3 that has a *concept* of
59
-// "junk" <wink>.
60
-//
61
-// Timing:  Basic R-O is cubic time worst case and quadratic time expected
62
-// case.  SequenceMatcher is quadratic time for the worst case and has
63
-// expected-case behavior dependent in a complicated way on how many
64
-// elements the sequences have in common; best case time is linear.
65
-type SequenceMatcher struct {
66
-	a              []string
67
-	b              []string
68
-	b2j            map[string][]int
69
-	IsJunk         func(string) bool
70
-	autoJunk       bool
71
-	bJunk          map[string]struct{}
72
-	matchingBlocks []Match
73
-	fullBCount     map[string]int
74
-	bPopular       map[string]struct{}
75
-	opCodes        []OpCode
76
-}
77
-
78
-// NewMatcher returns a new SequenceMatcher
79
-func NewMatcher(a, b []string) *SequenceMatcher {
80
-	m := SequenceMatcher{autoJunk: true}
81
-	m.SetSeqs(a, b)
82
-	return &m
83
-}
84
-
85
-// SetSeqs sets two sequences to be compared.
86
-func (m *SequenceMatcher) SetSeqs(a, b []string) {
87
-	m.SetSeq1(a)
88
-	m.SetSeq2(b)
89
-}
90
-
91
-// SetSeq1 sets the first sequence to be compared. The second sequence to be compared is
92
-// not changed.
93
-//
94
-// SequenceMatcher computes and caches detailed information about the second
95
-// sequence, so if you want to compare one sequence S against many sequences,
96
-// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
97
-// sequences.
98
-//
99
-// See also SetSeqs() and SetSeq2().
100
-func (m *SequenceMatcher) SetSeq1(a []string) {
101
-	if &a == &m.a {
102
-		return
103
-	}
104
-	m.a = a
105
-	m.matchingBlocks = nil
106
-	m.opCodes = nil
107
-}
108
-
109
-// SetSeq2 sets the second sequence to be compared. The first sequence to be compared is
110
-// not changed.
111
-func (m *SequenceMatcher) SetSeq2(b []string) {
112
-	if &b == &m.b {
113
-		return
114
-	}
115
-	m.b = b
116
-	m.matchingBlocks = nil
117
-	m.opCodes = nil
118
-	m.fullBCount = nil
119
-	m.chainB()
120
-}
121
-
122
-func (m *SequenceMatcher) chainB() {
123
-	// Populate line -> index mapping
124
-	b2j := map[string][]int{}
125
-	for i, s := range m.b {
126
-		indices := b2j[s]
127
-		indices = append(indices, i)
128
-		b2j[s] = indices
129
-	}
130
-
131
-	// Purge junk elements
132
-	m.bJunk = map[string]struct{}{}
133
-	if m.IsJunk != nil {
134
-		junk := m.bJunk
135
-		for s := range b2j {
136
-			if m.IsJunk(s) {
137
-				junk[s] = struct{}{}
138
-			}
139
-		}
140
-		for s := range junk {
141
-			delete(b2j, s)
142
-		}
143
-	}
144
-
145
-	// Purge remaining popular elements
146
-	popular := map[string]struct{}{}
147
-	n := len(m.b)
148
-	if m.autoJunk && n >= 200 {
149
-		ntest := n/100 + 1
150
-		for s, indices := range b2j {
151
-			if len(indices) > ntest {
152
-				popular[s] = struct{}{}
153
-			}
154
-		}
155
-		for s := range popular {
156
-			delete(b2j, s)
157
-		}
158
-	}
159
-	m.bPopular = popular
160
-	m.b2j = b2j
161
-}
162
-
163
-func (m *SequenceMatcher) isBJunk(s string) bool {
164
-	_, ok := m.bJunk[s]
165
-	return ok
166
-}
167
-
168
-// Find longest matching block in a[alo:ahi] and b[blo:bhi].
169
-//
170
-// If IsJunk is not defined:
171
-//
172
-// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
173
-//     alo <= i <= i+k <= ahi
174
-//     blo <= j <= j+k <= bhi
175
-// and for all (i',j',k') meeting those conditions,
176
-//     k >= k'
177
-//     i <= i'
178
-//     and if i == i', j <= j'
179
-//
180
-// In other words, of all maximal matching blocks, return one that
181
-// starts earliest in a, and of all those maximal matching blocks that
182
-// start earliest in a, return the one that starts earliest in b.
183
-//
184
-// If IsJunk is defined, first the longest matching block is
185
-// determined as above, but with the additional restriction that no
186
-// junk element appears in the block.  Then that block is extended as
187
-// far as possible by matching (only) junk elements on both sides.  So
188
-// the resulting block never matches on junk except as identical junk
189
-// happens to be adjacent to an "interesting" match.
190
-//
191
-// If no blocks match, return (alo, blo, 0).
192
-func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
193
-	// CAUTION:  stripping common prefix or suffix would be incorrect.
194
-	// E.g.,
195
-	//    ab
196
-	//    acab
197
-	// Longest matching block is "ab", but if common prefix is
198
-	// stripped, it's "a" (tied with "b").  UNIX(tm) diff does so
199
-	// strip, so ends up claiming that ab is changed to acab by
200
-	// inserting "ca" in the middle.  That's minimal but unintuitive:
201
-	// "it's obvious" that someone inserted "ac" at the front.
202
-	// Windiff ends up at the same place as diff, but by pairing up
203
-	// the unique 'b's and then matching the first two 'a's.
204
-	besti, bestj, bestsize := alo, blo, 0
205
-
206
-	// find longest junk-free match
207
-	// during an iteration of the loop, j2len[j] = length of longest
208
-	// junk-free match ending with a[i-1] and b[j]
209
-	j2len := map[int]int{}
210
-	for i := alo; i != ahi; i++ {
211
-		// look at all instances of a[i] in b; note that because
212
-		// b2j has no junk keys, the loop is skipped if a[i] is junk
213
-		newj2len := map[int]int{}
214
-		for _, j := range m.b2j[m.a[i]] {
215
-			// a[i] matches b[j]
216
-			if j < blo {
217
-				continue
218
-			}
219
-			if j >= bhi {
220
-				break
221
-			}
222
-			k := j2len[j-1] + 1
223
-			newj2len[j] = k
224
-			if k > bestsize {
225
-				besti, bestj, bestsize = i-k+1, j-k+1, k
226
-			}
227
-		}
228
-		j2len = newj2len
229
-	}
230
-
231
-	// Extend the best by non-junk elements on each end.  In particular,
232
-	// "popular" non-junk elements aren't in b2j, which greatly speeds
233
-	// the inner loop above, but also means "the best" match so far
234
-	// doesn't contain any junk *or* popular non-junk elements.
235
-	for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
236
-		m.a[besti-1] == m.b[bestj-1] {
237
-		besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
238
-	}
239
-	for besti+bestsize < ahi && bestj+bestsize < bhi &&
240
-		!m.isBJunk(m.b[bestj+bestsize]) &&
241
-		m.a[besti+bestsize] == m.b[bestj+bestsize] {
242
-		bestsize += 1
243
-	}
244
-
245
-	// Now that we have a wholly interesting match (albeit possibly
246
-	// empty!), we may as well suck up the matching junk on each
247
-	// side of it too.  Can't think of a good reason not to, and it
248
-	// saves post-processing the (possibly considerable) expense of
249
-	// figuring out what to do with it.  In the case of an empty
250
-	// interesting match, this is clearly the right thing to do,
251
-	// because no other kind of match is possible in the regions.
252
-	for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
253
-		m.a[besti-1] == m.b[bestj-1] {
254
-		besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
255
-	}
256
-	for besti+bestsize < ahi && bestj+bestsize < bhi &&
257
-		m.isBJunk(m.b[bestj+bestsize]) &&
258
-		m.a[besti+bestsize] == m.b[bestj+bestsize] {
259
-		bestsize += 1
260
-	}
261
-
262
-	return Match{A: besti, B: bestj, Size: bestsize}
263
-}
264
-
265
-// GetMatchingBlocks returns a list of triples describing matching subsequences.
266
-//
267
-// Each triple is of the form (i, j, n), and means that
268
-// a[i:i+n] == b[j:j+n].  The triples are monotonically increasing in
269
-// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
270
-// adjacent triples in the list, and the second is not the last triple in the
271
-// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
272
-// adjacent equal blocks.
273
-//
274
-// The last triple is a dummy, (len(a), len(b), 0), and is the only
275
-// triple with n==0.
276
-func (m *SequenceMatcher) GetMatchingBlocks() []Match {
277
-	if m.matchingBlocks != nil {
278
-		return m.matchingBlocks
279
-	}
280
-
281
-	var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
282
-	matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
283
-		match := m.findLongestMatch(alo, ahi, blo, bhi)
284
-		i, j, k := match.A, match.B, match.Size
285
-		if match.Size > 0 {
286
-			if alo < i && blo < j {
287
-				matched = matchBlocks(alo, i, blo, j, matched)
288
-			}
289
-			matched = append(matched, match)
290
-			if i+k < ahi && j+k < bhi {
291
-				matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
292
-			}
293
-		}
294
-		return matched
295
-	}
296
-	matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
297
-
298
-	// It's possible that we have adjacent equal blocks in the
299
-	// matching_blocks list now.
300
-	nonAdjacent := []Match{}
301
-	i1, j1, k1 := 0, 0, 0
302
-	for _, b := range matched {
303
-		// Is this block adjacent to i1, j1, k1?
304
-		i2, j2, k2 := b.A, b.B, b.Size
305
-		if i1+k1 == i2 && j1+k1 == j2 {
306
-			// Yes, so collapse them -- this just increases the length of
307
-			// the first block by the length of the second, and the first
308
-			// block so lengthened remains the block to compare against.
309
-			k1 += k2
310
-		} else {
311
-			// Not adjacent.  Remember the first block (k1==0 means it's
312
-			// the dummy we started with), and make the second block the
313
-			// new block to compare against.
314
-			if k1 > 0 {
315
-				nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
316
-			}
317
-			i1, j1, k1 = i2, j2, k2
318
-		}
319
-	}
320
-	if k1 > 0 {
321
-		nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
322
-	}
323
-
324
-	nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
325
-	m.matchingBlocks = nonAdjacent
326
-	return m.matchingBlocks
327
-}
328
-
329
-// GetOpCodes returns a list of 5-tuples describing how to turn a into b.
330
-//
331
-// Each tuple is of the form (tag, i1, i2, j1, j2).  The first tuple
332
-// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
333
-// tuple preceding it, and likewise for j1 == the previous j2.
334
-//
335
-// The tags are characters, with these meanings:
336
-//
337
-// 'r' (replace):  a[i1:i2] should be replaced by b[j1:j2]
338
-//
339
-// 'd' (delete):   a[i1:i2] should be deleted, j1==j2 in this case.
340
-//
341
-// 'i' (insert):   b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
342
-//
343
-// 'e' (equal):    a[i1:i2] == b[j1:j2]
344
-func (m *SequenceMatcher) GetOpCodes() []OpCode {
345
-	if m.opCodes != nil {
346
-		return m.opCodes
347
-	}
348
-	i, j := 0, 0
349
-	matching := m.GetMatchingBlocks()
350
-	opCodes := make([]OpCode, 0, len(matching))
351
-	for _, m := range matching {
352
-		//  invariant:  we've pumped out correct diffs to change
353
-		//  a[:i] into b[:j], and the next matching block is
354
-		//  a[ai:ai+size] == b[bj:bj+size]. So we need to pump
355
-		//  out a diff to change a[i:ai] into b[j:bj], pump out
356
-		//  the matching block, and move (i,j) beyond the match
357
-		ai, bj, size := m.A, m.B, m.Size
358
-		tag := byte(0)
359
-		if i < ai && j < bj {
360
-			tag = 'r'
361
-		} else if i < ai {
362
-			tag = 'd'
363
-		} else if j < bj {
364
-			tag = 'i'
365
-		}
366
-		if tag > 0 {
367
-			opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
368
-		}
369
-		i, j = ai+size, bj+size
370
-		// the list of matching blocks is terminated by a
371
-		// sentinel with size 0
372
-		if size > 0 {
373
-			opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
374
-		}
375
-	}
376
-	m.opCodes = opCodes
377
-	return m.opCodes
378
-}
379
-
380
-// GetGroupedOpCodes isolates change clusters by eliminating ranges with no changes.
381
-//
382
-// Return a generator of groups with up to n lines of context.
383
-// Each group is in the same format as returned by GetOpCodes().
384
-func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
385
-	if n < 0 {
386
-		n = 3
387
-	}
388
-	codes := m.GetOpCodes()
389
-	if len(codes) == 0 {
390
-		codes = []OpCode{{'e', 0, 1, 0, 1}}
391
-	}
392
-	// Fixup leading and trailing groups if they show no changes.
393
-	if codes[0].Tag == 'e' {
394
-		c := codes[0]
395
-		i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
396
-		codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
397
-	}
398
-	if codes[len(codes)-1].Tag == 'e' {
399
-		c := codes[len(codes)-1]
400
-		i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
401
-		codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
402
-	}
403
-	nn := n + n
404
-	groups := [][]OpCode{}
405
-	group := []OpCode{}
406
-	for _, c := range codes {
407
-		i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
408
-		// End the current group and start a new one whenever
409
-		// there is a large range with no changes.
410
-		if c.Tag == 'e' && i2-i1 > nn {
411
-			group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
412
-				j1, min(j2, j1+n)})
413
-			groups = append(groups, group)
414
-			group = []OpCode{}
415
-			i1, j1 = max(i1, i2-n), max(j1, j2-n)
416
-		}
417
-		group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
418
-	}
419
-	if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
420
-		groups = append(groups, group)
421
-	}
422
-	return groups
423
-}
424 1
deleted file mode 100644
... ...
@@ -1,161 +0,0 @@
1
-package format
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"strings"
7
-	"unicode"
8
-
9
-	"gotest.tools/internal/difflib"
10
-)
11
-
12
-const (
13
-	contextLines = 2
14
-)
15
-
16
-// DiffConfig for a unified diff
17
-type DiffConfig struct {
18
-	A    string
19
-	B    string
20
-	From string
21
-	To   string
22
-}
23
-
24
-// UnifiedDiff is a modified version of difflib.WriteUnifiedDiff with better
25
-// support for showing the whitespace differences.
26
-func UnifiedDiff(conf DiffConfig) string {
27
-	a := strings.SplitAfter(conf.A, "\n")
28
-	b := strings.SplitAfter(conf.B, "\n")
29
-	groups := difflib.NewMatcher(a, b).GetGroupedOpCodes(contextLines)
30
-	if len(groups) == 0 {
31
-		return ""
32
-	}
33
-
34
-	buf := new(bytes.Buffer)
35
-	writeFormat := func(format string, args ...interface{}) {
36
-		buf.WriteString(fmt.Sprintf(format, args...))
37
-	}
38
-	writeLine := func(prefix string, s string) {
39
-		buf.WriteString(prefix + s)
40
-	}
41
-	if hasWhitespaceDiffLines(groups, a, b) {
42
-		writeLine = visibleWhitespaceLine(writeLine)
43
-	}
44
-	formatHeader(writeFormat, conf)
45
-	for _, group := range groups {
46
-		formatRangeLine(writeFormat, group)
47
-		for _, opCode := range group {
48
-			in, out := a[opCode.I1:opCode.I2], b[opCode.J1:opCode.J2]
49
-			switch opCode.Tag {
50
-			case 'e':
51
-				formatLines(writeLine, " ", in)
52
-			case 'r':
53
-				formatLines(writeLine, "-", in)
54
-				formatLines(writeLine, "+", out)
55
-			case 'd':
56
-				formatLines(writeLine, "-", in)
57
-			case 'i':
58
-				formatLines(writeLine, "+", out)
59
-			}
60
-		}
61
-	}
62
-	return buf.String()
63
-}
64
-
65
-// hasWhitespaceDiffLines returns true if any diff groups is only different
66
-// because of whitespace characters.
67
-func hasWhitespaceDiffLines(groups [][]difflib.OpCode, a, b []string) bool {
68
-	for _, group := range groups {
69
-		in, out := new(bytes.Buffer), new(bytes.Buffer)
70
-		for _, opCode := range group {
71
-			if opCode.Tag == 'e' {
72
-				continue
73
-			}
74
-			for _, line := range a[opCode.I1:opCode.I2] {
75
-				in.WriteString(line)
76
-			}
77
-			for _, line := range b[opCode.J1:opCode.J2] {
78
-				out.WriteString(line)
79
-			}
80
-		}
81
-		if removeWhitespace(in.String()) == removeWhitespace(out.String()) {
82
-			return true
83
-		}
84
-	}
85
-	return false
86
-}
87
-
88
-func removeWhitespace(s string) string {
89
-	var result []rune
90
-	for _, r := range s {
91
-		if !unicode.IsSpace(r) {
92
-			result = append(result, r)
93
-		}
94
-	}
95
-	return string(result)
96
-}
97
-
98
-func visibleWhitespaceLine(ws func(string, string)) func(string, string) {
99
-	mapToVisibleSpace := func(r rune) rune {
100
-		switch r {
101
-		case '\n':
102
-		case ' ':
103
-			return '·'
104
-		case '\t':
105
-			return '▷'
106
-		case '\v':
107
-			return '▽'
108
-		case '\r':
109
-			return '↵'
110
-		case '\f':
111
-			return '↓'
112
-		default:
113
-			if unicode.IsSpace(r) {
114
-				return '�'
115
-			}
116
-		}
117
-		return r
118
-	}
119
-	return func(prefix, s string) {
120
-		ws(prefix, strings.Map(mapToVisibleSpace, s))
121
-	}
122
-}
123
-
124
-func formatHeader(wf func(string, ...interface{}), conf DiffConfig) {
125
-	if conf.From != "" || conf.To != "" {
126
-		wf("--- %s\n", conf.From)
127
-		wf("+++ %s\n", conf.To)
128
-	}
129
-}
130
-
131
-func formatRangeLine(wf func(string, ...interface{}), group []difflib.OpCode) {
132
-	first, last := group[0], group[len(group)-1]
133
-	range1 := formatRangeUnified(first.I1, last.I2)
134
-	range2 := formatRangeUnified(first.J1, last.J2)
135
-	wf("@@ -%s +%s @@\n", range1, range2)
136
-}
137
-
138
-// Convert range to the "ed" format
139
-func formatRangeUnified(start, stop int) string {
140
-	// Per the diff spec at http://www.unix.org/single_unix_specification/
141
-	beginning := start + 1 // lines start numbering with one
142
-	length := stop - start
143
-	if length == 1 {
144
-		return fmt.Sprintf("%d", beginning)
145
-	}
146
-	if length == 0 {
147
-		beginning-- // empty ranges begin at line just before the range
148
-	}
149
-	return fmt.Sprintf("%d,%d", beginning, length)
150
-}
151
-
152
-func formatLines(writeLine func(string, string), prefix string, lines []string) {
153
-	for _, line := range lines {
154
-		writeLine(prefix, line)
155
-	}
156
-	// Add a newline if the last line is missing one so that the diff displays
157
-	// properly.
158
-	if !strings.HasSuffix(lines[len(lines)-1], "\n") {
159
-		writeLine("", "\n")
160
-	}
161
-}
162 1
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-package format // import "gotest.tools/internal/format"
2
-
3
-import "fmt"
4
-
5
-// Message accepts a msgAndArgs varargs and formats it using fmt.Sprintf
6
-func Message(msgAndArgs ...interface{}) string {
7
-	switch len(msgAndArgs) {
8
-	case 0:
9
-		return ""
10
-	case 1:
11
-		return fmt.Sprintf("%v", msgAndArgs[0])
12
-	default:
13
-		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
14
-	}
15
-}
16
-
17
-// WithCustomMessage accepts one or two messages and formats them appropriately
18
-func WithCustomMessage(source string, msgAndArgs ...interface{}) string {
19
-	custom := Message(msgAndArgs...)
20
-	switch {
21
-	case custom == "":
22
-		return source
23
-	case source == "":
24
-		return custom
25
-	}
26
-	return fmt.Sprintf("%s: %s", source, custom)
27
-}
28 1
deleted file mode 100644
... ...
@@ -1,53 +0,0 @@
1
-package source
2
-
3
-import (
4
-	"go/ast"
5
-	"go/token"
6
-
7
-	"github.com/pkg/errors"
8
-)
9
-
10
-func scanToDeferLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
11
-	var matchedNode ast.Node
12
-	ast.Inspect(node, func(node ast.Node) bool {
13
-		switch {
14
-		case node == nil || matchedNode != nil:
15
-			return false
16
-		case fileset.Position(node.End()).Line == lineNum:
17
-			if funcLit, ok := node.(*ast.FuncLit); ok {
18
-				matchedNode = funcLit
19
-				return false
20
-			}
21
-		}
22
-		return true
23
-	})
24
-	debug("defer line node: %s", debugFormatNode{matchedNode})
25
-	return matchedNode
26
-}
27
-
28
-func guessDefer(node ast.Node) (ast.Node, error) {
29
-	defers := collectDefers(node)
30
-	switch len(defers) {
31
-	case 0:
32
-		return nil, errors.New("failed to expression in defer")
33
-	case 1:
34
-		return defers[0].Call, nil
35
-	default:
36
-		return nil, errors.Errorf(
37
-			"ambiguous call expression: multiple (%d) defers in call block",
38
-			len(defers))
39
-	}
40
-}
41
-
42
-func collectDefers(node ast.Node) []*ast.DeferStmt {
43
-	var defers []*ast.DeferStmt
44
-	ast.Inspect(node, func(node ast.Node) bool {
45
-		if d, ok := node.(*ast.DeferStmt); ok {
46
-			defers = append(defers, d)
47
-			debug("defer: %s", debugFormatNode{d})
48
-			return false
49
-		}
50
-		return true
51
-	})
52
-	return defers
53
-}
54 1
deleted file mode 100644
... ...
@@ -1,166 +0,0 @@
1
-package source // import "gotest.tools/internal/source"
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"go/ast"
7
-	"go/format"
8
-	"go/parser"
9
-	"go/token"
10
-	"os"
11
-	"runtime"
12
-	"strconv"
13
-	"strings"
14
-
15
-	"github.com/pkg/errors"
16
-)
17
-
18
-const baseStackIndex = 1
19
-
20
-// FormattedCallExprArg returns the argument from an ast.CallExpr at the
21
-// index in the call stack. The argument is formatted using FormatNode.
22
-func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
23
-	args, err := CallExprArgs(stackIndex + 1)
24
-	if err != nil {
25
-		return "", err
26
-	}
27
-	if argPos >= len(args) {
28
-		return "", errors.New("failed to find expression")
29
-	}
30
-	return FormatNode(args[argPos])
31
-}
32
-
33
-// CallExprArgs returns the ast.Expr slice for the args of an ast.CallExpr at
34
-// the index in the call stack.
35
-func CallExprArgs(stackIndex int) ([]ast.Expr, error) {
36
-	_, filename, lineNum, ok := runtime.Caller(baseStackIndex + stackIndex)
37
-	if !ok {
38
-		return nil, errors.New("failed to get call stack")
39
-	}
40
-	debug("call stack position: %s:%d", filename, lineNum)
41
-
42
-	node, err := getNodeAtLine(filename, lineNum)
43
-	if err != nil {
44
-		return nil, err
45
-	}
46
-	debug("found node: %s", debugFormatNode{node})
47
-
48
-	return getCallExprArgs(node)
49
-}
50
-
51
-func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
52
-	fileset := token.NewFileSet()
53
-	astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
54
-	if err != nil {
55
-		return nil, errors.Wrapf(err, "failed to parse source file: %s", filename)
56
-	}
57
-
58
-	if node := scanToLine(fileset, astFile, lineNum); node != nil {
59
-		return node, nil
60
-	}
61
-	if node := scanToDeferLine(fileset, astFile, lineNum); node != nil {
62
-		node, err := guessDefer(node)
63
-		if err != nil || node != nil {
64
-			return node, err
65
-		}
66
-	}
67
-	return nil, errors.Errorf(
68
-		"failed to find an expression on line %d in %s", lineNum, filename)
69
-}
70
-
71
-func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
72
-	var matchedNode ast.Node
73
-	ast.Inspect(node, func(node ast.Node) bool {
74
-		switch {
75
-		case node == nil || matchedNode != nil:
76
-			return false
77
-		case nodePosition(fileset, node).Line == lineNum:
78
-			matchedNode = node
79
-			return false
80
-		}
81
-		return true
82
-	})
83
-	return matchedNode
84
-}
85
-
86
-// In golang 1.9 the line number changed from being the line where the statement
87
-// ended to the line where the statement began.
88
-func nodePosition(fileset *token.FileSet, node ast.Node) token.Position {
89
-	if goVersionBefore19 {
90
-		return fileset.Position(node.End())
91
-	}
92
-	return fileset.Position(node.Pos())
93
-}
94
-
95
-var goVersionBefore19 = func() bool {
96
-	version := runtime.Version()
97
-	// not a release version
98
-	if !strings.HasPrefix(version, "go") {
99
-		return false
100
-	}
101
-	version = strings.TrimPrefix(version, "go")
102
-	parts := strings.Split(version, ".")
103
-	if len(parts) < 2 {
104
-		return false
105
-	}
106
-	minor, err := strconv.ParseInt(parts[1], 10, 32)
107
-	return err == nil && parts[0] == "1" && minor < 9
108
-}()
109
-
110
-func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
111
-	visitor := &callExprVisitor{}
112
-	ast.Walk(visitor, node)
113
-	if visitor.expr == nil {
114
-		return nil, errors.New("failed to find call expression")
115
-	}
116
-	debug("callExpr: %s", debugFormatNode{visitor.expr})
117
-	return visitor.expr.Args, nil
118
-}
119
-
120
-type callExprVisitor struct {
121
-	expr *ast.CallExpr
122
-}
123
-
124
-func (v *callExprVisitor) Visit(node ast.Node) ast.Visitor {
125
-	if v.expr != nil || node == nil {
126
-		return nil
127
-	}
128
-	debug("visit: %s", debugFormatNode{node})
129
-
130
-	switch typed := node.(type) {
131
-	case *ast.CallExpr:
132
-		v.expr = typed
133
-		return nil
134
-	case *ast.DeferStmt:
135
-		ast.Walk(v, typed.Call.Fun)
136
-		return nil
137
-	}
138
-	return v
139
-}
140
-
141
-// FormatNode using go/format.Node and return the result as a string
142
-func FormatNode(node ast.Node) (string, error) {
143
-	buf := new(bytes.Buffer)
144
-	err := format.Node(buf, token.NewFileSet(), node)
145
-	return buf.String(), err
146
-}
147
-
148
-var debugEnabled = os.Getenv("GOTESTTOOLS_DEBUG") != ""
149
-
150
-func debug(format string, args ...interface{}) {
151
-	if debugEnabled {
152
-		fmt.Fprintf(os.Stderr, "DEBUG: "+format+"\n", args...)
153
-	}
154
-}
155
-
156
-type debugFormatNode struct {
157
-	ast.Node
158
-}
159
-
160
-func (n debugFormatNode) String() string {
161
-	out, err := FormatNode(n.Node)
162
-	if err != nil {
163
-		return fmt.Sprintf("failed to format %s: %s", n.Node, err)
164
-	}
165
-	return fmt.Sprintf("(%T) %s", n.Node, out)
166
-}
167 1
deleted file mode 100644
... ...
@@ -1,39 +0,0 @@
1
-package poll
2
-
3
-import (
4
-	"net"
5
-	"os"
6
-)
7
-
8
-// Check is a function which will be used as check for the WaitOn method.
9
-type Check func(t LogT) Result
10
-
11
-// FileExists looks on filesystem and check that path exists.
12
-func FileExists(path string) Check {
13
-	return func(t LogT) Result {
14
-		_, err := os.Stat(path)
15
-		if os.IsNotExist(err) {
16
-			t.Logf("waiting on file %s to exist", path)
17
-			return Continue("file %s does not exist", path)
18
-		}
19
-		if err != nil {
20
-			return Error(err)
21
-		}
22
-
23
-		return Success()
24
-	}
25
-}
26
-
27
-// Connection try to open a connection to the address on the
28
-// named network. See net.Dial for a description of the network and
29
-// address parameters.
30
-func Connection(network, address string) Check {
31
-	return func(t LogT) Result {
32
-		_, err := net.Dial(network, address)
33
-		if err != nil {
34
-			t.Logf("waiting on socket %s://%s to be available...", network, address)
35
-			return Continue("socket %s://%s not available", network, address)
36
-		}
37
-		return Success()
38
-	}
39
-}
40 1
deleted file mode 100644
... ...
@@ -1,140 +0,0 @@
1
-/*Package poll provides tools for testing asynchronous code.
2
- */
3
-package poll // import "gotest.tools/poll"
4
-
5
-import (
6
-	"fmt"
7
-	"time"
8
-)
9
-
10
-// TestingT is the subset of testing.T used by WaitOn
11
-type TestingT interface {
12
-	LogT
13
-	Fatalf(format string, args ...interface{})
14
-}
15
-
16
-// LogT is a logging interface that is passed to the WaitOn check function
17
-type LogT interface {
18
-	Log(args ...interface{})
19
-	Logf(format string, args ...interface{})
20
-}
21
-
22
-type helperT interface {
23
-	Helper()
24
-}
25
-
26
-// Settings are used to configure the behaviour of WaitOn
27
-type Settings struct {
28
-	// Timeout is the maximum time to wait for the condition. Defaults to 10s.
29
-	Timeout time.Duration
30
-	// Delay is the time to sleep between checking the condition. Defaults to
31
-	// 100ms.
32
-	Delay time.Duration
33
-}
34
-
35
-func defaultConfig() *Settings {
36
-	return &Settings{Timeout: 10 * time.Second, Delay: 100 * time.Millisecond}
37
-}
38
-
39
-// SettingOp is a function which accepts and modifies Settings
40
-type SettingOp func(config *Settings)
41
-
42
-// WithDelay sets the delay to wait between polls
43
-func WithDelay(delay time.Duration) SettingOp {
44
-	return func(config *Settings) {
45
-		config.Delay = delay
46
-	}
47
-}
48
-
49
-// WithTimeout sets the timeout
50
-func WithTimeout(timeout time.Duration) SettingOp {
51
-	return func(config *Settings) {
52
-		config.Timeout = timeout
53
-	}
54
-}
55
-
56
-// Result of a check performed by WaitOn
57
-type Result interface {
58
-	// Error indicates that the check failed and polling should stop, and the
59
-	// the has failed
60
-	Error() error
61
-	// Done indicates that polling should stop, and the test should proceed
62
-	Done() bool
63
-	// Message provides the most recent state when polling has not completed
64
-	Message() string
65
-}
66
-
67
-type result struct {
68
-	done    bool
69
-	message string
70
-	err     error
71
-}
72
-
73
-func (r result) Done() bool {
74
-	return r.done
75
-}
76
-
77
-func (r result) Message() string {
78
-	return r.message
79
-}
80
-
81
-func (r result) Error() error {
82
-	return r.err
83
-}
84
-
85
-// Continue returns a Result that indicates to WaitOn that it should continue
86
-// polling. The message text will be used as the failure message if the timeout
87
-// is reached.
88
-func Continue(message string, args ...interface{}) Result {
89
-	return result{message: fmt.Sprintf(message, args...)}
90
-}
91
-
92
-// Success returns a Result where Done() returns true, which indicates to WaitOn
93
-// that it should stop polling and exit without an error.
94
-func Success() Result {
95
-	return result{done: true}
96
-}
97
-
98
-// Error returns a Result that indicates to WaitOn that it should fail the test
99
-// and stop polling.
100
-func Error(err error) Result {
101
-	return result{err: err}
102
-}
103
-
104
-// WaitOn a condition or until a timeout. Poll by calling check and exit when
105
-// check returns a done Result. To fail a test and exit polling with an error
106
-// return a error result.
107
-func WaitOn(t TestingT, check Check, pollOps ...SettingOp) {
108
-	if ht, ok := t.(helperT); ok {
109
-		ht.Helper()
110
-	}
111
-	config := defaultConfig()
112
-	for _, pollOp := range pollOps {
113
-		pollOp(config)
114
-	}
115
-
116
-	var lastMessage string
117
-	after := time.After(config.Timeout)
118
-	chResult := make(chan Result)
119
-	for {
120
-		go func() {
121
-			chResult <- check(t)
122
-		}()
123
-		select {
124
-		case <-after:
125
-			if lastMessage == "" {
126
-				lastMessage = "first check never completed"
127
-			}
128
-			t.Fatalf("timeout hit after %s: %s", config.Timeout, lastMessage)
129
-		case result := <-chResult:
130
-			switch {
131
-			case result.Error() != nil:
132
-				t.Fatalf("polling check failed: %s", result.Error())
133
-			case result.Done():
134
-				return
135
-			}
136
-			time.Sleep(config.Delay)
137
-			lastMessage = result.Message()
138
-		}
139
-	}
140
-}
141 1
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+Copyright 2018 gotest.tools authors
1
+
2
+Licensed under the Apache License, Version 2.0 (the "License");
3
+you may not use this file except in compliance with the License.
4
+You may obtain a copy of the License at
5
+
6
+    http://www.apache.org/licenses/LICENSE-2.0
7
+
8
+Unless required by applicable law or agreed to in writing, software
9
+distributed under the License is distributed on an "AS IS" BASIS,
10
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+See the License for the specific language governing permissions and
12
+limitations under the License.
0 13
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+# gotest.tools
1
+
2
+A collection of packages to augment `testing` and support common patterns.
3
+
4
+[![GoDoc](https://godoc.org/gotest.tools?status.svg)](http://gotest.tools)
5
+[![CircleCI](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master.svg?style=shield)](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master)
6
+[![Go Reportcard](https://goreportcard.com/badge/gotest.tools)](https://goreportcard.com/report/gotest.tools)
7
+
8
+## Usage
9
+
10
+With Go modules enabled (go1.11+)
11
+
12
+```
13
+$ go get gotest.tools/v3
14
+```
15
+
16
+```
17
+import "gotest.tools/v3/assert"
18
+```
19
+
20
+To use `gotest.tools` with an older version of Go that does not understand Go
21
+module paths pin to version `v2.3.0`.
22
+
23
+
24
+## Packages
25
+
26
+* [assert](http://gotest.tools/assert) -
27
+  compare values and fail the test when a comparison fails
28
+* [env](http://gotest.tools/env) -
29
+  test code which uses environment variables
30
+* [fs](http://gotest.tools/fs) -
31
+  create temporary files and compare a filesystem tree to an expected value
32
+* [golden](http://gotest.tools/golden) -
33
+  compare large multi-line strings against values frozen in golden files
34
+* [icmd](http://gotest.tools/icmd) -
35
+  execute binaries and test the output
36
+* [poll](http://gotest.tools/poll) -
37
+  test asynchronous code by polling until a desired state is reached
38
+* [skip](http://gotest.tools/skip) -
39
+  skip a test and print the source code of the condition used to skip the test
40
+
41
+## Related
42
+
43
+* [gotest.tools/gotestsum](https://github.com/gotestyourself/gotestsum) - go test runner with custom output
44
+* [maxbrunsfeld/counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) - generate fakes for interfaces
45
+* [jonboulle/clockwork](https://github.com/jonboulle/clockwork) - a fake clock for testing code that uses `time`
46
+
47
+## Contributing
48
+
49
+See [CONTRIBUTING.md](CONTRIBUTING.md).
0 50
new file mode 100644
... ...
@@ -0,0 +1,329 @@
0
+/*Package assert provides assertions for comparing expected values to actual
1
+values. When an assertion fails a helpful error message is printed.
2
+
3
+Assert and Check
4
+
5
+Assert() and Check() both accept a Comparison, and fail the test when the
6
+comparison fails. The one difference is that Assert() will end the test execution
7
+immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
8
+return the value of the comparison, then proceed with the rest of the test case.
9
+
10
+Example usage
11
+
12
+The example below shows assert used with some common types.
13
+
14
+
15
+	import (
16
+	    "testing"
17
+
18
+	    "gotest.tools/assert"
19
+	    is "gotest.tools/assert/cmp"
20
+	)
21
+
22
+	func TestEverything(t *testing.T) {
23
+	    // booleans
24
+	    assert.Assert(t, ok)
25
+	    assert.Assert(t, !missing)
26
+
27
+	    // primitives
28
+	    assert.Equal(t, count, 1)
29
+	    assert.Equal(t, msg, "the message")
30
+	    assert.Assert(t, total != 10) // NotEqual
31
+
32
+	    // errors
33
+	    assert.NilError(t, closer.Close())
34
+	    assert.Error(t, err, "the exact error message")
35
+	    assert.ErrorContains(t, err, "includes this")
36
+	    assert.ErrorType(t, err, os.IsNotExist)
37
+
38
+	    // complex types
39
+	    assert.DeepEqual(t, result, myStruct{Name: "title"})
40
+	    assert.Assert(t, is.Len(items, 3))
41
+	    assert.Assert(t, len(sequence) != 0) // NotEmpty
42
+	    assert.Assert(t, is.Contains(mapping, "key"))
43
+
44
+	    // pointers and interface
45
+	    assert.Assert(t, is.Nil(ref))
46
+	    assert.Assert(t, ref != nil) // NotNil
47
+	}
48
+
49
+Comparisons
50
+
51
+Package http://gotest.tools/assert/cmp provides
52
+many common comparisons. Additional comparisons can be written to compare
53
+values in other ways. See the example Assert (CustomComparison).
54
+
55
+Automated migration from testify
56
+
57
+gty-migrate-from-testify is a command which translates Go source code from
58
+testify assertions to the assertions provided by this package.
59
+
60
+See http://gotest.tools/assert/cmd/gty-migrate-from-testify.
61
+
62
+
63
+*/
64
+package assert // import "gotest.tools/v3/assert"
65
+
66
+import (
67
+	"fmt"
68
+	"go/ast"
69
+	"go/token"
70
+	"reflect"
71
+
72
+	gocmp "github.com/google/go-cmp/cmp"
73
+	"gotest.tools/v3/assert/cmp"
74
+	"gotest.tools/v3/internal/format"
75
+	"gotest.tools/v3/internal/source"
76
+)
77
+
78
+// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
79
+type BoolOrComparison interface{}
80
+
81
+// TestingT is the subset of testing.T used by the assert package.
82
+type TestingT interface {
83
+	FailNow()
84
+	Fail()
85
+	Log(args ...interface{})
86
+}
87
+
88
+type helperT interface {
89
+	Helper()
90
+}
91
+
92
+const failureMessage = "assertion failed: "
93
+
94
+// nolint: gocyclo
95
+func assert(
96
+	t TestingT,
97
+	failer func(),
98
+	argSelector argSelector,
99
+	comparison BoolOrComparison,
100
+	msgAndArgs ...interface{},
101
+) bool {
102
+	if ht, ok := t.(helperT); ok {
103
+		ht.Helper()
104
+	}
105
+	var success bool
106
+	switch check := comparison.(type) {
107
+	case bool:
108
+		if check {
109
+			return true
110
+		}
111
+		logFailureFromBool(t, msgAndArgs...)
112
+
113
+	// Undocumented legacy comparison without Result type
114
+	case func() (success bool, message string):
115
+		success = runCompareFunc(t, check, msgAndArgs...)
116
+
117
+	case nil:
118
+		return true
119
+
120
+	case error:
121
+		msg := failureMsgFromError(check)
122
+		t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
123
+
124
+	case cmp.Comparison:
125
+		success = runComparison(t, argSelector, check, msgAndArgs...)
126
+
127
+	case func() cmp.Result:
128
+		success = runComparison(t, argSelector, check, msgAndArgs...)
129
+
130
+	default:
131
+		t.Log(fmt.Sprintf("invalid Comparison: %v (%T)", check, check))
132
+	}
133
+
134
+	if success {
135
+		return true
136
+	}
137
+	failer()
138
+	return false
139
+}
140
+
141
+func runCompareFunc(
142
+	t TestingT,
143
+	f func() (success bool, message string),
144
+	msgAndArgs ...interface{},
145
+) bool {
146
+	if ht, ok := t.(helperT); ok {
147
+		ht.Helper()
148
+	}
149
+	if success, message := f(); !success {
150
+		t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
151
+		return false
152
+	}
153
+	return true
154
+}
155
+
156
+func logFailureFromBool(t TestingT, msgAndArgs ...interface{}) {
157
+	if ht, ok := t.(helperT); ok {
158
+		ht.Helper()
159
+	}
160
+	const stackIndex = 3 // Assert()/Check(), assert(), formatFailureFromBool()
161
+	const comparisonArgPos = 1
162
+	args, err := source.CallExprArgs(stackIndex)
163
+	if err != nil {
164
+		t.Log(err.Error())
165
+		return
166
+	}
167
+
168
+	msg, err := boolFailureMessage(args[comparisonArgPos])
169
+	if err != nil {
170
+		t.Log(err.Error())
171
+		msg = "expression is false"
172
+	}
173
+
174
+	t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
175
+}
176
+
177
+func failureMsgFromError(err error) string {
178
+	// Handle errors with non-nil types
179
+	v := reflect.ValueOf(err)
180
+	if v.Kind() == reflect.Ptr && v.IsNil() {
181
+		return fmt.Sprintf("error is not nil: error has type %T", err)
182
+	}
183
+	return "error is not nil: " + err.Error()
184
+}
185
+
186
+func boolFailureMessage(expr ast.Expr) (string, error) {
187
+	if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
188
+		x, err := source.FormatNode(binaryExpr.X)
189
+		if err != nil {
190
+			return "", err
191
+		}
192
+		y, err := source.FormatNode(binaryExpr.Y)
193
+		if err != nil {
194
+			return "", err
195
+		}
196
+		return x + " is " + y, nil
197
+	}
198
+
199
+	if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
200
+		x, err := source.FormatNode(unaryExpr.X)
201
+		if err != nil {
202
+			return "", err
203
+		}
204
+		return x + " is true", nil
205
+	}
206
+
207
+	formatted, err := source.FormatNode(expr)
208
+	if err != nil {
209
+		return "", err
210
+	}
211
+	return "expression is false: " + formatted, nil
212
+}
213
+
214
+// Assert performs a comparison. If the comparison fails, the test is marked as
215
+// failed, a failure message is logged, and execution is stopped immediately.
216
+//
217
+// The comparison argument may be one of three types:
218
+//   bool
219
+// True is success. False is a failure.
220
+// The failure message will contain the literal source code of the expression.
221
+//   cmp.Comparison
222
+// Uses cmp.Result.Success() to check for success of failure.
223
+// The comparison is responsible for producing a helpful failure message.
224
+// http://gotest.tools/assert/cmp provides many common comparisons.
225
+//   error
226
+// A nil value is considered success.
227
+// A non-nil error is a failure, err.Error() is used as the failure message.
228
+func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) {
229
+	if ht, ok := t.(helperT); ok {
230
+		ht.Helper()
231
+	}
232
+	assert(t, t.FailNow, argsFromComparisonCall, comparison, msgAndArgs...)
233
+}
234
+
235
+// Check performs a comparison. If the comparison fails the test is marked as
236
+// failed, a failure message is logged, and Check returns false. Otherwise returns
237
+// true.
238
+//
239
+// See Assert for details about the comparison arg and failure messages.
240
+func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) bool {
241
+	if ht, ok := t.(helperT); ok {
242
+		ht.Helper()
243
+	}
244
+	return assert(t, t.Fail, argsFromComparisonCall, comparison, msgAndArgs...)
245
+}
246
+
247
+// NilError fails the test immediately if err is not nil.
248
+// This is equivalent to Assert(t, err)
249
+func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
250
+	if ht, ok := t.(helperT); ok {
251
+		ht.Helper()
252
+	}
253
+	assert(t, t.FailNow, argsAfterT, err, msgAndArgs...)
254
+}
255
+
256
+// Equal uses the == operator to assert two values are equal and fails the test
257
+// if they are not equal.
258
+//
259
+// If the comparison fails Equal will use the variable names for x and y as part
260
+// of the failure message to identify the actual and expected values.
261
+//
262
+// If either x or y are a multi-line string the failure message will include a
263
+// unified diff of the two values. If the values only differ by whitespace
264
+// the unified diff will be augmented by replacing whitespace characters with
265
+// visible characters to identify the whitespace difference.
266
+//
267
+// This is equivalent to Assert(t, cmp.Equal(x, y)).
268
+func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
269
+	if ht, ok := t.(helperT); ok {
270
+		ht.Helper()
271
+	}
272
+	assert(t, t.FailNow, argsAfterT, cmp.Equal(x, y), msgAndArgs...)
273
+}
274
+
275
+// DeepEqual uses google/go-cmp (https://godoc.org/github.com/google/go-cmp/cmp)
276
+// to assert two values are equal and fails the test if they are not equal.
277
+//
278
+// Package http://gotest.tools/assert/opt provides some additional
279
+// commonly used Options.
280
+//
281
+// This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
282
+func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
283
+	if ht, ok := t.(helperT); ok {
284
+		ht.Helper()
285
+	}
286
+	assert(t, t.FailNow, argsAfterT, cmp.DeepEqual(x, y, opts...))
287
+}
288
+
289
+// Error fails the test if err is nil, or the error message is not the expected
290
+// message.
291
+// Equivalent to Assert(t, cmp.Error(err, message)).
292
+func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
293
+	if ht, ok := t.(helperT); ok {
294
+		ht.Helper()
295
+	}
296
+	assert(t, t.FailNow, argsAfterT, cmp.Error(err, message), msgAndArgs...)
297
+}
298
+
299
+// ErrorContains fails the test if err is nil, or the error message does not
300
+// contain the expected substring.
301
+// Equivalent to Assert(t, cmp.ErrorContains(err, substring)).
302
+func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interface{}) {
303
+	if ht, ok := t.(helperT); ok {
304
+		ht.Helper()
305
+	}
306
+	assert(t, t.FailNow, argsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...)
307
+}
308
+
309
+// ErrorType fails the test if err is nil, or err is not the expected type.
310
+// Equivalent to Assert(t, cmp.ErrorType(err, expected)).
311
+//
312
+// Expected can be one of:
313
+//   func(error) bool
314
+// Function should return true if the error is the expected type.
315
+//   type struct{}, type &struct{}
316
+// A struct or a pointer to a struct.
317
+// Fails if the error is not of the same type as expected.
318
+//   type &interface{}
319
+// A pointer to an interface type.
320
+// Fails if err does not implement the interface.
321
+//   reflect.Type
322
+// Fails if err does not implement the reflect.Type
323
+func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interface{}) {
324
+	if ht, ok := t.(helperT); ok {
325
+		ht.Helper()
326
+	}
327
+	assert(t, t.FailNow, argsAfterT, cmp.ErrorType(err, expected), msgAndArgs...)
328
+}
0 329
new file mode 100644
... ...
@@ -0,0 +1,365 @@
0
+/*Package cmp provides Comparisons for Assert and Check*/
1
+package cmp // import "gotest.tools/v3/assert/cmp"
2
+
3
+import (
4
+	"fmt"
5
+	"reflect"
6
+	"regexp"
7
+	"strings"
8
+
9
+	"github.com/google/go-cmp/cmp"
10
+	"gotest.tools/v3/internal/format"
11
+)
12
+
13
+// Comparison is a function which compares values and returns ResultSuccess if
14
+// the actual value matches the expected value. If the values do not match the
15
+// Result will contain a message about why it failed.
16
+type Comparison func() Result
17
+
18
+// DeepEqual compares two values using google/go-cmp
19
+// (https://godoc.org/github.com/google/go-cmp/cmp)
20
+// and succeeds if the values are equal.
21
+//
22
+// The comparison can be customized using comparison Options.
23
+// Package http://gotest.tools/assert/opt provides some additional
24
+// commonly used Options.
25
+func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
26
+	return func() (result Result) {
27
+		defer func() {
28
+			if panicmsg, handled := handleCmpPanic(recover()); handled {
29
+				result = ResultFailure(panicmsg)
30
+			}
31
+		}()
32
+		diff := cmp.Diff(x, y, opts...)
33
+		if diff == "" {
34
+			return ResultSuccess
35
+		}
36
+		return multiLineDiffResult(diff)
37
+	}
38
+}
39
+
40
+func handleCmpPanic(r interface{}) (string, bool) {
41
+	if r == nil {
42
+		return "", false
43
+	}
44
+	panicmsg, ok := r.(string)
45
+	if !ok {
46
+		panic(r)
47
+	}
48
+	switch {
49
+	case strings.HasPrefix(panicmsg, "cannot handle unexported field"):
50
+		return panicmsg, true
51
+	}
52
+	panic(r)
53
+}
54
+
55
+func toResult(success bool, msg string) Result {
56
+	if success {
57
+		return ResultSuccess
58
+	}
59
+	return ResultFailure(msg)
60
+}
61
+
62
+// RegexOrPattern may be either a *regexp.Regexp or a string that is a valid
63
+// regexp pattern.
64
+type RegexOrPattern interface{}
65
+
66
+// Regexp succeeds if value v matches regular expression re.
67
+//
68
+// Example:
69
+//   assert.Assert(t, cmp.Regexp("^[0-9a-f]{32}$", str))
70
+//   r := regexp.MustCompile("^[0-9a-f]{32}$")
71
+//   assert.Assert(t, cmp.Regexp(r, str))
72
+func Regexp(re RegexOrPattern, v string) Comparison {
73
+	match := func(re *regexp.Regexp) Result {
74
+		return toResult(
75
+			re.MatchString(v),
76
+			fmt.Sprintf("value %q does not match regexp %q", v, re.String()))
77
+	}
78
+
79
+	return func() Result {
80
+		switch regex := re.(type) {
81
+		case *regexp.Regexp:
82
+			return match(regex)
83
+		case string:
84
+			re, err := regexp.Compile(regex)
85
+			if err != nil {
86
+				return ResultFailure(err.Error())
87
+			}
88
+			return match(re)
89
+		default:
90
+			return ResultFailure(fmt.Sprintf("invalid type %T for regex pattern", regex))
91
+		}
92
+	}
93
+}
94
+
95
+// Equal succeeds if x == y. See assert.Equal for full documentation.
96
+func Equal(x, y interface{}) Comparison {
97
+	return func() Result {
98
+		switch {
99
+		case x == y:
100
+			return ResultSuccess
101
+		case isMultiLineStringCompare(x, y):
102
+			diff := format.UnifiedDiff(format.DiffConfig{A: x.(string), B: y.(string)})
103
+			return multiLineDiffResult(diff)
104
+		}
105
+		return ResultFailureTemplate(`
106
+			{{- printf "%v" .Data.x}} (
107
+				{{- with callArg 0 }}{{ formatNode . }} {{end -}}
108
+				{{- printf "%T" .Data.x -}}
109
+			) != {{ printf "%v" .Data.y}} (
110
+				{{- with callArg 1 }}{{ formatNode . }} {{end -}}
111
+				{{- printf "%T" .Data.y -}}
112
+			)`,
113
+			map[string]interface{}{"x": x, "y": y})
114
+	}
115
+}
116
+
117
+func isMultiLineStringCompare(x, y interface{}) bool {
118
+	strX, ok := x.(string)
119
+	if !ok {
120
+		return false
121
+	}
122
+	strY, ok := y.(string)
123
+	if !ok {
124
+		return false
125
+	}
126
+	return strings.Contains(strX, "\n") || strings.Contains(strY, "\n")
127
+}
128
+
129
+func multiLineDiffResult(diff string) Result {
130
+	return ResultFailureTemplate(`
131
+--- {{ with callArg 0 }}{{ formatNode . }}{{else}}←{{end}}
132
+{{ .Data.diff }}`,
133
+		map[string]interface{}{"diff": diff})
134
+}
135
+
136
+// Len succeeds if the sequence has the expected length.
137
+func Len(seq interface{}, expected int) Comparison {
138
+	return func() (result Result) {
139
+		defer func() {
140
+			if e := recover(); e != nil {
141
+				result = ResultFailure(fmt.Sprintf("type %T does not have a length", seq))
142
+			}
143
+		}()
144
+		value := reflect.ValueOf(seq)
145
+		length := value.Len()
146
+		if length == expected {
147
+			return ResultSuccess
148
+		}
149
+		msg := fmt.Sprintf("expected %s (length %d) to have length %d", seq, length, expected)
150
+		return ResultFailure(msg)
151
+	}
152
+}
153
+
154
+// Contains succeeds if item is in collection. Collection may be a string, map,
155
+// slice, or array.
156
+//
157
+// If collection is a string, item must also be a string, and is compared using
158
+// strings.Contains().
159
+// If collection is a Map, contains will succeed if item is a key in the map.
160
+// If collection is a slice or array, item is compared to each item in the
161
+// sequence using reflect.DeepEqual().
162
+func Contains(collection interface{}, item interface{}) Comparison {
163
+	return func() Result {
164
+		colValue := reflect.ValueOf(collection)
165
+		if !colValue.IsValid() {
166
+			return ResultFailure(fmt.Sprintf("nil does not contain items"))
167
+		}
168
+		msg := fmt.Sprintf("%v does not contain %v", collection, item)
169
+
170
+		itemValue := reflect.ValueOf(item)
171
+		switch colValue.Type().Kind() {
172
+		case reflect.String:
173
+			if itemValue.Type().Kind() != reflect.String {
174
+				return ResultFailure("string may only contain strings")
175
+			}
176
+			return toResult(
177
+				strings.Contains(colValue.String(), itemValue.String()),
178
+				fmt.Sprintf("string %q does not contain %q", collection, item))
179
+
180
+		case reflect.Map:
181
+			if itemValue.Type() != colValue.Type().Key() {
182
+				return ResultFailure(fmt.Sprintf(
183
+					"%v can not contain a %v key", colValue.Type(), itemValue.Type()))
184
+			}
185
+			return toResult(colValue.MapIndex(itemValue).IsValid(), msg)
186
+
187
+		case reflect.Slice, reflect.Array:
188
+			for i := 0; i < colValue.Len(); i++ {
189
+				if reflect.DeepEqual(colValue.Index(i).Interface(), item) {
190
+					return ResultSuccess
191
+				}
192
+			}
193
+			return ResultFailure(msg)
194
+		default:
195
+			return ResultFailure(fmt.Sprintf("type %T does not contain items", collection))
196
+		}
197
+	}
198
+}
199
+
200
+// Panics succeeds if f() panics.
201
+func Panics(f func()) Comparison {
202
+	return func() (result Result) {
203
+		defer func() {
204
+			if err := recover(); err != nil {
205
+				result = ResultSuccess
206
+			}
207
+		}()
208
+		f()
209
+		return ResultFailure("did not panic")
210
+	}
211
+}
212
+
213
+// Error succeeds if err is a non-nil error, and the error message equals the
214
+// expected message.
215
+func Error(err error, message string) Comparison {
216
+	return func() Result {
217
+		switch {
218
+		case err == nil:
219
+			return ResultFailure("expected an error, got nil")
220
+		case err.Error() != message:
221
+			return ResultFailure(fmt.Sprintf(
222
+				"expected error %q, got %s", message, formatErrorMessage(err)))
223
+		}
224
+		return ResultSuccess
225
+	}
226
+}
227
+
228
+// ErrorContains succeeds if err is a non-nil error, and the error message contains
229
+// the expected substring.
230
+func ErrorContains(err error, substring string) Comparison {
231
+	return func() Result {
232
+		switch {
233
+		case err == nil:
234
+			return ResultFailure("expected an error, got nil")
235
+		case !strings.Contains(err.Error(), substring):
236
+			return ResultFailure(fmt.Sprintf(
237
+				"expected error to contain %q, got %s", substring, formatErrorMessage(err)))
238
+		}
239
+		return ResultSuccess
240
+	}
241
+}
242
+
243
+type causer interface {
244
+	Cause() error
245
+}
246
+
247
+func formatErrorMessage(err error) string {
248
+	if _, ok := err.(causer); ok {
249
+		return fmt.Sprintf("%q\n%+v", err, err)
250
+	}
251
+	// This error was not wrapped with github.com/pkg/errors
252
+	return fmt.Sprintf("%q", err)
253
+}
254
+
255
+// Nil succeeds if obj is a nil interface, pointer, or function.
256
+//
257
+// Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,
258
+// maps, and channels.
259
+func Nil(obj interface{}) Comparison {
260
+	msgFunc := func(value reflect.Value) string {
261
+		return fmt.Sprintf("%v (type %s) is not nil", reflect.Indirect(value), value.Type())
262
+	}
263
+	return isNil(obj, msgFunc)
264
+}
265
+
266
+func isNil(obj interface{}, msgFunc func(reflect.Value) string) Comparison {
267
+	return func() Result {
268
+		if obj == nil {
269
+			return ResultSuccess
270
+		}
271
+		value := reflect.ValueOf(obj)
272
+		kind := value.Type().Kind()
273
+		if kind >= reflect.Chan && kind <= reflect.Slice {
274
+			if value.IsNil() {
275
+				return ResultSuccess
276
+			}
277
+			return ResultFailure(msgFunc(value))
278
+		}
279
+
280
+		return ResultFailure(fmt.Sprintf("%v (type %s) can not be nil", value, value.Type()))
281
+	}
282
+}
283
+
284
+// ErrorType succeeds if err is not nil and is of the expected type.
285
+//
286
+// Expected can be one of:
287
+//   func(error) bool
288
+// Function should return true if the error is the expected type.
289
+//   type struct{}, type &struct{}
290
+// A struct or a pointer to a struct.
291
+// Fails if the error is not of the same type as expected.
292
+//   type &interface{}
293
+// A pointer to an interface type.
294
+// Fails if err does not implement the interface.
295
+//   reflect.Type
296
+// Fails if err does not implement the reflect.Type
297
+func ErrorType(err error, expected interface{}) Comparison {
298
+	return func() Result {
299
+		switch expectedType := expected.(type) {
300
+		case func(error) bool:
301
+			return cmpErrorTypeFunc(err, expectedType)
302
+		case reflect.Type:
303
+			if expectedType.Kind() == reflect.Interface {
304
+				return cmpErrorTypeImplementsType(err, expectedType)
305
+			}
306
+			return cmpErrorTypeEqualType(err, expectedType)
307
+		case nil:
308
+			return ResultFailure(fmt.Sprintf("invalid type for expected: nil"))
309
+		}
310
+
311
+		expectedType := reflect.TypeOf(expected)
312
+		switch {
313
+		case expectedType.Kind() == reflect.Struct, isPtrToStruct(expectedType):
314
+			return cmpErrorTypeEqualType(err, expectedType)
315
+		case isPtrToInterface(expectedType):
316
+			return cmpErrorTypeImplementsType(err, expectedType.Elem())
317
+		}
318
+		return ResultFailure(fmt.Sprintf("invalid type for expected: %T", expected))
319
+	}
320
+}
321
+
322
+func cmpErrorTypeFunc(err error, f func(error) bool) Result {
323
+	if f(err) {
324
+		return ResultSuccess
325
+	}
326
+	actual := "nil"
327
+	if err != nil {
328
+		actual = fmt.Sprintf("%s (%T)", err, err)
329
+	}
330
+	return ResultFailureTemplate(`error is {{ .Data.actual }}
331
+		{{- with callArg 1 }}, not {{ formatNode . }}{{end -}}`,
332
+		map[string]interface{}{"actual": actual})
333
+}
334
+
335
+func cmpErrorTypeEqualType(err error, expectedType reflect.Type) Result {
336
+	if err == nil {
337
+		return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
338
+	}
339
+	errValue := reflect.ValueOf(err)
340
+	if errValue.Type() == expectedType {
341
+		return ResultSuccess
342
+	}
343
+	return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
344
+}
345
+
346
+func cmpErrorTypeImplementsType(err error, expectedType reflect.Type) Result {
347
+	if err == nil {
348
+		return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
349
+	}
350
+	errValue := reflect.ValueOf(err)
351
+	if errValue.Type().Implements(expectedType) {
352
+		return ResultSuccess
353
+	}
354
+	return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
355
+}
356
+
357
+func isPtrToInterface(typ reflect.Type) bool {
358
+	return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Interface
359
+}
360
+
361
+func isPtrToStruct(typ reflect.Type) bool {
362
+	return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct
363
+}
0 364
new file mode 100644
... ...
@@ -0,0 +1,100 @@
0
+package cmp
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"go/ast"
6
+	"text/template"
7
+
8
+	"gotest.tools/v3/internal/source"
9
+)
10
+
11
+// A Result of a Comparison.
12
+type Result interface {
13
+	Success() bool
14
+}
15
+
16
+// StringResult is an implementation of Result that reports the error message
17
+// string verbatim and does not provide any templating or formatting of the
18
+// message.
19
+type StringResult struct {
20
+	success bool
21
+	message string
22
+}
23
+
24
+// Success returns true if the comparison was successful.
25
+func (r StringResult) Success() bool {
26
+	return r.success
27
+}
28
+
29
+// FailureMessage returns the message used to provide additional information
30
+// about the failure.
31
+func (r StringResult) FailureMessage() string {
32
+	return r.message
33
+}
34
+
35
+// ResultSuccess is a constant which is returned by a ComparisonWithResult to
36
+// indicate success.
37
+var ResultSuccess = StringResult{success: true}
38
+
39
+// ResultFailure returns a failed Result with a failure message.
40
+func ResultFailure(message string) StringResult {
41
+	return StringResult{message: message}
42
+}
43
+
44
+// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
45
+// is returned with the error message as the failure message.
46
+func ResultFromError(err error) Result {
47
+	if err == nil {
48
+		return ResultSuccess
49
+	}
50
+	return ResultFailure(err.Error())
51
+}
52
+
53
+type templatedResult struct {
54
+	success  bool
55
+	template string
56
+	data     map[string]interface{}
57
+}
58
+
59
+func (r templatedResult) Success() bool {
60
+	return r.success
61
+}
62
+
63
+func (r templatedResult) FailureMessage(args []ast.Expr) string {
64
+	msg, err := renderMessage(r, args)
65
+	if err != nil {
66
+		return fmt.Sprintf("failed to render failure message: %s", err)
67
+	}
68
+	return msg
69
+}
70
+
71
+// ResultFailureTemplate returns a Result with a template string and data which
72
+// can be used to format a failure message. The template may access data from .Data,
73
+// the comparison args with the callArg function, and the formatNode function may
74
+// be used to format the call args.
75
+func ResultFailureTemplate(template string, data map[string]interface{}) Result {
76
+	return templatedResult{template: template, data: data}
77
+}
78
+
79
+func renderMessage(result templatedResult, args []ast.Expr) (string, error) {
80
+	tmpl := template.New("failure").Funcs(template.FuncMap{
81
+		"formatNode": source.FormatNode,
82
+		"callArg": func(index int) ast.Expr {
83
+			if index >= len(args) {
84
+				return nil
85
+			}
86
+			return args[index]
87
+		},
88
+	})
89
+	var err error
90
+	tmpl, err = tmpl.Parse(result.template)
91
+	if err != nil {
92
+		return "", err
93
+	}
94
+	buf := new(bytes.Buffer)
95
+	err = tmpl.Execute(buf, map[string]interface{}{
96
+		"Data": result.data,
97
+	})
98
+	return buf.String(), err
99
+}
0 100
new file mode 100644
... ...
@@ -0,0 +1,106 @@
0
+package assert
1
+
2
+import (
3
+	"fmt"
4
+	"go/ast"
5
+
6
+	"gotest.tools/v3/assert/cmp"
7
+	"gotest.tools/v3/internal/format"
8
+	"gotest.tools/v3/internal/source"
9
+)
10
+
11
+func runComparison(
12
+	t TestingT,
13
+	argSelector argSelector,
14
+	f cmp.Comparison,
15
+	msgAndArgs ...interface{},
16
+) bool {
17
+	if ht, ok := t.(helperT); ok {
18
+		ht.Helper()
19
+	}
20
+	result := f()
21
+	if result.Success() {
22
+		return true
23
+	}
24
+
25
+	var message string
26
+	switch typed := result.(type) {
27
+	case resultWithComparisonArgs:
28
+		const stackIndex = 3 // Assert/Check, assert, runComparison
29
+		args, err := source.CallExprArgs(stackIndex)
30
+		if err != nil {
31
+			t.Log(err.Error())
32
+		}
33
+		message = typed.FailureMessage(filterPrintableExpr(argSelector(args)))
34
+	case resultBasic:
35
+		message = typed.FailureMessage()
36
+	default:
37
+		message = fmt.Sprintf("comparison returned invalid Result type: %T", result)
38
+	}
39
+
40
+	t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
41
+	return false
42
+}
43
+
44
+type resultWithComparisonArgs interface {
45
+	FailureMessage(args []ast.Expr) string
46
+}
47
+
48
+type resultBasic interface {
49
+	FailureMessage() string
50
+}
51
+
52
+// filterPrintableExpr filters the ast.Expr slice to only include Expr that are
53
+// easy to read when printed and contain relevant information to an assertion.
54
+//
55
+// Ident and SelectorExpr are included because they print nicely and the variable
56
+// names may provide additional context to their values.
57
+// BasicLit and CompositeLit are excluded because their source is equivalent to
58
+// their value, which is already available.
59
+// Other types are ignored for now, but could be added if they are relevant.
60
+func filterPrintableExpr(args []ast.Expr) []ast.Expr {
61
+	result := make([]ast.Expr, len(args))
62
+	for i, arg := range args {
63
+		if isShortPrintableExpr(arg) {
64
+			result[i] = arg
65
+			continue
66
+		}
67
+
68
+		if starExpr, ok := arg.(*ast.StarExpr); ok {
69
+			result[i] = starExpr.X
70
+			continue
71
+		}
72
+	}
73
+	return result
74
+}
75
+
76
+func isShortPrintableExpr(expr ast.Expr) bool {
77
+	switch expr.(type) {
78
+	case *ast.Ident, *ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr:
79
+		return true
80
+	case *ast.BinaryExpr, *ast.UnaryExpr:
81
+		return true
82
+	default:
83
+		// CallExpr, ParenExpr, TypeAssertExpr, KeyValueExpr, StarExpr
84
+		return false
85
+	}
86
+}
87
+
88
+type argSelector func([]ast.Expr) []ast.Expr
89
+
90
+func argsAfterT(args []ast.Expr) []ast.Expr {
91
+	if len(args) < 1 {
92
+		return nil
93
+	}
94
+	return args[1:]
95
+}
96
+
97
+func argsFromComparisonCall(args []ast.Expr) []ast.Expr {
98
+	if len(args) < 1 {
99
+		return nil
100
+	}
101
+	if callExpr, ok := args[1].(*ast.CallExpr); ok {
102
+		return callExpr.Args
103
+	}
104
+	return nil
105
+}
0 106
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+module gotest.tools/v3
1
+
2
+require (
3
+	github.com/google/go-cmp v0.3.0
4
+	github.com/pkg/errors v0.8.1
5
+	github.com/spf13/pflag v1.0.3
6
+	golang.org/x/tools v0.0.0-20190624222133-a101b041ded4
7
+)
8
+
9
+go 1.11
0 10
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+Copyright (c) 2013, Patrick Mezard
1
+All rights reserved.
2
+
3
+Redistribution and use in source and binary forms, with or without
4
+modification, are permitted provided that the following conditions are
5
+met:
6
+
7
+    Redistributions of source code must retain the above copyright
8
+notice, this list of conditions and the following disclaimer.
9
+    Redistributions in binary form must reproduce the above copyright
10
+notice, this list of conditions and the following disclaimer in the
11
+documentation and/or other materials provided with the distribution.
12
+    The names of its contributors may not be used to endorse or promote
13
+products derived from this software without specific prior written
14
+permission.
15
+
16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
17
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 27
new file mode 100644
... ...
@@ -0,0 +1,423 @@
0
+/*Package difflib is a partial port of Python difflib module.
1
+
2
+Original source: https://github.com/pmezard/go-difflib
3
+
4
+This file is trimmed to only the parts used by this repository.
5
+*/
6
+package difflib // import "gotest.tools/v3/internal/difflib"
7
+
8
+func min(a, b int) int {
9
+	if a < b {
10
+		return a
11
+	}
12
+	return b
13
+}
14
+
15
+func max(a, b int) int {
16
+	if a > b {
17
+		return a
18
+	}
19
+	return b
20
+}
21
+
22
+// Match stores line numbers of size of match
23
+type Match struct {
24
+	A    int
25
+	B    int
26
+	Size int
27
+}
28
+
29
+// OpCode identifies the type of diff
30
+type OpCode struct {
31
+	Tag byte
32
+	I1  int
33
+	I2  int
34
+	J1  int
35
+	J2  int
36
+}
37
+
38
+// SequenceMatcher compares sequence of strings. The basic
39
+// algorithm predates, and is a little fancier than, an algorithm
40
+// published in the late 1980's by Ratcliff and Obershelp under the
41
+// hyperbolic name "gestalt pattern matching".  The basic idea is to find
42
+// the longest contiguous matching subsequence that contains no "junk"
43
+// elements (R-O doesn't address junk).  The same idea is then applied
44
+// recursively to the pieces of the sequences to the left and to the right
45
+// of the matching subsequence.  This does not yield minimal edit
46
+// sequences, but does tend to yield matches that "look right" to people.
47
+//
48
+// SequenceMatcher tries to compute a "human-friendly diff" between two
49
+// sequences.  Unlike e.g. UNIX(tm) diff, the fundamental notion is the
50
+// longest *contiguous* & junk-free matching subsequence.  That's what
51
+// catches peoples' eyes.  The Windows(tm) windiff has another interesting
52
+// notion, pairing up elements that appear uniquely in each sequence.
53
+// That, and the method here, appear to yield more intuitive difference
54
+// reports than does diff.  This method appears to be the least vulnerable
55
+// to synching up on blocks of "junk lines", though (like blank lines in
56
+// ordinary text files, or maybe "<P>" lines in HTML files).  That may be
57
+// because this is the only method of the 3 that has a *concept* of
58
+// "junk" <wink>.
59
+//
60
+// Timing:  Basic R-O is cubic time worst case and quadratic time expected
61
+// case.  SequenceMatcher is quadratic time for the worst case and has
62
+// expected-case behavior dependent in a complicated way on how many
63
+// elements the sequences have in common; best case time is linear.
64
+type SequenceMatcher struct {
65
+	a              []string
66
+	b              []string
67
+	b2j            map[string][]int
68
+	IsJunk         func(string) bool
69
+	autoJunk       bool
70
+	bJunk          map[string]struct{}
71
+	matchingBlocks []Match
72
+	fullBCount     map[string]int
73
+	bPopular       map[string]struct{}
74
+	opCodes        []OpCode
75
+}
76
+
77
+// NewMatcher returns a new SequenceMatcher
78
+func NewMatcher(a, b []string) *SequenceMatcher {
79
+	m := SequenceMatcher{autoJunk: true}
80
+	m.SetSeqs(a, b)
81
+	return &m
82
+}
83
+
84
+// SetSeqs sets two sequences to be compared.
85
+func (m *SequenceMatcher) SetSeqs(a, b []string) {
86
+	m.SetSeq1(a)
87
+	m.SetSeq2(b)
88
+}
89
+
90
+// SetSeq1 sets the first sequence to be compared. The second sequence to be compared is
91
+// not changed.
92
+//
93
+// SequenceMatcher computes and caches detailed information about the second
94
+// sequence, so if you want to compare one sequence S against many sequences,
95
+// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
96
+// sequences.
97
+//
98
+// See also SetSeqs() and SetSeq2().
99
+func (m *SequenceMatcher) SetSeq1(a []string) {
100
+	if &a == &m.a {
101
+		return
102
+	}
103
+	m.a = a
104
+	m.matchingBlocks = nil
105
+	m.opCodes = nil
106
+}
107
+
108
+// SetSeq2 sets the second sequence to be compared. The first sequence to be compared is
109
+// not changed.
110
+func (m *SequenceMatcher) SetSeq2(b []string) {
111
+	if &b == &m.b {
112
+		return
113
+	}
114
+	m.b = b
115
+	m.matchingBlocks = nil
116
+	m.opCodes = nil
117
+	m.fullBCount = nil
118
+	m.chainB()
119
+}
120
+
121
+func (m *SequenceMatcher) chainB() {
122
+	// Populate line -> index mapping
123
+	b2j := map[string][]int{}
124
+	for i, s := range m.b {
125
+		indices := b2j[s]
126
+		indices = append(indices, i)
127
+		b2j[s] = indices
128
+	}
129
+
130
+	// Purge junk elements
131
+	m.bJunk = map[string]struct{}{}
132
+	if m.IsJunk != nil {
133
+		junk := m.bJunk
134
+		for s := range b2j {
135
+			if m.IsJunk(s) {
136
+				junk[s] = struct{}{}
137
+			}
138
+		}
139
+		for s := range junk {
140
+			delete(b2j, s)
141
+		}
142
+	}
143
+
144
+	// Purge remaining popular elements
145
+	popular := map[string]struct{}{}
146
+	n := len(m.b)
147
+	if m.autoJunk && n >= 200 {
148
+		ntest := n/100 + 1
149
+		for s, indices := range b2j {
150
+			if len(indices) > ntest {
151
+				popular[s] = struct{}{}
152
+			}
153
+		}
154
+		for s := range popular {
155
+			delete(b2j, s)
156
+		}
157
+	}
158
+	m.bPopular = popular
159
+	m.b2j = b2j
160
+}
161
+
162
+func (m *SequenceMatcher) isBJunk(s string) bool {
163
+	_, ok := m.bJunk[s]
164
+	return ok
165
+}
166
+
167
+// Find longest matching block in a[alo:ahi] and b[blo:bhi].
168
+//
169
+// If IsJunk is not defined:
170
+//
171
+// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
172
+//     alo <= i <= i+k <= ahi
173
+//     blo <= j <= j+k <= bhi
174
+// and for all (i',j',k') meeting those conditions,
175
+//     k >= k'
176
+//     i <= i'
177
+//     and if i == i', j <= j'
178
+//
179
+// In other words, of all maximal matching blocks, return one that
180
+// starts earliest in a, and of all those maximal matching blocks that
181
+// start earliest in a, return the one that starts earliest in b.
182
+//
183
+// If IsJunk is defined, first the longest matching block is
184
+// determined as above, but with the additional restriction that no
185
+// junk element appears in the block.  Then that block is extended as
186
+// far as possible by matching (only) junk elements on both sides.  So
187
+// the resulting block never matches on junk except as identical junk
188
+// happens to be adjacent to an "interesting" match.
189
+//
190
+// If no blocks match, return (alo, blo, 0).
191
+func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
192
+	// CAUTION:  stripping common prefix or suffix would be incorrect.
193
+	// E.g.,
194
+	//    ab
195
+	//    acab
196
+	// Longest matching block is "ab", but if common prefix is
197
+	// stripped, it's "a" (tied with "b").  UNIX(tm) diff does so
198
+	// strip, so ends up claiming that ab is changed to acab by
199
+	// inserting "ca" in the middle.  That's minimal but unintuitive:
200
+	// "it's obvious" that someone inserted "ac" at the front.
201
+	// Windiff ends up at the same place as diff, but by pairing up
202
+	// the unique 'b's and then matching the first two 'a's.
203
+	besti, bestj, bestsize := alo, blo, 0
204
+
205
+	// find longest junk-free match
206
+	// during an iteration of the loop, j2len[j] = length of longest
207
+	// junk-free match ending with a[i-1] and b[j]
208
+	j2len := map[int]int{}
209
+	for i := alo; i != ahi; i++ {
210
+		// look at all instances of a[i] in b; note that because
211
+		// b2j has no junk keys, the loop is skipped if a[i] is junk
212
+		newj2len := map[int]int{}
213
+		for _, j := range m.b2j[m.a[i]] {
214
+			// a[i] matches b[j]
215
+			if j < blo {
216
+				continue
217
+			}
218
+			if j >= bhi {
219
+				break
220
+			}
221
+			k := j2len[j-1] + 1
222
+			newj2len[j] = k
223
+			if k > bestsize {
224
+				besti, bestj, bestsize = i-k+1, j-k+1, k
225
+			}
226
+		}
227
+		j2len = newj2len
228
+	}
229
+
230
+	// Extend the best by non-junk elements on each end.  In particular,
231
+	// "popular" non-junk elements aren't in b2j, which greatly speeds
232
+	// the inner loop above, but also means "the best" match so far
233
+	// doesn't contain any junk *or* popular non-junk elements.
234
+	for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
235
+		m.a[besti-1] == m.b[bestj-1] {
236
+		besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
237
+	}
238
+	for besti+bestsize < ahi && bestj+bestsize < bhi &&
239
+		!m.isBJunk(m.b[bestj+bestsize]) &&
240
+		m.a[besti+bestsize] == m.b[bestj+bestsize] {
241
+		bestsize += 1
242
+	}
243
+
244
+	// Now that we have a wholly interesting match (albeit possibly
245
+	// empty!), we may as well suck up the matching junk on each
246
+	// side of it too.  Can't think of a good reason not to, and it
247
+	// saves post-processing the (possibly considerable) expense of
248
+	// figuring out what to do with it.  In the case of an empty
249
+	// interesting match, this is clearly the right thing to do,
250
+	// because no other kind of match is possible in the regions.
251
+	for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
252
+		m.a[besti-1] == m.b[bestj-1] {
253
+		besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
254
+	}
255
+	for besti+bestsize < ahi && bestj+bestsize < bhi &&
256
+		m.isBJunk(m.b[bestj+bestsize]) &&
257
+		m.a[besti+bestsize] == m.b[bestj+bestsize] {
258
+		bestsize += 1
259
+	}
260
+
261
+	return Match{A: besti, B: bestj, Size: bestsize}
262
+}
263
+
264
+// GetMatchingBlocks returns a list of triples describing matching subsequences.
265
+//
266
+// Each triple is of the form (i, j, n), and means that
267
+// a[i:i+n] == b[j:j+n].  The triples are monotonically increasing in
268
+// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
269
+// adjacent triples in the list, and the second is not the last triple in the
270
+// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
271
+// adjacent equal blocks.
272
+//
273
+// The last triple is a dummy, (len(a), len(b), 0), and is the only
274
+// triple with n==0.
275
+func (m *SequenceMatcher) GetMatchingBlocks() []Match {
276
+	if m.matchingBlocks != nil {
277
+		return m.matchingBlocks
278
+	}
279
+
280
+	var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
281
+	matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
282
+		match := m.findLongestMatch(alo, ahi, blo, bhi)
283
+		i, j, k := match.A, match.B, match.Size
284
+		if match.Size > 0 {
285
+			if alo < i && blo < j {
286
+				matched = matchBlocks(alo, i, blo, j, matched)
287
+			}
288
+			matched = append(matched, match)
289
+			if i+k < ahi && j+k < bhi {
290
+				matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
291
+			}
292
+		}
293
+		return matched
294
+	}
295
+	matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
296
+
297
+	// It's possible that we have adjacent equal blocks in the
298
+	// matching_blocks list now.
299
+	nonAdjacent := []Match{}
300
+	i1, j1, k1 := 0, 0, 0
301
+	for _, b := range matched {
302
+		// Is this block adjacent to i1, j1, k1?
303
+		i2, j2, k2 := b.A, b.B, b.Size
304
+		if i1+k1 == i2 && j1+k1 == j2 {
305
+			// Yes, so collapse them -- this just increases the length of
306
+			// the first block by the length of the second, and the first
307
+			// block so lengthened remains the block to compare against.
308
+			k1 += k2
309
+		} else {
310
+			// Not adjacent.  Remember the first block (k1==0 means it's
311
+			// the dummy we started with), and make the second block the
312
+			// new block to compare against.
313
+			if k1 > 0 {
314
+				nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
315
+			}
316
+			i1, j1, k1 = i2, j2, k2
317
+		}
318
+	}
319
+	if k1 > 0 {
320
+		nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
321
+	}
322
+
323
+	nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
324
+	m.matchingBlocks = nonAdjacent
325
+	return m.matchingBlocks
326
+}
327
+
328
+// GetOpCodes returns a list of 5-tuples describing how to turn a into b.
329
+//
330
+// Each tuple is of the form (tag, i1, i2, j1, j2).  The first tuple
331
+// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
332
+// tuple preceding it, and likewise for j1 == the previous j2.
333
+//
334
+// The tags are characters, with these meanings:
335
+//
336
+// 'r' (replace):  a[i1:i2] should be replaced by b[j1:j2]
337
+//
338
+// 'd' (delete):   a[i1:i2] should be deleted, j1==j2 in this case.
339
+//
340
+// 'i' (insert):   b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
341
+//
342
+// 'e' (equal):    a[i1:i2] == b[j1:j2]
343
+func (m *SequenceMatcher) GetOpCodes() []OpCode {
344
+	if m.opCodes != nil {
345
+		return m.opCodes
346
+	}
347
+	i, j := 0, 0
348
+	matching := m.GetMatchingBlocks()
349
+	opCodes := make([]OpCode, 0, len(matching))
350
+	for _, m := range matching {
351
+		//  invariant:  we've pumped out correct diffs to change
352
+		//  a[:i] into b[:j], and the next matching block is
353
+		//  a[ai:ai+size] == b[bj:bj+size]. So we need to pump
354
+		//  out a diff to change a[i:ai] into b[j:bj], pump out
355
+		//  the matching block, and move (i,j) beyond the match
356
+		ai, bj, size := m.A, m.B, m.Size
357
+		tag := byte(0)
358
+		if i < ai && j < bj {
359
+			tag = 'r'
360
+		} else if i < ai {
361
+			tag = 'd'
362
+		} else if j < bj {
363
+			tag = 'i'
364
+		}
365
+		if tag > 0 {
366
+			opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
367
+		}
368
+		i, j = ai+size, bj+size
369
+		// the list of matching blocks is terminated by a
370
+		// sentinel with size 0
371
+		if size > 0 {
372
+			opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
373
+		}
374
+	}
375
+	m.opCodes = opCodes
376
+	return m.opCodes
377
+}
378
+
379
+// GetGroupedOpCodes isolates change clusters by eliminating ranges with no changes.
380
+//
381
+// Return a generator of groups with up to n lines of context.
382
+// Each group is in the same format as returned by GetOpCodes().
383
+func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
384
+	if n < 0 {
385
+		n = 3
386
+	}
387
+	codes := m.GetOpCodes()
388
+	if len(codes) == 0 {
389
+		codes = []OpCode{{'e', 0, 1, 0, 1}}
390
+	}
391
+	// Fixup leading and trailing groups if they show no changes.
392
+	if codes[0].Tag == 'e' {
393
+		c := codes[0]
394
+		i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
395
+		codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
396
+	}
397
+	if codes[len(codes)-1].Tag == 'e' {
398
+		c := codes[len(codes)-1]
399
+		i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
400
+		codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
401
+	}
402
+	nn := n + n
403
+	groups := [][]OpCode{}
404
+	group := []OpCode{}
405
+	for _, c := range codes {
406
+		i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
407
+		// End the current group and start a new one whenever
408
+		// there is a large range with no changes.
409
+		if c.Tag == 'e' && i2-i1 > nn {
410
+			group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
411
+				j1, min(j2, j1+n)})
412
+			groups = append(groups, group)
413
+			group = []OpCode{}
414
+			i1, j1 = max(i1, i2-n), max(j1, j2-n)
415
+		}
416
+		group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
417
+	}
418
+	if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
419
+		groups = append(groups, group)
420
+	}
421
+	return groups
422
+}
0 423
new file mode 100644
... ...
@@ -0,0 +1,161 @@
0
+package format
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"strings"
6
+	"unicode"
7
+
8
+	"gotest.tools/v3/internal/difflib"
9
+)
10
+
11
+const (
12
+	contextLines = 2
13
+)
14
+
15
+// DiffConfig for a unified diff
16
+type DiffConfig struct {
17
+	A    string
18
+	B    string
19
+	From string
20
+	To   string
21
+}
22
+
23
+// UnifiedDiff is a modified version of difflib.WriteUnifiedDiff with better
24
+// support for showing the whitespace differences.
25
+func UnifiedDiff(conf DiffConfig) string {
26
+	a := strings.SplitAfter(conf.A, "\n")
27
+	b := strings.SplitAfter(conf.B, "\n")
28
+	groups := difflib.NewMatcher(a, b).GetGroupedOpCodes(contextLines)
29
+	if len(groups) == 0 {
30
+		return ""
31
+	}
32
+
33
+	buf := new(bytes.Buffer)
34
+	writeFormat := func(format string, args ...interface{}) {
35
+		buf.WriteString(fmt.Sprintf(format, args...))
36
+	}
37
+	writeLine := func(prefix string, s string) {
38
+		buf.WriteString(prefix + s)
39
+	}
40
+	if hasWhitespaceDiffLines(groups, a, b) {
41
+		writeLine = visibleWhitespaceLine(writeLine)
42
+	}
43
+	formatHeader(writeFormat, conf)
44
+	for _, group := range groups {
45
+		formatRangeLine(writeFormat, group)
46
+		for _, opCode := range group {
47
+			in, out := a[opCode.I1:opCode.I2], b[opCode.J1:opCode.J2]
48
+			switch opCode.Tag {
49
+			case 'e':
50
+				formatLines(writeLine, " ", in)
51
+			case 'r':
52
+				formatLines(writeLine, "-", in)
53
+				formatLines(writeLine, "+", out)
54
+			case 'd':
55
+				formatLines(writeLine, "-", in)
56
+			case 'i':
57
+				formatLines(writeLine, "+", out)
58
+			}
59
+		}
60
+	}
61
+	return buf.String()
62
+}
63
+
64
+// hasWhitespaceDiffLines returns true if any diff groups is only different
65
+// because of whitespace characters.
66
+func hasWhitespaceDiffLines(groups [][]difflib.OpCode, a, b []string) bool {
67
+	for _, group := range groups {
68
+		in, out := new(bytes.Buffer), new(bytes.Buffer)
69
+		for _, opCode := range group {
70
+			if opCode.Tag == 'e' {
71
+				continue
72
+			}
73
+			for _, line := range a[opCode.I1:opCode.I2] {
74
+				in.WriteString(line)
75
+			}
76
+			for _, line := range b[opCode.J1:opCode.J2] {
77
+				out.WriteString(line)
78
+			}
79
+		}
80
+		if removeWhitespace(in.String()) == removeWhitespace(out.String()) {
81
+			return true
82
+		}
83
+	}
84
+	return false
85
+}
86
+
87
+func removeWhitespace(s string) string {
88
+	var result []rune
89
+	for _, r := range s {
90
+		if !unicode.IsSpace(r) {
91
+			result = append(result, r)
92
+		}
93
+	}
94
+	return string(result)
95
+}
96
+
97
+func visibleWhitespaceLine(ws func(string, string)) func(string, string) {
98
+	mapToVisibleSpace := func(r rune) rune {
99
+		switch r {
100
+		case '\n':
101
+		case ' ':
102
+			return '·'
103
+		case '\t':
104
+			return '▷'
105
+		case '\v':
106
+			return '▽'
107
+		case '\r':
108
+			return '↵'
109
+		case '\f':
110
+			return '↓'
111
+		default:
112
+			if unicode.IsSpace(r) {
113
+				return '�'
114
+			}
115
+		}
116
+		return r
117
+	}
118
+	return func(prefix, s string) {
119
+		ws(prefix, strings.Map(mapToVisibleSpace, s))
120
+	}
121
+}
122
+
123
+func formatHeader(wf func(string, ...interface{}), conf DiffConfig) {
124
+	if conf.From != "" || conf.To != "" {
125
+		wf("--- %s\n", conf.From)
126
+		wf("+++ %s\n", conf.To)
127
+	}
128
+}
129
+
130
+func formatRangeLine(wf func(string, ...interface{}), group []difflib.OpCode) {
131
+	first, last := group[0], group[len(group)-1]
132
+	range1 := formatRangeUnified(first.I1, last.I2)
133
+	range2 := formatRangeUnified(first.J1, last.J2)
134
+	wf("@@ -%s +%s @@\n", range1, range2)
135
+}
136
+
137
+// Convert range to the "ed" format
138
+func formatRangeUnified(start, stop int) string {
139
+	// Per the diff spec at http://www.unix.org/single_unix_specification/
140
+	beginning := start + 1 // lines start numbering with one
141
+	length := stop - start
142
+	if length == 1 {
143
+		return fmt.Sprintf("%d", beginning)
144
+	}
145
+	if length == 0 {
146
+		beginning-- // empty ranges begin at line just before the range
147
+	}
148
+	return fmt.Sprintf("%d,%d", beginning, length)
149
+}
150
+
151
+func formatLines(writeLine func(string, string), prefix string, lines []string) {
152
+	for _, line := range lines {
153
+		writeLine(prefix, line)
154
+	}
155
+	// Add a newline if the last line is missing one so that the diff displays
156
+	// properly.
157
+	if !strings.HasSuffix(lines[len(lines)-1], "\n") {
158
+		writeLine("", "\n")
159
+	}
160
+}
0 161
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+package format // import "gotest.tools/v3/internal/format"
1
+
2
+import "fmt"
3
+
4
+// Message accepts a msgAndArgs varargs and formats it using fmt.Sprintf
5
+func Message(msgAndArgs ...interface{}) string {
6
+	switch len(msgAndArgs) {
7
+	case 0:
8
+		return ""
9
+	case 1:
10
+		return fmt.Sprintf("%v", msgAndArgs[0])
11
+	default:
12
+		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
13
+	}
14
+}
15
+
16
+// WithCustomMessage accepts one or two messages and formats them appropriately
17
+func WithCustomMessage(source string, msgAndArgs ...interface{}) string {
18
+	custom := Message(msgAndArgs...)
19
+	switch {
20
+	case custom == "":
21
+		return source
22
+	case source == "":
23
+		return custom
24
+	}
25
+	return fmt.Sprintf("%s: %s", source, custom)
26
+}
0 27
new file mode 100644
... ...
@@ -0,0 +1,53 @@
0
+package source
1
+
2
+import (
3
+	"go/ast"
4
+	"go/token"
5
+
6
+	"github.com/pkg/errors"
7
+)
8
+
9
+func scanToDeferLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
10
+	var matchedNode ast.Node
11
+	ast.Inspect(node, func(node ast.Node) bool {
12
+		switch {
13
+		case node == nil || matchedNode != nil:
14
+			return false
15
+		case fileset.Position(node.End()).Line == lineNum:
16
+			if funcLit, ok := node.(*ast.FuncLit); ok {
17
+				matchedNode = funcLit
18
+				return false
19
+			}
20
+		}
21
+		return true
22
+	})
23
+	debug("defer line node: %s", debugFormatNode{matchedNode})
24
+	return matchedNode
25
+}
26
+
27
+func guessDefer(node ast.Node) (ast.Node, error) {
28
+	defers := collectDefers(node)
29
+	switch len(defers) {
30
+	case 0:
31
+		return nil, errors.New("failed to expression in defer")
32
+	case 1:
33
+		return defers[0].Call, nil
34
+	default:
35
+		return nil, errors.Errorf(
36
+			"ambiguous call expression: multiple (%d) defers in call block",
37
+			len(defers))
38
+	}
39
+}
40
+
41
+func collectDefers(node ast.Node) []*ast.DeferStmt {
42
+	var defers []*ast.DeferStmt
43
+	ast.Inspect(node, func(node ast.Node) bool {
44
+		if d, ok := node.(*ast.DeferStmt); ok {
45
+			defers = append(defers, d)
46
+			debug("defer: %s", debugFormatNode{d})
47
+			return false
48
+		}
49
+		return true
50
+	})
51
+	return defers
52
+}
0 53
new file mode 100644
... ...
@@ -0,0 +1,170 @@
0
+package source // import "gotest.tools/v3/internal/source"
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"go/ast"
6
+	"go/format"
7
+	"go/parser"
8
+	"go/token"
9
+	"os"
10
+	"runtime"
11
+	"strconv"
12
+	"strings"
13
+
14
+	"github.com/pkg/errors"
15
+)
16
+
17
+const baseStackIndex = 1
18
+
19
+// FormattedCallExprArg returns the argument from an ast.CallExpr at the
20
+// index in the call stack. The argument is formatted using FormatNode.
21
+func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
22
+	args, err := CallExprArgs(stackIndex + 1)
23
+	if err != nil {
24
+		return "", err
25
+	}
26
+	if argPos >= len(args) {
27
+		return "", errors.New("failed to find expression")
28
+	}
29
+	return FormatNode(args[argPos])
30
+}
31
+
32
+// CallExprArgs returns the ast.Expr slice for the args of an ast.CallExpr at
33
+// the index in the call stack.
34
+func CallExprArgs(stackIndex int) ([]ast.Expr, error) {
35
+	_, filename, lineNum, ok := runtime.Caller(baseStackIndex + stackIndex)
36
+	if !ok {
37
+		return nil, errors.New("failed to get call stack")
38
+	}
39
+	debug("call stack position: %s:%d", filename, lineNum)
40
+
41
+	node, err := getNodeAtLine(filename, lineNum)
42
+	if err != nil {
43
+		return nil, err
44
+	}
45
+	debug("found node: %s", debugFormatNode{node})
46
+
47
+	return getCallExprArgs(node)
48
+}
49
+
50
+func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
51
+	fileset := token.NewFileSet()
52
+	astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
53
+	if err != nil {
54
+		return nil, errors.Wrapf(err, "failed to parse source file: %s", filename)
55
+	}
56
+
57
+	if node := scanToLine(fileset, astFile, lineNum); node != nil {
58
+		return node, nil
59
+	}
60
+	if node := scanToDeferLine(fileset, astFile, lineNum); node != nil {
61
+		node, err := guessDefer(node)
62
+		if err != nil || node != nil {
63
+			return node, err
64
+		}
65
+	}
66
+	return nil, errors.Errorf(
67
+		"failed to find an expression on line %d in %s", lineNum, filename)
68
+}
69
+
70
+func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
71
+	var matchedNode ast.Node
72
+	ast.Inspect(node, func(node ast.Node) bool {
73
+		switch {
74
+		case node == nil || matchedNode != nil:
75
+			return false
76
+		case nodePosition(fileset, node).Line == lineNum:
77
+			matchedNode = node
78
+			return false
79
+		}
80
+		return true
81
+	})
82
+	return matchedNode
83
+}
84
+
85
+// In golang 1.9 the line number changed from being the line where the statement
86
+// ended to the line where the statement began.
87
+func nodePosition(fileset *token.FileSet, node ast.Node) token.Position {
88
+	if goVersionBefore19 {
89
+		return fileset.Position(node.End())
90
+	}
91
+	return fileset.Position(node.Pos())
92
+}
93
+
94
+// GoVersionLessThan returns true if runtime.Version() is semantically less than
95
+// version 1.minor.
96
+func GoVersionLessThan(minor int64) bool {
97
+	version := runtime.Version()
98
+	// not a release version
99
+	if !strings.HasPrefix(version, "go") {
100
+		return false
101
+	}
102
+	version = strings.TrimPrefix(version, "go")
103
+	parts := strings.Split(version, ".")
104
+	if len(parts) < 2 {
105
+		return false
106
+	}
107
+	actual, err := strconv.ParseInt(parts[1], 10, 32)
108
+	return err == nil && parts[0] == "1" && actual < minor
109
+}
110
+
111
+var goVersionBefore19 = GoVersionLessThan(9)
112
+
113
+func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
114
+	visitor := &callExprVisitor{}
115
+	ast.Walk(visitor, node)
116
+	if visitor.expr == nil {
117
+		return nil, errors.New("failed to find call expression")
118
+	}
119
+	debug("callExpr: %s", debugFormatNode{visitor.expr})
120
+	return visitor.expr.Args, nil
121
+}
122
+
123
+type callExprVisitor struct {
124
+	expr *ast.CallExpr
125
+}
126
+
127
+func (v *callExprVisitor) Visit(node ast.Node) ast.Visitor {
128
+	if v.expr != nil || node == nil {
129
+		return nil
130
+	}
131
+	debug("visit: %s", debugFormatNode{node})
132
+
133
+	switch typed := node.(type) {
134
+	case *ast.CallExpr:
135
+		v.expr = typed
136
+		return nil
137
+	case *ast.DeferStmt:
138
+		ast.Walk(v, typed.Call.Fun)
139
+		return nil
140
+	}
141
+	return v
142
+}
143
+
144
+// FormatNode using go/format.Node and return the result as a string
145
+func FormatNode(node ast.Node) (string, error) {
146
+	buf := new(bytes.Buffer)
147
+	err := format.Node(buf, token.NewFileSet(), node)
148
+	return buf.String(), err
149
+}
150
+
151
+var debugEnabled = os.Getenv("GOTESTTOOLS_DEBUG") != ""
152
+
153
+func debug(format string, args ...interface{}) {
154
+	if debugEnabled {
155
+		fmt.Fprintf(os.Stderr, "DEBUG: "+format+"\n", args...)
156
+	}
157
+}
158
+
159
+type debugFormatNode struct {
160
+	ast.Node
161
+}
162
+
163
+func (n debugFormatNode) String() string {
164
+	out, err := FormatNode(n.Node)
165
+	if err != nil {
166
+		return fmt.Sprintf("failed to format %s: %s", n.Node, err)
167
+	}
168
+	return fmt.Sprintf("(%T) %s", n.Node, out)
169
+}
0 170
new file mode 100644
... ...
@@ -0,0 +1,39 @@
0
+package poll
1
+
2
+import (
3
+	"net"
4
+	"os"
5
+)
6
+
7
+// Check is a function which will be used as check for the WaitOn method.
8
+type Check func(t LogT) Result
9
+
10
+// FileExists looks on filesystem and check that path exists.
11
+func FileExists(path string) Check {
12
+	return func(t LogT) Result {
13
+		_, err := os.Stat(path)
14
+		if os.IsNotExist(err) {
15
+			t.Logf("waiting on file %s to exist", path)
16
+			return Continue("file %s does not exist", path)
17
+		}
18
+		if err != nil {
19
+			return Error(err)
20
+		}
21
+
22
+		return Success()
23
+	}
24
+}
25
+
26
+// Connection try to open a connection to the address on the
27
+// named network. See net.Dial for a description of the network and
28
+// address parameters.
29
+func Connection(network, address string) Check {
30
+	return func(t LogT) Result {
31
+		_, err := net.Dial(network, address)
32
+		if err != nil {
33
+			t.Logf("waiting on socket %s://%s to be available...", network, address)
34
+			return Continue("socket %s://%s not available", network, address)
35
+		}
36
+		return Success()
37
+	}
38
+}
0 39
new file mode 100644
... ...
@@ -0,0 +1,140 @@
0
+/*Package poll provides tools for testing asynchronous code.
1
+ */
2
+package poll // import "gotest.tools/v3/poll"
3
+
4
+import (
5
+	"fmt"
6
+	"time"
7
+)
8
+
9
+// TestingT is the subset of testing.T used by WaitOn
10
+type TestingT interface {
11
+	LogT
12
+	Fatalf(format string, args ...interface{})
13
+}
14
+
15
+// LogT is a logging interface that is passed to the WaitOn check function
16
+type LogT interface {
17
+	Log(args ...interface{})
18
+	Logf(format string, args ...interface{})
19
+}
20
+
21
+type helperT interface {
22
+	Helper()
23
+}
24
+
25
+// Settings are used to configure the behaviour of WaitOn
26
+type Settings struct {
27
+	// Timeout is the maximum time to wait for the condition. Defaults to 10s.
28
+	Timeout time.Duration
29
+	// Delay is the time to sleep between checking the condition. Defaults to
30
+	// 100ms.
31
+	Delay time.Duration
32
+}
33
+
34
+func defaultConfig() *Settings {
35
+	return &Settings{Timeout: 10 * time.Second, Delay: 100 * time.Millisecond}
36
+}
37
+
38
+// SettingOp is a function which accepts and modifies Settings
39
+type SettingOp func(config *Settings)
40
+
41
+// WithDelay sets the delay to wait between polls
42
+func WithDelay(delay time.Duration) SettingOp {
43
+	return func(config *Settings) {
44
+		config.Delay = delay
45
+	}
46
+}
47
+
48
+// WithTimeout sets the timeout
49
+func WithTimeout(timeout time.Duration) SettingOp {
50
+	return func(config *Settings) {
51
+		config.Timeout = timeout
52
+	}
53
+}
54
+
55
+// Result of a check performed by WaitOn
56
+type Result interface {
57
+	// Error indicates that the check failed and polling should stop, and the
58
+	// the has failed
59
+	Error() error
60
+	// Done indicates that polling should stop, and the test should proceed
61
+	Done() bool
62
+	// Message provides the most recent state when polling has not completed
63
+	Message() string
64
+}
65
+
66
+type result struct {
67
+	done    bool
68
+	message string
69
+	err     error
70
+}
71
+
72
+func (r result) Done() bool {
73
+	return r.done
74
+}
75
+
76
+func (r result) Message() string {
77
+	return r.message
78
+}
79
+
80
+func (r result) Error() error {
81
+	return r.err
82
+}
83
+
84
+// Continue returns a Result that indicates to WaitOn that it should continue
85
+// polling. The message text will be used as the failure message if the timeout
86
+// is reached.
87
+func Continue(message string, args ...interface{}) Result {
88
+	return result{message: fmt.Sprintf(message, args...)}
89
+}
90
+
91
+// Success returns a Result where Done() returns true, which indicates to WaitOn
92
+// that it should stop polling and exit without an error.
93
+func Success() Result {
94
+	return result{done: true}
95
+}
96
+
97
+// Error returns a Result that indicates to WaitOn that it should fail the test
98
+// and stop polling.
99
+func Error(err error) Result {
100
+	return result{err: err}
101
+}
102
+
103
+// WaitOn a condition or until a timeout. Poll by calling check and exit when
104
+// check returns a done Result. To fail a test and exit polling with an error
105
+// return a error result.
106
+func WaitOn(t TestingT, check Check, pollOps ...SettingOp) {
107
+	if ht, ok := t.(helperT); ok {
108
+		ht.Helper()
109
+	}
110
+	config := defaultConfig()
111
+	for _, pollOp := range pollOps {
112
+		pollOp(config)
113
+	}
114
+
115
+	var lastMessage string
116
+	after := time.After(config.Timeout)
117
+	chResult := make(chan Result)
118
+	for {
119
+		go func() {
120
+			chResult <- check(t)
121
+		}()
122
+		select {
123
+		case <-after:
124
+			if lastMessage == "" {
125
+				lastMessage = "first check never completed"
126
+			}
127
+			t.Fatalf("timeout hit after %s: %s", config.Timeout, lastMessage)
128
+		case result := <-chResult:
129
+			switch {
130
+			case result.Error() != nil:
131
+				t.Fatalf("polling check failed: %s", result.Error())
132
+			case result.Done():
133
+				return
134
+			}
135
+			time.Sleep(config.Delay)
136
+			lastMessage = result.Message()
137
+		}
138
+	}
139
+}