aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gotest.tools
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gotest.tools')
-rw-r--r--vendor/gotest.tools/LICENSE202
-rw-r--r--vendor/gotest.tools/assert/assert.go311
-rw-r--r--vendor/gotest.tools/assert/cmp/compare.go312
-rw-r--r--vendor/gotest.tools/assert/cmp/result.go94
-rw-r--r--vendor/gotest.tools/assert/result.go107
-rw-r--r--vendor/gotest.tools/internal/difflib/LICENSE27
-rw-r--r--vendor/gotest.tools/internal/difflib/difflib.go420
-rw-r--r--vendor/gotest.tools/internal/format/diff.go161
-rw-r--r--vendor/gotest.tools/internal/format/format.go27
-rw-r--r--vendor/gotest.tools/internal/source/source.go163
10 files changed, 1824 insertions, 0 deletions
diff --git a/vendor/gotest.tools/LICENSE b/vendor/gotest.tools/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/vendor/gotest.tools/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/gotest.tools/assert/assert.go b/vendor/gotest.tools/assert/assert.go
new file mode 100644
index 00000000..05d66354
--- /dev/null
+++ b/vendor/gotest.tools/assert/assert.go
@@ -0,0 +1,311 @@
+/*Package assert provides assertions for comparing expected values to actual
+values. When an assertion fails a helpful error message is printed.
+
+Assert and Check
+
+Assert() and Check() both accept a Comparison, and fail the test when the
+comparison fails. The one difference is that Assert() will end the test execution
+immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
+return the value of the comparison, then proceed with the rest of the test case.
+
+Example usage
+
+The example below shows assert used with some common types.
+
+
+ import (
+ "testing"
+
+ "gotest.tools/assert"
+ is "gotest.tools/assert/cmp"
+ )
+
+ func TestEverything(t *testing.T) {
+ // booleans
+ assert.Assert(t, ok)
+ assert.Assert(t, !missing)
+
+ // primitives
+ assert.Equal(t, count, 1)
+ assert.Equal(t, msg, "the message")
+ assert.Assert(t, total != 10) // NotEqual
+
+ // errors
+ assert.NilError(t, closer.Close())
+ assert.Error(t, err, "the exact error message")
+ assert.ErrorContains(t, err, "includes this")
+ assert.ErrorType(t, err, os.IsNotExist)
+
+ // complex types
+ assert.DeepEqual(t, result, myStruct{Name: "title"})
+ assert.Assert(t, is.Len(items, 3))
+ assert.Assert(t, len(sequence) != 0) // NotEmpty
+ assert.Assert(t, is.Contains(mapping, "key"))
+
+ // pointers and interface
+ assert.Assert(t, is.Nil(ref))
+ assert.Assert(t, ref != nil) // NotNil
+ }
+
+Comparisons
+
+Package https://godoc.org/gotest.tools/assert/cmp provides
+many common comparisons. Additional comparisons can be written to compare
+values in other ways. See the example Assert (CustomComparison).
+
+Automated migration from testify
+
+gty-migrate-from-testify is a binary which can update source code which uses
+testify assertions to use the assertions provided by this package.
+
+See http://bit.do/cmd-gty-migrate-from-testify.
+
+
+*/
+package assert // import "gotest.tools/assert"
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ gocmp "github.com/google/go-cmp/cmp"
+ "gotest.tools/assert/cmp"
+ "gotest.tools/internal/format"
+ "gotest.tools/internal/source"
+)
+
+// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
+type BoolOrComparison interface{}
+
+// TestingT is the subset of testing.T used by the assert package.
+type TestingT interface {
+ FailNow()
+ Fail()
+ Log(args ...interface{})
+}
+
+type helperT interface {
+ Helper()
+}
+
+const failureMessage = "assertion failed: "
+
+// nolint: gocyclo
+func assert(
+ t TestingT,
+ failer func(),
+ argSelector argSelector,
+ comparison BoolOrComparison,
+ msgAndArgs ...interface{},
+) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ var success bool
+ switch check := comparison.(type) {
+ case bool:
+ if check {
+ return true
+ }
+ logFailureFromBool(t, msgAndArgs...)
+
+ // Undocumented legacy comparison without Result type
+ case func() (success bool, message string):
+ success = runCompareFunc(t, check, msgAndArgs...)
+
+ case nil:
+ return true
+
+ case error:
+ msg := "error is not nil: "
+ t.Log(format.WithCustomMessage(failureMessage+msg+check.Error(), msgAndArgs...))
+
+ case cmp.Comparison:
+ success = runComparison(t, argSelector, check, msgAndArgs...)
+
+ case func() cmp.Result:
+ success = runComparison(t, argSelector, check, msgAndArgs...)
+
+ default:
+ t.Log(fmt.Sprintf("invalid Comparison: %v (%T)", check, check))
+ }
+
+ if success {
+ return true
+ }
+ failer()
+ return false
+}
+
+func runCompareFunc(
+ t TestingT,
+ f func() (success bool, message string),
+ msgAndArgs ...interface{},
+) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ if success, message := f(); !success {
+ t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
+ return false
+ }
+ return true
+}
+
+func logFailureFromBool(t TestingT, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ const stackIndex = 3 // Assert()/Check(), assert(), formatFailureFromBool()
+ const comparisonArgPos = 1
+ args, err := source.CallExprArgs(stackIndex)
+ if err != nil {
+ t.Log(err.Error())
+ return
+ }
+
+ msg, err := boolFailureMessage(args[comparisonArgPos])
+ if err != nil {
+ t.Log(err.Error())
+ msg = "expression is false"
+ }
+
+ t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
+}
+
+func boolFailureMessage(expr ast.Expr) (string, error) {
+ if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
+ x, err := source.FormatNode(binaryExpr.X)
+ if err != nil {
+ return "", err
+ }
+ y, err := source.FormatNode(binaryExpr.Y)
+ if err != nil {
+ return "", err
+ }
+ return x + " is " + y, nil
+ }
+
+ if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
+ x, err := source.FormatNode(unaryExpr.X)
+ if err != nil {
+ return "", err
+ }
+ return x + " is true", nil
+ }
+
+ formatted, err := source.FormatNode(expr)
+ if err != nil {
+ return "", err
+ }
+ return "expression is false: " + formatted, nil
+}
+
+// Assert performs a comparison. If the comparison fails the test is marked as
+// failed, a failure message is logged, and execution is stopped immediately.
+//
+// The comparison argument may be one of three types: bool, cmp.Comparison or
+// error.
+// When called with a bool the failure message will contain the literal source
+// code of the expression.
+// When called with a cmp.Comparison the comparison is responsible for producing
+// a helpful failure message.
+// When called with an error a nil value is considered success. A non-nil error
+// is a failure, and Error() is used as the failure message.
+func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsFromComparisonCall, comparison, msgAndArgs...)
+}
+
+// Check performs a comparison. If the comparison fails the test is marked as
+// failed, a failure message is logged, and Check returns false. Otherwise returns
+// true.
+//
+// See Assert for details about the comparison arg and failure messages.
+func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ return assert(t, t.Fail, argsFromComparisonCall, comparison, msgAndArgs...)
+}
+
+// NilError fails the test immediately if err is not nil.
+// This is equivalent to Assert(t, err)
+func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, err, msgAndArgs...)
+}
+
+// Equal uses the == operator to assert two values are equal and fails the test
+// if they are not equal.
+//
+// If the comparison fails Equal will use the variable names for x and y as part
+// of the failure message to identify the actual and expected values.
+//
+// If either x or y are a multi-line string the failure message will include a
+// unified diff of the two values. If the values only differ by whitespace
+// the unified diff will be augmented by replacing whitespace characters with
+// visible characters to identify the whitespace difference.
+//
+// This is equivalent to Assert(t, cmp.Equal(x, y)).
+func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.Equal(x, y), msgAndArgs...)
+}
+
+// DeepEqual uses google/go-cmp (http://bit.do/go-cmp) to assert two values are
+// equal and fails the test if they are not equal.
+//
+// Package https://godoc.org/gotest.tools/assert/opt provides some additional
+// commonly used Options.
+//
+// This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
+func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.DeepEqual(x, y, opts...))
+}
+
+// Error fails the test if err is nil, or the error message is not the expected
+// message.
+// Equivalent to Assert(t, cmp.Error(err, message)).
+func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.Error(err, message), msgAndArgs...)
+}
+
+// ErrorContains fails the test if err is nil, or the error message does not
+// contain the expected substring.
+// Equivalent to Assert(t, cmp.ErrorContains(err, substring)).
+func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...)
+}
+
+// ErrorType fails the test if err is nil, or err is not the expected type.
+//
+// Expected can be one of:
+// a func(error) bool which returns true if the error is the expected type,
+// an instance of (or a pointer to) a struct of the expected type,
+// a pointer to an interface the error is expected to implement,
+// a reflect.Type of the expected struct or interface.
+//
+// Equivalent to Assert(t, cmp.ErrorType(err, expected)).
+func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interface{}) {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ assert(t, t.FailNow, argsAfterT, cmp.ErrorType(err, expected), msgAndArgs...)
+}
diff --git a/vendor/gotest.tools/assert/cmp/compare.go b/vendor/gotest.tools/assert/cmp/compare.go
new file mode 100644
index 00000000..ae03749e
--- /dev/null
+++ b/vendor/gotest.tools/assert/cmp/compare.go
@@ -0,0 +1,312 @@
+/*Package cmp provides Comparisons for Assert and Check*/
+package cmp // import "gotest.tools/assert/cmp"
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/google/go-cmp/cmp"
+ "gotest.tools/internal/format"
+)
+
+// Comparison is a function which compares values and returns ResultSuccess if
+// the actual value matches the expected value. If the values do not match the
+// Result will contain a message about why it failed.
+type Comparison func() Result
+
+// DeepEqual compares two values using google/go-cmp (http://bit.do/go-cmp)
+// and succeeds if the values are equal.
+//
+// The comparison can be customized using comparison Options.
+// Package https://godoc.org/gotest.tools/assert/opt provides some additional
+// commonly used Options.
+func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
+ return func() (result Result) {
+ defer func() {
+ if panicmsg, handled := handleCmpPanic(recover()); handled {
+ result = ResultFailure(panicmsg)
+ }
+ }()
+ diff := cmp.Diff(x, y, opts...)
+ if diff == "" {
+ return ResultSuccess
+ }
+ return multiLineDiffResult(diff)
+ }
+}
+
+func handleCmpPanic(r interface{}) (string, bool) {
+ if r == nil {
+ return "", false
+ }
+ panicmsg, ok := r.(string)
+ if !ok {
+ panic(r)
+ }
+ switch {
+ case strings.HasPrefix(panicmsg, "cannot handle unexported field"):
+ return panicmsg, true
+ }
+ panic(r)
+}
+
+func toResult(success bool, msg string) Result {
+ if success {
+ return ResultSuccess
+ }
+ return ResultFailure(msg)
+}
+
+// Equal succeeds if x == y. See assert.Equal for full documentation.
+func Equal(x, y interface{}) Comparison {
+ return func() Result {
+ switch {
+ case x == y:
+ return ResultSuccess
+ case isMultiLineStringCompare(x, y):
+ diff := format.UnifiedDiff(format.DiffConfig{A: x.(string), B: y.(string)})
+ return multiLineDiffResult(diff)
+ }
+ return ResultFailureTemplate(`
+ {{- .Data.x}} (
+ {{- with callArg 0 }}{{ formatNode . }} {{end -}}
+ {{- printf "%T" .Data.x -}}
+ ) != {{ .Data.y}} (
+ {{- with callArg 1 }}{{ formatNode . }} {{end -}}
+ {{- printf "%T" .Data.y -}}
+ )`,
+ map[string]interface{}{"x": x, "y": y})
+ }
+}
+
+func isMultiLineStringCompare(x, y interface{}) bool {
+ strX, ok := x.(string)
+ if !ok {
+ return false
+ }
+ strY, ok := y.(string)
+ if !ok {
+ return false
+ }
+ return strings.Contains(strX, "\n") || strings.Contains(strY, "\n")
+}
+
+func multiLineDiffResult(diff string) Result {
+ return ResultFailureTemplate(`
+--- {{ with callArg 0 }}{{ formatNode . }}{{else}}←{{end}}
++++ {{ with callArg 1 }}{{ formatNode . }}{{else}}→{{end}}
+{{ .Data.diff }}`,
+ map[string]interface{}{"diff": diff})
+}
+
+// Len succeeds if the sequence has the expected length.
+func Len(seq interface{}, expected int) Comparison {
+ return func() (result Result) {
+ defer func() {
+ if e := recover(); e != nil {
+ result = ResultFailure(fmt.Sprintf("type %T does not have a length", seq))
+ }
+ }()
+ value := reflect.ValueOf(seq)
+ length := value.Len()
+ if length == expected {
+ return ResultSuccess
+ }
+ msg := fmt.Sprintf("expected %s (length %d) to have length %d", seq, length, expected)
+ return ResultFailure(msg)
+ }
+}
+
+// Contains succeeds if item is in collection. Collection may be a string, map,
+// slice, or array.
+//
+// If collection is a string, item must also be a string, and is compared using
+// strings.Contains().
+// If collection is a Map, contains will succeed if item is a key in the map.
+// If collection is a slice or array, item is compared to each item in the
+// sequence using reflect.DeepEqual().
+func Contains(collection interface{}, item interface{}) Comparison {
+ return func() Result {
+ colValue := reflect.ValueOf(collection)
+ if !colValue.IsValid() {
+ return ResultFailure(fmt.Sprintf("nil does not contain items"))
+ }
+ msg := fmt.Sprintf("%v does not contain %v", collection, item)
+
+ itemValue := reflect.ValueOf(item)
+ switch colValue.Type().Kind() {
+ case reflect.String:
+ if itemValue.Type().Kind() != reflect.String {
+ return ResultFailure("string may only contain strings")
+ }
+ return toResult(
+ strings.Contains(colValue.String(), itemValue.String()),
+ fmt.Sprintf("string %q does not contain %q", collection, item))
+
+ case reflect.Map:
+ if itemValue.Type() != colValue.Type().Key() {
+ return ResultFailure(fmt.Sprintf(
+ "%v can not contain a %v key", colValue.Type(), itemValue.Type()))
+ }
+ return toResult(colValue.MapIndex(itemValue).IsValid(), msg)
+
+ case reflect.Slice, reflect.Array:
+ for i := 0; i < colValue.Len(); i++ {
+ if reflect.DeepEqual(colValue.Index(i).Interface(), item) {
+ return ResultSuccess
+ }
+ }
+ return ResultFailure(msg)
+ default:
+ return ResultFailure(fmt.Sprintf("type %T does not contain items", collection))
+ }
+ }
+}
+
+// Panics succeeds if f() panics.
+func Panics(f func()) Comparison {
+ return func() (result Result) {
+ defer func() {
+ if err := recover(); err != nil {
+ result = ResultSuccess
+ }
+ }()
+ f()
+ return ResultFailure("did not panic")
+ }
+}
+
+// Error succeeds if err is a non-nil error, and the error message equals the
+// expected message.
+func Error(err error, message string) Comparison {
+ return func() Result {
+ switch {
+ case err == nil:
+ return ResultFailure("expected an error, got nil")
+ case err.Error() != message:
+ return ResultFailure(fmt.Sprintf(
+ "expected error %q, got %+v", message, err))
+ }
+ return ResultSuccess
+ }
+}
+
+// ErrorContains succeeds if err is a non-nil error, and the error message contains
+// the expected substring.
+func ErrorContains(err error, substring string) Comparison {
+ return func() Result {
+ switch {
+ case err == nil:
+ return ResultFailure("expected an error, got nil")
+ case !strings.Contains(err.Error(), substring):
+ return ResultFailure(fmt.Sprintf(
+ "expected error to contain %q, got %+v", substring, err))
+ }
+ return ResultSuccess
+ }
+}
+
+// Nil succeeds if obj is a nil interface, pointer, or function.
+//
+// Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,
+// maps, and channels.
+func Nil(obj interface{}) Comparison {
+ msgFunc := func(value reflect.Value) string {
+ return fmt.Sprintf("%v (type %s) is not nil", reflect.Indirect(value), value.Type())
+ }
+ return isNil(obj, msgFunc)
+}
+
+func isNil(obj interface{}, msgFunc func(reflect.Value) string) Comparison {
+ return func() Result {
+ if obj == nil {
+ return ResultSuccess
+ }
+ value := reflect.ValueOf(obj)
+ kind := value.Type().Kind()
+ if kind >= reflect.Chan && kind <= reflect.Slice {
+ if value.IsNil() {
+ return ResultSuccess
+ }
+ return ResultFailure(msgFunc(value))
+ }
+
+ return ResultFailure(fmt.Sprintf("%v (type %s) can not be nil", value, value.Type()))
+ }
+}
+
+// ErrorType succeeds if err is not nil and is of the expected type.
+//
+// Expected can be one of:
+// a func(error) bool which returns true if the error is the expected type,
+// an instance of (or a pointer to) a struct of the expected type,
+// a pointer to an interface the error is expected to implement,
+// a reflect.Type of the expected struct or interface.
+func ErrorType(err error, expected interface{}) Comparison {
+ return func() Result {
+ switch expectedType := expected.(type) {
+ case func(error) bool:
+ return cmpErrorTypeFunc(err, expectedType)
+ case reflect.Type:
+ if expectedType.Kind() == reflect.Interface {
+ return cmpErrorTypeImplementsType(err, expectedType)
+ }
+ return cmpErrorTypeEqualType(err, expectedType)
+ case nil:
+ return ResultFailure(fmt.Sprintf("invalid type for expected: nil"))
+ }
+
+ expectedType := reflect.TypeOf(expected)
+ switch {
+ case expectedType.Kind() == reflect.Struct, isPtrToStruct(expectedType):
+ return cmpErrorTypeEqualType(err, expectedType)
+ case isPtrToInterface(expectedType):
+ return cmpErrorTypeImplementsType(err, expectedType.Elem())
+ }
+ return ResultFailure(fmt.Sprintf("invalid type for expected: %T", expected))
+ }
+}
+
+func cmpErrorTypeFunc(err error, f func(error) bool) Result {
+ if f(err) {
+ return ResultSuccess
+ }
+ actual := "nil"
+ if err != nil {
+ actual = fmt.Sprintf("%s (%T)", err, err)
+ }
+ return ResultFailureTemplate(`error is {{ .Data.actual }}
+ {{- with callArg 1 }}, not {{ formatNode . }}{{end -}}`,
+ map[string]interface{}{"actual": actual})
+}
+
+func cmpErrorTypeEqualType(err error, expectedType reflect.Type) Result {
+ if err == nil {
+ return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
+ }
+ errValue := reflect.ValueOf(err)
+ if errValue.Type() == expectedType {
+ return ResultSuccess
+ }
+ return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
+}
+
+func cmpErrorTypeImplementsType(err error, expectedType reflect.Type) Result {
+ if err == nil {
+ return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
+ }
+ errValue := reflect.ValueOf(err)
+ if errValue.Type().Implements(expectedType) {
+ return ResultSuccess
+ }
+ return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
+}
+
+func isPtrToInterface(typ reflect.Type) bool {
+ return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Interface
+}
+
+func isPtrToStruct(typ reflect.Type) bool {
+ return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct
+}
diff --git a/vendor/gotest.tools/assert/cmp/result.go b/vendor/gotest.tools/assert/cmp/result.go
new file mode 100644
index 00000000..7c3c37dd
--- /dev/null
+++ b/vendor/gotest.tools/assert/cmp/result.go
@@ -0,0 +1,94 @@
+package cmp
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "text/template"
+
+ "gotest.tools/internal/source"
+)
+
+// Result of a Comparison.
+type Result interface {
+ Success() bool
+}
+
+type result struct {
+ success bool
+ message string
+}
+
+func (r result) Success() bool {
+ return r.success
+}
+
+func (r result) FailureMessage() string {
+ return r.message
+}
+
+// ResultSuccess is a constant which is returned by a ComparisonWithResult to
+// indicate success.
+var ResultSuccess = result{success: true}
+
+// ResultFailure returns a failed Result with a failure message.
+func ResultFailure(message string) Result {
+ return result{message: message}
+}
+
+// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
+// is returned with the error message as the failure message.
+func ResultFromError(err error) Result {
+ if err == nil {
+ return ResultSuccess
+ }
+ return ResultFailure(err.Error())
+}
+
+type templatedResult struct {
+ success bool
+ template string
+ data map[string]interface{}
+}
+
+func (r templatedResult) Success() bool {
+ return r.success
+}
+
+func (r templatedResult) FailureMessage(args []ast.Expr) string {
+ msg, err := renderMessage(r, args)
+ if err != nil {
+ return fmt.Sprintf("failed to render failure message: %s", err)
+ }
+ return msg
+}
+
+// ResultFailureTemplate returns a Result with a template string and data which
+// can be used to format a failure message. The template may access data from .Data,
+// the comparison args with the callArg function, and the formatNode function may
+// be used to format the call args.
+func ResultFailureTemplate(template string, data map[string]interface{}) Result {
+ return templatedResult{template: template, data: data}
+}
+
+func renderMessage(result templatedResult, args []ast.Expr) (string, error) {
+ tmpl := template.New("failure").Funcs(template.FuncMap{
+ "formatNode": source.FormatNode,
+ "callArg": func(index int) ast.Expr {
+ if index >= len(args) {
+ return nil
+ }
+ return args[index]
+ },
+ })
+ var err error
+ tmpl, err = tmpl.Parse(result.template)
+ if err != nil {
+ return "", err
+ }
+ buf := new(bytes.Buffer)
+ err = tmpl.Execute(buf, map[string]interface{}{
+ "Data": result.data,
+ })
+ return buf.String(), err
+}
diff --git a/vendor/gotest.tools/assert/result.go b/vendor/gotest.tools/assert/result.go
new file mode 100644
index 00000000..3900264d
--- /dev/null
+++ b/vendor/gotest.tools/assert/result.go
@@ -0,0 +1,107 @@
+package assert
+
+import (
+ "fmt"
+ "go/ast"
+
+ "gotest.tools/assert/cmp"
+ "gotest.tools/internal/format"
+ "gotest.tools/internal/source"
+)
+
+func runComparison(
+ t TestingT,
+ argSelector argSelector,
+ f cmp.Comparison,
+ msgAndArgs ...interface{},
+) bool {
+ if ht, ok := t.(helperT); ok {
+ ht.Helper()
+ }
+ result := f()
+ if result.Success() {
+ return true
+ }
+
+ var message string
+ switch typed := result.(type) {
+ case resultWithComparisonArgs:
+ const stackIndex = 3 // Assert/Check, assert, runComparison
+ args, err := source.CallExprArgs(stackIndex)
+ if err != nil {
+ t.Log(err.Error())
+ }
+ message = typed.FailureMessage(filterPrintableExpr(argSelector(args)))
+ case resultBasic:
+ message = typed.FailureMessage()
+ default:
+ message = fmt.Sprintf("comparison returned invalid Result type: %T", result)
+ }
+
+ t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
+ return false
+}
+
+type resultWithComparisonArgs interface {
+ FailureMessage(args []ast.Expr) string
+}
+
+type resultBasic interface {
+ FailureMessage() string
+}
+
+// filterPrintableExpr filters the ast.Expr slice to only include Expr that are
+// easy to read when printed and contain relevant information to an assertion.
+//
+// Ident and SelectorExpr are included because they print nicely and the variable
+// names may provide additional context to their values.
+// BasicLit and CompositeLit are excluded because their source is equivalent to
+// their value, which is already available.
+// Other types are ignored for now, but could be added if they are relevant.
+func filterPrintableExpr(args []ast.Expr) []ast.Expr {
+ result := make([]ast.Expr, len(args))
+ for i, arg := range args {
+ if isShortPrintableExpr(arg) {
+ result[i] = arg
+ continue
+ }
+
+ if starExpr, ok := arg.(*ast.StarExpr); ok {
+ result[i] = starExpr.X
+ continue
+ }
+ result[i] = nil
+ }
+ return result
+}
+
+func isShortPrintableExpr(expr ast.Expr) bool {
+ switch expr.(type) {
+ case *ast.Ident, *ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr:
+ return true
+ case *ast.BinaryExpr, *ast.UnaryExpr:
+ return true
+ default:
+ // CallExpr, ParenExpr, TypeAssertExpr, KeyValueExpr, StarExpr
+ return false
+ }
+}
+
+type argSelector func([]ast.Expr) []ast.Expr
+
+func argsAfterT(args []ast.Expr) []ast.Expr {
+ if len(args) < 1 {
+ return nil
+ }
+ return args[1:]
+}
+
+func argsFromComparisonCall(args []ast.Expr) []ast.Expr {
+ if len(args) < 1 {
+ return nil
+ }
+ if callExpr, ok := args[1].(*ast.CallExpr); ok {
+ return callExpr.Args
+ }
+ return nil
+}
diff --git a/vendor/gotest.tools/internal/difflib/LICENSE b/vendor/gotest.tools/internal/difflib/LICENSE
new file mode 100644
index 00000000..c67dad61
--- /dev/null
+++ b/vendor/gotest.tools/internal/difflib/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2013, Patrick Mezard
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+ The names of its contributors may not be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/gotest.tools/internal/difflib/difflib.go b/vendor/gotest.tools/internal/difflib/difflib.go
new file mode 100644
index 00000000..5efa99c1
--- /dev/null
+++ b/vendor/gotest.tools/internal/difflib/difflib.go
@@ -0,0 +1,420 @@
+/* Package difflib is a partial port of Python difflib module.
+
+Original source: https://github.com/pmezard/go-difflib
+
+This file is trimmed to only the parts used by this repository.
+*/
+package difflib // import "gotest.tools/internal/difflib"
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+type Match struct {
+ A int
+ B int
+ Size int
+}
+
+type OpCode struct {
+ Tag byte
+ I1 int
+ I2 int
+ J1 int
+ J2 int
+}
+
+// SequenceMatcher compares sequence of strings. The basic
+// algorithm predates, and is a little fancier than, an algorithm
+// published in the late 1980's by Ratcliff and Obershelp under the
+// hyperbolic name "gestalt pattern matching". The basic idea is to find
+// the longest contiguous matching subsequence that contains no "junk"
+// elements (R-O doesn't address junk). The same idea is then applied
+// recursively to the pieces of the sequences to the left and to the right
+// of the matching subsequence. This does not yield minimal edit
+// sequences, but does tend to yield matches that "look right" to people.
+//
+// SequenceMatcher tries to compute a "human-friendly diff" between two
+// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
+// longest *contiguous* & junk-free matching subsequence. That's what
+// catches peoples' eyes. The Windows(tm) windiff has another interesting
+// notion, pairing up elements that appear uniquely in each sequence.
+// That, and the method here, appear to yield more intuitive difference
+// reports than does diff. This method appears to be the least vulnerable
+// to synching up on blocks of "junk lines", though (like blank lines in
+// ordinary text files, or maybe "<P>" lines in HTML files). That may be
+// because this is the only method of the 3 that has a *concept* of
+// "junk" <wink>.
+//
+// Timing: Basic R-O is cubic time worst case and quadratic time expected
+// case. SequenceMatcher is quadratic time for the worst case and has
+// expected-case behavior dependent in a complicated way on how many
+// elements the sequences have in common; best case time is linear.
+type SequenceMatcher struct {
+ a []string
+ b []string
+ b2j map[string][]int
+ IsJunk func(string) bool
+ autoJunk bool
+ bJunk map[string]struct{}
+ matchingBlocks []Match
+ fullBCount map[string]int
+ bPopular map[string]struct{}
+ opCodes []OpCode
+}
+
+func NewMatcher(a, b []string) *SequenceMatcher {
+ m := SequenceMatcher{autoJunk: true}
+ m.SetSeqs(a, b)
+ return &m
+}
+
+// Set two sequences to be compared.
+func (m *SequenceMatcher) SetSeqs(a, b []string) {
+ m.SetSeq1(a)
+ m.SetSeq2(b)
+}
+
+// Set the first sequence to be compared. The second sequence to be compared is
+// not changed.
+//
+// SequenceMatcher computes and caches detailed information about the second
+// sequence, so if you want to compare one sequence S against many sequences,
+// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
+// sequences.
+//
+// See also SetSeqs() and SetSeq2().
+func (m *SequenceMatcher) SetSeq1(a []string) {
+ if &a == &m.a {
+ return
+ }
+ m.a = a
+ m.matchingBlocks = nil
+ m.opCodes = nil
+}
+
+// Set the second sequence to be compared. The first sequence to be compared is
+// not changed.
+func (m *SequenceMatcher) SetSeq2(b []string) {
+ if &b == &m.b {
+ return
+ }
+ m.b = b
+ m.matchingBlocks = nil
+ m.opCodes = nil
+ m.fullBCount = nil
+ m.chainB()
+}
+
+func (m *SequenceMatcher) chainB() {
+ // Populate line -> index mapping
+ b2j := map[string][]int{}
+ for i, s := range m.b {
+ indices := b2j[s]
+ indices = append(indices, i)
+ b2j[s] = indices
+ }
+
+ // Purge junk elements
+ m.bJunk = map[string]struct{}{}
+ if m.IsJunk != nil {
+ junk := m.bJunk
+ for s, _ := range b2j {
+ if m.IsJunk(s) {
+ junk[s] = struct{}{}
+ }
+ }
+ for s, _ := range junk {
+ delete(b2j, s)
+ }
+ }
+
+ // Purge remaining popular elements
+ popular := map[string]struct{}{}
+ n := len(m.b)
+ if m.autoJunk && n >= 200 {
+ ntest := n/100 + 1
+ for s, indices := range b2j {
+ if len(indices) > ntest {
+ popular[s] = struct{}{}
+ }
+ }
+ for s, _ := range popular {
+ delete(b2j, s)
+ }
+ }
+ m.bPopular = popular
+ m.b2j = b2j
+}
+
+func (m *SequenceMatcher) isBJunk(s string) bool {
+ _, ok := m.bJunk[s]
+ return ok
+}
+
+// Find longest matching block in a[alo:ahi] and b[blo:bhi].
+//
+// If IsJunk is not defined:
+//
+// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+// alo <= i <= i+k <= ahi
+// blo <= j <= j+k <= bhi
+// and for all (i',j',k') meeting those conditions,
+// k >= k'
+// i <= i'
+// and if i == i', j <= j'
+//
+// In other words, of all maximal matching blocks, return one that
+// starts earliest in a, and of all those maximal matching blocks that
+// start earliest in a, return the one that starts earliest in b.
+//
+// If IsJunk is defined, first the longest matching block is
+// determined as above, but with the additional restriction that no
+// junk element appears in the block. Then that block is extended as
+// far as possible by matching (only) junk elements on both sides. So
+// the resulting block never matches on junk except as identical junk
+// happens to be adjacent to an "interesting" match.
+//
+// If no blocks match, return (alo, blo, 0).
+func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
+ // CAUTION: stripping common prefix or suffix would be incorrect.
+ // E.g.,
+ // ab
+ // acab
+ // Longest matching block is "ab", but if common prefix is
+ // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
+ // strip, so ends up claiming that ab is changed to acab by
+ // inserting "ca" in the middle. That's minimal but unintuitive:
+ // "it's obvious" that someone inserted "ac" at the front.
+ // Windiff ends up at the same place as diff, but by pairing up
+ // the unique 'b's and then matching the first two 'a's.
+ besti, bestj, bestsize := alo, blo, 0
+
+ // find longest junk-free match
+ // during an iteration of the loop, j2len[j] = length of longest
+ // junk-free match ending with a[i-1] and b[j]
+ j2len := map[int]int{}
+ for i := alo; i != ahi; i++ {
+ // look at all instances of a[i] in b; note that because
+ // b2j has no junk keys, the loop is skipped if a[i] is junk
+ newj2len := map[int]int{}
+ for _, j := range m.b2j[m.a[i]] {
+ // a[i] matches b[j]
+ if j < blo {
+ continue
+ }
+ if j >= bhi {
+ break
+ }
+ k := j2len[j-1] + 1
+ newj2len[j] = k
+ if k > bestsize {
+ besti, bestj, bestsize = i-k+1, j-k+1, k
+ }
+ }
+ j2len = newj2len
+ }
+
+ // Extend the best by non-junk elements on each end. In particular,
+ // "popular" non-junk elements aren't in b2j, which greatly speeds
+ // the inner loop above, but also means "the best" match so far
+ // doesn't contain any junk *or* popular non-junk elements.
+ for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
+ m.a[besti-1] == m.b[bestj-1] {
+ besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+ }
+ for besti+bestsize < ahi && bestj+bestsize < bhi &&
+ !m.isBJunk(m.b[bestj+bestsize]) &&
+ m.a[besti+bestsize] == m.b[bestj+bestsize] {
+ bestsize += 1
+ }
+
+ // Now that we have a wholly interesting match (albeit possibly
+ // empty!), we may as well suck up the matching junk on each
+ // side of it too. Can't think of a good reason not to, and it
+ // saves post-processing the (possibly considerable) expense of
+ // figuring out what to do with it. In the case of an empty
+ // interesting match, this is clearly the right thing to do,
+ // because no other kind of match is possible in the regions.
+ for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
+ m.a[besti-1] == m.b[bestj-1] {
+ besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+ }
+ for besti+bestsize < ahi && bestj+bestsize < bhi &&
+ m.isBJunk(m.b[bestj+bestsize]) &&
+ m.a[besti+bestsize] == m.b[bestj+bestsize] {
+ bestsize += 1
+ }
+
+ return Match{A: besti, B: bestj, Size: bestsize}
+}
+
+// Return list of triples describing matching subsequences.
+//
+// Each triple is of the form (i, j, n), and means that
+// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
+// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
+// adjacent triples in the list, and the second is not the last triple in the
+// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
+// adjacent equal blocks.
+//
+// The last triple is a dummy, (len(a), len(b), 0), and is the only
+// triple with n==0.
+func (m *SequenceMatcher) GetMatchingBlocks() []Match {
+ if m.matchingBlocks != nil {
+ return m.matchingBlocks
+ }
+
+ var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
+ matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
+ match := m.findLongestMatch(alo, ahi, blo, bhi)
+ i, j, k := match.A, match.B, match.Size
+ if match.Size > 0 {
+ if alo < i && blo < j {
+ matched = matchBlocks(alo, i, blo, j, matched)
+ }
+ matched = append(matched, match)
+ if i+k < ahi && j+k < bhi {
+ matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
+ }
+ }
+ return matched
+ }
+ matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
+
+ // It's possible that we have adjacent equal blocks in the
+ // matching_blocks list now.
+ nonAdjacent := []Match{}
+ i1, j1, k1 := 0, 0, 0
+ for _, b := range matched {
+ // Is this block adjacent to i1, j1, k1?
+ i2, j2, k2 := b.A, b.B, b.Size
+ if i1+k1 == i2 && j1+k1 == j2 {
+ // Yes, so collapse them -- this just increases the length of
+ // the first block by the length of the second, and the first
+ // block so lengthened remains the block to compare against.
+ k1 += k2
+ } else {
+ // Not adjacent. Remember the first block (k1==0 means it's
+ // the dummy we started with), and make the second block the
+ // new block to compare against.
+ if k1 > 0 {
+ nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+ }
+ i1, j1, k1 = i2, j2, k2
+ }
+ }
+ if k1 > 0 {
+ nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+ }
+
+ nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
+ m.matchingBlocks = nonAdjacent
+ return m.matchingBlocks
+}
+
+// Return list of 5-tuples describing how to turn a into b.
+//
+// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
+// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
+// tuple preceding it, and likewise for j1 == the previous j2.
+//
+// The tags are characters, with these meanings:
+//
+// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
+//
+// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
+//
+// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
+//
+// 'e' (equal): a[i1:i2] == b[j1:j2]
+func (m *SequenceMatcher) GetOpCodes() []OpCode {
+ if m.opCodes != nil {
+ return m.opCodes
+ }
+ i, j := 0, 0
+ matching := m.GetMatchingBlocks()
+ opCodes := make([]OpCode, 0, len(matching))
+ for _, m := range matching {
+ // invariant: we've pumped out correct diffs to change
+ // a[:i] into b[:j], and the next matching block is
+ // a[ai:ai+size] == b[bj:bj+size]. So we need to pump
+ // out a diff to change a[i:ai] into b[j:bj], pump out
+ // the matching block, and move (i,j) beyond the match
+ ai, bj, size := m.A, m.B, m.Size
+ tag := byte(0)
+ if i < ai && j < bj {
+ tag = 'r'
+ } else if i < ai {
+ tag = 'd'
+ } else if j < bj {
+ tag = 'i'
+ }
+ if tag > 0 {
+ opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
+ }
+ i, j = ai+size, bj+size
+ // the list of matching blocks is terminated by a
+ // sentinel with size 0
+ if size > 0 {
+ opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
+ }
+ }
+ m.opCodes = opCodes
+ return m.opCodes
+}
+
+// Isolate change clusters by eliminating ranges with no changes.
+//
+// Return a generator of groups with up to n lines of context.
+// Each group is in the same format as returned by GetOpCodes().
+func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
+ if n < 0 {
+ n = 3
+ }
+ codes := m.GetOpCodes()
+ if len(codes) == 0 {
+ codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
+ }
+ // Fixup leading and trailing groups if they show no changes.
+ if codes[0].Tag == 'e' {
+ c := codes[0]
+ i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+ codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
+ }
+ if codes[len(codes)-1].Tag == 'e' {
+ c := codes[len(codes)-1]
+ i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+ codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
+ }
+ nn := n + n
+ groups := [][]OpCode{}
+ group := []OpCode{}
+ for _, c := range codes {
+ i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+ // End the current group and start a new one whenever
+ // there is a large range with no changes.
+ if c.Tag == 'e' && i2-i1 > nn {
+ group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
+ j1, min(j2, j1+n)})
+ groups = append(groups, group)
+ group = []OpCode{}
+ i1, j1 = max(i1, i2-n), max(j1, j2-n)
+ }
+ group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
+ }
+ if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
+ groups = append(groups, group)
+ }
+ return groups
+}
diff --git a/vendor/gotest.tools/internal/format/diff.go b/vendor/gotest.tools/internal/format/diff.go
new file mode 100644
index 00000000..c938c97b
--- /dev/null
+++ b/vendor/gotest.tools/internal/format/diff.go
@@ -0,0 +1,161 @@
+package format
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "unicode"
+
+ "gotest.tools/internal/difflib"
+)
+
+const (
+ contextLines = 2
+)
+
+// DiffConfig for a unified diff
+type DiffConfig struct {
+ A string
+ B string
+ From string
+ To string
+}
+
+// UnifiedDiff is a modified version of difflib.WriteUnifiedDiff with better
+// support for showing the whitespace differences.
+func UnifiedDiff(conf DiffConfig) string {
+ a := strings.SplitAfter(conf.A, "\n")
+ b := strings.SplitAfter(conf.B, "\n")
+ groups := difflib.NewMatcher(a, b).GetGroupedOpCodes(contextLines)
+ if len(groups) == 0 {
+ return ""
+ }
+
+ buf := new(bytes.Buffer)
+ writeFormat := func(format string, args ...interface{}) {
+ buf.WriteString(fmt.Sprintf(format, args...))
+ }
+ writeLine := func(prefix string, s string) {
+ buf.WriteString(prefix + s)
+ }
+ if hasWhitespaceDiffLines(groups, a, b) {
+ writeLine = visibleWhitespaceLine(writeLine)
+ }
+ formatHeader(writeFormat, conf)
+ for _, group := range groups {
+ formatRangeLine(writeFormat, group)
+ for _, opCode := range group {
+ in, out := a[opCode.I1:opCode.I2], b[opCode.J1:opCode.J2]
+ switch opCode.Tag {
+ case 'e':
+ formatLines(writeLine, " ", in)
+ case 'r':
+ formatLines(writeLine, "-", in)
+ formatLines(writeLine, "+", out)
+ case 'd':
+ formatLines(writeLine, "-", in)
+ case 'i':
+ formatLines(writeLine, "+", out)
+ }
+ }
+ }
+ return buf.String()
+}
+
+// hasWhitespaceDiffLines returns true if any diff groups is only different
+// because of whitespace characters.
+func hasWhitespaceDiffLines(groups [][]difflib.OpCode, a, b []string) bool {
+ for _, group := range groups {
+ in, out := new(bytes.Buffer), new(bytes.Buffer)
+ for _, opCode := range group {
+ if opCode.Tag == 'e' {
+ continue
+ }
+ for _, line := range a[opCode.I1:opCode.I2] {
+ in.WriteString(line)
+ }
+ for _, line := range b[opCode.J1:opCode.J2] {
+ out.WriteString(line)
+ }
+ }
+ if removeWhitespace(in.String()) == removeWhitespace(out.String()) {
+ return true
+ }
+ }
+ return false
+}
+
+func removeWhitespace(s string) string {
+ var result []rune
+ for _, r := range s {
+ if !unicode.IsSpace(r) {
+ result = append(result, r)
+ }
+ }
+ return string(result)
+}
+
+func visibleWhitespaceLine(ws func(string, string)) func(string, string) {
+ mapToVisibleSpace := func(r rune) rune {
+ switch r {
+ case '\n':
+ case ' ':
+ return '·'
+ case '\t':
+ return '▷'
+ case '\v':
+ return '▽'
+ case '\r':
+ return '↵'
+ case '\f':
+ return '↓'
+ default:
+ if unicode.IsSpace(r) {
+ return '�'
+ }
+ }
+ return r
+ }
+ return func(prefix, s string) {
+ ws(prefix, strings.Map(mapToVisibleSpace, s))
+ }
+}
+
+func formatHeader(wf func(string, ...interface{}), conf DiffConfig) {
+ if conf.From != "" || conf.To != "" {
+ wf("--- %s\n", conf.From)
+ wf("+++ %s\n", conf.To)
+ }
+}
+
+func formatRangeLine(wf func(string, ...interface{}), group []difflib.OpCode) {
+ first, last := group[0], group[len(group)-1]
+ range1 := formatRangeUnified(first.I1, last.I2)
+ range2 := formatRangeUnified(first.J1, last.J2)
+ wf("@@ -%s +%s @@\n", range1, range2)
+}
+
+// Convert range to the "ed" format
+func formatRangeUnified(start, stop int) string {
+ // Per the diff spec at http://www.unix.org/single_unix_specification/
+ beginning := start + 1 // lines start numbering with one
+ length := stop - start
+ if length == 1 {
+ return fmt.Sprintf("%d", beginning)
+ }
+ if length == 0 {
+ beginning-- // empty ranges begin at line just before the range
+ }
+ return fmt.Sprintf("%d,%d", beginning, length)
+}
+
+func formatLines(writeLine func(string, string), prefix string, lines []string) {
+ for _, line := range lines {
+ writeLine(prefix, line)
+ }
+ // Add a newline if the last line is missing one so that the diff displays
+ // properly.
+ if !strings.HasSuffix(lines[len(lines)-1], "\n") {
+ writeLine("", "\n")
+ }
+}
diff --git a/vendor/gotest.tools/internal/format/format.go b/vendor/gotest.tools/internal/format/format.go
new file mode 100644
index 00000000..8f6494f9
--- /dev/null
+++ b/vendor/gotest.tools/internal/format/format.go
@@ -0,0 +1,27 @@
+package format // import "gotest.tools/internal/format"
+
+import "fmt"
+
+// Message accepts a msgAndArgs varargs and formats it using fmt.Sprintf
+func Message(msgAndArgs ...interface{}) string {
+ switch len(msgAndArgs) {
+ case 0:
+ return ""
+ case 1:
+ return fmt.Sprintf("%v", msgAndArgs[0])
+ default:
+ return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
+ }
+}
+
+// WithCustomMessage accepts one or two messages and formats them appropriately
+func WithCustomMessage(source string, msgAndArgs ...interface{}) string {
+ custom := Message(msgAndArgs...)
+ switch {
+ case custom == "":
+ return source
+ case source == "":
+ return custom
+ }
+ return fmt.Sprintf("%s: %s", source, custom)
+}
diff --git a/vendor/gotest.tools/internal/source/source.go b/vendor/gotest.tools/internal/source/source.go
new file mode 100644
index 00000000..a05933cc
--- /dev/null
+++ b/vendor/gotest.tools/internal/source/source.go
@@ -0,0 +1,163 @@
+package source // import "gotest.tools/internal/source"
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+const baseStackIndex = 1
+
+// FormattedCallExprArg returns the argument from an ast.CallExpr at the
+// index in the call stack. The argument is formatted using FormatNode.
+func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
+ args, err := CallExprArgs(stackIndex + 1)
+ if err != nil {
+ return "", err
+ }
+ return FormatNode(args[argPos])
+}
+
+func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
+ fileset := token.NewFileSet()
+ astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to parse source file: %s", filename)
+ }
+
+ node := scanToLine(fileset, astFile, lineNum)
+ if node == nil {
+ return nil, errors.Errorf(
+ "failed to find an expression on line %d in %s", lineNum, filename)
+ }
+ return node, nil
+}
+
+func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
+ v := &scanToLineVisitor{lineNum: lineNum, fileset: fileset}
+ ast.Walk(v, node)
+ return v.matchedNode
+}
+
+type scanToLineVisitor struct {
+ lineNum int
+ matchedNode ast.Node
+ fileset *token.FileSet
+}
+
+func (v *scanToLineVisitor) Visit(node ast.Node) ast.Visitor {
+ if node == nil || v.matchedNode != nil {
+ return nil
+ }
+ if v.nodePosition(node).Line == v.lineNum {
+ v.matchedNode = node
+ return nil
+ }
+ return v
+}
+
+// In golang 1.9 the line number changed from being the line where the statement
+// ended to the line where the statement began.
+func (v *scanToLineVisitor) nodePosition(node ast.Node) token.Position {
+ if goVersionBefore19 {
+ return v.fileset.Position(node.End())
+ }
+ return v.fileset.Position(node.Pos())
+}
+
+var goVersionBefore19 = isGOVersionBefore19()
+
+func isGOVersionBefore19() bool {
+ version := runtime.Version()
+ // not a release version
+ if !strings.HasPrefix(version, "go") {
+ return false
+ }
+ version = strings.TrimPrefix(version, "go")
+ parts := strings.Split(version, ".")
+ if len(parts) < 2 {
+ return false
+ }
+ minor, err := strconv.ParseInt(parts[1], 10, 32)
+ return err == nil && parts[0] == "1" && minor < 9
+}
+
+func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
+ visitor := &callExprVisitor{}
+ ast.Walk(visitor, node)
+ if visitor.expr == nil {
+ return nil, errors.New("failed to find call expression")
+ }
+ return visitor.expr.Args, nil
+}
+
+type callExprVisitor struct {
+ expr *ast.CallExpr
+}
+
+func (v *callExprVisitor) Visit(node ast.Node) ast.Visitor {
+ if v.expr != nil || node == nil {
+ return nil
+ }
+ debug("visit (%T): %s", node, debugFormatNode{node})
+
+ if callExpr, ok := node.(*ast.CallExpr); ok {
+ v.expr = callExpr
+ return nil
+ }
+ return v
+}
+
+// FormatNode using go/format.Node and return the result as a string
+func FormatNode(node ast.Node) (string, error) {
+ buf := new(bytes.Buffer)
+ err := format.Node(buf, token.NewFileSet(), node)
+ return buf.String(), err
+}
+
+// CallExprArgs returns the ast.Expr slice for the args of an ast.CallExpr at
+// the index in the call stack.
+func CallExprArgs(stackIndex int) ([]ast.Expr, error) {
+ _, filename, lineNum, ok := runtime.Caller(baseStackIndex + stackIndex)
+ if !ok {
+ return nil, errors.New("failed to get call stack")
+ }
+ debug("call stack position: %s:%d", filename, lineNum)
+
+ node, err := getNodeAtLine(filename, lineNum)
+ if err != nil {
+ return nil, err
+ }
+ debug("found node (%T): %s", node, debugFormatNode{node})
+
+ return getCallExprArgs(node)
+}
+
+var debugEnabled = os.Getenv("GOTESTYOURSELF_DEBUG") != ""
+
+func debug(format string, args ...interface{}) {
+ if debugEnabled {
+ fmt.Fprintf(os.Stderr, "DEBUG: "+format+"\n", args...)
+ }
+}
+
+type debugFormatNode struct {
+ ast.Node
+}
+
+func (n debugFormatNode) String() string {
+ out, err := FormatNode(n.Node)
+ if err != nil {
+ return fmt.Sprintf("failed to format %s: %s", n.Node, err)
+ }
+ return out
+}