Browse Source

bump gotest.tools v2.3.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 6 years ago
parent
commit
f86cac5713

+ 1 - 1
vendor.conf

@@ -19,7 +19,7 @@ golang.org/x/sys d455e41777fca6e8a5a79e34a14b8368bc11d9ba
 github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3
 github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3
 github.com/docker/go-connections 7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0
 github.com/docker/go-connections 7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0
 golang.org/x/text f21a4dfb5e38f5895301dc265a8def02365cc3d0 # v0.3.0
 golang.org/x/text f21a4dfb5e38f5895301dc265a8def02365cc3d0 # v0.3.0
-gotest.tools v2.1.0
+gotest.tools 1083505acf35a0bd8a696b26837e1fb3187a7a83 # v2.3.0
 github.com/google/go-cmp v0.2.0
 github.com/google/go-cmp v0.2.0
 
 
 github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
 github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5

+ 10 - 199
vendor/gotest.tools/LICENSE

@@ -1,202 +1,13 @@
+Copyright 2018 gotest.tools authors
 
 
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
+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
 
 
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+    http://www.apache.org/licenses/LICENSE-2.0
 
 
-   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.
+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.

+ 5 - 1
vendor/gotest.tools/README.md

@@ -3,7 +3,7 @@
 A collection of packages to augment `testing` and support common patterns.
 A collection of packages to augment `testing` and support common patterns.
 
 
 [![GoDoc](https://godoc.org/gotest.tools?status.svg)](https://godoc.org/gotest.tools)
 [![GoDoc](https://godoc.org/gotest.tools?status.svg)](https://godoc.org/gotest.tools)
-[![CircleCI](https://circleci.com/gh/gotestyourself/gotestyourself/tree/master.svg?style=shield)](https://circleci.com/gh/gotestyourself/gotestyourself/tree/master)
+[![CircleCI](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master.svg?style=shield)](https://circleci.com/gh/gotestyourself/gotest.tools/tree/master)
 [![Go Reportcard](https://goreportcard.com/badge/gotest.tools)](https://goreportcard.com/report/gotest.tools)
 [![Go Reportcard](https://goreportcard.com/badge/gotest.tools)](https://goreportcard.com/report/gotest.tools)
 
 
 
 
@@ -29,3 +29,7 @@ A collection of packages to augment `testing` and support common patterns.
 * [gotest.tools/gotestsum](https://github.com/gotestyourself/gotestsum) - go test runner with custom output
 * [gotest.tools/gotestsum](https://github.com/gotestyourself/gotestsum) - go test runner with custom output
 * [maxbrunsfeld/counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) - generate fakes for interfaces
 * [maxbrunsfeld/counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) - generate fakes for interfaces
 * [jonboulle/clockwork](https://github.com/jonboulle/clockwork) - a fake clock for testing code that uses `time`
 * [jonboulle/clockwork](https://github.com/jonboulle/clockwork) - a fake clock for testing code that uses `time`
+
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md).

+ 46 - 2
vendor/gotest.tools/assert/cmp/compare.go

@@ -4,6 +4,7 @@ package cmp // import "gotest.tools/assert/cmp"
 import (
 import (
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
+	"regexp"
 	"strings"
 	"strings"
 
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
@@ -58,6 +59,39 @@ func toResult(success bool, msg string) Result {
 	return ResultFailure(msg)
 	return ResultFailure(msg)
 }
 }
 
 
+// RegexOrPattern may be either a *regexp.Regexp or a string that is a valid
+// regexp pattern.
+type RegexOrPattern interface{}
+
+// Regexp succeeds if value v matches regular expression re.
+//
+// Example:
+//   assert.Assert(t, cmp.Regexp("^[0-9a-f]{32}$", str))
+//   r := regexp.MustCompile("^[0-9a-f]{32}$")
+//   assert.Assert(t, cmp.Regexp(r, str))
+func Regexp(re RegexOrPattern, v string) Comparison {
+	match := func(re *regexp.Regexp) Result {
+		return toResult(
+			re.MatchString(v),
+			fmt.Sprintf("value %q does not match regexp %q", v, re.String()))
+	}
+
+	return func() Result {
+		switch regex := re.(type) {
+		case *regexp.Regexp:
+			return match(regex)
+		case string:
+			re, err := regexp.Compile(regex)
+			if err != nil {
+				return ResultFailure(err.Error())
+			}
+			return match(re)
+		default:
+			return ResultFailure(fmt.Sprintf("invalid type %T for regex pattern", regex))
+		}
+	}
+}
+
 // Equal succeeds if x == y. See assert.Equal for full documentation.
 // Equal succeeds if x == y. See assert.Equal for full documentation.
 func Equal(x, y interface{}) Comparison {
 func Equal(x, y interface{}) Comparison {
 	return func() Result {
 	return func() Result {
@@ -186,7 +220,7 @@ func Error(err error, message string) Comparison {
 			return ResultFailure("expected an error, got nil")
 			return ResultFailure("expected an error, got nil")
 		case err.Error() != message:
 		case err.Error() != message:
 			return ResultFailure(fmt.Sprintf(
 			return ResultFailure(fmt.Sprintf(
-				"expected error %q, got %+v", message, err))
+				"expected error %q, got %s", message, formatErrorMessage(err)))
 		}
 		}
 		return ResultSuccess
 		return ResultSuccess
 	}
 	}
@@ -201,12 +235,22 @@ func ErrorContains(err error, substring string) Comparison {
 			return ResultFailure("expected an error, got nil")
 			return ResultFailure("expected an error, got nil")
 		case !strings.Contains(err.Error(), substring):
 		case !strings.Contains(err.Error(), substring):
 			return ResultFailure(fmt.Sprintf(
 			return ResultFailure(fmt.Sprintf(
-				"expected error to contain %q, got %+v", substring, err))
+				"expected error to contain %q, got %s", substring, formatErrorMessage(err)))
 		}
 		}
 		return ResultSuccess
 		return ResultSuccess
 	}
 	}
 }
 }
 
 
+func formatErrorMessage(err error) string {
+	if _, ok := err.(interface {
+		Cause() error
+	}); ok {
+		return fmt.Sprintf("%q\n%+v", err, err)
+	}
+	// This error was not wrapped with github.com/pkg/errors
+	return fmt.Sprintf("%q", err)
+}
+
 // Nil succeeds if obj is a nil interface, pointer, or function.
 // Nil succeeds if obj is a nil interface, pointer, or function.
 //
 //
 // Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,
 // Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,

+ 13 - 7
vendor/gotest.tools/assert/cmp/result.go

@@ -9,31 +9,37 @@ import (
 	"gotest.tools/internal/source"
 	"gotest.tools/internal/source"
 )
 )
 
 
-// Result of a Comparison.
+// A Result of a Comparison.
 type Result interface {
 type Result interface {
 	Success() bool
 	Success() bool
 }
 }
 
 
-type result struct {
+// StringResult is an implementation of Result that reports the error message
+// string verbatim and does not provide any templating or formatting of the
+// message.
+type StringResult struct {
 	success bool
 	success bool
 	message string
 	message string
 }
 }
 
 
-func (r result) Success() bool {
+// Success returns true if the comparison was successful.
+func (r StringResult) Success() bool {
 	return r.success
 	return r.success
 }
 }
 
 
-func (r result) FailureMessage() string {
+// FailureMessage returns the message used to provide additional information
+// about the failure.
+func (r StringResult) FailureMessage() string {
 	return r.message
 	return r.message
 }
 }
 
 
 // ResultSuccess is a constant which is returned by a ComparisonWithResult to
 // ResultSuccess is a constant which is returned by a ComparisonWithResult to
 // indicate success.
 // indicate success.
-var ResultSuccess = result{success: true}
+var ResultSuccess = StringResult{success: true}
 
 
 // ResultFailure returns a failed Result with a failure message.
 // ResultFailure returns a failed Result with a failure message.
-func ResultFailure(message string) Result {
-	return result{message: message}
+func ResultFailure(message string) StringResult {
+	return StringResult{message: message}
 }
 }
 
 
 // ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
 // ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure

+ 0 - 1
vendor/gotest.tools/assert/result.go

@@ -70,7 +70,6 @@ func filterPrintableExpr(args []ast.Expr) []ast.Expr {
 			result[i] = starExpr.X
 			result[i] = starExpr.X
 			continue
 			continue
 		}
 		}
-		result[i] = nil
 	}
 	}
 	return result
 	return result
 }
 }

+ 3 - 0
vendor/gotest.tools/env/env.go

@@ -79,6 +79,9 @@ func ToMap(env []string) map[string]string {
 }
 }
 
 
 func getParts(raw string) (string, string) {
 func getParts(raw string) (string, string) {
+	if raw == "" {
+		return "", ""
+	}
 	// Environment variables on windows can begin with =
 	// Environment variables on windows can begin with =
 	// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
 	// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
 	parts := strings.SplitN(raw[1:], "=", 2)
 	parts := strings.SplitN(raw[1:], "=", 2)

+ 14 - 10
vendor/gotest.tools/fs/file.go

@@ -7,6 +7,8 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
+	"runtime"
+	"strings"
 
 
 	"gotest.tools/assert"
 	"gotest.tools/assert"
 	"gotest.tools/x/subtest"
 	"gotest.tools/x/subtest"
@@ -40,20 +42,25 @@ func NewFile(t assert.TestingT, prefix string, ops ...PathOp) *File {
 	if ht, ok := t.(helperT); ok {
 	if ht, ok := t.(helperT); ok {
 		ht.Helper()
 		ht.Helper()
 	}
 	}
-	tempfile, err := ioutil.TempFile("", prefix+"-")
+	tempfile, err := ioutil.TempFile("", cleanPrefix(prefix)+"-")
 	assert.NilError(t, err)
 	assert.NilError(t, err)
 	file := &File{path: tempfile.Name()}
 	file := &File{path: tempfile.Name()}
 	assert.NilError(t, tempfile.Close())
 	assert.NilError(t, tempfile.Close())
-
-	for _, op := range ops {
-		assert.NilError(t, op(file))
-	}
+	assert.NilError(t, applyPathOps(file, ops))
 	if tc, ok := t.(subtest.TestContext); ok {
 	if tc, ok := t.(subtest.TestContext); ok {
 		tc.AddCleanup(file.Remove)
 		tc.AddCleanup(file.Remove)
 	}
 	}
 	return file
 	return file
 }
 }
 
 
+func cleanPrefix(prefix string) string {
+	// windows requires both / and \ are replaced
+	if runtime.GOOS == "windows" {
+		prefix = strings.Replace(prefix, string(os.PathSeparator), "-", -1)
+	}
+	return strings.Replace(prefix, "/", "-", -1)
+}
+
 // Path returns the full path to the file
 // Path returns the full path to the file
 func (f *File) Path() string {
 func (f *File) Path() string {
 	return f.path
 	return f.path
@@ -76,13 +83,10 @@ func NewDir(t assert.TestingT, prefix string, ops ...PathOp) *Dir {
 	if ht, ok := t.(helperT); ok {
 	if ht, ok := t.(helperT); ok {
 		ht.Helper()
 		ht.Helper()
 	}
 	}
-	path, err := ioutil.TempDir("", prefix+"-")
+	path, err := ioutil.TempDir("", cleanPrefix(prefix)+"-")
 	assert.NilError(t, err)
 	assert.NilError(t, err)
 	dir := &Dir{path: path}
 	dir := &Dir{path: path}
-
-	for _, op := range ops {
-		assert.NilError(t, op(dir))
-	}
+	assert.NilError(t, applyPathOps(dir, ops))
 	if tc, ok := t.(subtest.TestContext); ok {
 	if tc, ok := t.(subtest.TestContext); ok {
 		tc.AddCleanup(dir.Remove)
 		tc.AddCleanup(dir.Remove)
 	}
 	}

+ 14 - 4
vendor/gotest.tools/fs/manifest.go

@@ -24,7 +24,9 @@ type resource struct {
 
 
 type file struct {
 type file struct {
 	resource
 	resource
-	content io.ReadCloser
+	content             io.ReadCloser
+	ignoreCariageReturn bool
+	compareContentFunc  func(b []byte) CompareResult
 }
 }
 
 
 func (f *file) Type() string {
 func (f *file) Type() string {
@@ -42,7 +44,8 @@ func (f *symlink) Type() string {
 
 
 type directory struct {
 type directory struct {
 	resource
 	resource
-	items map[string]dirEntry
+	items         map[string]dirEntry
+	filepathGlobs map[string]*filePath
 }
 }
 
 
 func (f *directory) Type() string {
 func (f *directory) Type() string {
@@ -94,8 +97,9 @@ func newDirectory(path string, info os.FileInfo) (*directory, error) {
 	}
 	}
 
 
 	return &directory{
 	return &directory{
-		resource: newResourceFromInfo(info),
-		items:    items,
+		resource:      newResourceFromInfo(info),
+		items:         items,
+		filepathGlobs: make(map[string]*filePath),
 	}, nil
 	}, nil
 }
 }
 
 
@@ -113,6 +117,9 @@ func getTypedResource(path string, info os.FileInfo) (dirEntry, error) {
 
 
 func newSymlink(path string, info os.FileInfo) (*symlink, error) {
 func newSymlink(path string, info os.FileInfo) (*symlink, error) {
 	target, err := os.Readlink(path)
 	target, err := os.Readlink(path)
+	if err != nil {
+		return nil, err
+	}
 	return &symlink{
 	return &symlink{
 		resource: newResourceFromInfo(info),
 		resource: newResourceFromInfo(info),
 		target:   target,
 		target:   target,
@@ -122,6 +129,9 @@ func newSymlink(path string, info os.FileInfo) (*symlink, error) {
 func newFile(path string, info os.FileInfo) (*file, error) {
 func newFile(path string, info os.FileInfo) (*file, error) {
 	// TODO: defer file opening to reduce number of open FDs?
 	// TODO: defer file opening to reduce number of open FDs?
 	readCloser, err := os.Open(path)
 	readCloser, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
 	return &file{
 	return &file{
 		resource: newResourceFromInfo(info),
 		resource: newResourceFromInfo(info),
 		content:  readCloser,
 		content:  readCloser,

+ 29 - 8
vendor/gotest.tools/fs/ops.go

@@ -10,6 +10,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
+	"gotest.tools/assert"
 )
 )
 
 
 const defaultFileMode = 0644
 const defaultFileMode = 0644
@@ -144,6 +145,14 @@ func WithDir(name string, ops ...PathOp) PathOp {
 	}
 	}
 }
 }
 
 
+// Apply the PathOps to the File
+func Apply(t assert.TestingT, path Path, ops ...PathOp) {
+	if ht, ok := t.(helperT); ok {
+		ht.Helper()
+	}
+	assert.NilError(t, applyPathOps(path, ops))
+}
+
 func applyPathOps(path Path, ops []PathOp) error {
 func applyPathOps(path Path, ops []PathOp) error {
 	for _, op := range ops {
 	for _, op := range ops {
 		if err := op(path); err != nil {
 		if err := op(path); err != nil {
@@ -172,23 +181,35 @@ func copyDirectory(source, dest string) error {
 	for _, entry := range entries {
 	for _, entry := range entries {
 		sourcePath := filepath.Join(source, entry.Name())
 		sourcePath := filepath.Join(source, entry.Name())
 		destPath := filepath.Join(dest, entry.Name())
 		destPath := filepath.Join(dest, entry.Name())
-		if entry.IsDir() {
+		switch {
+		case entry.IsDir():
 			if err := os.Mkdir(destPath, 0755); err != nil {
 			if err := os.Mkdir(destPath, 0755); err != nil {
 				return err
 				return err
 			}
 			}
 			if err := copyDirectory(sourcePath, destPath); err != nil {
 			if err := copyDirectory(sourcePath, destPath); err != nil {
 				return err
 				return err
 			}
 			}
-			continue
-		}
-		// TODO: handle symlinks
-		if err := copyFile(sourcePath, destPath); err != nil {
-			return err
+		case entry.Mode()&os.ModeSymlink != 0:
+			if err := copySymLink(sourcePath, destPath); err != nil {
+				return err
+			}
+		default:
+			if err := copyFile(sourcePath, destPath); err != nil {
+				return err
+			}
 		}
 		}
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
+func copySymLink(source, dest string) error {
+	link, err := os.Readlink(source)
+	if err != nil {
+		return err
+	}
+	return os.Symlink(link, dest)
+}
+
 func copyFile(source, dest string) error {
 func copyFile(source, dest string) error {
 	content, err := ioutil.ReadFile(source)
 	content, err := ioutil.ReadFile(source)
 	if err != nil {
 	if err != nil {
@@ -219,7 +240,7 @@ func WithSymlink(path, target string) PathOp {
 func WithHardlink(path, target string) PathOp {
 func WithHardlink(path, target string) PathOp {
 	return func(root Path) error {
 	return func(root Path) error {
 		if _, ok := root.(manifestDirectory); ok {
 		if _, ok := root.(manifestDirectory); ok {
-			return errors.New("WithHardlink yet implemented for manifests")
+			return errors.New("WithHardlink not implemented for manifests")
 		}
 		}
 		return os.Link(filepath.Join(root.Path(), target), filepath.Join(root.Path(), path))
 		return os.Link(filepath.Join(root.Path(), target), filepath.Join(root.Path(), path))
 	}
 	}
@@ -230,7 +251,7 @@ func WithHardlink(path, target string) PathOp {
 func WithTimestamps(atime, mtime time.Time) PathOp {
 func WithTimestamps(atime, mtime time.Time) PathOp {
 	return func(root Path) error {
 	return func(root Path) error {
 		if _, ok := root.(manifestDirectory); ok {
 		if _, ok := root.(manifestDirectory); ok {
-			return errors.New("WithTimestamp yet implemented for manifests")
+			return errors.New("WithTimestamp not implemented for manifests")
 		}
 		}
 		return os.Chtimes(root.Path(), atime, mtime)
 		return os.Chtimes(root.Path(), atime, mtime)
 	}
 	}

+ 50 - 2
vendor/gotest.tools/fs/path.go

@@ -64,6 +64,13 @@ func (p *directoryPath) AddFile(path string, ops ...PathOp) error {
 	return applyPathOps(exp, ops)
 	return applyPathOps(exp, ops)
 }
 }
 
 
+func (p *directoryPath) AddGlobFiles(glob string, ops ...PathOp) error {
+	newFile := &file{resource: newResource(0)}
+	newFilePath := &filePath{file: newFile}
+	p.directory.filepathGlobs[glob] = newFilePath
+	return applyPathOps(newFilePath, ops)
+}
+
 func (p *directoryPath) AddDirectory(path string, ops ...PathOp) error {
 func (p *directoryPath) AddDirectory(path string, ops ...PathOp) error {
 	newDir := newDirectoryWithDefaults()
 	newDir := newDirectoryWithDefaults()
 	p.directory.items[path] = newDir
 	p.directory.items[path] = newDir
@@ -87,8 +94,9 @@ func Expected(t assert.TestingT, ops ...PathOp) Manifest {
 
 
 func newDirectoryWithDefaults() *directory {
 func newDirectoryWithDefaults() *directory {
 	return &directory{
 	return &directory{
-		resource: newResource(defaultRootDirMode),
-		items:    make(map[string]dirEntry),
+		resource:      newResource(defaultRootDirMode),
+		items:         make(map[string]dirEntry),
+		filepathGlobs: make(map[string]*filePath),
 	}
 	}
 }
 }
 
 
@@ -127,6 +135,15 @@ func MatchAnyFileContent(path Path) error {
 	return nil
 	return nil
 }
 }
 
 
+// MatchContentIgnoreCarriageReturn is a PathOp that ignores cariage return
+// discrepancies.
+func MatchContentIgnoreCarriageReturn(path Path) error {
+	if m, ok := path.(*filePath); ok {
+		m.file.ignoreCariageReturn = true
+	}
+	return nil
+}
+
 const anyFile = "*"
 const anyFile = "*"
 
 
 // MatchExtraFiles is a PathOp that updates a Manifest to allow a directory
 // MatchExtraFiles is a PathOp that updates a Manifest to allow a directory
@@ -138,6 +155,37 @@ func MatchExtraFiles(path Path) error {
 	return nil
 	return nil
 }
 }
 
 
+// CompareResult is the result of comparison.
+//
+// See gotest.tools/assert/cmp.StringResult for a convenient implementation of
+// this interface.
+type CompareResult interface {
+	Success() bool
+	FailureMessage() string
+}
+
+// MatchFileContent is a PathOp that updates a Manifest to use the provided
+// function to determine if a file's content matches the expectation.
+func MatchFileContent(f func([]byte) CompareResult) PathOp {
+	return func(path Path) error {
+		if m, ok := path.(*filePath); ok {
+			m.file.compareContentFunc = f
+		}
+		return nil
+	}
+}
+
+// MatchFilesWithGlob is a PathOp that updates a Manifest to match files using
+// glob pattern, and check them using the ops.
+func MatchFilesWithGlob(glob string, ops ...PathOp) PathOp {
+	return func(path Path) error {
+		if m, ok := path.(*directoryPath); ok {
+			m.AddGlobFiles(glob, ops...)
+		}
+		return nil
+	}
+}
+
 // anyFileMode is represented by uint32_max
 // anyFileMode is represented by uint32_max
 const anyFileMode os.FileMode = 4294967295
 const anyFileMode os.FileMode = 4294967295
 
 

+ 71 - 9
vendor/gotest.tools/fs/report.go

@@ -6,6 +6,7 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
+	"runtime"
 	"sort"
 	"sort"
 	"strings"
 	"strings"
 
 
@@ -67,6 +68,11 @@ func eqResource(x, y resource) []problem {
 	return p
 	return p
 }
 }
 
 
+func removeCarriageReturn(in []byte) []byte {
+	return bytes.Replace(in, []byte("\r\n"), []byte("\n"), -1)
+}
+
+// nolint: gocyclo
 func eqFile(x, y *file) []problem {
 func eqFile(x, y *file) []problem {
 	p := eqResource(x.resource, y.resource)
 	p := eqResource(x.resource, y.resource)
 
 
@@ -96,6 +102,19 @@ func eqFile(x, y *file) []problem {
 		return p
 		return p
 	}
 	}
 
 
+	if x.compareContentFunc != nil {
+		r := x.compareContentFunc(yContent)
+		if !r.Success() {
+			p = append(p, existenceProblem("content", r.FailureMessage()))
+		}
+		return p
+	}
+
+	if x.ignoreCariageReturn || y.ignoreCariageReturn {
+		xContent = removeCarriageReturn(xContent)
+		yContent = removeCarriageReturn(yContent)
+	}
+
 	if !bytes.Equal(xContent, yContent) {
 	if !bytes.Equal(xContent, yContent) {
 		p = append(p, diffContent(xContent, yContent))
 		p = append(p, diffContent(xContent, yContent))
 	}
 	}
@@ -126,7 +145,13 @@ func indent(s, prefix string) string {
 
 
 func eqSymlink(x, y *symlink) []problem {
 func eqSymlink(x, y *symlink) []problem {
 	p := eqResource(x.resource, y.resource)
 	p := eqResource(x.resource, y.resource)
-	if x.target != y.target {
+	xTarget := x.target
+	yTarget := y.target
+	if runtime.GOOS == "windows" {
+		xTarget = strings.ToLower(xTarget)
+		yTarget = strings.ToLower(yTarget)
+	}
+	if xTarget != yTarget {
 		p = append(p, notEqual("target", x.target, y.target))
 		p = append(p, notEqual("target", x.target, y.target))
 	}
 	}
 	return p
 	return p
@@ -135,11 +160,13 @@ func eqSymlink(x, y *symlink) []problem {
 func eqDirectory(path string, x, y *directory) []failure {
 func eqDirectory(path string, x, y *directory) []failure {
 	p := eqResource(x.resource, y.resource)
 	p := eqResource(x.resource, y.resource)
 	var f []failure
 	var f []failure
+	matchedFiles := make(map[string]bool)
 
 
 	for _, name := range sortedKeys(x.items) {
 	for _, name := range sortedKeys(x.items) {
 		if name == anyFile {
 		if name == anyFile {
 			continue
 			continue
 		}
 		}
+		matchedFiles[name] = true
 		xEntry := x.items[name]
 		xEntry := x.items[name]
 		yEntry, ok := y.items[name]
 		yEntry, ok := y.items[name]
 		if !ok {
 		if !ok {
@@ -155,19 +182,30 @@ func eqDirectory(path string, x, y *directory) []failure {
 		f = append(f, eqEntry(filepath.Join(path, name), xEntry, yEntry)...)
 		f = append(f, eqEntry(filepath.Join(path, name), xEntry, yEntry)...)
 	}
 	}
 
 
-	if _, ok := x.items[anyFile]; !ok {
+	if len(x.filepathGlobs) != 0 {
 		for _, name := range sortedKeys(y.items) {
 		for _, name := range sortedKeys(y.items) {
-			if _, ok := x.items[name]; !ok {
-				yEntry := y.items[name]
-				p = append(p, existenceProblem(name, "unexpected %s", yEntry.Type()))
-			}
+			m := matchGlob(name, y.items[name], x.filepathGlobs)
+			matchedFiles[name] = m.match
+			f = append(f, m.failures...)
 		}
 		}
 	}
 	}
 
 
-	if len(p) > 0 {
-		f = append(f, failure{path: path, problems: p})
+	if _, ok := x.items[anyFile]; ok {
+		return maybeAppendFailure(f, path, p)
 	}
 	}
-	return f
+	for _, name := range sortedKeys(y.items) {
+		if !matchedFiles[name] {
+			p = append(p, existenceProblem(name, "unexpected %s", y.items[name].Type()))
+		}
+	}
+	return maybeAppendFailure(f, path, p)
+}
+
+func maybeAppendFailure(failures []failure, path string, problems []problem) []failure {
+	if len(problems) > 0 {
+		return append(failures, failure{path: path, problems: problems})
+	}
+	return failures
 }
 }
 
 
 func sortedKeys(items map[string]dirEntry) []string {
 func sortedKeys(items map[string]dirEntry) []string {
@@ -199,6 +237,30 @@ func eqEntry(path string, x, y dirEntry) []failure {
 	return nil
 	return nil
 }
 }
 
 
+type globMatch struct {
+	match    bool
+	failures []failure
+}
+
+func matchGlob(name string, yEntry dirEntry, globs map[string]*filePath) globMatch {
+	m := globMatch{}
+
+	for glob, expectedFile := range globs {
+		ok, err := filepath.Match(glob, name)
+		if err != nil {
+			p := errProblem("failed to match glob pattern", err)
+			f := failure{path: name, problems: []problem{p}}
+			m.failures = append(m.failures, f)
+		}
+		if ok {
+			m.match = true
+			m.failures = eqEntry(name, expectedFile.file, yEntry)
+			return m
+		}
+	}
+	return m
+}
+
 func formatFailures(failures []failure) string {
 func formatFailures(failures []failure) string {
 	sort.Slice(failures, func(i, j int) bool {
 	sort.Slice(failures, func(i, j int) bool {
 		return failures[i].path < failures[j].path
 		return failures[i].path < failures[j].path

+ 6 - 3
vendor/gotest.tools/icmd/command.go

@@ -132,18 +132,21 @@ func (r *Result) String() string {
 	if r.Timeout {
 	if r.Timeout {
 		timeout = " (timeout)"
 		timeout = " (timeout)"
 	}
 	}
+	var errString string
+	if r.Error != nil {
+		errString = "\nError:    " + r.Error.Error()
+	}
 
 
 	return fmt.Sprintf(`
 	return fmt.Sprintf(`
 Command:  %s
 Command:  %s
-ExitCode: %d%s
-Error:    %v
+ExitCode: %d%s%s
 Stdout:   %v
 Stdout:   %v
 Stderr:   %v
 Stderr:   %v
 `,
 `,
 		strings.Join(r.Cmd.Args, " "),
 		strings.Join(r.Cmd.Args, " "),
 		r.ExitCode,
 		r.ExitCode,
 		timeout,
 		timeout,
-		r.Error,
+		errString,
 		r.Stdout(),
 		r.Stdout(),
 		r.Stderr())
 		r.Stderr())
 }
 }

+ 34 - 0
vendor/gotest.tools/icmd/ops.go

@@ -1,4 +1,38 @@
 package icmd
 package icmd
 
 
+import (
+	"io"
+	"time"
+)
+
 // CmdOp is an operation which modified a Cmd structure used to execute commands
 // CmdOp is an operation which modified a Cmd structure used to execute commands
 type CmdOp func(*Cmd)
 type CmdOp func(*Cmd)
+
+// WithTimeout sets the timeout duration of the command
+func WithTimeout(timeout time.Duration) CmdOp {
+	return func(c *Cmd) {
+		c.Timeout = timeout
+	}
+}
+
+// WithEnv sets the environment variable of the command.
+// Each arguments are in the form of KEY=VALUE
+func WithEnv(env ...string) CmdOp {
+	return func(c *Cmd) {
+		c.Env = env
+	}
+}
+
+// Dir sets the working directory of the command
+func Dir(path string) CmdOp {
+	return func(c *Cmd) {
+		c.Dir = path
+	}
+}
+
+// WithStdin sets the standard input of the command to the specified reader
+func WithStdin(r io.Reader) CmdOp {
+	return func(c *Cmd) {
+		c.Stdin = r
+	}
+}

+ 14 - 11
vendor/gotest.tools/internal/difflib/difflib.go

@@ -1,4 +1,4 @@
-/* Package difflib is a partial port of Python difflib module.
+/*Package difflib is a partial port of Python difflib module.
 
 
 Original source: https://github.com/pmezard/go-difflib
 Original source: https://github.com/pmezard/go-difflib
 
 
@@ -20,12 +20,14 @@ func max(a, b int) int {
 	return b
 	return b
 }
 }
 
 
+// Match stores line numbers of size of match
 type Match struct {
 type Match struct {
 	A    int
 	A    int
 	B    int
 	B    int
 	Size int
 	Size int
 }
 }
 
 
+// OpCode identifies the type of diff
 type OpCode struct {
 type OpCode struct {
 	Tag byte
 	Tag byte
 	I1  int
 	I1  int
@@ -73,19 +75,20 @@ type SequenceMatcher struct {
 	opCodes        []OpCode
 	opCodes        []OpCode
 }
 }
 
 
+// NewMatcher returns a new SequenceMatcher
 func NewMatcher(a, b []string) *SequenceMatcher {
 func NewMatcher(a, b []string) *SequenceMatcher {
 	m := SequenceMatcher{autoJunk: true}
 	m := SequenceMatcher{autoJunk: true}
 	m.SetSeqs(a, b)
 	m.SetSeqs(a, b)
 	return &m
 	return &m
 }
 }
 
 
-// Set two sequences to be compared.
+// SetSeqs sets two sequences to be compared.
 func (m *SequenceMatcher) SetSeqs(a, b []string) {
 func (m *SequenceMatcher) SetSeqs(a, b []string) {
 	m.SetSeq1(a)
 	m.SetSeq1(a)
 	m.SetSeq2(b)
 	m.SetSeq2(b)
 }
 }
 
 
-// Set the first sequence to be compared. The second sequence to be compared is
+// SetSeq1 sets the first sequence to be compared. The second sequence to be compared is
 // not changed.
 // not changed.
 //
 //
 // SequenceMatcher computes and caches detailed information about the second
 // SequenceMatcher computes and caches detailed information about the second
@@ -103,7 +106,7 @@ func (m *SequenceMatcher) SetSeq1(a []string) {
 	m.opCodes = nil
 	m.opCodes = nil
 }
 }
 
 
-// Set the second sequence to be compared. The first sequence to be compared is
+// SetSeq2 sets the second sequence to be compared. The first sequence to be compared is
 // not changed.
 // not changed.
 func (m *SequenceMatcher) SetSeq2(b []string) {
 func (m *SequenceMatcher) SetSeq2(b []string) {
 	if &b == &m.b {
 	if &b == &m.b {
@@ -129,12 +132,12 @@ func (m *SequenceMatcher) chainB() {
 	m.bJunk = map[string]struct{}{}
 	m.bJunk = map[string]struct{}{}
 	if m.IsJunk != nil {
 	if m.IsJunk != nil {
 		junk := m.bJunk
 		junk := m.bJunk
-		for s, _ := range b2j {
+		for s := range b2j {
 			if m.IsJunk(s) {
 			if m.IsJunk(s) {
 				junk[s] = struct{}{}
 				junk[s] = struct{}{}
 			}
 			}
 		}
 		}
-		for s, _ := range junk {
+		for s := range junk {
 			delete(b2j, s)
 			delete(b2j, s)
 		}
 		}
 	}
 	}
@@ -149,7 +152,7 @@ func (m *SequenceMatcher) chainB() {
 				popular[s] = struct{}{}
 				popular[s] = struct{}{}
 			}
 			}
 		}
 		}
-		for s, _ := range popular {
+		for s := range popular {
 			delete(b2j, s)
 			delete(b2j, s)
 		}
 		}
 	}
 	}
@@ -259,7 +262,7 @@ func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
 	return Match{A: besti, B: bestj, Size: bestsize}
 	return Match{A: besti, B: bestj, Size: bestsize}
 }
 }
 
 
-// Return list of triples describing matching subsequences.
+// GetMatchingBlocks returns a list of triples describing matching subsequences.
 //
 //
 // Each triple is of the form (i, j, n), and means that
 // 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
 // a[i:i+n] == b[j:j+n].  The triples are monotonically increasing in
@@ -323,7 +326,7 @@ func (m *SequenceMatcher) GetMatchingBlocks() []Match {
 	return m.matchingBlocks
 	return m.matchingBlocks
 }
 }
 
 
-// Return list of 5-tuples describing how to turn a into b.
+// GetOpCodes returns a 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
 // 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
 // has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
@@ -374,7 +377,7 @@ func (m *SequenceMatcher) GetOpCodes() []OpCode {
 	return m.opCodes
 	return m.opCodes
 }
 }
 
 
-// Isolate change clusters by eliminating ranges with no changes.
+// GetGroupedOpCodes isolates change clusters by eliminating ranges with no changes.
 //
 //
 // Return a generator of groups with up to n lines of context.
 // Return a generator of groups with up to n lines of context.
 // Each group is in the same format as returned by GetOpCodes().
 // Each group is in the same format as returned by GetOpCodes().
@@ -384,7 +387,7 @@ func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
 	}
 	}
 	codes := m.GetOpCodes()
 	codes := m.GetOpCodes()
 	if len(codes) == 0 {
 	if len(codes) == 0 {
-		codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
+		codes = []OpCode{{'e', 0, 1, 0, 1}}
 	}
 	}
 	// Fixup leading and trailing groups if they show no changes.
 	// Fixup leading and trailing groups if they show no changes.
 	if codes[0].Tag == 'e' {
 	if codes[0].Tag == 'e' {

+ 53 - 0
vendor/gotest.tools/internal/source/defers.go

@@ -0,0 +1,53 @@
+package source
+
+import (
+	"go/ast"
+	"go/token"
+
+	"github.com/pkg/errors"
+)
+
+func scanToDeferLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
+	var matchedNode ast.Node
+	ast.Inspect(node, func(node ast.Node) bool {
+		switch {
+		case node == nil || matchedNode != nil:
+			return false
+		case fileset.Position(node.End()).Line == lineNum:
+			if funcLit, ok := node.(*ast.FuncLit); ok {
+				matchedNode = funcLit
+				return false
+			}
+		}
+		return true
+	})
+	debug("defer line node: %s", debugFormatNode{matchedNode})
+	return matchedNode
+}
+
+func guessDefer(node ast.Node) (ast.Node, error) {
+	defers := collectDefers(node)
+	switch len(defers) {
+	case 0:
+		return nil, errors.New("failed to expression in defer")
+	case 1:
+		return defers[0].Call, nil
+	default:
+		return nil, errors.Errorf(
+			"ambiguous call expression: multiple (%d) defers in call block",
+			len(defers))
+	}
+}
+
+func collectDefers(node ast.Node) []*ast.DeferStmt {
+	var defers []*ast.DeferStmt
+	ast.Inspect(node, func(node ast.Node) bool {
+		if d, ok := node.(*ast.DeferStmt); ok {
+			defers = append(defers, d)
+			debug("defer: %s", debugFormatNode{d})
+			return false
+		}
+		return true
+	})
+	return defers
+}

+ 58 - 55
vendor/gotest.tools/internal/source/source.go

@@ -24,9 +24,30 @@ func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
+	if argPos >= len(args) {
+		return "", errors.New("failed to find expression")
+	}
 	return FormatNode(args[argPos])
 	return FormatNode(args[argPos])
 }
 }
 
 
+// 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: %s", debugFormatNode{node})
+
+	return getCallExprArgs(node)
+}
+
 func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
 func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
 	fileset := token.NewFileSet()
 	fileset := token.NewFileSet()
 	astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
 	astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
@@ -34,49 +55,44 @@ func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
 		return nil, errors.Wrapf(err, "failed to parse source file: %s", filename)
 		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)
+	if node := scanToLine(fileset, astFile, lineNum); node != nil {
+		return node, nil
 	}
 	}
-	return node, nil
+	if node := scanToDeferLine(fileset, astFile, lineNum); node != nil {
+		node, err := guessDefer(node)
+		if err != nil || node != nil {
+			return node, err
+		}
+	}
+	return nil, errors.Errorf(
+		"failed to find an expression on line %d in %s", lineNum, filename)
 }
 }
 
 
 func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
 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
+	var matchedNode ast.Node
+	ast.Inspect(node, func(node ast.Node) bool {
+		switch {
+		case node == nil || matchedNode != nil:
+			return false
+		case nodePosition(fileset, node).Line == lineNum:
+			matchedNode = node
+			return false
+		}
+		return true
+	})
+	return matchedNode
 }
 }
 
 
 // In golang 1.9 the line number changed from being the line where the statement
 // In golang 1.9 the line number changed from being the line where the statement
 // ended to the line where the statement began.
 // ended to the line where the statement began.
-func (v *scanToLineVisitor) nodePosition(node ast.Node) token.Position {
+func nodePosition(fileset *token.FileSet, node ast.Node) token.Position {
 	if goVersionBefore19 {
 	if goVersionBefore19 {
-		return v.fileset.Position(node.End())
+		return fileset.Position(node.End())
 	}
 	}
-	return v.fileset.Position(node.Pos())
+	return fileset.Position(node.Pos())
 }
 }
 
 
-var goVersionBefore19 = isGOVersionBefore19()
-
-func isGOVersionBefore19() bool {
+var goVersionBefore19 = func() bool {
 	version := runtime.Version()
 	version := runtime.Version()
 	// not a release version
 	// not a release version
 	if !strings.HasPrefix(version, "go") {
 	if !strings.HasPrefix(version, "go") {
@@ -89,7 +105,7 @@ func isGOVersionBefore19() bool {
 	}
 	}
 	minor, err := strconv.ParseInt(parts[1], 10, 32)
 	minor, err := strconv.ParseInt(parts[1], 10, 32)
 	return err == nil && parts[0] == "1" && minor < 9
 	return err == nil && parts[0] == "1" && minor < 9
-}
+}()
 
 
 func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
 func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
 	visitor := &callExprVisitor{}
 	visitor := &callExprVisitor{}
@@ -97,6 +113,7 @@ func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
 	if visitor.expr == nil {
 	if visitor.expr == nil {
 		return nil, errors.New("failed to find call expression")
 		return nil, errors.New("failed to find call expression")
 	}
 	}
+	debug("callExpr: %s", debugFormatNode{visitor.expr})
 	return visitor.expr.Args, nil
 	return visitor.expr.Args, nil
 }
 }
 
 
@@ -108,10 +125,14 @@ func (v *callExprVisitor) Visit(node ast.Node) ast.Visitor {
 	if v.expr != nil || node == nil {
 	if v.expr != nil || node == nil {
 		return nil
 		return nil
 	}
 	}
-	debug("visit (%T): %s", node, debugFormatNode{node})
+	debug("visit: %s", debugFormatNode{node})
 
 
-	if callExpr, ok := node.(*ast.CallExpr); ok {
-		v.expr = callExpr
+	switch typed := node.(type) {
+	case *ast.CallExpr:
+		v.expr = typed
+		return nil
+	case *ast.DeferStmt:
+		ast.Walk(v, typed.Call.Fun)
 		return nil
 		return nil
 	}
 	}
 	return v
 	return v
@@ -124,25 +145,7 @@ func FormatNode(node ast.Node) (string, error) {
 	return buf.String(), err
 	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") != ""
+var debugEnabled = os.Getenv("GOTESTTOOLS_DEBUG") != ""
 
 
 func debug(format string, args ...interface{}) {
 func debug(format string, args ...interface{}) {
 	if debugEnabled {
 	if debugEnabled {
@@ -159,5 +162,5 @@ func (n debugFormatNode) String() string {
 	if err != nil {
 	if err != nil {
 		return fmt.Sprintf("failed to format %s: %s", n.Node, err)
 		return fmt.Sprintf("failed to format %s: %s", n.Node, err)
 	}
 	}
-	return out
+	return fmt.Sprintf("(%T) %s", n.Node, out)
 }
 }

+ 39 - 0
vendor/gotest.tools/poll/check.go

@@ -0,0 +1,39 @@
+package poll
+
+import (
+	"net"
+	"os"
+)
+
+// Check is a function which will be used as check for the WaitOn method.
+type Check func(t LogT) Result
+
+// FileExists looks on filesystem and check that path exists.
+func FileExists(path string) Check {
+	return func(t LogT) Result {
+		_, err := os.Stat(path)
+		if os.IsNotExist(err) {
+			t.Logf("waiting on file %s to exist", path)
+			return Continue("file %s does not exist", path)
+		}
+		if err != nil {
+			return Error(err)
+		}
+
+		return Success()
+	}
+}
+
+// Connection try to open a connection to the address on the
+// named network. See net.Dial for a description of the network and
+// address parameters.
+func Connection(network, address string) Check {
+	return func(t LogT) Result {
+		_, err := net.Dial(network, address)
+		if err != nil {
+			t.Logf("waiting on socket %s://%s to be available...", network, address)
+			return Continue("socket %s://%s not available", network, address)
+		}
+		return Success()
+	}
+}

+ 1 - 1
vendor/gotest.tools/poll/poll.go

@@ -104,7 +104,7 @@ func Error(err error) Result {
 // WaitOn a condition or until a timeout. Poll by calling check and exit when
 // WaitOn a condition or until a timeout. Poll by calling check and exit when
 // check returns a done Result. To fail a test and exit polling with an error
 // check returns a done Result. To fail a test and exit polling with an error
 // return a error result.
 // return a error result.
-func WaitOn(t TestingT, check func(t LogT) Result, pollOps ...SettingOp) {
+func WaitOn(t TestingT, check Check, pollOps ...SettingOp) {
 	if ht, ok := t.(helperT); ok {
 	if ht, ok := t.(helperT); ok {
 		ht.Helper()
 		ht.Helper()
 	}
 	}

+ 23 - 5
vendor/gotest.tools/skip/skip.go

@@ -19,17 +19,29 @@ type skipT interface {
 	Log(args ...interface{})
 	Log(args ...interface{})
 }
 }
 
 
+// Result of skip function
+type Result interface {
+	Skip() bool
+	Message() string
+}
+
 type helperT interface {
 type helperT interface {
 	Helper()
 	Helper()
 }
 }
 
 
-// BoolOrCheckFunc can be a bool or func() bool, other types will panic
+// BoolOrCheckFunc can be a bool, func() bool, or func() Result. Other types will panic
 type BoolOrCheckFunc interface{}
 type BoolOrCheckFunc interface{}
 
 
-// If the condition expression evaluates to true, or the condition function returns
-// true, skip the test.
+// If the condition expression evaluates to true, skip the test.
+//
+// The condition argument may be one of three types: bool, func() bool, or
+// func() SkipResult.
+// When called with a bool, the test will be skip if the condition evaluates to true.
+// When called with a func() bool, the test will be skip if the function returns true.
+// When called with a func() Result, the test will be skip if the Skip method
+// of the result returns true.
 // The skip message will contain the source code of the expression.
 // The skip message will contain the source code of the expression.
-// Extra message text can be passed as a format string with args
+// Extra message text can be passed as a format string with args.
 func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
 func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
 	if ht, ok := t.(helperT); ok {
 	if ht, ok := t.(helperT); ok {
 		ht.Helper()
 		ht.Helper()
@@ -41,12 +53,18 @@ func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
 		if check() {
 		if check() {
 			t.Skip(format.WithCustomMessage(getFunctionName(check), msgAndArgs...))
 			t.Skip(format.WithCustomMessage(getFunctionName(check), msgAndArgs...))
 		}
 		}
+	case func() Result:
+		result := check()
+		if result.Skip() {
+			msg := getFunctionName(check) + ": " + result.Message()
+			t.Skip(format.WithCustomMessage(msg, msgAndArgs...))
+		}
 	default:
 	default:
 		panic(fmt.Sprintf("invalid type for condition arg: %T", check))
 		panic(fmt.Sprintf("invalid type for condition arg: %T", check))
 	}
 	}
 }
 }
 
 
-func getFunctionName(function func() bool) string {
+func getFunctionName(function interface{}) string {
 	funcPath := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name()
 	funcPath := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name()
 	return strings.SplitN(path.Base(funcPath), ".", 2)[1]
 	return strings.SplitN(path.Base(funcPath), ".", 2)[1]
 }
 }