Browse Source

vendor: github.com/google/go-cmp v0.5.5

Remove the replace rule, and use the version as specified by (indirect) dependencies:

full diff: https://github.com/google/go-cmp/compare/v0.2.0...v0.5.5

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 3 years ago
parent
commit
42d2f0bbc7
40 changed files with 3714 additions and 1058 deletions
  1. 0 1
      vendor.mod
  2. 10 1
      vendor.sum
  3. 60 1
      vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
  4. 15 0
      vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go
  5. 18 0
      vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go
  6. 67 6
      vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go
  7. 18 17
      vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go
  8. 0 46
      vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go17.go
  9. 0 31
      vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go18.go
  10. 13 8
      vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go
  11. 35 0
      vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go
  12. 393 264
      vendor/github.com/google/go-cmp/cmp/compare.go
  13. 15 0
      vendor/github.com/google/go-cmp/cmp/export_panic.go
  14. 35 0
      vendor/github.com/google/go-cmp/cmp/export_unsafe.go
  15. 2 2
      vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
  16. 3 3
      vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
  17. 52 17
      vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
  18. 9 0
      vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go
  19. 10 0
      vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go
  20. 10 0
      vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go
  21. 58 8
      vendor/github.com/google/go-cmp/cmp/internal/function/func.go
  22. 0 277
      vendor/github.com/google/go-cmp/cmp/internal/value/format.go
  23. 157 0
      vendor/github.com/google/go-cmp/cmp/internal/value/name.go
  24. 33 0
      vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go
  25. 36 0
      vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go
  26. 4 9
      vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
  27. 48 0
      vendor/github.com/google/go-cmp/cmp/internal/value/zero.go
  28. 201 102
      vendor/github.com/google/go-cmp/cmp/options.go
  29. 240 171
      vendor/github.com/google/go-cmp/cmp/path.go
  30. 54 0
      vendor/github.com/google/go-cmp/cmp/report.go
  31. 432 0
      vendor/github.com/google/go-cmp/cmp/report_compare.go
  32. 264 0
      vendor/github.com/google/go-cmp/cmp/report_references.go
  33. 402 0
      vendor/github.com/google/go-cmp/cmp/report_reflect.go
  34. 465 0
      vendor/github.com/google/go-cmp/cmp/report_slices.go
  35. 431 0
      vendor/github.com/google/go-cmp/cmp/report_text.go
  36. 121 0
      vendor/github.com/google/go-cmp/cmp/report_value.go
  37. 0 53
      vendor/github.com/google/go-cmp/cmp/reporter.go
  38. 0 15
      vendor/github.com/google/go-cmp/cmp/unsafe_panic.go
  39. 0 23
      vendor/github.com/google/go-cmp/cmp/unsafe_reflect.go
  40. 3 3
      vendor/modules.txt

+ 0 - 1
vendor.mod

@@ -157,7 +157,6 @@ replace (
 	github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
 	github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
 	github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2
 	github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2
 	github.com/golang/protobuf => github.com/golang/protobuf v1.3.5
 	github.com/golang/protobuf => github.com/golang/protobuf v1.3.5
-	github.com/google/go-cmp => github.com/google/go-cmp v0.2.0
 	github.com/hashicorp/go-immutable-radix => github.com/tonistiigi/go-immutable-radix v0.0.0-20170803185627-826af9ccf0fe
 	github.com/hashicorp/go-immutable-radix => github.com/tonistiigi/go-immutable-radix v0.0.0-20170803185627-826af9ccf0fe
 	github.com/hashicorp/go-msgpack => github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67
 	github.com/hashicorp/go-msgpack => github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67
 	github.com/hashicorp/go-multierror => github.com/hashicorp/go-multierror v1.0.0
 	github.com/hashicorp/go-multierror => github.com/hashicorp/go-multierror v1.0.0

+ 10 - 1
vendor.sum

@@ -354,8 +354,17 @@ github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
 github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
 github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
 github.com/google/certificate-transparency-go v1.0.20 h1:azETE79toaBOyp+StoEBy8atzQujL0PyBPEmsEeDCXI=
 github.com/google/certificate-transparency-go v1.0.20 h1:azETE79toaBOyp+StoEBy8atzQujL0PyBPEmsEeDCXI=
 github.com/google/certificate-transparency-go v1.0.20/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
 github.com/google/certificate-transparency-go v1.0.20/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
-github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=

+ 60 - 1
vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go

@@ -1,6 +1,6 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 // Package cmpopts provides common options for the cmp package.
 // Package cmpopts provides common options for the cmp package.
 package cmpopts
 package cmpopts
@@ -8,6 +8,7 @@ package cmpopts
 import (
 import (
 	"math"
 	"math"
 	"reflect"
 	"reflect"
+	"time"
 
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
 )
 )
@@ -87,3 +88,61 @@ func areNaNsF64s(x, y float64) bool {
 func areNaNsF32s(x, y float32) bool {
 func areNaNsF32s(x, y float32) bool {
 	return areNaNsF64s(float64(x), float64(y))
 	return areNaNsF64s(float64(x), float64(y))
 }
 }
+
+// EquateApproxTime returns a Comparer option that determines two non-zero
+// time.Time values to be equal if they are within some margin of one another.
+// If both times have a monotonic clock reading, then the monotonic time
+// difference will be used. The margin must be non-negative.
+func EquateApproxTime(margin time.Duration) cmp.Option {
+	if margin < 0 {
+		panic("margin must be a non-negative number")
+	}
+	a := timeApproximator{margin}
+	return cmp.FilterValues(areNonZeroTimes, cmp.Comparer(a.compare))
+}
+
+func areNonZeroTimes(x, y time.Time) bool {
+	return !x.IsZero() && !y.IsZero()
+}
+
+type timeApproximator struct {
+	margin time.Duration
+}
+
+func (a timeApproximator) compare(x, y time.Time) bool {
+	// Avoid subtracting times to avoid overflow when the
+	// difference is larger than the largest representible duration.
+	if x.After(y) {
+		// Ensure x is always before y
+		x, y = y, x
+	}
+	// We're within the margin if x+margin >= y.
+	// Note: time.Time doesn't have AfterOrEqual method hence the negation.
+	return !x.Add(a.margin).Before(y)
+}
+
+// AnyError is an error that matches any non-nil error.
+var AnyError anyError
+
+type anyError struct{}
+
+func (anyError) Error() string     { return "any error" }
+func (anyError) Is(err error) bool { return err != nil }
+
+// EquateErrors returns a Comparer option that determines errors to be equal
+// if errors.Is reports them to match. The AnyError error can be used to
+// match any non-nil error.
+func EquateErrors() cmp.Option {
+	return cmp.FilterValues(areConcreteErrors, cmp.Comparer(compareErrors))
+}
+
+// areConcreteErrors reports whether x and y are types that implement error.
+// The input types are deliberately of the interface{} type rather than the
+// error type so that we can handle situations where the current type is an
+// interface{}, but the underlying concrete types both happen to implement
+// the error interface.
+func areConcreteErrors(x, y interface{}) bool {
+	_, ok1 := x.(error)
+	_, ok2 := y.(error)
+	return ok1 && ok2
+}

+ 15 - 0
vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go

@@ -0,0 +1,15 @@
+// Copyright 2021, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.13
+
+package cmpopts
+
+import "errors"
+
+func compareErrors(x, y interface{}) bool {
+	xe := x.(error)
+	ye := y.(error)
+	return errors.Is(xe, ye) || errors.Is(ye, xe)
+}

+ 18 - 0
vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go

@@ -0,0 +1,18 @@
+// Copyright 2021, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.13
+
+// TODO(≥go1.13): For support on <go1.13, we use the xerrors package.
+// Drop this file when we no longer support older Go versions.
+
+package cmpopts
+
+import "golang.org/x/xerrors"
+
+func compareErrors(x, y interface{}) bool {
+	xe := x.(error)
+	ye := y.(error)
+	return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
+}

+ 67 - 6
vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go

@@ -1,6 +1,6 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 package cmpopts
 package cmpopts
 
 
@@ -11,16 +11,16 @@ import (
 	"unicode/utf8"
 	"unicode/utf8"
 
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/internal/function"
 )
 )
 
 
-// IgnoreFields returns an Option that ignores exported fields of the
-// given names on a single struct type.
+// IgnoreFields returns an Option that ignores fields of the
+// given names on a single struct type. It respects the names of exported fields
+// that are forwarded due to struct embedding.
 // The struct type is specified by passing in a value of that type.
 // The struct type is specified by passing in a value of that type.
 //
 //
 // The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a
 // The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a
 // specific sub-field that is embedded or nested within the parent struct.
 // specific sub-field that is embedded or nested within the parent struct.
-//
-// This does not handle unexported fields; use IgnoreUnexported instead.
 func IgnoreFields(typ interface{}, names ...string) cmp.Option {
 func IgnoreFields(typ interface{}, names ...string) cmp.Option {
 	sf := newStructFilter(typ, names...)
 	sf := newStructFilter(typ, names...)
 	return cmp.FilterPath(sf.filter, cmp.Ignore())
 	return cmp.FilterPath(sf.filter, cmp.Ignore())
@@ -112,6 +112,10 @@ func (tf ifaceFilter) filter(p cmp.Path) bool {
 // In particular, unexported fields within the struct's exported fields
 // In particular, unexported fields within the struct's exported fields
 // of struct types, including anonymous fields, will not be ignored unless the
 // of struct types, including anonymous fields, will not be ignored unless the
 // type of the field itself is also passed to IgnoreUnexported.
 // type of the field itself is also passed to IgnoreUnexported.
+//
+// Avoid ignoring unexported fields of a type which you do not control (i.e. a
+// type from another repository), as changes to the implementation of such types
+// may change how the comparison behaves. Prefer a custom Comparer instead.
 func IgnoreUnexported(typs ...interface{}) cmp.Option {
 func IgnoreUnexported(typs ...interface{}) cmp.Option {
 	ux := newUnexportedFilter(typs...)
 	ux := newUnexportedFilter(typs...)
 	return cmp.FilterPath(ux.filter, cmp.Ignore())
 	return cmp.FilterPath(ux.filter, cmp.Ignore())
@@ -124,7 +128,7 @@ func newUnexportedFilter(typs ...interface{}) unexportedFilter {
 	for _, typ := range typs {
 	for _, typ := range typs {
 		t := reflect.TypeOf(typ)
 		t := reflect.TypeOf(typ)
 		if t == nil || t.Kind() != reflect.Struct {
 		if t == nil || t.Kind() != reflect.Struct {
-			panic(fmt.Sprintf("invalid struct type: %T", typ))
+			panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
 		}
 		}
 		ux.m[t] = true
 		ux.m[t] = true
 	}
 	}
@@ -143,3 +147,60 @@ func isExported(id string) bool {
 	r, _ := utf8.DecodeRuneInString(id)
 	r, _ := utf8.DecodeRuneInString(id)
 	return unicode.IsUpper(r)
 	return unicode.IsUpper(r)
 }
 }
+
+// IgnoreSliceElements returns an Option that ignores elements of []V.
+// The discard function must be of the form "func(T) bool" which is used to
+// ignore slice elements of type V, where V is assignable to T.
+// Elements are ignored if the function reports true.
+func IgnoreSliceElements(discardFunc interface{}) cmp.Option {
+	vf := reflect.ValueOf(discardFunc)
+	if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() {
+		panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
+	}
+	return cmp.FilterPath(func(p cmp.Path) bool {
+		si, ok := p.Index(-1).(cmp.SliceIndex)
+		if !ok {
+			return false
+		}
+		if !si.Type().AssignableTo(vf.Type().In(0)) {
+			return false
+		}
+		vx, vy := si.Values()
+		if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() {
+			return true
+		}
+		if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() {
+			return true
+		}
+		return false
+	}, cmp.Ignore())
+}
+
+// IgnoreMapEntries returns an Option that ignores entries of map[K]V.
+// The discard function must be of the form "func(T, R) bool" which is used to
+// ignore map entries of type K and V, where K and V are assignable to T and R.
+// Entries are ignored if the function reports true.
+func IgnoreMapEntries(discardFunc interface{}) cmp.Option {
+	vf := reflect.ValueOf(discardFunc)
+	if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() {
+		panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
+	}
+	return cmp.FilterPath(func(p cmp.Path) bool {
+		mi, ok := p.Index(-1).(cmp.MapIndex)
+		if !ok {
+			return false
+		}
+		if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) {
+			return false
+		}
+		k := mi.Key()
+		vx, vy := mi.Values()
+		if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() {
+			return true
+		}
+		if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() {
+			return true
+		}
+		return false
+	}, cmp.Ignore())
+}

+ 18 - 17
vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go

@@ -1,12 +1,13 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 package cmpopts
 package cmpopts
 
 
 import (
 import (
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
+	"sort"
 
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/internal/function"
 	"github.com/google/go-cmp/cmp/internal/function"
@@ -25,13 +26,13 @@ import (
 // !less(y, x) for two elements x and y, their relative order is maintained.
 // !less(y, x) for two elements x and y, their relative order is maintained.
 //
 //
 // SortSlices can be used in conjunction with EquateEmpty.
 // SortSlices can be used in conjunction with EquateEmpty.
-func SortSlices(less interface{}) cmp.Option {
-	vf := reflect.ValueOf(less)
+func SortSlices(lessFunc interface{}) cmp.Option {
+	vf := reflect.ValueOf(lessFunc)
 	if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
 	if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
-		panic(fmt.Sprintf("invalid less function: %T", less))
+		panic(fmt.Sprintf("invalid less function: %T", lessFunc))
 	}
 	}
 	ss := sliceSorter{vf.Type().In(0), vf}
 	ss := sliceSorter{vf.Type().In(0), vf}
-	return cmp.FilterValues(ss.filter, cmp.Transformer("Sort", ss.sort))
+	return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort))
 }
 }
 
 
 type sliceSorter struct {
 type sliceSorter struct {
@@ -48,8 +49,8 @@ func (ss sliceSorter) filter(x, y interface{}) bool {
 	}
 	}
 	// Check whether the slices are already sorted to avoid an infinite
 	// Check whether the slices are already sorted to avoid an infinite
 	// recursion cycle applying the same transform to itself.
 	// recursion cycle applying the same transform to itself.
-	ok1 := sliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) })
-	ok2 := sliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) })
+	ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) })
+	ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) })
 	return !ok1 || !ok2
 	return !ok1 || !ok2
 }
 }
 func (ss sliceSorter) sort(x interface{}) interface{} {
 func (ss sliceSorter) sort(x interface{}) interface{} {
@@ -58,7 +59,7 @@ func (ss sliceSorter) sort(x interface{}) interface{} {
 	for i := 0; i < src.Len(); i++ {
 	for i := 0; i < src.Len(); i++ {
 		dst.Index(i).Set(src.Index(i))
 		dst.Index(i).Set(src.Index(i))
 	}
 	}
-	sortSliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) })
+	sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) })
 	ss.checkSort(dst)
 	ss.checkSort(dst)
 	return dst.Interface()
 	return dst.Interface()
 }
 }
@@ -96,13 +97,13 @@ func (ss sliceSorter) less(v reflect.Value, i, j int) bool {
 //	• Total: if x != y, then either less(x, y) or less(y, x)
 //	• Total: if x != y, then either less(x, y) or less(y, x)
 //
 //
 // SortMaps can be used in conjunction with EquateEmpty.
 // SortMaps can be used in conjunction with EquateEmpty.
-func SortMaps(less interface{}) cmp.Option {
-	vf := reflect.ValueOf(less)
+func SortMaps(lessFunc interface{}) cmp.Option {
+	vf := reflect.ValueOf(lessFunc)
 	if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
 	if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
-		panic(fmt.Sprintf("invalid less function: %T", less))
+		panic(fmt.Sprintf("invalid less function: %T", lessFunc))
 	}
 	}
 	ms := mapSorter{vf.Type().In(0), vf}
 	ms := mapSorter{vf.Type().In(0), vf}
-	return cmp.FilterValues(ms.filter, cmp.Transformer("Sort", ms.sort))
+	return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort))
 }
 }
 
 
 type mapSorter struct {
 type mapSorter struct {
@@ -118,7 +119,10 @@ func (ms mapSorter) filter(x, y interface{}) bool {
 }
 }
 func (ms mapSorter) sort(x interface{}) interface{} {
 func (ms mapSorter) sort(x interface{}) interface{} {
 	src := reflect.ValueOf(x)
 	src := reflect.ValueOf(x)
-	outType := mapEntryType(src.Type())
+	outType := reflect.StructOf([]reflect.StructField{
+		{Name: "K", Type: src.Type().Key()},
+		{Name: "V", Type: src.Type().Elem()},
+	})
 	dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len())
 	dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len())
 	for i, k := range src.MapKeys() {
 	for i, k := range src.MapKeys() {
 		v := reflect.New(outType).Elem()
 		v := reflect.New(outType).Elem()
@@ -126,7 +130,7 @@ func (ms mapSorter) sort(x interface{}) interface{} {
 		v.Field(1).Set(src.MapIndex(k))
 		v.Field(1).Set(src.MapIndex(k))
 		dst.Index(i).Set(v)
 		dst.Index(i).Set(v)
 	}
 	}
-	sortSlice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) })
+	sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) })
 	ms.checkSort(dst)
 	ms.checkSort(dst)
 	return dst.Interface()
 	return dst.Interface()
 }
 }
@@ -139,8 +143,5 @@ func (ms mapSorter) checkSort(v reflect.Value) {
 }
 }
 func (ms mapSorter) less(v reflect.Value, i, j int) bool {
 func (ms mapSorter) less(v reflect.Value, i, j int) bool {
 	vx, vy := v.Index(i).Field(0), v.Index(j).Field(0)
 	vx, vy := v.Index(i).Field(0), v.Index(j).Field(0)
-	if !hasReflectStructOf {
-		vx, vy = vx.Elem(), vy.Elem()
-	}
 	return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
 	return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
 }
 }

+ 0 - 46
vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go17.go

@@ -1,46 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
-
-// +build !go1.8
-
-package cmpopts
-
-import (
-	"reflect"
-	"sort"
-)
-
-const hasReflectStructOf = false
-
-func mapEntryType(reflect.Type) reflect.Type {
-	return reflect.TypeOf(struct{ K, V interface{} }{})
-}
-
-func sliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
-	return sort.IsSorted(reflectSliceSorter{reflect.ValueOf(slice), less})
-}
-func sortSlice(slice interface{}, less func(i, j int) bool) {
-	sort.Sort(reflectSliceSorter{reflect.ValueOf(slice), less})
-}
-func sortSliceStable(slice interface{}, less func(i, j int) bool) {
-	sort.Stable(reflectSliceSorter{reflect.ValueOf(slice), less})
-}
-
-type reflectSliceSorter struct {
-	slice reflect.Value
-	less  func(i, j int) bool
-}
-
-func (ss reflectSliceSorter) Len() int {
-	return ss.slice.Len()
-}
-func (ss reflectSliceSorter) Less(i, j int) bool {
-	return ss.less(i, j)
-}
-func (ss reflectSliceSorter) Swap(i, j int) {
-	vi := ss.slice.Index(i).Interface()
-	vj := ss.slice.Index(j).Interface()
-	ss.slice.Index(i).Set(reflect.ValueOf(vj))
-	ss.slice.Index(j).Set(reflect.ValueOf(vi))
-}

+ 0 - 31
vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go18.go

@@ -1,31 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
-
-// +build go1.8
-
-package cmpopts
-
-import (
-	"reflect"
-	"sort"
-)
-
-const hasReflectStructOf = true
-
-func mapEntryType(t reflect.Type) reflect.Type {
-	return reflect.StructOf([]reflect.StructField{
-		{Name: "K", Type: t.Key()},
-		{Name: "V", Type: t.Elem()},
-	})
-}
-
-func sliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
-	return sort.SliceIsSorted(slice, less)
-}
-func sortSlice(slice interface{}, less func(i, j int) bool) {
-	sort.Slice(slice, less)
-}
-func sortSliceStable(slice interface{}, less func(i, j int) bool) {
-	sort.SliceStable(slice, less)
-}

+ 13 - 8
vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go

@@ -1,6 +1,6 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 package cmpopts
 package cmpopts
 
 
@@ -42,7 +42,7 @@ func newStructFilter(typ interface{}, names ...string) structFilter {
 
 
 	t := reflect.TypeOf(typ)
 	t := reflect.TypeOf(typ)
 	if t == nil || t.Kind() != reflect.Struct {
 	if t == nil || t.Kind() != reflect.Struct {
-		panic(fmt.Sprintf("%T must be a struct", typ))
+		panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
 	}
 	}
 	var ft fieldTree
 	var ft fieldTree
 	for _, name := range names {
 	for _, name := range names {
@@ -160,14 +160,19 @@ func canonicalName(t reflect.Type, sel string) ([]string, error) {
 
 
 	// Find the canonical name for this current field name.
 	// Find the canonical name for this current field name.
 	// If the field exists in an embedded struct, then it will be expanded.
 	// If the field exists in an embedded struct, then it will be expanded.
+	sf, _ := t.FieldByName(name)
 	if !isExported(name) {
 	if !isExported(name) {
-		// Disallow unexported fields:
-		//	* To discourage people from actually touching unexported fields
-		//	* FieldByName is buggy (https://golang.org/issue/4876)
-		return []string{name}, fmt.Errorf("name must be exported")
+		// Avoid using reflect.Type.FieldByName for unexported fields due to
+		// buggy behavior with regard to embeddeding and unexported fields.
+		// See https://golang.org/issue/4876 for details.
+		sf = reflect.StructField{}
+		for i := 0; i < t.NumField() && sf.Name == ""; i++ {
+			if t.Field(i).Name == name {
+				sf = t.Field(i)
+			}
+		}
 	}
 	}
-	sf, ok := t.FieldByName(name)
-	if !ok {
+	if sf.Name == "" {
 		return []string{name}, fmt.Errorf("does not exist")
 		return []string{name}, fmt.Errorf("does not exist")
 	}
 	}
 	var ss []string
 	var ss []string

+ 35 - 0
vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go

@@ -0,0 +1,35 @@
+// Copyright 2018, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmpopts
+
+import (
+	"github.com/google/go-cmp/cmp"
+)
+
+type xformFilter struct{ xform cmp.Option }
+
+func (xf xformFilter) filter(p cmp.Path) bool {
+	for _, ps := range p {
+		if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform {
+			return false
+		}
+	}
+	return true
+}
+
+// AcyclicTransformer returns a Transformer with a filter applied that ensures
+// that the transformer cannot be recursively applied upon its own output.
+//
+// An example use case is a transformer that splits a string by lines:
+//	AcyclicTransformer("SplitLines", func(s string) []string{
+//		return strings.Split(s, "\n")
+//	})
+//
+// Had this been an unfiltered Transformer instead, this would result in an
+// infinite cycle converting a string to []string to [][]string and so on.
+func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option {
+	xf := xformFilter{cmp.Transformer(name, xformFunc)}
+	return cmp.FilterPath(xf.filter, xf.xform)
+}

+ 393 - 264
vendor/github.com/google/go-cmp/cmp/compare.go

@@ -1,11 +1,15 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 // Package cmp determines equality of values.
 // Package cmp determines equality of values.
 //
 //
 // This package is intended to be a more powerful and safer alternative to
 // This package is intended to be a more powerful and safer alternative to
 // reflect.DeepEqual for comparing whether two values are semantically equal.
 // reflect.DeepEqual for comparing whether two values are semantically equal.
+// It is intended to only be used in tests, as performance is not a goal and
+// it may panic if it cannot compare the values. Its propensity towards
+// panicking means that its unsuitable for production environments where a
+// spurious panic may be fatal.
 //
 //
 // The primary features of cmp are:
 // The primary features of cmp are:
 //
 //
@@ -22,33 +26,24 @@
 // equality is determined by recursively comparing the primitive kinds on both
 // equality is determined by recursively comparing the primitive kinds on both
 // values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
 // values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
 // fields are not compared by default; they result in panics unless suppressed
 // fields are not compared by default; they result in panics unless suppressed
-// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly compared
-// using the AllowUnexported option.
+// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly
+// compared using the Exporter option.
 package cmp
 package cmp
 
 
 import (
 import (
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
+	"strings"
 
 
 	"github.com/google/go-cmp/cmp/internal/diff"
 	"github.com/google/go-cmp/cmp/internal/diff"
+	"github.com/google/go-cmp/cmp/internal/flags"
 	"github.com/google/go-cmp/cmp/internal/function"
 	"github.com/google/go-cmp/cmp/internal/function"
 	"github.com/google/go-cmp/cmp/internal/value"
 	"github.com/google/go-cmp/cmp/internal/value"
 )
 )
 
 
-// BUG(dsnet): Maps with keys containing NaN values cannot be properly compared due to
-// the reflection package's inability to retrieve such entries. Equal will panic
-// anytime it comes across a NaN key, but this behavior may change.
-//
-// See https://golang.org/issue/11104 for more details.
-
-var nothing = reflect.Value{}
-
 // Equal reports whether x and y are equal by recursively applying the
 // Equal reports whether x and y are equal by recursively applying the
 // following rules in the given order to x and y and all of their sub-values:
 // following rules in the given order to x and y and all of their sub-values:
 //
 //
-// • If two values are not of the same type, then they are never equal
-// and the overall result is false.
-//
 // • Let S be the set of all Ignore, Transformer, and Comparer options that
 // • Let S be the set of all Ignore, Transformer, and Comparer options that
 // remain after applying all path filters, value filters, and type filters.
 // remain after applying all path filters, value filters, and type filters.
 // If at least one Ignore exists in S, then the comparison is ignored.
 // If at least one Ignore exists in S, then the comparison is ignored.
@@ -61,71 +56,137 @@ var nothing = reflect.Value{}
 //
 //
 // • If the values have an Equal method of the form "(T) Equal(T) bool" or
 // • If the values have an Equal method of the form "(T) Equal(T) bool" or
 // "(T) Equal(I) bool" where T is assignable to I, then use the result of
 // "(T) Equal(I) bool" where T is assignable to I, then use the result of
-// x.Equal(y) even if x or y is nil.
-// Otherwise, no such method exists and evaluation proceeds to the next rule.
+// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
+// evaluation proceeds to the next rule.
 //
 //
 // • Lastly, try to compare x and y based on their basic kinds.
 // • Lastly, try to compare x and y based on their basic kinds.
 // Simple kinds like booleans, integers, floats, complex numbers, strings, and
 // Simple kinds like booleans, integers, floats, complex numbers, strings, and
 // channels are compared using the equivalent of the == operator in Go.
 // channels are compared using the equivalent of the == operator in Go.
 // Functions are only equal if they are both nil, otherwise they are unequal.
 // Functions are only equal if they are both nil, otherwise they are unequal.
-// Pointers are equal if the underlying values they point to are also equal.
-// Interfaces are equal if their underlying concrete values are also equal.
 //
 //
-// Structs are equal if all of their fields are equal. If a struct contains
-// unexported fields, Equal panics unless the AllowUnexported option is used or
-// an Ignore option (e.g., cmpopts.IgnoreUnexported) ignores that field.
+// Structs are equal if recursively calling Equal on all fields report equal.
+// If a struct contains unexported fields, Equal panics unless an Ignore option
+// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option
+// explicitly permits comparing the unexported field.
+//
+// Slices are equal if they are both nil or both non-nil, where recursively
+// calling Equal on all non-ignored slice or array elements report equal.
+// Empty non-nil slices and nil slices are not equal; to equate empty slices,
+// consider using cmpopts.EquateEmpty.
 //
 //
-// Arrays, slices, and maps are equal if they are both nil or both non-nil
-// with the same length and the elements at each index or key are equal.
-// Note that a non-nil empty slice and a nil slice are not equal.
-// To equate empty slices and maps, consider using cmpopts.EquateEmpty.
+// Maps are equal if they are both nil or both non-nil, where recursively
+// calling Equal on all non-ignored map entries report equal.
 // Map keys are equal according to the == operator.
 // Map keys are equal according to the == operator.
 // To use custom comparisons for map keys, consider using cmpopts.SortMaps.
 // To use custom comparisons for map keys, consider using cmpopts.SortMaps.
+// Empty non-nil maps and nil maps are not equal; to equate empty maps,
+// consider using cmpopts.EquateEmpty.
+//
+// Pointers and interfaces are equal if they are both nil or both non-nil,
+// where they have the same underlying concrete type and recursively
+// calling Equal on the underlying values reports equal.
+//
+// Before recursing into a pointer, slice element, or map, the current path
+// is checked to detect whether the address has already been visited.
+// If there is a cycle, then the pointed at values are considered equal
+// only if both addresses were previously visited in the same path step.
 func Equal(x, y interface{}, opts ...Option) bool {
 func Equal(x, y interface{}, opts ...Option) bool {
 	s := newState(opts)
 	s := newState(opts)
-	s.compareAny(reflect.ValueOf(x), reflect.ValueOf(y))
+	s.compareAny(rootStep(x, y))
 	return s.result.Equal()
 	return s.result.Equal()
 }
 }
 
 
-// Diff returns a human-readable report of the differences between two values.
-// It returns an empty string if and only if Equal returns true for the same
-// input values and options. The output string will use the "-" symbol to
-// indicate elements removed from x, and the "+" symbol to indicate elements
-// added to y.
+// Diff returns a human-readable report of the differences between two values:
+// y - x. It returns an empty string if and only if Equal returns true for the
+// same input values and options.
+//
+// The output is displayed as a literal in pseudo-Go syntax.
+// At the start of each line, a "-" prefix indicates an element removed from x,
+// a "+" prefix to indicates an element added from y, and the lack of a prefix
+// indicates an element common to both x and y. If possible, the output
+// uses fmt.Stringer.String or error.Error methods to produce more humanly
+// readable outputs. In such cases, the string is prefixed with either an
+// 's' or 'e' character, respectively, to indicate that the method was called.
 //
 //
-// Do not depend on this output being stable.
+// Do not depend on this output being stable. If you need the ability to
+// programmatically interpret the difference, consider using a custom Reporter.
 func Diff(x, y interface{}, opts ...Option) string {
 func Diff(x, y interface{}, opts ...Option) string {
+	s := newState(opts)
+
+	// Optimization: If there are no other reporters, we can optimize for the
+	// common case where the result is equal (and thus no reported difference).
+	// This avoids the expensive construction of a difference tree.
+	if len(s.reporters) == 0 {
+		s.compareAny(rootStep(x, y))
+		if s.result.Equal() {
+			return ""
+		}
+		s.result = diff.Result{} // Reset results
+	}
+
 	r := new(defaultReporter)
 	r := new(defaultReporter)
-	opts = Options{Options(opts), r}
-	eq := Equal(x, y, opts...)
+	s.reporters = append(s.reporters, reporter{r})
+	s.compareAny(rootStep(x, y))
 	d := r.String()
 	d := r.String()
-	if (d == "") != eq {
+	if (d == "") != s.result.Equal() {
 		panic("inconsistent difference and equality results")
 		panic("inconsistent difference and equality results")
 	}
 	}
 	return d
 	return d
 }
 }
 
 
+// rootStep constructs the first path step. If x and y have differing types,
+// then they are stored within an empty interface type.
+func rootStep(x, y interface{}) PathStep {
+	vx := reflect.ValueOf(x)
+	vy := reflect.ValueOf(y)
+
+	// If the inputs are different types, auto-wrap them in an empty interface
+	// so that they have the same parent type.
+	var t reflect.Type
+	if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() {
+		t = reflect.TypeOf((*interface{})(nil)).Elem()
+		if vx.IsValid() {
+			vvx := reflect.New(t).Elem()
+			vvx.Set(vx)
+			vx = vvx
+		}
+		if vy.IsValid() {
+			vvy := reflect.New(t).Elem()
+			vvy.Set(vy)
+			vy = vvy
+		}
+	} else {
+		t = vx.Type()
+	}
+
+	return &pathStep{t, vx, vy}
+}
+
 type state struct {
 type state struct {
 	// These fields represent the "comparison state".
 	// These fields represent the "comparison state".
 	// Calling statelessCompare must not result in observable changes to these.
 	// Calling statelessCompare must not result in observable changes to these.
-	result   diff.Result // The current result of comparison
-	curPath  Path        // The current path in the value tree
-	reporter reporter    // Optional reporter used for difference formatting
+	result    diff.Result // The current result of comparison
+	curPath   Path        // The current path in the value tree
+	curPtrs   pointerPath // The current set of visited pointers
+	reporters []reporter  // Optional reporters
+
+	// recChecker checks for infinite cycles applying the same set of
+	// transformers upon the output of itself.
+	recChecker recChecker
 
 
 	// dynChecker triggers pseudo-random checks for option correctness.
 	// dynChecker triggers pseudo-random checks for option correctness.
 	// It is safe for statelessCompare to mutate this value.
 	// It is safe for statelessCompare to mutate this value.
 	dynChecker dynChecker
 	dynChecker dynChecker
 
 
 	// These fields, once set by processOption, will not change.
 	// These fields, once set by processOption, will not change.
-	exporters map[reflect.Type]bool // Set of structs with unexported field visibility
-	opts      Options               // List of all fundamental and filter options
+	exporters []exporter // List of exporters for structs with unexported fields
+	opts      Options    // List of all fundamental and filter options
 }
 }
 
 
 func newState(opts []Option) *state {
 func newState(opts []Option) *state {
-	s := new(state)
-	for _, opt := range opts {
-		s.processOption(opt)
-	}
+	// Always ensure a validator option exists to validate the inputs.
+	s := &state{opts: Options{validator{}}}
+	s.curPtrs.Init()
+	s.processOption(Options(opts))
 	return s
 	return s
 }
 }
 
 
@@ -144,18 +205,10 @@ func (s *state) processOption(opt Option) {
 			panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt))
 			panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt))
 		}
 		}
 		s.opts = append(s.opts, opt)
 		s.opts = append(s.opts, opt)
-	case visibleStructs:
-		if s.exporters == nil {
-			s.exporters = make(map[reflect.Type]bool)
-		}
-		for t := range opt {
-			s.exporters[t] = true
-		}
+	case exporter:
+		s.exporters = append(s.exporters, opt)
 	case reporter:
 	case reporter:
-		if s.reporter != nil {
-			panic("difference reporter already registered")
-		}
-		s.reporter = opt
+		s.reporters = append(s.reporters, opt)
 	default:
 	default:
 		panic(fmt.Sprintf("unknown option %T", opt))
 		panic(fmt.Sprintf("unknown option %T", opt))
 	}
 	}
@@ -164,153 +217,96 @@ func (s *state) processOption(opt Option) {
 // statelessCompare compares two values and returns the result.
 // statelessCompare compares two values and returns the result.
 // This function is stateless in that it does not alter the current result,
 // This function is stateless in that it does not alter the current result,
 // or output to any registered reporters.
 // or output to any registered reporters.
-func (s *state) statelessCompare(vx, vy reflect.Value) diff.Result {
-	// We do not save and restore the curPath because all of the compareX
-	// methods should properly push and pop from the path.
-	// It is an implementation bug if the contents of curPath differs from
+func (s *state) statelessCompare(step PathStep) diff.Result {
+	// We do not save and restore curPath and curPtrs because all of the
+	// compareX methods should properly push and pop from them.
+	// It is an implementation bug if the contents of the paths differ from
 	// when calling this function to when returning from it.
 	// when calling this function to when returning from it.
 
 
-	oldResult, oldReporter := s.result, s.reporter
+	oldResult, oldReporters := s.result, s.reporters
 	s.result = diff.Result{} // Reset result
 	s.result = diff.Result{} // Reset result
-	s.reporter = nil         // Remove reporter to avoid spurious printouts
-	s.compareAny(vx, vy)
+	s.reporters = nil        // Remove reporters to avoid spurious printouts
+	s.compareAny(step)
 	res := s.result
 	res := s.result
-	s.result, s.reporter = oldResult, oldReporter
+	s.result, s.reporters = oldResult, oldReporters
 	return res
 	return res
 }
 }
 
 
-func (s *state) compareAny(vx, vy reflect.Value) {
-	// TODO: Support cyclic data structures.
-
-	// Rule 0: Differing types are never equal.
-	if !vx.IsValid() || !vy.IsValid() {
-		s.report(vx.IsValid() == vy.IsValid(), vx, vy)
-		return
-	}
-	if vx.Type() != vy.Type() {
-		s.report(false, vx, vy) // Possible for path to be empty
-		return
+func (s *state) compareAny(step PathStep) {
+	// Update the path stack.
+	s.curPath.push(step)
+	defer s.curPath.pop()
+	for _, r := range s.reporters {
+		r.PushStep(step)
+		defer r.PopStep()
 	}
 	}
-	t := vx.Type()
-	if len(s.curPath) == 0 {
-		s.curPath.push(&pathStep{typ: t})
-		defer s.curPath.pop()
+	s.recChecker.Check(s.curPath)
+
+	// Cycle-detection for slice elements (see NOTE in compareSlice).
+	t := step.Type()
+	vx, vy := step.Values()
+	if si, ok := step.(SliceIndex); ok && si.isSlice && vx.IsValid() && vy.IsValid() {
+		px, py := vx.Addr(), vy.Addr()
+		if eq, visited := s.curPtrs.Push(px, py); visited {
+			s.report(eq, reportByCycle)
+			return
+		}
+		defer s.curPtrs.Pop(px, py)
 	}
 	}
-	vx, vy = s.tryExporting(vx, vy)
 
 
 	// Rule 1: Check whether an option applies on this node in the value tree.
 	// Rule 1: Check whether an option applies on this node in the value tree.
-	if s.tryOptions(vx, vy, t) {
+	if s.tryOptions(t, vx, vy) {
 		return
 		return
 	}
 	}
 
 
 	// Rule 2: Check whether the type has a valid Equal method.
 	// Rule 2: Check whether the type has a valid Equal method.
-	if s.tryMethod(vx, vy, t) {
+	if s.tryMethod(t, vx, vy) {
 		return
 		return
 	}
 	}
 
 
-	// Rule 3: Recursively descend into each value's underlying kind.
+	// Rule 3: Compare based on the underlying kind.
 	switch t.Kind() {
 	switch t.Kind() {
 	case reflect.Bool:
 	case reflect.Bool:
-		s.report(vx.Bool() == vy.Bool(), vx, vy)
-		return
+		s.report(vx.Bool() == vy.Bool(), 0)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		s.report(vx.Int() == vy.Int(), vx, vy)
-		return
+		s.report(vx.Int() == vy.Int(), 0)
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		s.report(vx.Uint() == vy.Uint(), vx, vy)
-		return
+		s.report(vx.Uint() == vy.Uint(), 0)
 	case reflect.Float32, reflect.Float64:
 	case reflect.Float32, reflect.Float64:
-		s.report(vx.Float() == vy.Float(), vx, vy)
-		return
+		s.report(vx.Float() == vy.Float(), 0)
 	case reflect.Complex64, reflect.Complex128:
 	case reflect.Complex64, reflect.Complex128:
-		s.report(vx.Complex() == vy.Complex(), vx, vy)
-		return
+		s.report(vx.Complex() == vy.Complex(), 0)
 	case reflect.String:
 	case reflect.String:
-		s.report(vx.String() == vy.String(), vx, vy)
-		return
+		s.report(vx.String() == vy.String(), 0)
 	case reflect.Chan, reflect.UnsafePointer:
 	case reflect.Chan, reflect.UnsafePointer:
-		s.report(vx.Pointer() == vy.Pointer(), vx, vy)
-		return
+		s.report(vx.Pointer() == vy.Pointer(), 0)
 	case reflect.Func:
 	case reflect.Func:
-		s.report(vx.IsNil() && vy.IsNil(), vx, vy)
-		return
+		s.report(vx.IsNil() && vy.IsNil(), 0)
+	case reflect.Struct:
+		s.compareStruct(t, vx, vy)
+	case reflect.Slice, reflect.Array:
+		s.compareSlice(t, vx, vy)
+	case reflect.Map:
+		s.compareMap(t, vx, vy)
 	case reflect.Ptr:
 	case reflect.Ptr:
-		if vx.IsNil() || vy.IsNil() {
-			s.report(vx.IsNil() && vy.IsNil(), vx, vy)
-			return
-		}
-		s.curPath.push(&indirect{pathStep{t.Elem()}})
-		defer s.curPath.pop()
-		s.compareAny(vx.Elem(), vy.Elem())
-		return
+		s.comparePtr(t, vx, vy)
 	case reflect.Interface:
 	case reflect.Interface:
-		if vx.IsNil() || vy.IsNil() {
-			s.report(vx.IsNil() && vy.IsNil(), vx, vy)
-			return
-		}
-		if vx.Elem().Type() != vy.Elem().Type() {
-			s.report(false, vx.Elem(), vy.Elem())
-			return
-		}
-		s.curPath.push(&typeAssertion{pathStep{vx.Elem().Type()}})
-		defer s.curPath.pop()
-		s.compareAny(vx.Elem(), vy.Elem())
-		return
-	case reflect.Slice:
-		if vx.IsNil() || vy.IsNil() {
-			s.report(vx.IsNil() && vy.IsNil(), vx, vy)
-			return
-		}
-		fallthrough
-	case reflect.Array:
-		s.compareArray(vx, vy, t)
-		return
-	case reflect.Map:
-		s.compareMap(vx, vy, t)
-		return
-	case reflect.Struct:
-		s.compareStruct(vx, vy, t)
-		return
+		s.compareInterface(t, vx, vy)
 	default:
 	default:
 		panic(fmt.Sprintf("%v kind not handled", t.Kind()))
 		panic(fmt.Sprintf("%v kind not handled", t.Kind()))
 	}
 	}
 }
 }
 
 
-func (s *state) tryExporting(vx, vy reflect.Value) (reflect.Value, reflect.Value) {
-	if sf, ok := s.curPath[len(s.curPath)-1].(*structField); ok && sf.unexported {
-		if sf.force {
-			// Use unsafe pointer arithmetic to get read-write access to an
-			// unexported field in the struct.
-			vx = unsafeRetrieveField(sf.pvx, sf.field)
-			vy = unsafeRetrieveField(sf.pvy, sf.field)
-		} else {
-			// We are not allowed to export the value, so invalidate them
-			// so that tryOptions can panic later if not explicitly ignored.
-			vx = nothing
-			vy = nothing
-		}
-	}
-	return vx, vy
-}
-
-func (s *state) tryOptions(vx, vy reflect.Value, t reflect.Type) bool {
-	// If there were no FilterValues, we will not detect invalid inputs,
-	// so manually check for them and append invalid if necessary.
-	// We still evaluate the options since an ignore can override invalid.
-	opts := s.opts
-	if !vx.IsValid() || !vy.IsValid() {
-		opts = Options{opts, invalid{}}
-	}
-
+func (s *state) tryOptions(t reflect.Type, vx, vy reflect.Value) bool {
 	// Evaluate all filters and apply the remaining options.
 	// Evaluate all filters and apply the remaining options.
-	if opt := opts.filter(s, vx, vy, t); opt != nil {
+	if opt := s.opts.filter(s, t, vx, vy); opt != nil {
 		opt.apply(s, vx, vy)
 		opt.apply(s, vx, vy)
 		return true
 		return true
 	}
 	}
 	return false
 	return false
 }
 }
 
 
-func (s *state) tryMethod(vx, vy reflect.Value, t reflect.Type) bool {
+func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool {
 	// Check if this type even has an Equal method.
 	// Check if this type even has an Equal method.
 	m, ok := t.MethodByName("Equal")
 	m, ok := t.MethodByName("Equal")
 	if !ok || !function.IsType(m.Type, function.EqualAssignable) {
 	if !ok || !function.IsType(m.Type, function.EqualAssignable) {
@@ -318,11 +314,11 @@ func (s *state) tryMethod(vx, vy reflect.Value, t reflect.Type) bool {
 	}
 	}
 
 
 	eq := s.callTTBFunc(m.Func, vx, vy)
 	eq := s.callTTBFunc(m.Func, vx, vy)
-	s.report(eq, vx, vy)
+	s.report(eq, reportByMethod)
 	return true
 	return true
 }
 }
 
 
-func (s *state) callTRFunc(f, v reflect.Value) reflect.Value {
+func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value {
 	v = sanitizeValue(v, f.Type().In(0))
 	v = sanitizeValue(v, f.Type().In(0))
 	if !s.dynChecker.Next() {
 	if !s.dynChecker.Next() {
 		return f.Call([]reflect.Value{v})[0]
 		return f.Call([]reflect.Value{v})[0]
@@ -333,15 +329,15 @@ func (s *state) callTRFunc(f, v reflect.Value) reflect.Value {
 	// unsafe mutations to the input.
 	// unsafe mutations to the input.
 	c := make(chan reflect.Value)
 	c := make(chan reflect.Value)
 	go detectRaces(c, f, v)
 	go detectRaces(c, f, v)
+	got := <-c
 	want := f.Call([]reflect.Value{v})[0]
 	want := f.Call([]reflect.Value{v})[0]
-	if got := <-c; !s.statelessCompare(got, want).Equal() {
+	if step.vx, step.vy = got, want; !s.statelessCompare(step).Equal() {
 		// To avoid false-positives with non-reflexive equality operations,
 		// To avoid false-positives with non-reflexive equality operations,
 		// we sanity check whether a value is equal to itself.
 		// we sanity check whether a value is equal to itself.
-		if !s.statelessCompare(want, want).Equal() {
+		if step.vx, step.vy = want, want; !s.statelessCompare(step).Equal() {
 			return want
 			return want
 		}
 		}
-		fn := getFuncName(f.Pointer())
-		panic(fmt.Sprintf("non-deterministic function detected: %s", fn))
+		panic(fmt.Sprintf("non-deterministic function detected: %s", function.NameOf(f)))
 	}
 	}
 	return want
 	return want
 }
 }
@@ -359,10 +355,10 @@ func (s *state) callTTBFunc(f, x, y reflect.Value) bool {
 	// unsafe mutations to the input.
 	// unsafe mutations to the input.
 	c := make(chan reflect.Value)
 	c := make(chan reflect.Value)
 	go detectRaces(c, f, y, x)
 	go detectRaces(c, f, y, x)
+	got := <-c
 	want := f.Call([]reflect.Value{x, y})[0].Bool()
 	want := f.Call([]reflect.Value{x, y})[0].Bool()
-	if got := <-c; !got.IsValid() || got.Bool() != want {
-		fn := getFuncName(f.Pointer())
-		panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", fn))
+	if !got.IsValid() || got.Bool() != want {
+		panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", function.NameOf(f)))
 	}
 	}
 	return want
 	return want
 }
 }
@@ -380,140 +376,273 @@ func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) {
 // assuming that T is assignable to R.
 // assuming that T is assignable to R.
 // Otherwise, it returns the input value as is.
 // Otherwise, it returns the input value as is.
 func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
 func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
-	// TODO(dsnet): Remove this hacky workaround.
-	// See https://golang.org/issue/22143
-	if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t {
-		return reflect.New(t).Elem()
+	// TODO(≥go1.10): Workaround for reflect bug (https://golang.org/issue/22143).
+	if !flags.AtLeastGo110 {
+		if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t {
+			return reflect.New(t).Elem()
+		}
 	}
 	}
 	return v
 	return v
 }
 }
 
 
-func (s *state) compareArray(vx, vy reflect.Value, t reflect.Type) {
-	step := &sliceIndex{pathStep{t.Elem()}, 0, 0}
-	s.curPath.push(step)
+func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
+	var addr bool
+	var vax, vay reflect.Value // Addressable versions of vx and vy
 
 
-	// Compute an edit-script for slices vx and vy.
-	es := diff.Difference(vx.Len(), vy.Len(), func(ix, iy int) diff.Result {
-		step.xkey, step.ykey = ix, iy
-		return s.statelessCompare(vx.Index(ix), vy.Index(iy))
-	})
+	var mayForce, mayForceInit bool
+	step := StructField{&structField{}}
+	for i := 0; i < t.NumField(); i++ {
+		step.typ = t.Field(i).Type
+		step.vx = vx.Field(i)
+		step.vy = vy.Field(i)
+		step.name = t.Field(i).Name
+		step.idx = i
+		step.unexported = !isExported(step.name)
+		if step.unexported {
+			if step.name == "_" {
+				continue
+			}
+			// Defer checking of unexported fields until later to give an
+			// Ignore a chance to ignore the field.
+			if !vax.IsValid() || !vay.IsValid() {
+				// For retrieveUnexportedField to work, the parent struct must
+				// be addressable. Create a new copy of the values if
+				// necessary to make them addressable.
+				addr = vx.CanAddr() || vy.CanAddr()
+				vax = makeAddressable(vx)
+				vay = makeAddressable(vy)
+			}
+			if !mayForceInit {
+				for _, xf := range s.exporters {
+					mayForce = mayForce || xf(t)
+				}
+				mayForceInit = true
+			}
+			step.mayForce = mayForce
+			step.paddr = addr
+			step.pvx = vax
+			step.pvy = vay
+			step.field = t.Field(i)
+		}
+		s.compareAny(step)
+	}
+}
 
 
-	// Report the entire slice as is if the arrays are of primitive kind,
-	// and the arrays are different enough.
-	isPrimitive := false
-	switch t.Elem().Kind() {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
-		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
-		reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
-		isPrimitive = true
-	}
-	if isPrimitive && es.Dist() > (vx.Len()+vy.Len())/4 {
-		s.curPath.pop() // Pop first since we are reporting the whole slice
-		s.report(false, vx, vy)
+func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) {
+	isSlice := t.Kind() == reflect.Slice
+	if isSlice && (vx.IsNil() || vy.IsNil()) {
+		s.report(vx.IsNil() && vy.IsNil(), 0)
 		return
 		return
 	}
 	}
 
 
-	// Replay the edit-script.
+	// NOTE: It is incorrect to call curPtrs.Push on the slice header pointer
+	// since slices represents a list of pointers, rather than a single pointer.
+	// The pointer checking logic must be handled on a per-element basis
+	// in compareAny.
+	//
+	// A slice header (see reflect.SliceHeader) in Go is a tuple of a starting
+	// pointer P, a length N, and a capacity C. Supposing each slice element has
+	// a memory size of M, then the slice is equivalent to the list of pointers:
+	//	[P+i*M for i in range(N)]
+	//
+	// For example, v[:0] and v[:1] are slices with the same starting pointer,
+	// but they are clearly different values. Using the slice pointer alone
+	// violates the assumption that equal pointers implies equal values.
+
+	step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}, isSlice: isSlice}}
+	withIndexes := func(ix, iy int) SliceIndex {
+		if ix >= 0 {
+			step.vx, step.xkey = vx.Index(ix), ix
+		} else {
+			step.vx, step.xkey = reflect.Value{}, -1
+		}
+		if iy >= 0 {
+			step.vy, step.ykey = vy.Index(iy), iy
+		} else {
+			step.vy, step.ykey = reflect.Value{}, -1
+		}
+		return step
+	}
+
+	// Ignore options are able to ignore missing elements in a slice.
+	// However, detecting these reliably requires an optimal differencing
+	// algorithm, for which diff.Difference is not.
+	//
+	// Instead, we first iterate through both slices to detect which elements
+	// would be ignored if standing alone. The index of non-discarded elements
+	// are stored in a separate slice, which diffing is then performed on.
+	var indexesX, indexesY []int
+	var ignoredX, ignoredY []bool
+	for ix := 0; ix < vx.Len(); ix++ {
+		ignored := s.statelessCompare(withIndexes(ix, -1)).NumDiff == 0
+		if !ignored {
+			indexesX = append(indexesX, ix)
+		}
+		ignoredX = append(ignoredX, ignored)
+	}
+	for iy := 0; iy < vy.Len(); iy++ {
+		ignored := s.statelessCompare(withIndexes(-1, iy)).NumDiff == 0
+		if !ignored {
+			indexesY = append(indexesY, iy)
+		}
+		ignoredY = append(ignoredY, ignored)
+	}
+
+	// Compute an edit-script for slices vx and vy (excluding ignored elements).
+	edits := diff.Difference(len(indexesX), len(indexesY), func(ix, iy int) diff.Result {
+		return s.statelessCompare(withIndexes(indexesX[ix], indexesY[iy]))
+	})
+
+	// Replay the ignore-scripts and the edit-script.
 	var ix, iy int
 	var ix, iy int
-	for _, e := range es {
+	for ix < vx.Len() || iy < vy.Len() {
+		var e diff.EditType
+		switch {
+		case ix < len(ignoredX) && ignoredX[ix]:
+			e = diff.UniqueX
+		case iy < len(ignoredY) && ignoredY[iy]:
+			e = diff.UniqueY
+		default:
+			e, edits = edits[0], edits[1:]
+		}
 		switch e {
 		switch e {
 		case diff.UniqueX:
 		case diff.UniqueX:
-			step.xkey, step.ykey = ix, -1
-			s.report(false, vx.Index(ix), nothing)
+			s.compareAny(withIndexes(ix, -1))
 			ix++
 			ix++
 		case diff.UniqueY:
 		case diff.UniqueY:
-			step.xkey, step.ykey = -1, iy
-			s.report(false, nothing, vy.Index(iy))
+			s.compareAny(withIndexes(-1, iy))
 			iy++
 			iy++
 		default:
 		default:
-			step.xkey, step.ykey = ix, iy
-			if e == diff.Identity {
-				s.report(true, vx.Index(ix), vy.Index(iy))
-			} else {
-				s.compareAny(vx.Index(ix), vy.Index(iy))
-			}
+			s.compareAny(withIndexes(ix, iy))
 			ix++
 			ix++
 			iy++
 			iy++
 		}
 		}
 	}
 	}
-	s.curPath.pop()
-	return
 }
 }
 
 
-func (s *state) compareMap(vx, vy reflect.Value, t reflect.Type) {
+func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) {
 	if vx.IsNil() || vy.IsNil() {
 	if vx.IsNil() || vy.IsNil() {
-		s.report(vx.IsNil() && vy.IsNil(), vx, vy)
+		s.report(vx.IsNil() && vy.IsNil(), 0)
+		return
+	}
+
+	// Cycle-detection for maps.
+	if eq, visited := s.curPtrs.Push(vx, vy); visited {
+		s.report(eq, reportByCycle)
 		return
 		return
 	}
 	}
+	defer s.curPtrs.Pop(vx, vy)
 
 
 	// We combine and sort the two map keys so that we can perform the
 	// We combine and sort the two map keys so that we can perform the
 	// comparisons in a deterministic order.
 	// comparisons in a deterministic order.
-	step := &mapIndex{pathStep: pathStep{t.Elem()}}
-	s.curPath.push(step)
-	defer s.curPath.pop()
+	step := MapIndex{&mapIndex{pathStep: pathStep{typ: t.Elem()}}}
 	for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) {
 	for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) {
+		step.vx = vx.MapIndex(k)
+		step.vy = vy.MapIndex(k)
 		step.key = k
 		step.key = k
-		vvx := vx.MapIndex(k)
-		vvy := vy.MapIndex(k)
-		switch {
-		case vvx.IsValid() && vvy.IsValid():
-			s.compareAny(vvx, vvy)
-		case vvx.IsValid() && !vvy.IsValid():
-			s.report(false, vvx, nothing)
-		case !vvx.IsValid() && vvy.IsValid():
-			s.report(false, nothing, vvy)
-		default:
-			// It is possible for both vvx and vvy to be invalid if the
-			// key contained a NaN value in it. There is no way in
-			// reflection to be able to retrieve these values.
-			// See https://golang.org/issue/11104
-			panic(fmt.Sprintf("%#v has map key with NaNs", s.curPath))
+		if !step.vx.IsValid() && !step.vy.IsValid() {
+			// It is possible for both vx and vy to be invalid if the
+			// key contained a NaN value in it.
+			//
+			// Even with the ability to retrieve NaN keys in Go 1.12,
+			// there still isn't a sensible way to compare the values since
+			// a NaN key may map to multiple unordered values.
+			// The most reasonable way to compare NaNs would be to compare the
+			// set of values. However, this is impossible to do efficiently
+			// since set equality is provably an O(n^2) operation given only
+			// an Equal function. If we had a Less function or Hash function,
+			// this could be done in O(n*log(n)) or O(n), respectively.
+			//
+			// Rather than adding complex logic to deal with NaNs, make it
+			// the user's responsibility to compare such obscure maps.
+			const help = "consider providing a Comparer to compare the map"
+			panic(fmt.Sprintf("%#v has map key with NaNs\n%s", s.curPath, help))
 		}
 		}
+		s.compareAny(step)
 	}
 	}
 }
 }
 
 
-func (s *state) compareStruct(vx, vy reflect.Value, t reflect.Type) {
-	var vax, vay reflect.Value // Addressable versions of vx and vy
+func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) {
+	if vx.IsNil() || vy.IsNil() {
+		s.report(vx.IsNil() && vy.IsNil(), 0)
+		return
+	}
 
 
-	step := &structField{}
-	s.curPath.push(step)
-	defer s.curPath.pop()
-	for i := 0; i < t.NumField(); i++ {
-		vvx := vx.Field(i)
-		vvy := vy.Field(i)
-		step.typ = t.Field(i).Type
-		step.name = t.Field(i).Name
-		step.idx = i
-		step.unexported = !isExported(step.name)
-		if step.unexported {
-			// Defer checking of unexported fields until later to give an
-			// Ignore a chance to ignore the field.
-			if !vax.IsValid() || !vay.IsValid() {
-				// For unsafeRetrieveField to work, the parent struct must
-				// be addressable. Create a new copy of the values if
-				// necessary to make them addressable.
-				vax = makeAddressable(vx)
-				vay = makeAddressable(vy)
-			}
-			step.force = s.exporters[t]
-			step.pvx = vax
-			step.pvy = vay
-			step.field = t.Field(i)
+	// Cycle-detection for pointers.
+	if eq, visited := s.curPtrs.Push(vx, vy); visited {
+		s.report(eq, reportByCycle)
+		return
+	}
+	defer s.curPtrs.Pop(vx, vy)
+
+	vx, vy = vx.Elem(), vy.Elem()
+	s.compareAny(Indirect{&indirect{pathStep{t.Elem(), vx, vy}}})
+}
+
+func (s *state) compareInterface(t reflect.Type, vx, vy reflect.Value) {
+	if vx.IsNil() || vy.IsNil() {
+		s.report(vx.IsNil() && vy.IsNil(), 0)
+		return
+	}
+	vx, vy = vx.Elem(), vy.Elem()
+	if vx.Type() != vy.Type() {
+		s.report(false, 0)
+		return
+	}
+	s.compareAny(TypeAssertion{&typeAssertion{pathStep{vx.Type(), vx, vy}}})
+}
+
+func (s *state) report(eq bool, rf resultFlags) {
+	if rf&reportByIgnore == 0 {
+		if eq {
+			s.result.NumSame++
+			rf |= reportEqual
+		} else {
+			s.result.NumDiff++
+			rf |= reportUnequal
 		}
 		}
-		s.compareAny(vvx, vvy)
+	}
+	for _, r := range s.reporters {
+		r.Report(Result{flags: rf})
 	}
 	}
 }
 }
 
 
-// report records the result of a single comparison.
-// It also calls Report if any reporter is registered.
-func (s *state) report(eq bool, vx, vy reflect.Value) {
-	if eq {
-		s.result.NSame++
-	} else {
-		s.result.NDiff++
+// recChecker tracks the state needed to periodically perform checks that
+// user provided transformers are not stuck in an infinitely recursive cycle.
+type recChecker struct{ next int }
+
+// Check scans the Path for any recursive transformers and panics when any
+// recursive transformers are detected. Note that the presence of a
+// recursive Transformer does not necessarily imply an infinite cycle.
+// As such, this check only activates after some minimal number of path steps.
+func (rc *recChecker) Check(p Path) {
+	const minLen = 1 << 16
+	if rc.next == 0 {
+		rc.next = minLen
+	}
+	if len(p) < rc.next {
+		return
+	}
+	rc.next <<= 1
+
+	// Check whether the same transformer has appeared at least twice.
+	var ss []string
+	m := map[Option]int{}
+	for _, ps := range p {
+		if t, ok := ps.(Transform); ok {
+			t := t.Option()
+			if m[t] == 1 { // Transformer was used exactly once before
+				tf := t.(*transformer).fnc.Type()
+				ss = append(ss, fmt.Sprintf("%v: %v => %v", t, tf.In(0), tf.Out(0)))
+			}
+			m[t]++
+		}
 	}
 	}
-	if s.reporter != nil {
-		s.reporter.Report(vx, vy, eq, s.curPath)
+	if len(ss) > 0 {
+		const warning = "recursive set of Transformers detected"
+		const help = "consider using cmpopts.AcyclicTransformer"
+		set := strings.Join(ss, "\n\t")
+		panic(fmt.Sprintf("%s:\n\t%s\n%s", warning, set, help))
 	}
 	}
 }
 }
 
 

+ 15 - 0
vendor/github.com/google/go-cmp/cmp/export_panic.go

@@ -0,0 +1,15 @@
+// Copyright 2017, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build purego
+
+package cmp
+
+import "reflect"
+
+const supportExporters = false
+
+func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value {
+	panic("no support for forcibly accessing unexported fields")
+}

+ 35 - 0
vendor/github.com/google/go-cmp/cmp/export_unsafe.go

@@ -0,0 +1,35 @@
+// Copyright 2017, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !purego
+
+package cmp
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+const supportExporters = true
+
+// retrieveUnexportedField uses unsafe to forcibly retrieve any field from
+// a struct such that the value has read-write permissions.
+//
+// The parent struct, v, must be addressable, while f must be a StructField
+// describing the field to retrieve. If addr is false,
+// then the returned value will be shallowed copied to be non-addressable.
+func retrieveUnexportedField(v reflect.Value, f reflect.StructField, addr bool) reflect.Value {
+	ve := reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem()
+	if !addr {
+		// A field is addressable if and only if the struct is addressable.
+		// If the original parent value was not addressable, shallow copy the
+		// value to make it non-addressable to avoid leaking an implementation
+		// detail of how forcibly exporting a field works.
+		if ve.Kind() == reflect.Interface && ve.IsNil() {
+			return reflect.Zero(f.Type)
+		}
+		return reflect.ValueOf(ve.Interface()).Convert(f.Type)
+	}
+	return ve
+}

+ 2 - 2
vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go

@@ -1,8 +1,8 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
-// +build !debug
+// +build !cmp_debug
 
 
 package diff
 package diff
 
 

+ 3 - 3
vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go

@@ -1,8 +1,8 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
-// +build debug
+// +build cmp_debug
 
 
 package diff
 package diff
 
 
@@ -14,7 +14,7 @@ import (
 )
 )
 
 
 // The algorithm can be seen running in real-time by enabling debugging:
 // The algorithm can be seen running in real-time by enabling debugging:
-//	go test -tags=debug -v
+//	go test -tags=cmp_debug -v
 //
 //
 // Example output:
 // Example output:
 //	=== RUN   TestDifference/#34
 //	=== RUN   TestDifference/#34

+ 52 - 17
vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go

@@ -1,6 +1,6 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 // Package diff implements an algorithm for producing edit-scripts.
 // Package diff implements an algorithm for producing edit-scripts.
 // The edit-script is a sequence of operations needed to transform one list
 // The edit-script is a sequence of operations needed to transform one list
@@ -12,6 +12,13 @@
 // is more important than obtaining a minimal Levenshtein distance.
 // is more important than obtaining a minimal Levenshtein distance.
 package diff
 package diff
 
 
+import (
+	"math/rand"
+	"time"
+
+	"github.com/google/go-cmp/cmp/internal/flags"
+)
+
 // EditType represents a single operation within an edit-script.
 // EditType represents a single operation within an edit-script.
 type EditType uint8
 type EditType uint8
 
 
@@ -85,24 +92,35 @@ func (es EditScript) LenY() int { return len(es) - es.stats().NX }
 type EqualFunc func(ix int, iy int) Result
 type EqualFunc func(ix int, iy int) Result
 
 
 // Result is the result of comparison.
 // Result is the result of comparison.
-// NSame is the number of sub-elements that are equal.
-// NDiff is the number of sub-elements that are not equal.
-type Result struct{ NSame, NDiff int }
+// NumSame is the number of sub-elements that are equal.
+// NumDiff is the number of sub-elements that are not equal.
+type Result struct{ NumSame, NumDiff int }
+
+// BoolResult returns a Result that is either Equal or not Equal.
+func BoolResult(b bool) Result {
+	if b {
+		return Result{NumSame: 1} // Equal, Similar
+	} else {
+		return Result{NumDiff: 2} // Not Equal, not Similar
+	}
+}
 
 
 // Equal indicates whether the symbols are equal. Two symbols are equal
 // Equal indicates whether the symbols are equal. Two symbols are equal
-// if and only if NDiff == 0. If Equal, then they are also Similar.
-func (r Result) Equal() bool { return r.NDiff == 0 }
+// if and only if NumDiff == 0. If Equal, then they are also Similar.
+func (r Result) Equal() bool { return r.NumDiff == 0 }
 
 
 // Similar indicates whether two symbols are similar and may be represented
 // Similar indicates whether two symbols are similar and may be represented
 // by using the Modified type. As a special case, we consider binary comparisons
 // by using the Modified type. As a special case, we consider binary comparisons
 // (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar.
 // (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar.
 //
 //
-// The exact ratio of NSame to NDiff to determine similarity may change.
+// The exact ratio of NumSame to NumDiff to determine similarity may change.
 func (r Result) Similar() bool {
 func (r Result) Similar() bool {
-	// Use NSame+1 to offset NSame so that binary comparisons are similar.
-	return r.NSame+1 >= r.NDiff
+	// Use NumSame+1 to offset NumSame so that binary comparisons are similar.
+	return r.NumSame+1 >= r.NumDiff
 }
 }
 
 
+var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
+
 // Difference reports whether two lists of lengths nx and ny are equal
 // Difference reports whether two lists of lengths nx and ny are equal
 // given the definition of equality provided as f.
 // given the definition of equality provided as f.
 //
 //
@@ -168,6 +186,11 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
 	// approximately the square-root of the search budget.
 	// approximately the square-root of the search budget.
 	searchBudget := 4 * (nx + ny) // O(n)
 	searchBudget := 4 * (nx + ny) // O(n)
 
 
+	// Running the tests with the "cmp_debug" build tag prints a visualization
+	// of the algorithm running in real-time. This is educational for
+	// understanding how the algorithm works. See debug_enable.go.
+	f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es)
+
 	// The algorithm below is a greedy, meet-in-the-middle algorithm for
 	// The algorithm below is a greedy, meet-in-the-middle algorithm for
 	// computing sub-optimal edit-scripts between two lists.
 	// computing sub-optimal edit-scripts between two lists.
 	//
 	//
@@ -185,20 +208,26 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
 	//	frontier towards the opposite corner.
 	//	frontier towards the opposite corner.
 	//	• This algorithm terminates when either the X coordinates or the
 	//	• This algorithm terminates when either the X coordinates or the
 	//	Y coordinates of the forward and reverse frontier points ever intersect.
 	//	Y coordinates of the forward and reverse frontier points ever intersect.
-	//
+
 	// This algorithm is correct even if searching only in the forward direction
 	// This algorithm is correct even if searching only in the forward direction
 	// or in the reverse direction. We do both because it is commonly observed
 	// or in the reverse direction. We do both because it is commonly observed
 	// that two lists commonly differ because elements were added to the front
 	// that two lists commonly differ because elements were added to the front
 	// or end of the other list.
 	// or end of the other list.
 	//
 	//
-	// Running the tests with the "debug" build tag prints a visualization of
-	// the algorithm running in real-time. This is educational for understanding
-	// how the algorithm works. See debug_enable.go.
-	f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es)
-	for {
+	// Non-deterministically start with either the forward or reverse direction
+	// to introduce some deliberate instability so that we have the flexibility
+	// to change this algorithm in the future.
+	if flags.Deterministic || randBool {
+		goto forwardSearch
+	} else {
+		goto reverseSearch
+	}
+
+forwardSearch:
+	{
 		// Forward search from the beginning.
 		// Forward search from the beginning.
 		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 {
 		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 {
-			break
+			goto finishSearch
 		}
 		}
 		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ {
 		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ {
 			// Search in a diagonal pattern for a match.
 			// Search in a diagonal pattern for a match.
@@ -233,10 +262,14 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
 		} else {
 		} else {
 			fwdFrontier.Y++
 			fwdFrontier.Y++
 		}
 		}
+		goto reverseSearch
+	}
 
 
+reverseSearch:
+	{
 		// Reverse search from the end.
 		// Reverse search from the end.
 		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 {
 		if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 {
-			break
+			goto finishSearch
 		}
 		}
 		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ {
 		for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ {
 			// Search in a diagonal pattern for a match.
 			// Search in a diagonal pattern for a match.
@@ -271,8 +304,10 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
 		} else {
 		} else {
 			revFrontier.Y--
 			revFrontier.Y--
 		}
 		}
+		goto forwardSearch
 	}
 	}
 
 
+finishSearch:
 	// Join the forward and reverse paths and then append the reverse path.
 	// Join the forward and reverse paths and then append the reverse path.
 	fwdPath.connect(revPath.point, f)
 	fwdPath.connect(revPath.point, f)
 	for i := len(revPath.es) - 1; i >= 0; i-- {
 	for i := len(revPath.es) - 1; i >= 0; i-- {

+ 9 - 0
vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go

@@ -0,0 +1,9 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flags
+
+// Deterministic controls whether the output of Diff should be deterministic.
+// This is only used for testing.
+var Deterministic bool

+ 10 - 0
vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go

@@ -0,0 +1,10 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.10
+
+package flags
+
+// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10.
+const AtLeastGo110 = false

+ 10 - 0
vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go

@@ -0,0 +1,10 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.10
+
+package flags
+
+// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10.
+const AtLeastGo110 = true

+ 58 - 8
vendor/github.com/google/go-cmp/cmp/internal/function/func.go

@@ -1,26 +1,35 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
-// Package function identifies function types.
+// Package function provides functionality for identifying function types.
 package function
 package function
 
 
-import "reflect"
+import (
+	"reflect"
+	"regexp"
+	"runtime"
+	"strings"
+)
 
 
 type funcType int
 type funcType int
 
 
 const (
 const (
 	_ funcType = iota
 	_ funcType = iota
 
 
+	tbFunc  // func(T) bool
 	ttbFunc // func(T, T) bool
 	ttbFunc // func(T, T) bool
+	trbFunc // func(T, R) bool
 	tibFunc // func(T, I) bool
 	tibFunc // func(T, I) bool
 	trFunc  // func(T) R
 	trFunc  // func(T) R
 
 
-	Equal           = ttbFunc // func(T, T) bool
-	EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool
-	Transformer     = trFunc  // func(T) R
-	ValueFilter     = ttbFunc // func(T, T) bool
-	Less            = ttbFunc // func(T, T) bool
+	Equal             = ttbFunc // func(T, T) bool
+	EqualAssignable   = tibFunc // func(T, I) bool; encapsulates func(T, T) bool
+	Transformer       = trFunc  // func(T) R
+	ValueFilter       = ttbFunc // func(T, T) bool
+	Less              = ttbFunc // func(T, T) bool
+	ValuePredicate    = tbFunc  // func(T) bool
+	KeyValuePredicate = trbFunc // func(T, R) bool
 )
 )
 
 
 var boolType = reflect.TypeOf(true)
 var boolType = reflect.TypeOf(true)
@@ -32,10 +41,18 @@ func IsType(t reflect.Type, ft funcType) bool {
 	}
 	}
 	ni, no := t.NumIn(), t.NumOut()
 	ni, no := t.NumIn(), t.NumOut()
 	switch ft {
 	switch ft {
+	case tbFunc: // func(T) bool
+		if ni == 1 && no == 1 && t.Out(0) == boolType {
+			return true
+		}
 	case ttbFunc: // func(T, T) bool
 	case ttbFunc: // func(T, T) bool
 		if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType {
 		if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType {
 			return true
 			return true
 		}
 		}
+	case trbFunc: // func(T, R) bool
+		if ni == 2 && no == 1 && t.Out(0) == boolType {
+			return true
+		}
 	case tibFunc: // func(T, I) bool
 	case tibFunc: // func(T, I) bool
 		if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType {
 		if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType {
 			return true
 			return true
@@ -47,3 +64,36 @@ func IsType(t reflect.Type, ft funcType) bool {
 	}
 	}
 	return false
 	return false
 }
 }
+
+var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`)
+
+// NameOf returns the name of the function value.
+func NameOf(v reflect.Value) string {
+	fnc := runtime.FuncForPC(v.Pointer())
+	if fnc == nil {
+		return "<unknown>"
+	}
+	fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm"
+
+	// Method closures have a "-fm" suffix.
+	fullName = strings.TrimSuffix(fullName, "-fm")
+
+	var name string
+	for len(fullName) > 0 {
+		inParen := strings.HasSuffix(fullName, ")")
+		fullName = strings.TrimSuffix(fullName, ")")
+
+		s := lastIdentRx.FindString(fullName)
+		if s == "" {
+			break
+		}
+		name = s + "." + name
+		fullName = strings.TrimSuffix(fullName, s)
+
+		if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 {
+			fullName = fullName[:i]
+		}
+		fullName = strings.TrimSuffix(fullName, ".")
+	}
+	return strings.TrimSuffix(name, ".")
+}

+ 0 - 277
vendor/github.com/google/go-cmp/cmp/internal/value/format.go

@@ -1,277 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
-
-// Package value provides functionality for reflect.Value types.
-package value
-
-import (
-	"fmt"
-	"reflect"
-	"strconv"
-	"strings"
-	"unicode"
-)
-
-var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
-
-// Format formats the value v as a string.
-//
-// This is similar to fmt.Sprintf("%+v", v) except this:
-//	* Prints the type unless it can be elided
-//	* Avoids printing struct fields that are zero
-//	* Prints a nil-slice as being nil, not empty
-//	* Prints map entries in deterministic order
-func Format(v reflect.Value, conf FormatConfig) string {
-	conf.printType = true
-	conf.followPointers = true
-	conf.realPointers = true
-	return formatAny(v, conf, nil)
-}
-
-type FormatConfig struct {
-	UseStringer        bool // Should the String method be used if available?
-	printType          bool // Should we print the type before the value?
-	PrintPrimitiveType bool // Should we print the type of primitives?
-	followPointers     bool // Should we recursively follow pointers?
-	realPointers       bool // Should we print the real address of pointers?
-}
-
-func formatAny(v reflect.Value, conf FormatConfig, visited map[uintptr]bool) string {
-	// TODO: Should this be a multi-line printout in certain situations?
-
-	if !v.IsValid() {
-		return "<non-existent>"
-	}
-	if conf.UseStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
-		if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
-			return "<nil>"
-		}
-
-		const stringerPrefix = "s" // Indicates that the String method was used
-		s := v.Interface().(fmt.Stringer).String()
-		return stringerPrefix + formatString(s)
-	}
-
-	switch v.Kind() {
-	case reflect.Bool:
-		return formatPrimitive(v.Type(), v.Bool(), conf)
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return formatPrimitive(v.Type(), v.Int(), conf)
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		if v.Type().PkgPath() == "" || v.Kind() == reflect.Uintptr {
-			// Unnamed uints are usually bytes or words, so use hexadecimal.
-			return formatPrimitive(v.Type(), formatHex(v.Uint()), conf)
-		}
-		return formatPrimitive(v.Type(), v.Uint(), conf)
-	case reflect.Float32, reflect.Float64:
-		return formatPrimitive(v.Type(), v.Float(), conf)
-	case reflect.Complex64, reflect.Complex128:
-		return formatPrimitive(v.Type(), v.Complex(), conf)
-	case reflect.String:
-		return formatPrimitive(v.Type(), formatString(v.String()), conf)
-	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
-		return formatPointer(v, conf)
-	case reflect.Ptr:
-		if v.IsNil() {
-			if conf.printType {
-				return fmt.Sprintf("(%v)(nil)", v.Type())
-			}
-			return "<nil>"
-		}
-		if visited[v.Pointer()] || !conf.followPointers {
-			return formatPointer(v, conf)
-		}
-		visited = insertPointer(visited, v.Pointer())
-		return "&" + formatAny(v.Elem(), conf, visited)
-	case reflect.Interface:
-		if v.IsNil() {
-			if conf.printType {
-				return fmt.Sprintf("%v(nil)", v.Type())
-			}
-			return "<nil>"
-		}
-		return formatAny(v.Elem(), conf, visited)
-	case reflect.Slice:
-		if v.IsNil() {
-			if conf.printType {
-				return fmt.Sprintf("%v(nil)", v.Type())
-			}
-			return "<nil>"
-		}
-		if visited[v.Pointer()] {
-			return formatPointer(v, conf)
-		}
-		visited = insertPointer(visited, v.Pointer())
-		fallthrough
-	case reflect.Array:
-		var ss []string
-		subConf := conf
-		subConf.printType = v.Type().Elem().Kind() == reflect.Interface
-		for i := 0; i < v.Len(); i++ {
-			s := formatAny(v.Index(i), subConf, visited)
-			ss = append(ss, s)
-		}
-		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
-		if conf.printType {
-			return v.Type().String() + s
-		}
-		return s
-	case reflect.Map:
-		if v.IsNil() {
-			if conf.printType {
-				return fmt.Sprintf("%v(nil)", v.Type())
-			}
-			return "<nil>"
-		}
-		if visited[v.Pointer()] {
-			return formatPointer(v, conf)
-		}
-		visited = insertPointer(visited, v.Pointer())
-
-		var ss []string
-		keyConf, valConf := conf, conf
-		keyConf.printType = v.Type().Key().Kind() == reflect.Interface
-		keyConf.followPointers = false
-		valConf.printType = v.Type().Elem().Kind() == reflect.Interface
-		for _, k := range SortKeys(v.MapKeys()) {
-			sk := formatAny(k, keyConf, visited)
-			sv := formatAny(v.MapIndex(k), valConf, visited)
-			ss = append(ss, fmt.Sprintf("%s: %s", sk, sv))
-		}
-		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
-		if conf.printType {
-			return v.Type().String() + s
-		}
-		return s
-	case reflect.Struct:
-		var ss []string
-		subConf := conf
-		subConf.printType = true
-		for i := 0; i < v.NumField(); i++ {
-			vv := v.Field(i)
-			if isZero(vv) {
-				continue // Elide zero value fields
-			}
-			name := v.Type().Field(i).Name
-			subConf.UseStringer = conf.UseStringer
-			s := formatAny(vv, subConf, visited)
-			ss = append(ss, fmt.Sprintf("%s: %s", name, s))
-		}
-		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
-		if conf.printType {
-			return v.Type().String() + s
-		}
-		return s
-	default:
-		panic(fmt.Sprintf("%v kind not handled", v.Kind()))
-	}
-}
-
-func formatString(s string) string {
-	// Use quoted string if it the same length as a raw string literal.
-	// Otherwise, attempt to use the raw string form.
-	qs := strconv.Quote(s)
-	if len(qs) == 1+len(s)+1 {
-		return qs
-	}
-
-	// Disallow newlines to ensure output is a single line.
-	// Only allow printable runes for readability purposes.
-	rawInvalid := func(r rune) bool {
-		return r == '`' || r == '\n' || !unicode.IsPrint(r)
-	}
-	if strings.IndexFunc(s, rawInvalid) < 0 {
-		return "`" + s + "`"
-	}
-	return qs
-}
-
-func formatPrimitive(t reflect.Type, v interface{}, conf FormatConfig) string {
-	if conf.printType && (conf.PrintPrimitiveType || t.PkgPath() != "") {
-		return fmt.Sprintf("%v(%v)", t, v)
-	}
-	return fmt.Sprintf("%v", v)
-}
-
-func formatPointer(v reflect.Value, conf FormatConfig) string {
-	p := v.Pointer()
-	if !conf.realPointers {
-		p = 0 // For deterministic printing purposes
-	}
-	s := formatHex(uint64(p))
-	if conf.printType {
-		return fmt.Sprintf("(%v)(%s)", v.Type(), s)
-	}
-	return s
-}
-
-func formatHex(u uint64) string {
-	var f string
-	switch {
-	case u <= 0xff:
-		f = "0x%02x"
-	case u <= 0xffff:
-		f = "0x%04x"
-	case u <= 0xffffff:
-		f = "0x%06x"
-	case u <= 0xffffffff:
-		f = "0x%08x"
-	case u <= 0xffffffffff:
-		f = "0x%010x"
-	case u <= 0xffffffffffff:
-		f = "0x%012x"
-	case u <= 0xffffffffffffff:
-		f = "0x%014x"
-	case u <= 0xffffffffffffffff:
-		f = "0x%016x"
-	}
-	return fmt.Sprintf(f, u)
-}
-
-// insertPointer insert p into m, allocating m if necessary.
-func insertPointer(m map[uintptr]bool, p uintptr) map[uintptr]bool {
-	if m == nil {
-		m = make(map[uintptr]bool)
-	}
-	m[p] = true
-	return m
-}
-
-// isZero reports whether v is the zero value.
-// This does not rely on Interface and so can be used on unexported fields.
-func isZero(v reflect.Value) bool {
-	switch v.Kind() {
-	case reflect.Bool:
-		return v.Bool() == false
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return v.Int() == 0
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return v.Uint() == 0
-	case reflect.Float32, reflect.Float64:
-		return v.Float() == 0
-	case reflect.Complex64, reflect.Complex128:
-		return v.Complex() == 0
-	case reflect.String:
-		return v.String() == ""
-	case reflect.UnsafePointer:
-		return v.Pointer() == 0
-	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
-		return v.IsNil()
-	case reflect.Array:
-		for i := 0; i < v.Len(); i++ {
-			if !isZero(v.Index(i)) {
-				return false
-			}
-		}
-		return true
-	case reflect.Struct:
-		for i := 0; i < v.NumField(); i++ {
-			if !isZero(v.Field(i)) {
-				return false
-			}
-		}
-		return true
-	}
-	return false
-}

+ 157 - 0
vendor/github.com/google/go-cmp/cmp/internal/value/name.go

@@ -0,0 +1,157 @@
+// Copyright 2020, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package value
+
+import (
+	"reflect"
+	"strconv"
+)
+
+// TypeString is nearly identical to reflect.Type.String,
+// but has an additional option to specify that full type names be used.
+func TypeString(t reflect.Type, qualified bool) string {
+	return string(appendTypeName(nil, t, qualified, false))
+}
+
+func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte {
+	// BUG: Go reflection provides no way to disambiguate two named types
+	// of the same name and within the same package,
+	// but declared within the namespace of different functions.
+
+	// Named type.
+	if t.Name() != "" {
+		if qualified && t.PkgPath() != "" {
+			b = append(b, '"')
+			b = append(b, t.PkgPath()...)
+			b = append(b, '"')
+			b = append(b, '.')
+			b = append(b, t.Name()...)
+		} else {
+			b = append(b, t.String()...)
+		}
+		return b
+	}
+
+	// Unnamed type.
+	switch k := t.Kind(); k {
+	case reflect.Bool, reflect.String, reflect.UnsafePointer,
+		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
+		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
+		b = append(b, k.String()...)
+	case reflect.Chan:
+		if t.ChanDir() == reflect.RecvDir {
+			b = append(b, "<-"...)
+		}
+		b = append(b, "chan"...)
+		if t.ChanDir() == reflect.SendDir {
+			b = append(b, "<-"...)
+		}
+		b = append(b, ' ')
+		b = appendTypeName(b, t.Elem(), qualified, false)
+	case reflect.Func:
+		if !elideFunc {
+			b = append(b, "func"...)
+		}
+		b = append(b, '(')
+		for i := 0; i < t.NumIn(); i++ {
+			if i > 0 {
+				b = append(b, ", "...)
+			}
+			if i == t.NumIn()-1 && t.IsVariadic() {
+				b = append(b, "..."...)
+				b = appendTypeName(b, t.In(i).Elem(), qualified, false)
+			} else {
+				b = appendTypeName(b, t.In(i), qualified, false)
+			}
+		}
+		b = append(b, ')')
+		switch t.NumOut() {
+		case 0:
+			// Do nothing
+		case 1:
+			b = append(b, ' ')
+			b = appendTypeName(b, t.Out(0), qualified, false)
+		default:
+			b = append(b, " ("...)
+			for i := 0; i < t.NumOut(); i++ {
+				if i > 0 {
+					b = append(b, ", "...)
+				}
+				b = appendTypeName(b, t.Out(i), qualified, false)
+			}
+			b = append(b, ')')
+		}
+	case reflect.Struct:
+		b = append(b, "struct{ "...)
+		for i := 0; i < t.NumField(); i++ {
+			if i > 0 {
+				b = append(b, "; "...)
+			}
+			sf := t.Field(i)
+			if !sf.Anonymous {
+				if qualified && sf.PkgPath != "" {
+					b = append(b, '"')
+					b = append(b, sf.PkgPath...)
+					b = append(b, '"')
+					b = append(b, '.')
+				}
+				b = append(b, sf.Name...)
+				b = append(b, ' ')
+			}
+			b = appendTypeName(b, sf.Type, qualified, false)
+			if sf.Tag != "" {
+				b = append(b, ' ')
+				b = strconv.AppendQuote(b, string(sf.Tag))
+			}
+		}
+		if b[len(b)-1] == ' ' {
+			b = b[:len(b)-1]
+		} else {
+			b = append(b, ' ')
+		}
+		b = append(b, '}')
+	case reflect.Slice, reflect.Array:
+		b = append(b, '[')
+		if k == reflect.Array {
+			b = strconv.AppendUint(b, uint64(t.Len()), 10)
+		}
+		b = append(b, ']')
+		b = appendTypeName(b, t.Elem(), qualified, false)
+	case reflect.Map:
+		b = append(b, "map["...)
+		b = appendTypeName(b, t.Key(), qualified, false)
+		b = append(b, ']')
+		b = appendTypeName(b, t.Elem(), qualified, false)
+	case reflect.Ptr:
+		b = append(b, '*')
+		b = appendTypeName(b, t.Elem(), qualified, false)
+	case reflect.Interface:
+		b = append(b, "interface{ "...)
+		for i := 0; i < t.NumMethod(); i++ {
+			if i > 0 {
+				b = append(b, "; "...)
+			}
+			m := t.Method(i)
+			if qualified && m.PkgPath != "" {
+				b = append(b, '"')
+				b = append(b, m.PkgPath...)
+				b = append(b, '"')
+				b = append(b, '.')
+			}
+			b = append(b, m.Name...)
+			b = appendTypeName(b, m.Type, qualified, true)
+		}
+		if b[len(b)-1] == ' ' {
+			b = b[:len(b)-1]
+		} else {
+			b = append(b, ' ')
+		}
+		b = append(b, '}')
+	default:
+		panic("invalid kind: " + k.String())
+	}
+	return b
+}

+ 33 - 0
vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go

@@ -0,0 +1,33 @@
+// Copyright 2018, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build purego
+
+package value
+
+import "reflect"
+
+// Pointer is an opaque typed pointer and is guaranteed to be comparable.
+type Pointer struct {
+	p uintptr
+	t reflect.Type
+}
+
+// PointerOf returns a Pointer from v, which must be a
+// reflect.Ptr, reflect.Slice, or reflect.Map.
+func PointerOf(v reflect.Value) Pointer {
+	// NOTE: Storing a pointer as an uintptr is technically incorrect as it
+	// assumes that the GC implementation does not use a moving collector.
+	return Pointer{v.Pointer(), v.Type()}
+}
+
+// IsNil reports whether the pointer is nil.
+func (p Pointer) IsNil() bool {
+	return p.p == 0
+}
+
+// Uintptr returns the pointer as a uintptr.
+func (p Pointer) Uintptr() uintptr {
+	return p.p
+}

+ 36 - 0
vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go

@@ -0,0 +1,36 @@
+// Copyright 2018, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !purego
+
+package value
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+// Pointer is an opaque typed pointer and is guaranteed to be comparable.
+type Pointer struct {
+	p unsafe.Pointer
+	t reflect.Type
+}
+
+// PointerOf returns a Pointer from v, which must be a
+// reflect.Ptr, reflect.Slice, or reflect.Map.
+func PointerOf(v reflect.Value) Pointer {
+	// The proper representation of a pointer is unsafe.Pointer,
+	// which is necessary if the GC ever uses a moving collector.
+	return Pointer{unsafe.Pointer(v.Pointer()), v.Type()}
+}
+
+// IsNil reports whether the pointer is nil.
+func (p Pointer) IsNil() bool {
+	return p.p == nil
+}
+
+// Uintptr returns the pointer as a uintptr.
+func (p Pointer) Uintptr() uintptr {
+	return uintptr(p.p)
+}

+ 4 - 9
vendor/github.com/google/go-cmp/cmp/internal/value/sort.go

@@ -1,6 +1,6 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 package value
 package value
 
 
@@ -19,7 +19,7 @@ func SortKeys(vs []reflect.Value) []reflect.Value {
 	}
 	}
 
 
 	// Sort the map keys.
 	// Sort the map keys.
-	sort.Sort(valueSorter(vs))
+	sort.SliceStable(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) })
 
 
 	// Deduplicate keys (fails for NaNs).
 	// Deduplicate keys (fails for NaNs).
 	vs2 := vs[:1]
 	vs2 := vs[:1]
@@ -31,13 +31,6 @@ func SortKeys(vs []reflect.Value) []reflect.Value {
 	return vs2
 	return vs2
 }
 }
 
 
-// TODO: Use sort.Slice once Google AppEngine is on Go1.8 or above.
-type valueSorter []reflect.Value
-
-func (vs valueSorter) Len() int           { return len(vs) }
-func (vs valueSorter) Less(i, j int) bool { return isLess(vs[i], vs[j]) }
-func (vs valueSorter) Swap(i, j int)      { vs[i], vs[j] = vs[j], vs[i] }
-
 // isLess is a generic function for sorting arbitrary map keys.
 // isLess is a generic function for sorting arbitrary map keys.
 // The inputs must be of the same type and must be comparable.
 // The inputs must be of the same type and must be comparable.
 func isLess(x, y reflect.Value) bool {
 func isLess(x, y reflect.Value) bool {
@@ -49,6 +42,8 @@ func isLess(x, y reflect.Value) bool {
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 		return x.Uint() < y.Uint()
 		return x.Uint() < y.Uint()
 	case reflect.Float32, reflect.Float64:
 	case reflect.Float32, reflect.Float64:
+		// NOTE: This does not sort -0 as less than +0
+		// since Go maps treat -0 and +0 as equal keys.
 		fx, fy := x.Float(), y.Float()
 		fx, fy := x.Float(), y.Float()
 		return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy)
 		return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy)
 	case reflect.Complex64, reflect.Complex128:
 	case reflect.Complex64, reflect.Complex128:

+ 48 - 0
vendor/github.com/google/go-cmp/cmp/internal/value/zero.go

@@ -0,0 +1,48 @@
+// Copyright 2017, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package value
+
+import (
+	"math"
+	"reflect"
+)
+
+// IsZero reports whether v is the zero value.
+// This does not rely on Interface and so can be used on unexported fields.
+func IsZero(v reflect.Value) bool {
+	switch v.Kind() {
+	case reflect.Bool:
+		return v.Bool() == false
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Float32, reflect.Float64:
+		return math.Float64bits(v.Float()) == 0
+	case reflect.Complex64, reflect.Complex128:
+		return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0
+	case reflect.String:
+		return v.String() == ""
+	case reflect.UnsafePointer:
+		return v.Pointer() == 0
+	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
+		return v.IsNil()
+	case reflect.Array:
+		for i := 0; i < v.Len(); i++ {
+			if !IsZero(v.Index(i)) {
+				return false
+			}
+		}
+		return true
+	case reflect.Struct:
+		for i := 0; i < v.NumField(); i++ {
+			if !IsZero(v.Field(i)) {
+				return false
+			}
+		}
+		return true
+	}
+	return false
+}

+ 201 - 102
vendor/github.com/google/go-cmp/cmp/options.go

@@ -1,13 +1,13 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 package cmp
 package cmp
 
 
 import (
 import (
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
-	"runtime"
+	"regexp"
 	"strings"
 	"strings"
 
 
 	"github.com/google/go-cmp/cmp/internal/function"
 	"github.com/google/go-cmp/cmp/internal/function"
@@ -29,11 +29,11 @@ type Option interface {
 	// An Options is returned only if multiple comparers or transformers
 	// An Options is returned only if multiple comparers or transformers
 	// can apply simultaneously and will only contain values of those types
 	// can apply simultaneously and will only contain values of those types
 	// or sub-Options containing values of those types.
 	// or sub-Options containing values of those types.
-	filter(s *state, vx, vy reflect.Value, t reflect.Type) applicableOption
+	filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption
 }
 }
 
 
 // applicableOption represents the following types:
 // applicableOption represents the following types:
-//	Fundamental: ignore | invalid | *comparer | *transformer
+//	Fundamental: ignore | validator | *comparer | *transformer
 //	Grouping:    Options
 //	Grouping:    Options
 type applicableOption interface {
 type applicableOption interface {
 	Option
 	Option
@@ -43,7 +43,7 @@ type applicableOption interface {
 }
 }
 
 
 // coreOption represents the following types:
 // coreOption represents the following types:
-//	Fundamental: ignore | invalid | *comparer | *transformer
+//	Fundamental: ignore | validator | *comparer | *transformer
 //	Filters:     *pathFilter | *valuesFilter
 //	Filters:     *pathFilter | *valuesFilter
 type coreOption interface {
 type coreOption interface {
 	Option
 	Option
@@ -63,19 +63,19 @@ func (core) isCore() {}
 // on all individual options held within.
 // on all individual options held within.
 type Options []Option
 type Options []Option
 
 
-func (opts Options) filter(s *state, vx, vy reflect.Value, t reflect.Type) (out applicableOption) {
+func (opts Options) filter(s *state, t reflect.Type, vx, vy reflect.Value) (out applicableOption) {
 	for _, opt := range opts {
 	for _, opt := range opts {
-		switch opt := opt.filter(s, vx, vy, t); opt.(type) {
+		switch opt := opt.filter(s, t, vx, vy); opt.(type) {
 		case ignore:
 		case ignore:
 			return ignore{} // Only ignore can short-circuit evaluation
 			return ignore{} // Only ignore can short-circuit evaluation
-		case invalid:
-			out = invalid{} // Takes precedence over comparer or transformer
+		case validator:
+			out = validator{} // Takes precedence over comparer or transformer
 		case *comparer, *transformer, Options:
 		case *comparer, *transformer, Options:
 			switch out.(type) {
 			switch out.(type) {
 			case nil:
 			case nil:
 				out = opt
 				out = opt
-			case invalid:
-				// Keep invalid
+			case validator:
+				// Keep validator
 			case *comparer, *transformer, Options:
 			case *comparer, *transformer, Options:
 				out = Options{out, opt} // Conflicting comparers or transformers
 				out = Options{out, opt} // Conflicting comparers or transformers
 			}
 			}
@@ -106,6 +106,11 @@ func (opts Options) String() string {
 // FilterPath returns a new Option where opt is only evaluated if filter f
 // FilterPath returns a new Option where opt is only evaluated if filter f
 // returns true for the current Path in the value tree.
 // returns true for the current Path in the value tree.
 //
 //
+// This filter is called even if a slice element or map entry is missing and
+// provides an opportunity to ignore such cases. The filter function must be
+// symmetric such that the filter result is identical regardless of whether the
+// missing value is from x or y.
+//
 // The option passed in may be an Ignore, Transformer, Comparer, Options, or
 // The option passed in may be an Ignore, Transformer, Comparer, Options, or
 // a previously filtered Option.
 // a previously filtered Option.
 func FilterPath(f func(Path) bool, opt Option) Option {
 func FilterPath(f func(Path) bool, opt Option) Option {
@@ -124,22 +129,22 @@ type pathFilter struct {
 	opt Option
 	opt Option
 }
 }
 
 
-func (f pathFilter) filter(s *state, vx, vy reflect.Value, t reflect.Type) applicableOption {
+func (f pathFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption {
 	if f.fnc(s.curPath) {
 	if f.fnc(s.curPath) {
-		return f.opt.filter(s, vx, vy, t)
+		return f.opt.filter(s, t, vx, vy)
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
 func (f pathFilter) String() string {
 func (f pathFilter) String() string {
-	fn := getFuncName(reflect.ValueOf(f.fnc).Pointer())
-	return fmt.Sprintf("FilterPath(%s, %v)", fn, f.opt)
+	return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt)
 }
 }
 
 
 // FilterValues returns a new Option where opt is only evaluated if filter f,
 // FilterValues returns a new Option where opt is only evaluated if filter f,
 // which is a function of the form "func(T, T) bool", returns true for the
 // which is a function of the form "func(T, T) bool", returns true for the
-// current pair of values being compared. If the type of the values is not
-// assignable to T, then this filter implicitly returns false.
+// current pair of values being compared. If either value is invalid or
+// the type of the values is not assignable to T, then this filter implicitly
+// returns false.
 //
 //
 // The filter function must be
 // The filter function must be
 // symmetric (i.e., agnostic to the order of the inputs) and
 // symmetric (i.e., agnostic to the order of the inputs) and
@@ -171,19 +176,18 @@ type valuesFilter struct {
 	opt Option
 	opt Option
 }
 }
 
 
-func (f valuesFilter) filter(s *state, vx, vy reflect.Value, t reflect.Type) applicableOption {
-	if !vx.IsValid() || !vy.IsValid() {
-		return invalid{}
+func (f valuesFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption {
+	if !vx.IsValid() || !vx.CanInterface() || !vy.IsValid() || !vy.CanInterface() {
+		return nil
 	}
 	}
 	if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) {
 	if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) {
-		return f.opt.filter(s, vx, vy, t)
+		return f.opt.filter(s, t, vx, vy)
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
 func (f valuesFilter) String() string {
 func (f valuesFilter) String() string {
-	fn := getFuncName(f.fnc.Pointer())
-	return fmt.Sprintf("FilterValues(%s, %v)", fn, f.opt)
+	return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt)
 }
 }
 
 
 // Ignore is an Option that causes all comparisons to be ignored.
 // Ignore is an Option that causes all comparisons to be ignored.
@@ -194,20 +198,60 @@ func Ignore() Option { return ignore{} }
 type ignore struct{ core }
 type ignore struct{ core }
 
 
 func (ignore) isFiltered() bool                                                     { return false }
 func (ignore) isFiltered() bool                                                     { return false }
-func (ignore) filter(_ *state, _, _ reflect.Value, _ reflect.Type) applicableOption { return ignore{} }
-func (ignore) apply(_ *state, _, _ reflect.Value)                                   { return }
+func (ignore) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { return ignore{} }
+func (ignore) apply(s *state, _, _ reflect.Value)                                   { s.report(true, reportByIgnore) }
 func (ignore) String() string                                                       { return "Ignore()" }
 func (ignore) String() string                                                       { return "Ignore()" }
 
 
-// invalid is a sentinel Option type to indicate that some options could not
-// be evaluated due to unexported fields.
-type invalid struct{ core }
+// validator is a sentinel Option type to indicate that some options could not
+// be evaluated due to unexported fields, missing slice elements, or
+// missing map entries. Both values are validator only for unexported fields.
+type validator struct{ core }
+
+func (validator) filter(_ *state, _ reflect.Type, vx, vy reflect.Value) applicableOption {
+	if !vx.IsValid() || !vy.IsValid() {
+		return validator{}
+	}
+	if !vx.CanInterface() || !vy.CanInterface() {
+		return validator{}
+	}
+	return nil
+}
+func (validator) apply(s *state, vx, vy reflect.Value) {
+	// Implies missing slice element or map entry.
+	if !vx.IsValid() || !vy.IsValid() {
+		s.report(vx.IsValid() == vy.IsValid(), 0)
+		return
+	}
+
+	// Unable to Interface implies unexported field without visibility access.
+	if !vx.CanInterface() || !vy.CanInterface() {
+		help := "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported"
+		var name string
+		if t := s.curPath.Index(-2).Type(); t.Name() != "" {
+			// Named type with unexported fields.
+			name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType
+			if _, ok := reflect.New(t).Interface().(error); ok {
+				help = "consider using cmpopts.EquateErrors to compare error values"
+			}
+		} else {
+			// Unnamed type with unexported fields. Derive PkgPath from field.
+			var pkgPath string
+			for i := 0; i < t.NumField() && pkgPath == ""; i++ {
+				pkgPath = t.Field(i).PkgPath
+			}
+			name = fmt.Sprintf("%q.(%v)", pkgPath, t.String()) // e.g., "path/to/package".(struct { a int })
+		}
+		panic(fmt.Sprintf("cannot handle unexported field at %#v:\n\t%v\n%s", s.curPath, name, help))
+	}
 
 
-func (invalid) filter(_ *state, _, _ reflect.Value, _ reflect.Type) applicableOption { return invalid{} }
-func (invalid) apply(s *state, _, _ reflect.Value) {
-	const help = "consider using AllowUnexported or cmpopts.IgnoreUnexported"
-	panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help))
+	panic("not reachable")
 }
 }
 
 
+// identRx represents a valid identifier according to the Go specification.
+const identRx = `[_\p{L}][_\p{L}\p{N}]*`
+
+var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`)
+
 // Transformer returns an Option that applies a transformation function that
 // Transformer returns an Option that applies a transformation function that
 // converts values of a certain type into that of another.
 // converts values of a certain type into that of another.
 //
 //
@@ -220,18 +264,25 @@ func (invalid) apply(s *state, _, _ reflect.Value) {
 // input and output types are the same), an implicit filter is added such that
 // input and output types are the same), an implicit filter is added such that
 // a transformer is applicable only if that exact transformer is not already
 // a transformer is applicable only if that exact transformer is not already
 // in the tail of the Path since the last non-Transform step.
 // in the tail of the Path since the last non-Transform step.
+// For situations where the implicit filter is still insufficient,
+// consider using cmpopts.AcyclicTransformer, which adds a filter
+// to prevent the transformer from being recursively applied upon itself.
 //
 //
 // The name is a user provided label that is used as the Transform.Name in the
 // The name is a user provided label that is used as the Transform.Name in the
-// transformation PathStep. If empty, an arbitrary name is used.
+// transformation PathStep (and eventually shown in the Diff output).
+// The name must be a valid identifier or qualified identifier in Go syntax.
+// If empty, an arbitrary name is used.
 func Transformer(name string, f interface{}) Option {
 func Transformer(name string, f interface{}) Option {
 	v := reflect.ValueOf(f)
 	v := reflect.ValueOf(f)
 	if !function.IsType(v.Type(), function.Transformer) || v.IsNil() {
 	if !function.IsType(v.Type(), function.Transformer) || v.IsNil() {
 		panic(fmt.Sprintf("invalid transformer function: %T", f))
 		panic(fmt.Sprintf("invalid transformer function: %T", f))
 	}
 	}
 	if name == "" {
 	if name == "" {
-		name = "λ" // Lambda-symbol as place-holder for anonymous transformer
-	}
-	if !isValid(name) {
+		name = function.NameOf(v)
+		if !identsRx.MatchString(name) {
+			name = "λ" // Lambda-symbol as placeholder name
+		}
+	} else if !identsRx.MatchString(name) {
 		panic(fmt.Sprintf("invalid name: %q", name))
 		panic(fmt.Sprintf("invalid name: %q", name))
 	}
 	}
 	tr := &transformer{name: name, fnc: reflect.ValueOf(f)}
 	tr := &transformer{name: name, fnc: reflect.ValueOf(f)}
@@ -250,9 +301,9 @@ type transformer struct {
 
 
 func (tr *transformer) isFiltered() bool { return tr.typ != nil }
 func (tr *transformer) isFiltered() bool { return tr.typ != nil }
 
 
-func (tr *transformer) filter(s *state, _, _ reflect.Value, t reflect.Type) applicableOption {
+func (tr *transformer) filter(s *state, t reflect.Type, _, _ reflect.Value) applicableOption {
 	for i := len(s.curPath) - 1; i >= 0; i-- {
 	for i := len(s.curPath) - 1; i >= 0; i-- {
-		if t, ok := s.curPath[i].(*transform); !ok {
+		if t, ok := s.curPath[i].(Transform); !ok {
 			break // Hit most recent non-Transform step
 			break // Hit most recent non-Transform step
 		} else if tr == t.trans {
 		} else if tr == t.trans {
 			return nil // Cannot directly use same Transform
 			return nil // Cannot directly use same Transform
@@ -265,18 +316,15 @@ func (tr *transformer) filter(s *state, _, _ reflect.Value, t reflect.Type) appl
 }
 }
 
 
 func (tr *transformer) apply(s *state, vx, vy reflect.Value) {
 func (tr *transformer) apply(s *state, vx, vy reflect.Value) {
-	// Update path before calling the Transformer so that dynamic checks
-	// will use the updated path.
-	s.curPath.push(&transform{pathStep{tr.fnc.Type().Out(0)}, tr})
-	defer s.curPath.pop()
-
-	vx = s.callTRFunc(tr.fnc, vx)
-	vy = s.callTRFunc(tr.fnc, vy)
-	s.compareAny(vx, vy)
+	step := Transform{&transform{pathStep{typ: tr.fnc.Type().Out(0)}, tr}}
+	vvx := s.callTRFunc(tr.fnc, vx, step)
+	vvy := s.callTRFunc(tr.fnc, vy, step)
+	step.vx, step.vy = vvx, vvy
+	s.compareAny(step)
 }
 }
 
 
 func (tr transformer) String() string {
 func (tr transformer) String() string {
-	return fmt.Sprintf("Transformer(%s, %s)", tr.name, getFuncName(tr.fnc.Pointer()))
+	return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc))
 }
 }
 
 
 // Comparer returns an Option that determines whether two values are equal
 // Comparer returns an Option that determines whether two values are equal
@@ -311,7 +359,7 @@ type comparer struct {
 
 
 func (cm *comparer) isFiltered() bool { return cm.typ != nil }
 func (cm *comparer) isFiltered() bool { return cm.typ != nil }
 
 
-func (cm *comparer) filter(_ *state, _, _ reflect.Value, t reflect.Type) applicableOption {
+func (cm *comparer) filter(_ *state, t reflect.Type, _, _ reflect.Value) applicableOption {
 	if cm.typ == nil || t.AssignableTo(cm.typ) {
 	if cm.typ == nil || t.AssignableTo(cm.typ) {
 		return cm
 		return cm
 	}
 	}
@@ -320,16 +368,15 @@ func (cm *comparer) filter(_ *state, _, _ reflect.Value, t reflect.Type) applica
 
 
 func (cm *comparer) apply(s *state, vx, vy reflect.Value) {
 func (cm *comparer) apply(s *state, vx, vy reflect.Value) {
 	eq := s.callTTBFunc(cm.fnc, vx, vy)
 	eq := s.callTTBFunc(cm.fnc, vx, vy)
-	s.report(eq, vx, vy)
+	s.report(eq, reportByFunc)
 }
 }
 
 
 func (cm comparer) String() string {
 func (cm comparer) String() string {
-	return fmt.Sprintf("Comparer(%s)", getFuncName(cm.fnc.Pointer()))
+	return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc))
 }
 }
 
 
-// AllowUnexported returns an Option that forcibly allows operations on
-// unexported fields in certain structs, which are specified by passing in a
-// value of each struct type.
+// Exporter returns an Option that specifies whether Equal is allowed to
+// introspect into the unexported fields of certain struct types.
 //
 //
 // Users of this option must understand that comparing on unexported fields
 // Users of this option must understand that comparing on unexported fields
 // from external packages is not safe since changes in the internal
 // from external packages is not safe since changes in the internal
@@ -338,7 +385,7 @@ func (cm comparer) String() string {
 // defined in an internal package where the semantic meaning of an unexported
 // defined in an internal package where the semantic meaning of an unexported
 // field is in the control of the user.
 // field is in the control of the user.
 //
 //
-// For some cases, a custom Comparer should be used instead that defines
+// In many cases, a custom Comparer should be used instead that defines
 // equality as a function of the public API of a type rather than the underlying
 // equality as a function of the public API of a type rather than the underlying
 // unexported implementation.
 // unexported implementation.
 //
 //
@@ -353,10 +400,24 @@ func (cm comparer) String() string {
 //
 //
 // In other cases, the cmpopts.IgnoreUnexported option can be used to ignore
 // In other cases, the cmpopts.IgnoreUnexported option can be used to ignore
 // all unexported fields on specified struct types.
 // all unexported fields on specified struct types.
-func AllowUnexported(types ...interface{}) Option {
-	if !supportAllowUnexported {
-		panic("AllowUnexported is not supported on purego builds, Google App Engine Standard, or GopherJS")
+func Exporter(f func(reflect.Type) bool) Option {
+	if !supportExporters {
+		panic("Exporter is not supported on purego builds")
 	}
 	}
+	return exporter(f)
+}
+
+type exporter func(reflect.Type) bool
+
+func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
+	panic("not implemented")
+}
+
+// AllowUnexported returns an Options that allows Equal to forcibly introspect
+// unexported fields of the specified struct types.
+//
+// See Exporter for the proper use of this option.
+func AllowUnexported(types ...interface{}) Option {
 	m := make(map[reflect.Type]bool)
 	m := make(map[reflect.Type]bool)
 	for _, typ := range types {
 	for _, typ := range types {
 		t := reflect.TypeOf(typ)
 		t := reflect.TypeOf(typ)
@@ -365,32 +426,97 @@ func AllowUnexported(types ...interface{}) Option {
 		}
 		}
 		m[t] = true
 		m[t] = true
 	}
 	}
-	return visibleStructs(m)
+	return exporter(func(t reflect.Type) bool { return m[t] })
 }
 }
 
 
-type visibleStructs map[reflect.Type]bool
+// Result represents the comparison result for a single node and
+// is provided by cmp when calling Result (see Reporter).
+type Result struct {
+	_     [0]func() // Make Result incomparable
+	flags resultFlags
+}
 
 
-func (visibleStructs) filter(_ *state, _, _ reflect.Value, _ reflect.Type) applicableOption {
-	panic("not implemented")
+// Equal reports whether the node was determined to be equal or not.
+// As a special case, ignored nodes are considered equal.
+func (r Result) Equal() bool {
+	return r.flags&(reportEqual|reportByIgnore) != 0
+}
+
+// ByIgnore reports whether the node is equal because it was ignored.
+// This never reports true if Equal reports false.
+func (r Result) ByIgnore() bool {
+	return r.flags&reportByIgnore != 0
+}
+
+// ByMethod reports whether the Equal method determined equality.
+func (r Result) ByMethod() bool {
+	return r.flags&reportByMethod != 0
+}
+
+// ByFunc reports whether a Comparer function determined equality.
+func (r Result) ByFunc() bool {
+	return r.flags&reportByFunc != 0
 }
 }
 
 
-// reporter is an Option that configures how differences are reported.
-type reporter interface {
-	// TODO: Not exported yet.
+// ByCycle reports whether a reference cycle was detected.
+func (r Result) ByCycle() bool {
+	return r.flags&reportByCycle != 0
+}
+
+type resultFlags uint
+
+const (
+	_ resultFlags = (1 << iota) / 2
+
+	reportEqual
+	reportUnequal
+	reportByIgnore
+	reportByMethod
+	reportByFunc
+	reportByCycle
+)
+
+// Reporter is an Option that can be passed to Equal. When Equal traverses
+// the value trees, it calls PushStep as it descends into each node in the
+// tree and PopStep as it ascend out of the node. The leaves of the tree are
+// either compared (determined to be equal or not equal) or ignored and reported
+// as such by calling the Report method.
+func Reporter(r interface {
+	// PushStep is called when a tree-traversal operation is performed.
+	// The PathStep itself is only valid until the step is popped.
+	// The PathStep.Values are valid for the duration of the entire traversal
+	// and must not be mutated.
 	//
 	//
-	// Perhaps add PushStep and PopStep and change Report to only accept
-	// a PathStep instead of the full-path? Adding a PushStep and PopStep makes
-	// it clear that we are traversing the value tree in a depth-first-search
-	// manner, which has an effect on how values are printed.
+	// Equal always calls PushStep at the start to provide an operation-less
+	// PathStep used to report the root values.
+	//
+	// Within a slice, the exact set of inserted, removed, or modified elements
+	// is unspecified and may change in future implementations.
+	// The entries of a map are iterated through in an unspecified order.
+	PushStep(PathStep)
+
+	// Report is called exactly once on leaf nodes to report whether the
+	// comparison identified the node as equal, unequal, or ignored.
+	// A leaf node is one that is immediately preceded by and followed by
+	// a pair of PushStep and PopStep calls.
+	Report(Result)
+
+	// PopStep ascends back up the value tree.
+	// There is always a matching pop call for every push call.
+	PopStep()
+}) Option {
+	return reporter{r}
+}
 
 
-	Option
+type reporter struct{ reporterIface }
+type reporterIface interface {
+	PushStep(PathStep)
+	Report(Result)
+	PopStep()
+}
 
 
-	// Report is called for every comparison made and will be provided with
-	// the two values being compared, the equality result, and the
-	// current path in the value tree. It is possible for x or y to be an
-	// invalid reflect.Value if one of the values is non-existent;
-	// which is possible with maps and slices.
-	Report(x, y reflect.Value, eq bool, p Path)
+func (reporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
+	panic("not implemented")
 }
 }
 
 
 // normalizeOption normalizes the input options such that all Options groups
 // normalizeOption normalizes the input options such that all Options groups
@@ -424,30 +550,3 @@ func flattenOptions(dst, src Options) Options {
 	}
 	}
 	return dst
 	return dst
 }
 }
-
-// getFuncName returns a short function name from the pointer.
-// The string parsing logic works up until Go1.9.
-func getFuncName(p uintptr) string {
-	fnc := runtime.FuncForPC(p)
-	if fnc == nil {
-		return "<unknown>"
-	}
-	name := fnc.Name() // E.g., "long/path/name/mypkg.(mytype).(long/path/name/mypkg.myfunc)-fm"
-	if strings.HasSuffix(name, ")-fm") || strings.HasSuffix(name, ")·fm") {
-		// Strip the package name from method name.
-		name = strings.TrimSuffix(name, ")-fm")
-		name = strings.TrimSuffix(name, ")·fm")
-		if i := strings.LastIndexByte(name, '('); i >= 0 {
-			methodName := name[i+1:] // E.g., "long/path/name/mypkg.myfunc"
-			if j := strings.LastIndexByte(methodName, '.'); j >= 0 {
-				methodName = methodName[j+1:] // E.g., "myfunc"
-			}
-			name = name[:i] + methodName // E.g., "long/path/name/mypkg.(mytype)." + "myfunc"
-		}
-	}
-	if i := strings.LastIndexByte(name, '/'); i >= 0 {
-		// Strip the package name.
-		name = name[i+1:] // E.g., "mypkg.(mytype).myfunc"
-	}
-	return name
-}

+ 240 - 171
vendor/github.com/google/go-cmp/cmp/path.go

@@ -1,6 +1,6 @@
 // Copyright 2017, The Go Authors. All rights reserved.
 // Copyright 2017, The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
+// license that can be found in the LICENSE file.
 
 
 package cmp
 package cmp
 
 
@@ -10,82 +10,56 @@ import (
 	"strings"
 	"strings"
 	"unicode"
 	"unicode"
 	"unicode/utf8"
 	"unicode/utf8"
+
+	"github.com/google/go-cmp/cmp/internal/value"
 )
 )
 
 
-type (
-	// Path is a list of PathSteps describing the sequence of operations to get
-	// from some root type to the current position in the value tree.
-	// The first Path element is always an operation-less PathStep that exists
-	// simply to identify the initial type.
-	//
-	// When traversing structs with embedded structs, the embedded struct will
-	// always be accessed as a field before traversing the fields of the
-	// embedded struct themselves. That is, an exported field from the
-	// embedded struct will never be accessed directly from the parent struct.
-	Path []PathStep
-
-	// PathStep is a union-type for specific operations to traverse
-	// a value's tree structure. Users of this package never need to implement
-	// these types as values of this type will be returned by this package.
-	PathStep interface {
-		String() string
-		Type() reflect.Type // Resulting type after performing the path step
-		isPathStep()
-	}
+// Path is a list of PathSteps describing the sequence of operations to get
+// from some root type to the current position in the value tree.
+// The first Path element is always an operation-less PathStep that exists
+// simply to identify the initial type.
+//
+// When traversing structs with embedded structs, the embedded struct will
+// always be accessed as a field before traversing the fields of the
+// embedded struct themselves. That is, an exported field from the
+// embedded struct will never be accessed directly from the parent struct.
+type Path []PathStep
 
 
-	// SliceIndex is an index operation on a slice or array at some index Key.
-	SliceIndex interface {
-		PathStep
-		Key() int // May return -1 if in a split state
-
-		// SplitKeys returns the indexes for indexing into slices in the
-		// x and y values, respectively. These indexes may differ due to the
-		// insertion or removal of an element in one of the slices, causing
-		// all of the indexes to be shifted. If an index is -1, then that
-		// indicates that the element does not exist in the associated slice.
-		//
-		// Key is guaranteed to return -1 if and only if the indexes returned
-		// by SplitKeys are not the same. SplitKeys will never return -1 for
-		// both indexes.
-		SplitKeys() (x int, y int)
-
-		isSliceIndex()
-	}
-	// MapIndex is an index operation on a map at some index Key.
-	MapIndex interface {
-		PathStep
-		Key() reflect.Value
-		isMapIndex()
-	}
-	// TypeAssertion represents a type assertion on an interface.
-	TypeAssertion interface {
-		PathStep
-		isTypeAssertion()
-	}
-	// StructField represents a struct field access on a field called Name.
-	StructField interface {
-		PathStep
-		Name() string
-		Index() int
-		isStructField()
-	}
-	// Indirect represents pointer indirection on the parent type.
-	Indirect interface {
-		PathStep
-		isIndirect()
-	}
-	// Transform is a transformation from the parent type to the current type.
-	Transform interface {
-		PathStep
-		Name() string
-		Func() reflect.Value
+// PathStep is a union-type for specific operations to traverse
+// a value's tree structure. Users of this package never need to implement
+// these types as values of this type will be returned by this package.
+//
+// Implementations of this interface are
+// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform.
+type PathStep interface {
+	String() string
 
 
-		// Option returns the originally constructed Transformer option.
-		// The == operator can be used to detect the exact option used.
-		Option() Option
+	// Type is the resulting type after performing the path step.
+	Type() reflect.Type
 
 
-		isTransform()
-	}
+	// Values is the resulting values after performing the path step.
+	// The type of each valid value is guaranteed to be identical to Type.
+	//
+	// In some cases, one or both may be invalid or have restrictions:
+	//	• For StructField, both are not interface-able if the current field
+	//	is unexported and the struct type is not explicitly permitted by
+	//	an Exporter to traverse unexported fields.
+	//	• For SliceIndex, one may be invalid if an element is missing from
+	//	either the x or y slice.
+	//	• For MapIndex, one may be invalid if an entry is missing from
+	//	either the x or y map.
+	//
+	// The provided values must not be mutated.
+	Values() (vx, vy reflect.Value)
+}
+
+var (
+	_ PathStep = StructField{}
+	_ PathStep = SliceIndex{}
+	_ PathStep = MapIndex{}
+	_ PathStep = Indirect{}
+	_ PathStep = TypeAssertion{}
+	_ PathStep = Transform{}
 )
 )
 
 
 func (pa *Path) push(s PathStep) {
 func (pa *Path) push(s PathStep) {
@@ -124,7 +98,7 @@ func (pa Path) Index(i int) PathStep {
 func (pa Path) String() string {
 func (pa Path) String() string {
 	var ss []string
 	var ss []string
 	for _, s := range pa {
 	for _, s := range pa {
-		if _, ok := s.(*structField); ok {
+		if _, ok := s.(StructField); ok {
 			ss = append(ss, s.String())
 			ss = append(ss, s.String())
 		}
 		}
 	}
 	}
@@ -144,13 +118,13 @@ func (pa Path) GoString() string {
 			nextStep = pa[i+1]
 			nextStep = pa[i+1]
 		}
 		}
 		switch s := s.(type) {
 		switch s := s.(type) {
-		case *indirect:
+		case Indirect:
 			numIndirect++
 			numIndirect++
 			pPre, pPost := "(", ")"
 			pPre, pPost := "(", ")"
 			switch nextStep.(type) {
 			switch nextStep.(type) {
-			case *indirect:
+			case Indirect:
 				continue // Next step is indirection, so let them batch up
 				continue // Next step is indirection, so let them batch up
-			case *structField:
+			case StructField:
 				numIndirect-- // Automatic indirection on struct fields
 				numIndirect-- // Automatic indirection on struct fields
 			case nil:
 			case nil:
 				pPre, pPost = "", "" // Last step; no need for parenthesis
 				pPre, pPost = "", "" // Last step; no need for parenthesis
@@ -161,19 +135,10 @@ func (pa Path) GoString() string {
 			}
 			}
 			numIndirect = 0
 			numIndirect = 0
 			continue
 			continue
-		case *transform:
+		case Transform:
 			ssPre = append(ssPre, s.trans.name+"(")
 			ssPre = append(ssPre, s.trans.name+"(")
 			ssPost = append(ssPost, ")")
 			ssPost = append(ssPost, ")")
 			continue
 			continue
-		case *typeAssertion:
-			// As a special-case, elide type assertions on anonymous types
-			// since they are typically generated dynamically and can be very
-			// verbose. For example, some transforms return interface{} because
-			// of Go's lack of generics, but typically take in and return the
-			// exact same concrete type.
-			if s.Type().PkgPath() == "" {
-				continue
-			}
 		}
 		}
 		ssPost = append(ssPost, s.String())
 		ssPost = append(ssPost, s.String())
 	}
 	}
@@ -183,44 +148,13 @@ func (pa Path) GoString() string {
 	return strings.Join(ssPre, "") + strings.Join(ssPost, "")
 	return strings.Join(ssPre, "") + strings.Join(ssPost, "")
 }
 }
 
 
-type (
-	pathStep struct {
-		typ reflect.Type
-	}
-
-	sliceIndex struct {
-		pathStep
-		xkey, ykey int
-	}
-	mapIndex struct {
-		pathStep
-		key reflect.Value
-	}
-	typeAssertion struct {
-		pathStep
-	}
-	structField struct {
-		pathStep
-		name string
-		idx  int
-
-		// These fields are used for forcibly accessing an unexported field.
-		// pvx, pvy, and field are only valid if unexported is true.
-		unexported bool
-		force      bool                // Forcibly allow visibility
-		pvx, pvy   reflect.Value       // Parent values
-		field      reflect.StructField // Field information
-	}
-	indirect struct {
-		pathStep
-	}
-	transform struct {
-		pathStep
-		trans *transformer
-	}
-)
+type pathStep struct {
+	typ    reflect.Type
+	vx, vy reflect.Value
+}
 
 
-func (ps pathStep) Type() reflect.Type { return ps.typ }
+func (ps pathStep) Type() reflect.Type             { return ps.typ }
+func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy }
 func (ps pathStep) String() string {
 func (ps pathStep) String() string {
 	if ps.typ == nil {
 	if ps.typ == nil {
 		return "<nil>"
 		return "<nil>"
@@ -232,7 +166,56 @@ func (ps pathStep) String() string {
 	return fmt.Sprintf("{%s}", s)
 	return fmt.Sprintf("{%s}", s)
 }
 }
 
 
-func (si sliceIndex) String() string {
+// StructField represents a struct field access on a field called Name.
+type StructField struct{ *structField }
+type structField struct {
+	pathStep
+	name string
+	idx  int
+
+	// These fields are used for forcibly accessing an unexported field.
+	// pvx, pvy, and field are only valid if unexported is true.
+	unexported bool
+	mayForce   bool                // Forcibly allow visibility
+	paddr      bool                // Was parent addressable?
+	pvx, pvy   reflect.Value       // Parent values (always addressible)
+	field      reflect.StructField // Field information
+}
+
+func (sf StructField) Type() reflect.Type { return sf.typ }
+func (sf StructField) Values() (vx, vy reflect.Value) {
+	if !sf.unexported {
+		return sf.vx, sf.vy // CanInterface reports true
+	}
+
+	// Forcibly obtain read-write access to an unexported struct field.
+	if sf.mayForce {
+		vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr)
+		vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr)
+		return vx, vy // CanInterface reports true
+	}
+	return sf.vx, sf.vy // CanInterface reports false
+}
+func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) }
+
+// Name is the field name.
+func (sf StructField) Name() string { return sf.name }
+
+// Index is the index of the field in the parent struct type.
+// See reflect.Type.Field.
+func (sf StructField) Index() int { return sf.idx }
+
+// SliceIndex is an index operation on a slice or array at some index Key.
+type SliceIndex struct{ *sliceIndex }
+type sliceIndex struct {
+	pathStep
+	xkey, ykey int
+	isSlice    bool // False for reflect.Array
+}
+
+func (si SliceIndex) Type() reflect.Type             { return si.typ }
+func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy }
+func (si SliceIndex) String() string {
 	switch {
 	switch {
 	case si.xkey == si.ykey:
 	case si.xkey == si.ykey:
 		return fmt.Sprintf("[%d]", si.xkey)
 		return fmt.Sprintf("[%d]", si.xkey)
@@ -247,63 +230,149 @@ func (si sliceIndex) String() string {
 		return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey)
 		return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey)
 	}
 	}
 }
 }
-func (mi mapIndex) String() string      { return fmt.Sprintf("[%#v]", mi.key) }
-func (ta typeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
-func (sf structField) String() string   { return fmt.Sprintf(".%s", sf.name) }
-func (in indirect) String() string      { return "*" }
-func (tf transform) String() string     { return fmt.Sprintf("%s()", tf.trans.name) }
 
 
-func (si sliceIndex) Key() int {
+// Key is the index key; it may return -1 if in a split state
+func (si SliceIndex) Key() int {
 	if si.xkey != si.ykey {
 	if si.xkey != si.ykey {
 		return -1
 		return -1
 	}
 	}
 	return si.xkey
 	return si.xkey
 }
 }
-func (si sliceIndex) SplitKeys() (x, y int) { return si.xkey, si.ykey }
-func (mi mapIndex) Key() reflect.Value      { return mi.key }
-func (sf structField) Name() string         { return sf.name }
-func (sf structField) Index() int           { return sf.idx }
-func (tf transform) Name() string           { return tf.trans.name }
-func (tf transform) Func() reflect.Value    { return tf.trans.fnc }
-func (tf transform) Option() Option         { return tf.trans }
-
-func (pathStep) isPathStep()           {}
-func (sliceIndex) isSliceIndex()       {}
-func (mapIndex) isMapIndex()           {}
-func (typeAssertion) isTypeAssertion() {}
-func (structField) isStructField()     {}
-func (indirect) isIndirect()           {}
-func (transform) isTransform()         {}
 
 
-var (
-	_ SliceIndex    = sliceIndex{}
-	_ MapIndex      = mapIndex{}
-	_ TypeAssertion = typeAssertion{}
-	_ StructField   = structField{}
-	_ Indirect      = indirect{}
-	_ Transform     = transform{}
-
-	_ PathStep = sliceIndex{}
-	_ PathStep = mapIndex{}
-	_ PathStep = typeAssertion{}
-	_ PathStep = structField{}
-	_ PathStep = indirect{}
-	_ PathStep = transform{}
-)
+// SplitKeys are the indexes for indexing into slices in the
+// x and y values, respectively. These indexes may differ due to the
+// insertion or removal of an element in one of the slices, causing
+// all of the indexes to be shifted. If an index is -1, then that
+// indicates that the element does not exist in the associated slice.
+//
+// Key is guaranteed to return -1 if and only if the indexes returned
+// by SplitKeys are not the same. SplitKeys will never return -1 for
+// both indexes.
+func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey }
+
+// MapIndex is an index operation on a map at some index Key.
+type MapIndex struct{ *mapIndex }
+type mapIndex struct {
+	pathStep
+	key reflect.Value
+}
+
+func (mi MapIndex) Type() reflect.Type             { return mi.typ }
+func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy }
+func (mi MapIndex) String() string                 { return fmt.Sprintf("[%#v]", mi.key) }
+
+// Key is the value of the map key.
+func (mi MapIndex) Key() reflect.Value { return mi.key }
+
+// Indirect represents pointer indirection on the parent type.
+type Indirect struct{ *indirect }
+type indirect struct {
+	pathStep
+}
+
+func (in Indirect) Type() reflect.Type             { return in.typ }
+func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy }
+func (in Indirect) String() string                 { return "*" }
+
+// TypeAssertion represents a type assertion on an interface.
+type TypeAssertion struct{ *typeAssertion }
+type typeAssertion struct {
+	pathStep
+}
+
+func (ta TypeAssertion) Type() reflect.Type             { return ta.typ }
+func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
+func (ta TypeAssertion) String() string                 { return fmt.Sprintf(".(%v)", ta.typ) }
+
+// Transform is a transformation from the parent type to the current type.
+type Transform struct{ *transform }
+type transform struct {
+	pathStep
+	trans *transformer
+}
+
+func (tf Transform) Type() reflect.Type             { return tf.typ }
+func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy }
+func (tf Transform) String() string                 { return fmt.Sprintf("%s()", tf.trans.name) }
+
+// Name is the name of the Transformer.
+func (tf Transform) Name() string { return tf.trans.name }
+
+// Func is the function pointer to the transformer function.
+func (tf Transform) Func() reflect.Value { return tf.trans.fnc }
+
+// Option returns the originally constructed Transformer option.
+// The == operator can be used to detect the exact option used.
+func (tf Transform) Option() Option { return tf.trans }
+
+// pointerPath represents a dual-stack of pointers encountered when
+// recursively traversing the x and y values. This data structure supports
+// detection of cycles and determining whether the cycles are equal.
+// In Go, cycles can occur via pointers, slices, and maps.
+//
+// The pointerPath uses a map to represent a stack; where descension into a
+// pointer pushes the address onto the stack, and ascension from a pointer
+// pops the address from the stack. Thus, when traversing into a pointer from
+// reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles
+// by checking whether the pointer has already been visited. The cycle detection
+// uses a seperate stack for the x and y values.
+//
+// If a cycle is detected we need to determine whether the two pointers
+// should be considered equal. The definition of equality chosen by Equal
+// requires two graphs to have the same structure. To determine this, both the
+// x and y values must have a cycle where the previous pointers were also
+// encountered together as a pair.
+//
+// Semantically, this is equivalent to augmenting Indirect, SliceIndex, and
+// MapIndex with pointer information for the x and y values.
+// Suppose px and py are two pointers to compare, we then search the
+// Path for whether px was ever encountered in the Path history of x, and
+// similarly so with py. If either side has a cycle, the comparison is only
+// equal if both px and py have a cycle resulting from the same PathStep.
+//
+// Using a map as a stack is more performant as we can perform cycle detection
+// in O(1) instead of O(N) where N is len(Path).
+type pointerPath struct {
+	// mx is keyed by x pointers, where the value is the associated y pointer.
+	mx map[value.Pointer]value.Pointer
+	// my is keyed by y pointers, where the value is the associated x pointer.
+	my map[value.Pointer]value.Pointer
+}
+
+func (p *pointerPath) Init() {
+	p.mx = make(map[value.Pointer]value.Pointer)
+	p.my = make(map[value.Pointer]value.Pointer)
+}
+
+// Push indicates intent to descend into pointers vx and vy where
+// visited reports whether either has been seen before. If visited before,
+// equal reports whether both pointers were encountered together.
+// Pop must be called if and only if the pointers were never visited.
+//
+// The pointers vx and vy must be a reflect.Ptr, reflect.Slice, or reflect.Map
+// and be non-nil.
+func (p pointerPath) Push(vx, vy reflect.Value) (equal, visited bool) {
+	px := value.PointerOf(vx)
+	py := value.PointerOf(vy)
+	_, ok1 := p.mx[px]
+	_, ok2 := p.my[py]
+	if ok1 || ok2 {
+		equal = p.mx[px] == py && p.my[py] == px // Pointers paired together
+		return equal, true
+	}
+	p.mx[px] = py
+	p.my[py] = px
+	return false, false
+}
+
+// Pop ascends from pointers vx and vy.
+func (p pointerPath) Pop(vx, vy reflect.Value) {
+	delete(p.mx, value.PointerOf(vx))
+	delete(p.my, value.PointerOf(vy))
+}
 
 
 // isExported reports whether the identifier is exported.
 // isExported reports whether the identifier is exported.
 func isExported(id string) bool {
 func isExported(id string) bool {
 	r, _ := utf8.DecodeRuneInString(id)
 	r, _ := utf8.DecodeRuneInString(id)
 	return unicode.IsUpper(r)
 	return unicode.IsUpper(r)
 }
 }
-
-// isValid reports whether the identifier is valid.
-// Empty and underscore-only strings are not valid.
-func isValid(id string) bool {
-	ok := id != "" && id != "_"
-	for j, c := range id {
-		ok = ok && (j > 0 || !unicode.IsDigit(c))
-		ok = ok && (c == '_' || unicode.IsLetter(c) || unicode.IsDigit(c))
-	}
-	return ok
-}

+ 54 - 0
vendor/github.com/google/go-cmp/cmp/report.go

@@ -0,0 +1,54 @@
+// Copyright 2017, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmp
+
+// defaultReporter implements the reporter interface.
+//
+// As Equal serially calls the PushStep, Report, and PopStep methods, the
+// defaultReporter constructs a tree-based representation of the compared value
+// and the result of each comparison (see valueNode).
+//
+// When the String method is called, the FormatDiff method transforms the
+// valueNode tree into a textNode tree, which is a tree-based representation
+// of the textual output (see textNode).
+//
+// Lastly, the textNode.String method produces the final report as a string.
+type defaultReporter struct {
+	root *valueNode
+	curr *valueNode
+}
+
+func (r *defaultReporter) PushStep(ps PathStep) {
+	r.curr = r.curr.PushStep(ps)
+	if r.root == nil {
+		r.root = r.curr
+	}
+}
+func (r *defaultReporter) Report(rs Result) {
+	r.curr.Report(rs)
+}
+func (r *defaultReporter) PopStep() {
+	r.curr = r.curr.PopStep()
+}
+
+// String provides a full report of the differences detected as a structured
+// literal in pseudo-Go syntax. String may only be called after the entire tree
+// has been traversed.
+func (r *defaultReporter) String() string {
+	assert(r.root != nil && r.curr == nil)
+	if r.root.NumDiff == 0 {
+		return ""
+	}
+	ptrs := new(pointerReferences)
+	text := formatOptions{}.FormatDiff(r.root, ptrs)
+	resolveReferences(text)
+	return text.String()
+}
+
+func assert(ok bool) {
+	if !ok {
+		panic("assertion failure")
+	}
+}

+ 432 - 0
vendor/github.com/google/go-cmp/cmp/report_compare.go

@@ -0,0 +1,432 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmp
+
+import (
+	"fmt"
+	"reflect"
+
+	"github.com/google/go-cmp/cmp/internal/value"
+)
+
+// numContextRecords is the number of surrounding equal records to print.
+const numContextRecords = 2
+
+type diffMode byte
+
+const (
+	diffUnknown   diffMode = 0
+	diffIdentical diffMode = ' '
+	diffRemoved   diffMode = '-'
+	diffInserted  diffMode = '+'
+)
+
+type typeMode int
+
+const (
+	// emitType always prints the type.
+	emitType typeMode = iota
+	// elideType never prints the type.
+	elideType
+	// autoType prints the type only for composite kinds
+	// (i.e., structs, slices, arrays, and maps).
+	autoType
+)
+
+type formatOptions struct {
+	// DiffMode controls the output mode of FormatDiff.
+	//
+	// If diffUnknown,   then produce a diff of the x and y values.
+	// If diffIdentical, then emit values as if they were equal.
+	// If diffRemoved,   then only emit x values (ignoring y values).
+	// If diffInserted,  then only emit y values (ignoring x values).
+	DiffMode diffMode
+
+	// TypeMode controls whether to print the type for the current node.
+	//
+	// As a general rule of thumb, we always print the type of the next node
+	// after an interface, and always elide the type of the next node after
+	// a slice or map node.
+	TypeMode typeMode
+
+	// formatValueOptions are options specific to printing reflect.Values.
+	formatValueOptions
+}
+
+func (opts formatOptions) WithDiffMode(d diffMode) formatOptions {
+	opts.DiffMode = d
+	return opts
+}
+func (opts formatOptions) WithTypeMode(t typeMode) formatOptions {
+	opts.TypeMode = t
+	return opts
+}
+func (opts formatOptions) WithVerbosity(level int) formatOptions {
+	opts.VerbosityLevel = level
+	opts.LimitVerbosity = true
+	return opts
+}
+func (opts formatOptions) verbosity() uint {
+	switch {
+	case opts.VerbosityLevel < 0:
+		return 0
+	case opts.VerbosityLevel > 16:
+		return 16 // some reasonable maximum to avoid shift overflow
+	default:
+		return uint(opts.VerbosityLevel)
+	}
+}
+
+const maxVerbosityPreset = 6
+
+// verbosityPreset modifies the verbosity settings given an index
+// between 0 and maxVerbosityPreset, inclusive.
+func verbosityPreset(opts formatOptions, i int) formatOptions {
+	opts.VerbosityLevel = int(opts.verbosity()) + 2*i
+	if i > 0 {
+		opts.AvoidStringer = true
+	}
+	if i >= maxVerbosityPreset {
+		opts.PrintAddresses = true
+		opts.QualifiedNames = true
+	}
+	return opts
+}
+
+// FormatDiff converts a valueNode tree into a textNode tree, where the later
+// is a textual representation of the differences detected in the former.
+func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) {
+	if opts.DiffMode == diffIdentical {
+		opts = opts.WithVerbosity(1)
+	} else if opts.verbosity() < 3 {
+		opts = opts.WithVerbosity(3)
+	}
+
+	// Check whether we have specialized formatting for this node.
+	// This is not necessary, but helpful for producing more readable outputs.
+	if opts.CanFormatDiffSlice(v) {
+		return opts.FormatDiffSlice(v)
+	}
+
+	var parentKind reflect.Kind
+	if v.parent != nil && v.parent.TransformerName == "" {
+		parentKind = v.parent.Type.Kind()
+	}
+
+	// For leaf nodes, format the value based on the reflect.Values alone.
+	if v.MaxDepth == 0 {
+		switch opts.DiffMode {
+		case diffUnknown, diffIdentical:
+			// Format Equal.
+			if v.NumDiff == 0 {
+				outx := opts.FormatValue(v.ValueX, parentKind, ptrs)
+				outy := opts.FormatValue(v.ValueY, parentKind, ptrs)
+				if v.NumIgnored > 0 && v.NumSame == 0 {
+					return textEllipsis
+				} else if outx.Len() < outy.Len() {
+					return outx
+				} else {
+					return outy
+				}
+			}
+
+			// Format unequal.
+			assert(opts.DiffMode == diffUnknown)
+			var list textList
+			outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs)
+			outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, parentKind, ptrs)
+			for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ {
+				opts2 := verbosityPreset(opts, i).WithTypeMode(elideType)
+				outx = opts2.FormatValue(v.ValueX, parentKind, ptrs)
+				outy = opts2.FormatValue(v.ValueY, parentKind, ptrs)
+			}
+			if outx != nil {
+				list = append(list, textRecord{Diff: '-', Value: outx})
+			}
+			if outy != nil {
+				list = append(list, textRecord{Diff: '+', Value: outy})
+			}
+			return opts.WithTypeMode(emitType).FormatType(v.Type, list)
+		case diffRemoved:
+			return opts.FormatValue(v.ValueX, parentKind, ptrs)
+		case diffInserted:
+			return opts.FormatValue(v.ValueY, parentKind, ptrs)
+		default:
+			panic("invalid diff mode")
+		}
+	}
+
+	// Register slice element to support cycle detection.
+	if parentKind == reflect.Slice {
+		ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, true)
+		defer ptrs.Pop()
+		defer func() { out = wrapTrunkReferences(ptrRefs, out) }()
+	}
+
+	// Descend into the child value node.
+	if v.TransformerName != "" {
+		out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
+		out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"}
+		return opts.FormatType(v.Type, out)
+	} else {
+		switch k := v.Type.Kind(); k {
+		case reflect.Struct, reflect.Array, reflect.Slice:
+			out = opts.formatDiffList(v.Records, k, ptrs)
+			out = opts.FormatType(v.Type, out)
+		case reflect.Map:
+			// Register map to support cycle detection.
+			ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false)
+			defer ptrs.Pop()
+
+			out = opts.formatDiffList(v.Records, k, ptrs)
+			out = wrapTrunkReferences(ptrRefs, out)
+			out = opts.FormatType(v.Type, out)
+		case reflect.Ptr:
+			// Register pointer to support cycle detection.
+			ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false)
+			defer ptrs.Pop()
+
+			out = opts.FormatDiff(v.Value, ptrs)
+			out = wrapTrunkReferences(ptrRefs, out)
+			out = &textWrap{Prefix: "&", Value: out}
+		case reflect.Interface:
+			out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
+		default:
+			panic(fmt.Sprintf("%v cannot have children", k))
+		}
+		return out
+	}
+}
+
+func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode {
+	// Derive record name based on the data structure kind.
+	var name string
+	var formatKey func(reflect.Value) string
+	switch k {
+	case reflect.Struct:
+		name = "field"
+		opts = opts.WithTypeMode(autoType)
+		formatKey = func(v reflect.Value) string { return v.String() }
+	case reflect.Slice, reflect.Array:
+		name = "element"
+		opts = opts.WithTypeMode(elideType)
+		formatKey = func(reflect.Value) string { return "" }
+	case reflect.Map:
+		name = "entry"
+		opts = opts.WithTypeMode(elideType)
+		formatKey = func(v reflect.Value) string { return formatMapKey(v, false, ptrs) }
+	}
+
+	maxLen := -1
+	if opts.LimitVerbosity {
+		if opts.DiffMode == diffIdentical {
+			maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
+		} else {
+			maxLen = (1 << opts.verbosity()) << 1 // 2, 4, 8, 16, 32, 64, etc...
+		}
+		opts.VerbosityLevel--
+	}
+
+	// Handle unification.
+	switch opts.DiffMode {
+	case diffIdentical, diffRemoved, diffInserted:
+		var list textList
+		var deferredEllipsis bool // Add final "..." to indicate records were dropped
+		for _, r := range recs {
+			if len(list) == maxLen {
+				deferredEllipsis = true
+				break
+			}
+
+			// Elide struct fields that are zero value.
+			if k == reflect.Struct {
+				var isZero bool
+				switch opts.DiffMode {
+				case diffIdentical:
+					isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY)
+				case diffRemoved:
+					isZero = value.IsZero(r.Value.ValueX)
+				case diffInserted:
+					isZero = value.IsZero(r.Value.ValueY)
+				}
+				if isZero {
+					continue
+				}
+			}
+			// Elide ignored nodes.
+			if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 {
+				deferredEllipsis = !(k == reflect.Slice || k == reflect.Array)
+				if !deferredEllipsis {
+					list.AppendEllipsis(diffStats{})
+				}
+				continue
+			}
+			if out := opts.FormatDiff(r.Value, ptrs); out != nil {
+				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+			}
+		}
+		if deferredEllipsis {
+			list.AppendEllipsis(diffStats{})
+		}
+		return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+	case diffUnknown:
+	default:
+		panic("invalid diff mode")
+	}
+
+	// Handle differencing.
+	var numDiffs int
+	var list textList
+	var keys []reflect.Value // invariant: len(list) == len(keys)
+	groups := coalesceAdjacentRecords(name, recs)
+	maxGroup := diffStats{Name: name}
+	for i, ds := range groups {
+		if maxLen >= 0 && numDiffs >= maxLen {
+			maxGroup = maxGroup.Append(ds)
+			continue
+		}
+
+		// Handle equal records.
+		if ds.NumDiff() == 0 {
+			// Compute the number of leading and trailing records to print.
+			var numLo, numHi int
+			numEqual := ds.NumIgnored + ds.NumIdentical
+			for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 {
+				if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 {
+					break
+				}
+				numLo++
+			}
+			for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 {
+				if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 {
+					break
+				}
+				numHi++
+			}
+			if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 {
+				numHi++ // Avoid pointless coalescing of a single equal record
+			}
+
+			// Format the equal values.
+			for _, r := range recs[:numLo] {
+				out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
+				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+				keys = append(keys, r.Key)
+			}
+			if numEqual > numLo+numHi {
+				ds.NumIdentical -= numLo + numHi
+				list.AppendEllipsis(ds)
+				for len(keys) < len(list) {
+					keys = append(keys, reflect.Value{})
+				}
+			}
+			for _, r := range recs[numEqual-numHi : numEqual] {
+				out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
+				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+				keys = append(keys, r.Key)
+			}
+			recs = recs[numEqual:]
+			continue
+		}
+
+		// Handle unequal records.
+		for _, r := range recs[:ds.NumDiff()] {
+			switch {
+			case opts.CanFormatDiffSlice(r.Value):
+				out := opts.FormatDiffSlice(r.Value)
+				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+				keys = append(keys, r.Key)
+			case r.Value.NumChildren == r.Value.MaxDepth:
+				outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs)
+				outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs)
+				for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ {
+					opts2 := verbosityPreset(opts, i)
+					outx = opts2.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs)
+					outy = opts2.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs)
+				}
+				if outx != nil {
+					list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx})
+					keys = append(keys, r.Key)
+				}
+				if outy != nil {
+					list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy})
+					keys = append(keys, r.Key)
+				}
+			default:
+				out := opts.FormatDiff(r.Value, ptrs)
+				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
+				keys = append(keys, r.Key)
+			}
+		}
+		recs = recs[ds.NumDiff():]
+		numDiffs += ds.NumDiff()
+	}
+	if maxGroup.IsZero() {
+		assert(len(recs) == 0)
+	} else {
+		list.AppendEllipsis(maxGroup)
+		for len(keys) < len(list) {
+			keys = append(keys, reflect.Value{})
+		}
+	}
+	assert(len(list) == len(keys))
+
+	// For maps, the default formatting logic uses fmt.Stringer which may
+	// produce ambiguous output. Avoid calling String to disambiguate.
+	if k == reflect.Map {
+		var ambiguous bool
+		seenKeys := map[string]reflect.Value{}
+		for i, currKey := range keys {
+			if currKey.IsValid() {
+				strKey := list[i].Key
+				prevKey, seen := seenKeys[strKey]
+				if seen && prevKey.CanInterface() && currKey.CanInterface() {
+					ambiguous = prevKey.Interface() != currKey.Interface()
+					if ambiguous {
+						break
+					}
+				}
+				seenKeys[strKey] = currKey
+			}
+		}
+		if ambiguous {
+			for i, k := range keys {
+				if k.IsValid() {
+					list[i].Key = formatMapKey(k, true, ptrs)
+				}
+			}
+		}
+	}
+
+	return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+}
+
+// coalesceAdjacentRecords coalesces the list of records into groups of
+// adjacent equal, or unequal counts.
+func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) {
+	var prevCase int // Arbitrary index into which case last occurred
+	lastStats := func(i int) *diffStats {
+		if prevCase != i {
+			groups = append(groups, diffStats{Name: name})
+			prevCase = i
+		}
+		return &groups[len(groups)-1]
+	}
+	for _, r := range recs {
+		switch rv := r.Value; {
+		case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0:
+			lastStats(1).NumIgnored++
+		case rv.NumDiff == 0:
+			lastStats(1).NumIdentical++
+		case rv.NumDiff > 0 && !rv.ValueY.IsValid():
+			lastStats(2).NumRemoved++
+		case rv.NumDiff > 0 && !rv.ValueX.IsValid():
+			lastStats(2).NumInserted++
+		default:
+			lastStats(2).NumModified++
+		}
+	}
+	return groups
+}

+ 264 - 0
vendor/github.com/google/go-cmp/cmp/report_references.go

@@ -0,0 +1,264 @@
+// Copyright 2020, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmp
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/google/go-cmp/cmp/internal/flags"
+	"github.com/google/go-cmp/cmp/internal/value"
+)
+
+const (
+	pointerDelimPrefix = "⟪"
+	pointerDelimSuffix = "⟫"
+)
+
+// formatPointer prints the address of the pointer.
+func formatPointer(p value.Pointer, withDelims bool) string {
+	v := p.Uintptr()
+	if flags.Deterministic {
+		v = 0xdeadf00f // Only used for stable testing purposes
+	}
+	if withDelims {
+		return pointerDelimPrefix + formatHex(uint64(v)) + pointerDelimSuffix
+	}
+	return formatHex(uint64(v))
+}
+
+// pointerReferences is a stack of pointers visited so far.
+type pointerReferences [][2]value.Pointer
+
+func (ps *pointerReferences) PushPair(vx, vy reflect.Value, d diffMode, deref bool) (pp [2]value.Pointer) {
+	if deref && vx.IsValid() {
+		vx = vx.Addr()
+	}
+	if deref && vy.IsValid() {
+		vy = vy.Addr()
+	}
+	switch d {
+	case diffUnknown, diffIdentical:
+		pp = [2]value.Pointer{value.PointerOf(vx), value.PointerOf(vy)}
+	case diffRemoved:
+		pp = [2]value.Pointer{value.PointerOf(vx), value.Pointer{}}
+	case diffInserted:
+		pp = [2]value.Pointer{value.Pointer{}, value.PointerOf(vy)}
+	}
+	*ps = append(*ps, pp)
+	return pp
+}
+
+func (ps *pointerReferences) Push(v reflect.Value) (p value.Pointer, seen bool) {
+	p = value.PointerOf(v)
+	for _, pp := range *ps {
+		if p == pp[0] || p == pp[1] {
+			return p, true
+		}
+	}
+	*ps = append(*ps, [2]value.Pointer{p, p})
+	return p, false
+}
+
+func (ps *pointerReferences) Pop() {
+	*ps = (*ps)[:len(*ps)-1]
+}
+
+// trunkReferences is metadata for a textNode indicating that the sub-tree
+// represents the value for either pointer in a pair of references.
+type trunkReferences struct{ pp [2]value.Pointer }
+
+// trunkReference is metadata for a textNode indicating that the sub-tree
+// represents the value for the given pointer reference.
+type trunkReference struct{ p value.Pointer }
+
+// leafReference is metadata for a textNode indicating that the value is
+// truncated as it refers to another part of the tree (i.e., a trunk).
+type leafReference struct{ p value.Pointer }
+
+func wrapTrunkReferences(pp [2]value.Pointer, s textNode) textNode {
+	switch {
+	case pp[0].IsNil():
+		return &textWrap{Value: s, Metadata: trunkReference{pp[1]}}
+	case pp[1].IsNil():
+		return &textWrap{Value: s, Metadata: trunkReference{pp[0]}}
+	case pp[0] == pp[1]:
+		return &textWrap{Value: s, Metadata: trunkReference{pp[0]}}
+	default:
+		return &textWrap{Value: s, Metadata: trunkReferences{pp}}
+	}
+}
+func wrapTrunkReference(p value.Pointer, printAddress bool, s textNode) textNode {
+	var prefix string
+	if printAddress {
+		prefix = formatPointer(p, true)
+	}
+	return &textWrap{Prefix: prefix, Value: s, Metadata: trunkReference{p}}
+}
+func makeLeafReference(p value.Pointer, printAddress bool) textNode {
+	out := &textWrap{Prefix: "(", Value: textEllipsis, Suffix: ")"}
+	var prefix string
+	if printAddress {
+		prefix = formatPointer(p, true)
+	}
+	return &textWrap{Prefix: prefix, Value: out, Metadata: leafReference{p}}
+}
+
+// resolveReferences walks the textNode tree searching for any leaf reference
+// metadata and resolves each against the corresponding trunk references.
+// Since pointer addresses in memory are not particularly readable to the user,
+// it replaces each pointer value with an arbitrary and unique reference ID.
+func resolveReferences(s textNode) {
+	var walkNodes func(textNode, func(textNode))
+	walkNodes = func(s textNode, f func(textNode)) {
+		f(s)
+		switch s := s.(type) {
+		case *textWrap:
+			walkNodes(s.Value, f)
+		case textList:
+			for _, r := range s {
+				walkNodes(r.Value, f)
+			}
+		}
+	}
+
+	// Collect all trunks and leaves with reference metadata.
+	var trunks, leaves []*textWrap
+	walkNodes(s, func(s textNode) {
+		if s, ok := s.(*textWrap); ok {
+			switch s.Metadata.(type) {
+			case leafReference:
+				leaves = append(leaves, s)
+			case trunkReference, trunkReferences:
+				trunks = append(trunks, s)
+			}
+		}
+	})
+
+	// No leaf references to resolve.
+	if len(leaves) == 0 {
+		return
+	}
+
+	// Collect the set of all leaf references to resolve.
+	leafPtrs := make(map[value.Pointer]bool)
+	for _, leaf := range leaves {
+		leafPtrs[leaf.Metadata.(leafReference).p] = true
+	}
+
+	// Collect the set of trunk pointers that are always paired together.
+	// This allows us to assign a single ID to both pointers for brevity.
+	// If a pointer in a pair ever occurs by itself or as a different pair,
+	// then the pair is broken.
+	pairedTrunkPtrs := make(map[value.Pointer]value.Pointer)
+	unpair := func(p value.Pointer) {
+		if !pairedTrunkPtrs[p].IsNil() {
+			pairedTrunkPtrs[pairedTrunkPtrs[p]] = value.Pointer{} // invalidate other half
+		}
+		pairedTrunkPtrs[p] = value.Pointer{} // invalidate this half
+	}
+	for _, trunk := range trunks {
+		switch p := trunk.Metadata.(type) {
+		case trunkReference:
+			unpair(p.p) // standalone pointer cannot be part of a pair
+		case trunkReferences:
+			p0, ok0 := pairedTrunkPtrs[p.pp[0]]
+			p1, ok1 := pairedTrunkPtrs[p.pp[1]]
+			switch {
+			case !ok0 && !ok1:
+				// Register the newly seen pair.
+				pairedTrunkPtrs[p.pp[0]] = p.pp[1]
+				pairedTrunkPtrs[p.pp[1]] = p.pp[0]
+			case ok0 && ok1 && p0 == p.pp[1] && p1 == p.pp[0]:
+				// Exact pair already seen; do nothing.
+			default:
+				// Pair conflicts with some other pair; break all pairs.
+				unpair(p.pp[0])
+				unpair(p.pp[1])
+			}
+		}
+	}
+
+	// Correlate each pointer referenced by leaves to a unique identifier,
+	// and print the IDs for each trunk that matches those pointers.
+	var nextID uint
+	ptrIDs := make(map[value.Pointer]uint)
+	newID := func() uint {
+		id := nextID
+		nextID++
+		return id
+	}
+	for _, trunk := range trunks {
+		switch p := trunk.Metadata.(type) {
+		case trunkReference:
+			if print := leafPtrs[p.p]; print {
+				id, ok := ptrIDs[p.p]
+				if !ok {
+					id = newID()
+					ptrIDs[p.p] = id
+				}
+				trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id))
+			}
+		case trunkReferences:
+			print0 := leafPtrs[p.pp[0]]
+			print1 := leafPtrs[p.pp[1]]
+			if print0 || print1 {
+				id0, ok0 := ptrIDs[p.pp[0]]
+				id1, ok1 := ptrIDs[p.pp[1]]
+				isPair := pairedTrunkPtrs[p.pp[0]] == p.pp[1] && pairedTrunkPtrs[p.pp[1]] == p.pp[0]
+				if isPair {
+					var id uint
+					assert(ok0 == ok1) // must be seen together or not at all
+					if ok0 {
+						assert(id0 == id1) // must have the same ID
+						id = id0
+					} else {
+						id = newID()
+						ptrIDs[p.pp[0]] = id
+						ptrIDs[p.pp[1]] = id
+					}
+					trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id))
+				} else {
+					if print0 && !ok0 {
+						id0 = newID()
+						ptrIDs[p.pp[0]] = id0
+					}
+					if print1 && !ok1 {
+						id1 = newID()
+						ptrIDs[p.pp[1]] = id1
+					}
+					switch {
+					case print0 && print1:
+						trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)+","+formatReference(id1))
+					case print0:
+						trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0))
+					case print1:
+						trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id1))
+					}
+				}
+			}
+		}
+	}
+
+	// Update all leaf references with the unique identifier.
+	for _, leaf := range leaves {
+		if id, ok := ptrIDs[leaf.Metadata.(leafReference).p]; ok {
+			leaf.Prefix = updateReferencePrefix(leaf.Prefix, formatReference(id))
+		}
+	}
+}
+
+func formatReference(id uint) string {
+	return fmt.Sprintf("ref#%d", id)
+}
+
+func updateReferencePrefix(prefix, ref string) string {
+	if prefix == "" {
+		return pointerDelimPrefix + ref + pointerDelimSuffix
+	}
+	suffix := strings.TrimPrefix(prefix, pointerDelimPrefix)
+	return pointerDelimPrefix + ref + ": " + suffix
+}

+ 402 - 0
vendor/github.com/google/go-cmp/cmp/report_reflect.go

@@ -0,0 +1,402 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmp
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+
+	"github.com/google/go-cmp/cmp/internal/value"
+)
+
+type formatValueOptions struct {
+	// AvoidStringer controls whether to avoid calling custom stringer
+	// methods like error.Error or fmt.Stringer.String.
+	AvoidStringer bool
+
+	// PrintAddresses controls whether to print the address of all pointers,
+	// slice elements, and maps.
+	PrintAddresses bool
+
+	// QualifiedNames controls whether FormatType uses the fully qualified name
+	// (including the full package path as opposed to just the package name).
+	QualifiedNames bool
+
+	// VerbosityLevel controls the amount of output to produce.
+	// A higher value produces more output. A value of zero or lower produces
+	// no output (represented using an ellipsis).
+	// If LimitVerbosity is false, then the level is treated as infinite.
+	VerbosityLevel int
+
+	// LimitVerbosity specifies that formatting should respect VerbosityLevel.
+	LimitVerbosity bool
+}
+
+// FormatType prints the type as if it were wrapping s.
+// This may return s as-is depending on the current type and TypeMode mode.
+func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode {
+	// Check whether to emit the type or not.
+	switch opts.TypeMode {
+	case autoType:
+		switch t.Kind() {
+		case reflect.Struct, reflect.Slice, reflect.Array, reflect.Map:
+			if s.Equal(textNil) {
+				return s
+			}
+		default:
+			return s
+		}
+		if opts.DiffMode == diffIdentical {
+			return s // elide type for identical nodes
+		}
+	case elideType:
+		return s
+	}
+
+	// Determine the type label, applying special handling for unnamed types.
+	typeName := value.TypeString(t, opts.QualifiedNames)
+	if t.Name() == "" {
+		// According to Go grammar, certain type literals contain symbols that
+		// do not strongly bind to the next lexicographical token (e.g., *T).
+		switch t.Kind() {
+		case reflect.Chan, reflect.Func, reflect.Ptr:
+			typeName = "(" + typeName + ")"
+		}
+	}
+	return &textWrap{Prefix: typeName, Value: wrapParens(s)}
+}
+
+// wrapParens wraps s with a set of parenthesis, but avoids it if the
+// wrapped node itself is already surrounded by a pair of parenthesis or braces.
+// It handles unwrapping one level of pointer-reference nodes.
+func wrapParens(s textNode) textNode {
+	var refNode *textWrap
+	if s2, ok := s.(*textWrap); ok {
+		// Unwrap a single pointer reference node.
+		switch s2.Metadata.(type) {
+		case leafReference, trunkReference, trunkReferences:
+			refNode = s2
+			if s3, ok := refNode.Value.(*textWrap); ok {
+				s2 = s3
+			}
+		}
+
+		// Already has delimiters that make parenthesis unnecessary.
+		hasParens := strings.HasPrefix(s2.Prefix, "(") && strings.HasSuffix(s2.Suffix, ")")
+		hasBraces := strings.HasPrefix(s2.Prefix, "{") && strings.HasSuffix(s2.Suffix, "}")
+		if hasParens || hasBraces {
+			return s
+		}
+	}
+	if refNode != nil {
+		refNode.Value = &textWrap{Prefix: "(", Value: refNode.Value, Suffix: ")"}
+		return s
+	}
+	return &textWrap{Prefix: "(", Value: s, Suffix: ")"}
+}
+
+// FormatValue prints the reflect.Value, taking extra care to avoid descending
+// into pointers already in ptrs. As pointers are visited, ptrs is also updated.
+func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, ptrs *pointerReferences) (out textNode) {
+	if !v.IsValid() {
+		return nil
+	}
+	t := v.Type()
+
+	// Check slice element for cycles.
+	if parentKind == reflect.Slice {
+		ptrRef, visited := ptrs.Push(v.Addr())
+		if visited {
+			return makeLeafReference(ptrRef, false)
+		}
+		defer ptrs.Pop()
+		defer func() { out = wrapTrunkReference(ptrRef, false, out) }()
+	}
+
+	// Check whether there is an Error or String method to call.
+	if !opts.AvoidStringer && v.CanInterface() {
+		// Avoid calling Error or String methods on nil receivers since many
+		// implementations crash when doing so.
+		if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() {
+			var prefix, strVal string
+			func() {
+				// Swallow and ignore any panics from String or Error.
+				defer func() { recover() }()
+				switch v := v.Interface().(type) {
+				case error:
+					strVal = v.Error()
+					prefix = "e"
+				case fmt.Stringer:
+					strVal = v.String()
+					prefix = "s"
+				}
+			}()
+			if prefix != "" {
+				return opts.formatString(prefix, strVal)
+			}
+		}
+	}
+
+	// Check whether to explicitly wrap the result with the type.
+	var skipType bool
+	defer func() {
+		if !skipType {
+			out = opts.FormatType(t, out)
+		}
+	}()
+
+	switch t.Kind() {
+	case reflect.Bool:
+		return textLine(fmt.Sprint(v.Bool()))
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return textLine(fmt.Sprint(v.Int()))
+	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return textLine(fmt.Sprint(v.Uint()))
+	case reflect.Uint8:
+		if parentKind == reflect.Slice || parentKind == reflect.Array {
+			return textLine(formatHex(v.Uint()))
+		}
+		return textLine(fmt.Sprint(v.Uint()))
+	case reflect.Uintptr:
+		return textLine(formatHex(v.Uint()))
+	case reflect.Float32, reflect.Float64:
+		return textLine(fmt.Sprint(v.Float()))
+	case reflect.Complex64, reflect.Complex128:
+		return textLine(fmt.Sprint(v.Complex()))
+	case reflect.String:
+		return opts.formatString("", v.String())
+	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+		return textLine(formatPointer(value.PointerOf(v), true))
+	case reflect.Struct:
+		var list textList
+		v := makeAddressable(v) // needed for retrieveUnexportedField
+		maxLen := v.NumField()
+		if opts.LimitVerbosity {
+			maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
+			opts.VerbosityLevel--
+		}
+		for i := 0; i < v.NumField(); i++ {
+			vv := v.Field(i)
+			if value.IsZero(vv) {
+				continue // Elide fields with zero values
+			}
+			if len(list) == maxLen {
+				list.AppendEllipsis(diffStats{})
+				break
+			}
+			sf := t.Field(i)
+			if supportExporters && !isExported(sf.Name) {
+				vv = retrieveUnexportedField(v, sf, true)
+			}
+			s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs)
+			list = append(list, textRecord{Key: sf.Name, Value: s})
+		}
+		return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+	case reflect.Slice:
+		if v.IsNil() {
+			return textNil
+		}
+
+		// Check whether this is a []byte of text data.
+		if t.Elem() == reflect.TypeOf(byte(0)) {
+			b := v.Bytes()
+			isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) && unicode.IsSpace(r) }
+			if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 {
+				out = opts.formatString("", string(b))
+				return opts.WithTypeMode(emitType).FormatType(t, out)
+			}
+		}
+
+		fallthrough
+	case reflect.Array:
+		maxLen := v.Len()
+		if opts.LimitVerbosity {
+			maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
+			opts.VerbosityLevel--
+		}
+		var list textList
+		for i := 0; i < v.Len(); i++ {
+			if len(list) == maxLen {
+				list.AppendEllipsis(diffStats{})
+				break
+			}
+			s := opts.WithTypeMode(elideType).FormatValue(v.Index(i), t.Kind(), ptrs)
+			list = append(list, textRecord{Value: s})
+		}
+
+		out = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+		if t.Kind() == reflect.Slice && opts.PrintAddresses {
+			header := fmt.Sprintf("ptr:%v, len:%d, cap:%d", formatPointer(value.PointerOf(v), false), v.Len(), v.Cap())
+			out = &textWrap{Prefix: pointerDelimPrefix + header + pointerDelimSuffix, Value: out}
+		}
+		return out
+	case reflect.Map:
+		if v.IsNil() {
+			return textNil
+		}
+
+		// Check pointer for cycles.
+		ptrRef, visited := ptrs.Push(v)
+		if visited {
+			return makeLeafReference(ptrRef, opts.PrintAddresses)
+		}
+		defer ptrs.Pop()
+
+		maxLen := v.Len()
+		if opts.LimitVerbosity {
+			maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
+			opts.VerbosityLevel--
+		}
+		var list textList
+		for _, k := range value.SortKeys(v.MapKeys()) {
+			if len(list) == maxLen {
+				list.AppendEllipsis(diffStats{})
+				break
+			}
+			sk := formatMapKey(k, false, ptrs)
+			sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), t.Kind(), ptrs)
+			list = append(list, textRecord{Key: sk, Value: sv})
+		}
+
+		out = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+		out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
+		return out
+	case reflect.Ptr:
+		if v.IsNil() {
+			return textNil
+		}
+
+		// Check pointer for cycles.
+		ptrRef, visited := ptrs.Push(v)
+		if visited {
+			out = makeLeafReference(ptrRef, opts.PrintAddresses)
+			return &textWrap{Prefix: "&", Value: out}
+		}
+		defer ptrs.Pop()
+
+		skipType = true // Let the underlying value print the type instead
+		out = opts.FormatValue(v.Elem(), t.Kind(), ptrs)
+		out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
+		out = &textWrap{Prefix: "&", Value: out}
+		return out
+	case reflect.Interface:
+		if v.IsNil() {
+			return textNil
+		}
+		// Interfaces accept different concrete types,
+		// so configure the underlying value to explicitly print the type.
+		skipType = true // Print the concrete type instead
+		return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs)
+	default:
+		panic(fmt.Sprintf("%v kind not handled", v.Kind()))
+	}
+}
+
+func (opts formatOptions) formatString(prefix, s string) textNode {
+	maxLen := len(s)
+	maxLines := strings.Count(s, "\n") + 1
+	if opts.LimitVerbosity {
+		maxLen = (1 << opts.verbosity()) << 5   // 32, 64, 128, 256, etc...
+		maxLines = (1 << opts.verbosity()) << 2 //  4, 8, 16, 32, 64, etc...
+	}
+
+	// For multiline strings, use the triple-quote syntax,
+	// but only use it when printing removed or inserted nodes since
+	// we only want the extra verbosity for those cases.
+	lines := strings.Split(strings.TrimSuffix(s, "\n"), "\n")
+	isTripleQuoted := len(lines) >= 4 && (opts.DiffMode == '-' || opts.DiffMode == '+')
+	for i := 0; i < len(lines) && isTripleQuoted; i++ {
+		lines[i] = strings.TrimPrefix(strings.TrimSuffix(lines[i], "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support
+		isPrintable := func(r rune) bool {
+			return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable
+		}
+		line := lines[i]
+		isTripleQuoted = !strings.HasPrefix(strings.TrimPrefix(line, prefix), `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" && len(line) <= maxLen
+	}
+	if isTripleQuoted {
+		var list textList
+		list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true})
+		for i, line := range lines {
+			if numElided := len(lines) - i; i == maxLines-1 && numElided > 1 {
+				comment := commentString(fmt.Sprintf("%d elided lines", numElided))
+				list = append(list, textRecord{Diff: opts.DiffMode, Value: textEllipsis, ElideComma: true, Comment: comment})
+				break
+			}
+			list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(line), ElideComma: true})
+		}
+		list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true})
+		return &textWrap{Prefix: "(", Value: list, Suffix: ")"}
+	}
+
+	// Format the string as a single-line quoted string.
+	if len(s) > maxLen+len(textEllipsis) {
+		return textLine(prefix + formatString(s[:maxLen]) + string(textEllipsis))
+	}
+	return textLine(prefix + formatString(s))
+}
+
+// formatMapKey formats v as if it were a map key.
+// The result is guaranteed to be a single line.
+func formatMapKey(v reflect.Value, disambiguate bool, ptrs *pointerReferences) string {
+	var opts formatOptions
+	opts.DiffMode = diffIdentical
+	opts.TypeMode = elideType
+	opts.PrintAddresses = disambiguate
+	opts.AvoidStringer = disambiguate
+	opts.QualifiedNames = disambiguate
+	opts.VerbosityLevel = maxVerbosityPreset
+	opts.LimitVerbosity = true
+	s := opts.FormatValue(v, reflect.Map, ptrs).String()
+	return strings.TrimSpace(s)
+}
+
+// formatString prints s as a double-quoted or backtick-quoted string.
+func formatString(s string) string {
+	// Use quoted string if it the same length as a raw string literal.
+	// Otherwise, attempt to use the raw string form.
+	qs := strconv.Quote(s)
+	if len(qs) == 1+len(s)+1 {
+		return qs
+	}
+
+	// Disallow newlines to ensure output is a single line.
+	// Only allow printable runes for readability purposes.
+	rawInvalid := func(r rune) bool {
+		return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t')
+	}
+	if utf8.ValidString(s) && strings.IndexFunc(s, rawInvalid) < 0 {
+		return "`" + s + "`"
+	}
+	return qs
+}
+
+// formatHex prints u as a hexadecimal integer in Go notation.
+func formatHex(u uint64) string {
+	var f string
+	switch {
+	case u <= 0xff:
+		f = "0x%02x"
+	case u <= 0xffff:
+		f = "0x%04x"
+	case u <= 0xffffff:
+		f = "0x%06x"
+	case u <= 0xffffffff:
+		f = "0x%08x"
+	case u <= 0xffffffffff:
+		f = "0x%010x"
+	case u <= 0xffffffffffff:
+		f = "0x%012x"
+	case u <= 0xffffffffffffff:
+		f = "0x%014x"
+	case u <= 0xffffffffffffffff:
+		f = "0x%016x"
+	}
+	return fmt.Sprintf(f, u)
+}

+ 465 - 0
vendor/github.com/google/go-cmp/cmp/report_slices.go

@@ -0,0 +1,465 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmp
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+
+	"github.com/google/go-cmp/cmp/internal/diff"
+)
+
+// CanFormatDiffSlice reports whether we support custom formatting for nodes
+// that are slices of primitive kinds or strings.
+func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
+	switch {
+	case opts.DiffMode != diffUnknown:
+		return false // Must be formatting in diff mode
+	case v.NumDiff == 0:
+		return false // No differences detected
+	case !v.ValueX.IsValid() || !v.ValueY.IsValid():
+		return false // Both values must be valid
+	case v.NumIgnored > 0:
+		return false // Some ignore option was used
+	case v.NumTransformed > 0:
+		return false // Some transform option was used
+	case v.NumCompared > 1:
+		return false // More than one comparison was used
+	case v.NumCompared == 1 && v.Type.Name() != "":
+		// The need for cmp to check applicability of options on every element
+		// in a slice is a significant performance detriment for large []byte.
+		// The workaround is to specify Comparer(bytes.Equal),
+		// which enables cmp to compare []byte more efficiently.
+		// If they differ, we still want to provide batched diffing.
+		// The logic disallows named types since they tend to have their own
+		// String method, with nicer formatting than what this provides.
+		return false
+	}
+
+	// Check whether this is an interface with the same concrete types.
+	t := v.Type
+	vx, vy := v.ValueX, v.ValueY
+	if t.Kind() == reflect.Interface && !vx.IsNil() && !vy.IsNil() && vx.Elem().Type() == vy.Elem().Type() {
+		vx, vy = vx.Elem(), vy.Elem()
+		t = vx.Type()
+	}
+
+	// Check whether we provide specialized diffing for this type.
+	switch t.Kind() {
+	case reflect.String:
+	case reflect.Array, reflect.Slice:
+		// Only slices of primitive types have specialized handling.
+		switch t.Elem().Kind() {
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
+			reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
+		default:
+			return false
+		}
+
+		// Both slice values have to be non-empty.
+		if t.Kind() == reflect.Slice && (vx.Len() == 0 || vy.Len() == 0) {
+			return false
+		}
+
+		// If a sufficient number of elements already differ,
+		// use specialized formatting even if length requirement is not met.
+		if v.NumDiff > v.NumSame {
+			return true
+		}
+	default:
+		return false
+	}
+
+	// Use specialized string diffing for longer slices or strings.
+	const minLength = 64
+	return vx.Len() >= minLength && vy.Len() >= minLength
+}
+
+// FormatDiffSlice prints a diff for the slices (or strings) represented by v.
+// This provides custom-tailored logic to make printing of differences in
+// textual strings and slices of primitive kinds more readable.
+func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
+	assert(opts.DiffMode == diffUnknown)
+	t, vx, vy := v.Type, v.ValueX, v.ValueY
+	if t.Kind() == reflect.Interface {
+		vx, vy = vx.Elem(), vy.Elem()
+		t = vx.Type()
+		opts = opts.WithTypeMode(emitType)
+	}
+
+	// Auto-detect the type of the data.
+	var isLinedText, isText, isBinary bool
+	var sx, sy string
+	switch {
+	case t.Kind() == reflect.String:
+		sx, sy = vx.String(), vy.String()
+		isText = true // Initial estimate, verify later
+	case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)):
+		sx, sy = string(vx.Bytes()), string(vy.Bytes())
+		isBinary = true // Initial estimate, verify later
+	case t.Kind() == reflect.Array:
+		// Arrays need to be addressable for slice operations to work.
+		vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem()
+		vx2.Set(vx)
+		vy2.Set(vy)
+		vx, vy = vx2, vy2
+	}
+	if isText || isBinary {
+		var numLines, lastLineIdx, maxLineLen int
+		isBinary = !utf8.ValidString(sx) || !utf8.ValidString(sy)
+		for i, r := range sx + sy {
+			if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError {
+				isBinary = true
+				break
+			}
+			if r == '\n' {
+				if maxLineLen < i-lastLineIdx {
+					maxLineLen = i - lastLineIdx
+				}
+				lastLineIdx = i + 1
+				numLines++
+			}
+		}
+		isText = !isBinary
+		isLinedText = isText && numLines >= 4 && maxLineLen <= 1024
+	}
+
+	// Format the string into printable records.
+	var list textList
+	var delim string
+	switch {
+	// If the text appears to be multi-lined text,
+	// then perform differencing across individual lines.
+	case isLinedText:
+		ssx := strings.Split(sx, "\n")
+		ssy := strings.Split(sy, "\n")
+		list = opts.formatDiffSlice(
+			reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line",
+			func(v reflect.Value, d diffMode) textRecord {
+				s := formatString(v.Index(0).String())
+				return textRecord{Diff: d, Value: textLine(s)}
+			},
+		)
+		delim = "\n"
+
+		// If possible, use a custom triple-quote (""") syntax for printing
+		// differences in a string literal. This format is more readable,
+		// but has edge-cases where differences are visually indistinguishable.
+		// This format is avoided under the following conditions:
+		//	• A line starts with `"""`
+		//	• A line starts with "..."
+		//	• A line contains non-printable characters
+		//	• Adjacent different lines differ only by whitespace
+		//
+		// For example:
+		//		"""
+		//		... // 3 identical lines
+		//		foo
+		//		bar
+		//	-	baz
+		//	+	BAZ
+		//		"""
+		isTripleQuoted := true
+		prevRemoveLines := map[string]bool{}
+		prevInsertLines := map[string]bool{}
+		var list2 textList
+		list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true})
+		for _, r := range list {
+			if !r.Value.Equal(textEllipsis) {
+				line, _ := strconv.Unquote(string(r.Value.(textLine)))
+				line = strings.TrimPrefix(strings.TrimSuffix(line, "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support
+				normLine := strings.Map(func(r rune) rune {
+					if unicode.IsSpace(r) {
+						return -1 // drop whitespace to avoid visually indistinguishable output
+					}
+					return r
+				}, line)
+				isPrintable := func(r rune) bool {
+					return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable
+				}
+				isTripleQuoted = !strings.HasPrefix(line, `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == ""
+				switch r.Diff {
+				case diffRemoved:
+					isTripleQuoted = isTripleQuoted && !prevInsertLines[normLine]
+					prevRemoveLines[normLine] = true
+				case diffInserted:
+					isTripleQuoted = isTripleQuoted && !prevRemoveLines[normLine]
+					prevInsertLines[normLine] = true
+				}
+				if !isTripleQuoted {
+					break
+				}
+				r.Value = textLine(line)
+				r.ElideComma = true
+			}
+			if !(r.Diff == diffRemoved || r.Diff == diffInserted) { // start a new non-adjacent difference group
+				prevRemoveLines = map[string]bool{}
+				prevInsertLines = map[string]bool{}
+			}
+			list2 = append(list2, r)
+		}
+		if r := list2[len(list2)-1]; r.Diff == diffIdentical && len(r.Value.(textLine)) == 0 {
+			list2 = list2[:len(list2)-1] // elide single empty line at the end
+		}
+		list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true})
+		if isTripleQuoted {
+			var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"}
+			switch t.Kind() {
+			case reflect.String:
+				if t != reflect.TypeOf(string("")) {
+					out = opts.FormatType(t, out)
+				}
+			case reflect.Slice:
+				// Always emit type for slices since the triple-quote syntax
+				// looks like a string (not a slice).
+				opts = opts.WithTypeMode(emitType)
+				out = opts.FormatType(t, out)
+			}
+			return out
+		}
+
+	// If the text appears to be single-lined text,
+	// then perform differencing in approximately fixed-sized chunks.
+	// The output is printed as quoted strings.
+	case isText:
+		list = opts.formatDiffSlice(
+			reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte",
+			func(v reflect.Value, d diffMode) textRecord {
+				s := formatString(v.String())
+				return textRecord{Diff: d, Value: textLine(s)}
+			},
+		)
+		delim = ""
+
+	// If the text appears to be binary data,
+	// then perform differencing in approximately fixed-sized chunks.
+	// The output is inspired by hexdump.
+	case isBinary:
+		list = opts.formatDiffSlice(
+			reflect.ValueOf(sx), reflect.ValueOf(sy), 16, "byte",
+			func(v reflect.Value, d diffMode) textRecord {
+				var ss []string
+				for i := 0; i < v.Len(); i++ {
+					ss = append(ss, formatHex(v.Index(i).Uint()))
+				}
+				s := strings.Join(ss, ", ")
+				comment := commentString(fmt.Sprintf("%c|%v|", d, formatASCII(v.String())))
+				return textRecord{Diff: d, Value: textLine(s), Comment: comment}
+			},
+		)
+
+	// For all other slices of primitive types,
+	// then perform differencing in approximately fixed-sized chunks.
+	// The size of each chunk depends on the width of the element kind.
+	default:
+		var chunkSize int
+		if t.Elem().Kind() == reflect.Bool {
+			chunkSize = 16
+		} else {
+			switch t.Elem().Bits() {
+			case 8:
+				chunkSize = 16
+			case 16:
+				chunkSize = 12
+			case 32:
+				chunkSize = 8
+			default:
+				chunkSize = 8
+			}
+		}
+		list = opts.formatDiffSlice(
+			vx, vy, chunkSize, t.Elem().Kind().String(),
+			func(v reflect.Value, d diffMode) textRecord {
+				var ss []string
+				for i := 0; i < v.Len(); i++ {
+					switch t.Elem().Kind() {
+					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+						ss = append(ss, fmt.Sprint(v.Index(i).Int()))
+					case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+						ss = append(ss, fmt.Sprint(v.Index(i).Uint()))
+					case reflect.Uint8, reflect.Uintptr:
+						ss = append(ss, formatHex(v.Index(i).Uint()))
+					case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
+						ss = append(ss, fmt.Sprint(v.Index(i).Interface()))
+					}
+				}
+				s := strings.Join(ss, ", ")
+				return textRecord{Diff: d, Value: textLine(s)}
+			},
+		)
+	}
+
+	// Wrap the output with appropriate type information.
+	var out textNode = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
+	if !isText {
+		// The "{...}" byte-sequence literal is not valid Go syntax for strings.
+		// Emit the type for extra clarity (e.g. "string{...}").
+		if t.Kind() == reflect.String {
+			opts = opts.WithTypeMode(emitType)
+		}
+		return opts.FormatType(t, out)
+	}
+	switch t.Kind() {
+	case reflect.String:
+		out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
+		if t != reflect.TypeOf(string("")) {
+			out = opts.FormatType(t, out)
+		}
+	case reflect.Slice:
+		out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
+		if t != reflect.TypeOf([]byte(nil)) {
+			out = opts.FormatType(t, out)
+		}
+	}
+	return out
+}
+
+// formatASCII formats s as an ASCII string.
+// This is useful for printing binary strings in a semi-legible way.
+func formatASCII(s string) string {
+	b := bytes.Repeat([]byte{'.'}, len(s))
+	for i := 0; i < len(s); i++ {
+		if ' ' <= s[i] && s[i] <= '~' {
+			b[i] = s[i]
+		}
+	}
+	return string(b)
+}
+
+func (opts formatOptions) formatDiffSlice(
+	vx, vy reflect.Value, chunkSize int, name string,
+	makeRec func(reflect.Value, diffMode) textRecord,
+) (list textList) {
+	es := diff.Difference(vx.Len(), vy.Len(), func(ix int, iy int) diff.Result {
+		return diff.BoolResult(vx.Index(ix).Interface() == vy.Index(iy).Interface())
+	})
+
+	appendChunks := func(v reflect.Value, d diffMode) int {
+		n0 := v.Len()
+		for v.Len() > 0 {
+			n := chunkSize
+			if n > v.Len() {
+				n = v.Len()
+			}
+			list = append(list, makeRec(v.Slice(0, n), d))
+			v = v.Slice(n, v.Len())
+		}
+		return n0 - v.Len()
+	}
+
+	var numDiffs int
+	maxLen := -1
+	if opts.LimitVerbosity {
+		maxLen = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc...
+		opts.VerbosityLevel--
+	}
+
+	groups := coalesceAdjacentEdits(name, es)
+	groups = coalesceInterveningIdentical(groups, chunkSize/4)
+	maxGroup := diffStats{Name: name}
+	for i, ds := range groups {
+		if maxLen >= 0 && numDiffs >= maxLen {
+			maxGroup = maxGroup.Append(ds)
+			continue
+		}
+
+		// Print equal.
+		if ds.NumDiff() == 0 {
+			// Compute the number of leading and trailing equal bytes to print.
+			var numLo, numHi int
+			numEqual := ds.NumIgnored + ds.NumIdentical
+			for numLo < chunkSize*numContextRecords && numLo+numHi < numEqual && i != 0 {
+				numLo++
+			}
+			for numHi < chunkSize*numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 {
+				numHi++
+			}
+			if numEqual-(numLo+numHi) <= chunkSize && ds.NumIgnored == 0 {
+				numHi = numEqual - numLo // Avoid pointless coalescing of single equal row
+			}
+
+			// Print the equal bytes.
+			appendChunks(vx.Slice(0, numLo), diffIdentical)
+			if numEqual > numLo+numHi {
+				ds.NumIdentical -= numLo + numHi
+				list.AppendEllipsis(ds)
+			}
+			appendChunks(vx.Slice(numEqual-numHi, numEqual), diffIdentical)
+			vx = vx.Slice(numEqual, vx.Len())
+			vy = vy.Slice(numEqual, vy.Len())
+			continue
+		}
+
+		// Print unequal.
+		len0 := len(list)
+		nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved)
+		vx = vx.Slice(nx, vx.Len())
+		ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted)
+		vy = vy.Slice(ny, vy.Len())
+		numDiffs += len(list) - len0
+	}
+	if maxGroup.IsZero() {
+		assert(vx.Len() == 0 && vy.Len() == 0)
+	} else {
+		list.AppendEllipsis(maxGroup)
+	}
+	return list
+}
+
+// coalesceAdjacentEdits coalesces the list of edits into groups of adjacent
+// equal or unequal counts.
+func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) {
+	var prevCase int // Arbitrary index into which case last occurred
+	lastStats := func(i int) *diffStats {
+		if prevCase != i {
+			groups = append(groups, diffStats{Name: name})
+			prevCase = i
+		}
+		return &groups[len(groups)-1]
+	}
+	for _, e := range es {
+		switch e {
+		case diff.Identity:
+			lastStats(1).NumIdentical++
+		case diff.UniqueX:
+			lastStats(2).NumRemoved++
+		case diff.UniqueY:
+			lastStats(2).NumInserted++
+		case diff.Modified:
+			lastStats(2).NumModified++
+		}
+	}
+	return groups
+}
+
+// coalesceInterveningIdentical coalesces sufficiently short (<= windowSize)
+// equal groups into adjacent unequal groups that currently result in a
+// dual inserted/removed printout. This acts as a high-pass filter to smooth
+// out high-frequency changes within the windowSize.
+func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats {
+	groups, groupsOrig := groups[:0], groups
+	for i, ds := range groupsOrig {
+		if len(groups) >= 2 && ds.NumDiff() > 0 {
+			prev := &groups[len(groups)-2] // Unequal group
+			curr := &groups[len(groups)-1] // Equal group
+			next := &groupsOrig[i]         // Unequal group
+			hadX, hadY := prev.NumRemoved > 0, prev.NumInserted > 0
+			hasX, hasY := next.NumRemoved > 0, next.NumInserted > 0
+			if ((hadX || hasX) && (hadY || hasY)) && curr.NumIdentical <= windowSize {
+				*prev = prev.Append(*curr).Append(*next)
+				groups = groups[:len(groups)-1] // Truncate off equal group
+				continue
+			}
+		}
+		groups = append(groups, ds)
+	}
+	return groups
+}

+ 431 - 0
vendor/github.com/google/go-cmp/cmp/report_text.go

@@ -0,0 +1,431 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmp
+
+import (
+	"bytes"
+	"fmt"
+	"math/rand"
+	"strings"
+	"time"
+	"unicode/utf8"
+
+	"github.com/google/go-cmp/cmp/internal/flags"
+)
+
+var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
+
+const maxColumnLength = 80
+
+type indentMode int
+
+func (n indentMode) appendIndent(b []byte, d diffMode) []byte {
+	// The output of Diff is documented as being unstable to provide future
+	// flexibility in changing the output for more humanly readable reports.
+	// This logic intentionally introduces instability to the exact output
+	// so that users can detect accidental reliance on stability early on,
+	// rather than much later when an actual change to the format occurs.
+	if flags.Deterministic || randBool {
+		// Use regular spaces (U+0020).
+		switch d {
+		case diffUnknown, diffIdentical:
+			b = append(b, "  "...)
+		case diffRemoved:
+			b = append(b, "- "...)
+		case diffInserted:
+			b = append(b, "+ "...)
+		}
+	} else {
+		// Use non-breaking spaces (U+00a0).
+		switch d {
+		case diffUnknown, diffIdentical:
+			b = append(b, "  "...)
+		case diffRemoved:
+			b = append(b, "- "...)
+		case diffInserted:
+			b = append(b, "+ "...)
+		}
+	}
+	return repeatCount(n).appendChar(b, '\t')
+}
+
+type repeatCount int
+
+func (n repeatCount) appendChar(b []byte, c byte) []byte {
+	for ; n > 0; n-- {
+		b = append(b, c)
+	}
+	return b
+}
+
+// textNode is a simplified tree-based representation of structured text.
+// Possible node types are textWrap, textList, or textLine.
+type textNode interface {
+	// Len reports the length in bytes of a single-line version of the tree.
+	// Nested textRecord.Diff and textRecord.Comment fields are ignored.
+	Len() int
+	// Equal reports whether the two trees are structurally identical.
+	// Nested textRecord.Diff and textRecord.Comment fields are compared.
+	Equal(textNode) bool
+	// String returns the string representation of the text tree.
+	// It is not guaranteed that len(x.String()) == x.Len(),
+	// nor that x.String() == y.String() implies that x.Equal(y).
+	String() string
+
+	// formatCompactTo formats the contents of the tree as a single-line string
+	// to the provided buffer. Any nested textRecord.Diff and textRecord.Comment
+	// fields are ignored.
+	//
+	// However, not all nodes in the tree should be collapsed as a single-line.
+	// If a node can be collapsed as a single-line, it is replaced by a textLine
+	// node. Since the top-level node cannot replace itself, this also returns
+	// the current node itself.
+	//
+	// This does not mutate the receiver.
+	formatCompactTo([]byte, diffMode) ([]byte, textNode)
+	// formatExpandedTo formats the contents of the tree as a multi-line string
+	// to the provided buffer. In order for column alignment to operate well,
+	// formatCompactTo must be called before calling formatExpandedTo.
+	formatExpandedTo([]byte, diffMode, indentMode) []byte
+}
+
+// textWrap is a wrapper that concatenates a prefix and/or a suffix
+// to the underlying node.
+type textWrap struct {
+	Prefix   string      // e.g., "bytes.Buffer{"
+	Value    textNode    // textWrap | textList | textLine
+	Suffix   string      // e.g., "}"
+	Metadata interface{} // arbitrary metadata; has no effect on formatting
+}
+
+func (s *textWrap) Len() int {
+	return len(s.Prefix) + s.Value.Len() + len(s.Suffix)
+}
+func (s1 *textWrap) Equal(s2 textNode) bool {
+	if s2, ok := s2.(*textWrap); ok {
+		return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix
+	}
+	return false
+}
+func (s *textWrap) String() string {
+	var d diffMode
+	var n indentMode
+	_, s2 := s.formatCompactTo(nil, d)
+	b := n.appendIndent(nil, d)      // Leading indent
+	b = s2.formatExpandedTo(b, d, n) // Main body
+	b = append(b, '\n')              // Trailing newline
+	return string(b)
+}
+func (s *textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
+	n0 := len(b) // Original buffer length
+	b = append(b, s.Prefix...)
+	b, s.Value = s.Value.formatCompactTo(b, d)
+	b = append(b, s.Suffix...)
+	if _, ok := s.Value.(textLine); ok {
+		return b, textLine(b[n0:])
+	}
+	return b, s
+}
+func (s *textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
+	b = append(b, s.Prefix...)
+	b = s.Value.formatExpandedTo(b, d, n)
+	b = append(b, s.Suffix...)
+	return b
+}
+
+// textList is a comma-separated list of textWrap or textLine nodes.
+// The list may be formatted as multi-lines or single-line at the discretion
+// of the textList.formatCompactTo method.
+type textList []textRecord
+type textRecord struct {
+	Diff       diffMode     // e.g., 0 or '-' or '+'
+	Key        string       // e.g., "MyField"
+	Value      textNode     // textWrap | textLine
+	ElideComma bool         // avoid trailing comma
+	Comment    fmt.Stringer // e.g., "6 identical fields"
+}
+
+// AppendEllipsis appends a new ellipsis node to the list if none already
+// exists at the end. If cs is non-zero it coalesces the statistics with the
+// previous diffStats.
+func (s *textList) AppendEllipsis(ds diffStats) {
+	hasStats := !ds.IsZero()
+	if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) {
+		if hasStats {
+			*s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds})
+		} else {
+			*s = append(*s, textRecord{Value: textEllipsis, ElideComma: true})
+		}
+		return
+	}
+	if hasStats {
+		(*s)[len(*s)-1].Comment = (*s)[len(*s)-1].Comment.(diffStats).Append(ds)
+	}
+}
+
+func (s textList) Len() (n int) {
+	for i, r := range s {
+		n += len(r.Key)
+		if r.Key != "" {
+			n += len(": ")
+		}
+		n += r.Value.Len()
+		if i < len(s)-1 {
+			n += len(", ")
+		}
+	}
+	return n
+}
+
+func (s1 textList) Equal(s2 textNode) bool {
+	if s2, ok := s2.(textList); ok {
+		if len(s1) != len(s2) {
+			return false
+		}
+		for i := range s1 {
+			r1, r2 := s1[i], s2[i]
+			if !(r1.Diff == r2.Diff && r1.Key == r2.Key && r1.Value.Equal(r2.Value) && r1.Comment == r2.Comment) {
+				return false
+			}
+		}
+		return true
+	}
+	return false
+}
+
+func (s textList) String() string {
+	return (&textWrap{Prefix: "{", Value: s, Suffix: "}"}).String()
+}
+
+func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
+	s = append(textList(nil), s...) // Avoid mutating original
+
+	// Determine whether we can collapse this list as a single line.
+	n0 := len(b) // Original buffer length
+	var multiLine bool
+	for i, r := range s {
+		if r.Diff == diffInserted || r.Diff == diffRemoved {
+			multiLine = true
+		}
+		b = append(b, r.Key...)
+		if r.Key != "" {
+			b = append(b, ": "...)
+		}
+		b, s[i].Value = r.Value.formatCompactTo(b, d|r.Diff)
+		if _, ok := s[i].Value.(textLine); !ok {
+			multiLine = true
+		}
+		if r.Comment != nil {
+			multiLine = true
+		}
+		if i < len(s)-1 {
+			b = append(b, ", "...)
+		}
+	}
+	// Force multi-lined output when printing a removed/inserted node that
+	// is sufficiently long.
+	if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > maxColumnLength {
+		multiLine = true
+	}
+	if !multiLine {
+		return b, textLine(b[n0:])
+	}
+	return b, s
+}
+
+func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
+	alignKeyLens := s.alignLens(
+		func(r textRecord) bool {
+			_, isLine := r.Value.(textLine)
+			return r.Key == "" || !isLine
+		},
+		func(r textRecord) int { return utf8.RuneCountInString(r.Key) },
+	)
+	alignValueLens := s.alignLens(
+		func(r textRecord) bool {
+			_, isLine := r.Value.(textLine)
+			return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil
+		},
+		func(r textRecord) int { return utf8.RuneCount(r.Value.(textLine)) },
+	)
+
+	// Format lists of simple lists in a batched form.
+	// If the list is sequence of only textLine values,
+	// then batch multiple values on a single line.
+	var isSimple bool
+	for _, r := range s {
+		_, isLine := r.Value.(textLine)
+		isSimple = r.Diff == 0 && r.Key == "" && isLine && r.Comment == nil
+		if !isSimple {
+			break
+		}
+	}
+	if isSimple {
+		n++
+		var batch []byte
+		emitBatch := func() {
+			if len(batch) > 0 {
+				b = n.appendIndent(append(b, '\n'), d)
+				b = append(b, bytes.TrimRight(batch, " ")...)
+				batch = batch[:0]
+			}
+		}
+		for _, r := range s {
+			line := r.Value.(textLine)
+			if len(batch)+len(line)+len(", ") > maxColumnLength {
+				emitBatch()
+			}
+			batch = append(batch, line...)
+			batch = append(batch, ", "...)
+		}
+		emitBatch()
+		n--
+		return n.appendIndent(append(b, '\n'), d)
+	}
+
+	// Format the list as a multi-lined output.
+	n++
+	for i, r := range s {
+		b = n.appendIndent(append(b, '\n'), d|r.Diff)
+		if r.Key != "" {
+			b = append(b, r.Key+": "...)
+		}
+		b = alignKeyLens[i].appendChar(b, ' ')
+
+		b = r.Value.formatExpandedTo(b, d|r.Diff, n)
+		if !r.ElideComma {
+			b = append(b, ',')
+		}
+		b = alignValueLens[i].appendChar(b, ' ')
+
+		if r.Comment != nil {
+			b = append(b, " // "+r.Comment.String()...)
+		}
+	}
+	n--
+
+	return n.appendIndent(append(b, '\n'), d)
+}
+
+func (s textList) alignLens(
+	skipFunc func(textRecord) bool,
+	lenFunc func(textRecord) int,
+) []repeatCount {
+	var startIdx, endIdx, maxLen int
+	lens := make([]repeatCount, len(s))
+	for i, r := range s {
+		if skipFunc(r) {
+			for j := startIdx; j < endIdx && j < len(s); j++ {
+				lens[j] = repeatCount(maxLen - lenFunc(s[j]))
+			}
+			startIdx, endIdx, maxLen = i+1, i+1, 0
+		} else {
+			if maxLen < lenFunc(r) {
+				maxLen = lenFunc(r)
+			}
+			endIdx = i + 1
+		}
+	}
+	for j := startIdx; j < endIdx && j < len(s); j++ {
+		lens[j] = repeatCount(maxLen - lenFunc(s[j]))
+	}
+	return lens
+}
+
+// textLine is a single-line segment of text and is always a leaf node
+// in the textNode tree.
+type textLine []byte
+
+var (
+	textNil      = textLine("nil")
+	textEllipsis = textLine("...")
+)
+
+func (s textLine) Len() int {
+	return len(s)
+}
+func (s1 textLine) Equal(s2 textNode) bool {
+	if s2, ok := s2.(textLine); ok {
+		return bytes.Equal([]byte(s1), []byte(s2))
+	}
+	return false
+}
+func (s textLine) String() string {
+	return string(s)
+}
+func (s textLine) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
+	return append(b, s...), s
+}
+func (s textLine) formatExpandedTo(b []byte, _ diffMode, _ indentMode) []byte {
+	return append(b, s...)
+}
+
+type diffStats struct {
+	Name         string
+	NumIgnored   int
+	NumIdentical int
+	NumRemoved   int
+	NumInserted  int
+	NumModified  int
+}
+
+func (s diffStats) IsZero() bool {
+	s.Name = ""
+	return s == diffStats{}
+}
+
+func (s diffStats) NumDiff() int {
+	return s.NumRemoved + s.NumInserted + s.NumModified
+}
+
+func (s diffStats) Append(ds diffStats) diffStats {
+	assert(s.Name == ds.Name)
+	s.NumIgnored += ds.NumIgnored
+	s.NumIdentical += ds.NumIdentical
+	s.NumRemoved += ds.NumRemoved
+	s.NumInserted += ds.NumInserted
+	s.NumModified += ds.NumModified
+	return s
+}
+
+// String prints a humanly-readable summary of coalesced records.
+//
+// Example:
+//	diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields"
+func (s diffStats) String() string {
+	var ss []string
+	var sum int
+	labels := [...]string{"ignored", "identical", "removed", "inserted", "modified"}
+	counts := [...]int{s.NumIgnored, s.NumIdentical, s.NumRemoved, s.NumInserted, s.NumModified}
+	for i, n := range counts {
+		if n > 0 {
+			ss = append(ss, fmt.Sprintf("%d %v", n, labels[i]))
+		}
+		sum += n
+	}
+
+	// Pluralize the name (adjusting for some obscure English grammar rules).
+	name := s.Name
+	if sum > 1 {
+		name += "s"
+		if strings.HasSuffix(name, "ys") {
+			name = name[:len(name)-2] + "ies" // e.g., "entrys" => "entries"
+		}
+	}
+
+	// Format the list according to English grammar (with Oxford comma).
+	switch n := len(ss); n {
+	case 0:
+		return ""
+	case 1, 2:
+		return strings.Join(ss, " and ") + " " + name
+	default:
+		return strings.Join(ss[:n-1], ", ") + ", and " + ss[n-1] + " " + name
+	}
+}
+
+type commentString string
+
+func (s commentString) String() string { return string(s) }

+ 121 - 0
vendor/github.com/google/go-cmp/cmp/report_value.go

@@ -0,0 +1,121 @@
+// Copyright 2019, The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmp
+
+import "reflect"
+
+// valueNode represents a single node within a report, which is a
+// structured representation of the value tree, containing information
+// regarding which nodes are equal or not.
+type valueNode struct {
+	parent *valueNode
+
+	Type   reflect.Type
+	ValueX reflect.Value
+	ValueY reflect.Value
+
+	// NumSame is the number of leaf nodes that are equal.
+	// All descendants are equal only if NumDiff is 0.
+	NumSame int
+	// NumDiff is the number of leaf nodes that are not equal.
+	NumDiff int
+	// NumIgnored is the number of leaf nodes that are ignored.
+	NumIgnored int
+	// NumCompared is the number of leaf nodes that were compared
+	// using an Equal method or Comparer function.
+	NumCompared int
+	// NumTransformed is the number of non-leaf nodes that were transformed.
+	NumTransformed int
+	// NumChildren is the number of transitive descendants of this node.
+	// This counts from zero; thus, leaf nodes have no descendants.
+	NumChildren int
+	// MaxDepth is the maximum depth of the tree. This counts from zero;
+	// thus, leaf nodes have a depth of zero.
+	MaxDepth int
+
+	// Records is a list of struct fields, slice elements, or map entries.
+	Records []reportRecord // If populated, implies Value is not populated
+
+	// Value is the result of a transformation, pointer indirect, of
+	// type assertion.
+	Value *valueNode // If populated, implies Records is not populated
+
+	// TransformerName is the name of the transformer.
+	TransformerName string // If non-empty, implies Value is populated
+}
+type reportRecord struct {
+	Key   reflect.Value // Invalid for slice element
+	Value *valueNode
+}
+
+func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) {
+	vx, vy := ps.Values()
+	child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy}
+	switch s := ps.(type) {
+	case StructField:
+		assert(parent.Value == nil)
+		parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child})
+	case SliceIndex:
+		assert(parent.Value == nil)
+		parent.Records = append(parent.Records, reportRecord{Value: child})
+	case MapIndex:
+		assert(parent.Value == nil)
+		parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child})
+	case Indirect:
+		assert(parent.Value == nil && parent.Records == nil)
+		parent.Value = child
+	case TypeAssertion:
+		assert(parent.Value == nil && parent.Records == nil)
+		parent.Value = child
+	case Transform:
+		assert(parent.Value == nil && parent.Records == nil)
+		parent.Value = child
+		parent.TransformerName = s.Name()
+		parent.NumTransformed++
+	default:
+		assert(parent == nil) // Must be the root step
+	}
+	return child
+}
+
+func (r *valueNode) Report(rs Result) {
+	assert(r.MaxDepth == 0) // May only be called on leaf nodes
+
+	if rs.ByIgnore() {
+		r.NumIgnored++
+	} else {
+		if rs.Equal() {
+			r.NumSame++
+		} else {
+			r.NumDiff++
+		}
+	}
+	assert(r.NumSame+r.NumDiff+r.NumIgnored == 1)
+
+	if rs.ByMethod() {
+		r.NumCompared++
+	}
+	if rs.ByFunc() {
+		r.NumCompared++
+	}
+	assert(r.NumCompared <= 1)
+}
+
+func (child *valueNode) PopStep() (parent *valueNode) {
+	if child.parent == nil {
+		return nil
+	}
+	parent = child.parent
+	parent.NumSame += child.NumSame
+	parent.NumDiff += child.NumDiff
+	parent.NumIgnored += child.NumIgnored
+	parent.NumCompared += child.NumCompared
+	parent.NumTransformed += child.NumTransformed
+	parent.NumChildren += child.NumChildren + 1
+	if parent.MaxDepth < child.MaxDepth+1 {
+		parent.MaxDepth = child.MaxDepth + 1
+	}
+	return parent
+}

+ 0 - 53
vendor/github.com/google/go-cmp/cmp/reporter.go

@@ -1,53 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
-
-package cmp
-
-import (
-	"fmt"
-	"reflect"
-	"strings"
-
-	"github.com/google/go-cmp/cmp/internal/value"
-)
-
-type defaultReporter struct {
-	Option
-	diffs  []string // List of differences, possibly truncated
-	ndiffs int      // Total number of differences
-	nbytes int      // Number of bytes in diffs
-	nlines int      // Number of lines in diffs
-}
-
-var _ reporter = (*defaultReporter)(nil)
-
-func (r *defaultReporter) Report(x, y reflect.Value, eq bool, p Path) {
-	if eq {
-		return // Ignore equal results
-	}
-	const maxBytes = 4096
-	const maxLines = 256
-	r.ndiffs++
-	if r.nbytes < maxBytes && r.nlines < maxLines {
-		sx := value.Format(x, value.FormatConfig{UseStringer: true})
-		sy := value.Format(y, value.FormatConfig{UseStringer: true})
-		if sx == sy {
-			// Unhelpful output, so use more exact formatting.
-			sx = value.Format(x, value.FormatConfig{PrintPrimitiveType: true})
-			sy = value.Format(y, value.FormatConfig{PrintPrimitiveType: true})
-		}
-		s := fmt.Sprintf("%#v:\n\t-: %s\n\t+: %s\n", p, sx, sy)
-		r.diffs = append(r.diffs, s)
-		r.nbytes += len(s)
-		r.nlines += strings.Count(s, "\n")
-	}
-}
-
-func (r *defaultReporter) String() string {
-	s := strings.Join(r.diffs, "")
-	if r.ndiffs == len(r.diffs) {
-		return s
-	}
-	return fmt.Sprintf("%s... %d more differences ...", s, r.ndiffs-len(r.diffs))
-}

+ 0 - 15
vendor/github.com/google/go-cmp/cmp/unsafe_panic.go

@@ -1,15 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
-
-// +build purego appengine js
-
-package cmp
-
-import "reflect"
-
-const supportAllowUnexported = false
-
-func unsafeRetrieveField(reflect.Value, reflect.StructField) reflect.Value {
-	panic("unsafeRetrieveField is not implemented")
-}

+ 0 - 23
vendor/github.com/google/go-cmp/cmp/unsafe_reflect.go

@@ -1,23 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE.md file.
-
-// +build !purego,!appengine,!js
-
-package cmp
-
-import (
-	"reflect"
-	"unsafe"
-)
-
-const supportAllowUnexported = true
-
-// unsafeRetrieveField uses unsafe to forcibly retrieve any field from a struct
-// such that the value has read-write permissions.
-//
-// The parent struct, v, must be addressable, while f must be a StructField
-// describing the field to retrieve.
-func unsafeRetrieveField(v reflect.Value, f reflect.StructField) reflect.Value {
-	return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem()
-}

+ 3 - 3
vendor/modules.txt

@@ -443,11 +443,12 @@ github.com/google/certificate-transparency-go/jsonclient
 github.com/google/certificate-transparency-go/tls
 github.com/google/certificate-transparency-go/tls
 github.com/google/certificate-transparency-go/x509
 github.com/google/certificate-transparency-go/x509
 github.com/google/certificate-transparency-go/x509/pkix
 github.com/google/certificate-transparency-go/x509/pkix
-# github.com/google/go-cmp v0.5.5 => github.com/google/go-cmp v0.2.0
-## explicit
+# github.com/google/go-cmp v0.5.5
+## explicit; go 1.8
 github.com/google/go-cmp/cmp
 github.com/google/go-cmp/cmp
 github.com/google/go-cmp/cmp/cmpopts
 github.com/google/go-cmp/cmp/cmpopts
 github.com/google/go-cmp/cmp/internal/diff
 github.com/google/go-cmp/cmp/internal/diff
+github.com/google/go-cmp/cmp/internal/flags
 github.com/google/go-cmp/cmp/internal/function
 github.com/google/go-cmp/cmp/internal/function
 github.com/google/go-cmp/cmp/internal/value
 github.com/google/go-cmp/cmp/internal/value
 # github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
 # github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
@@ -992,7 +993,6 @@ gotest.tools/v3/skip
 # github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
 # github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
 # github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2
 # github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2
 # github.com/golang/protobuf => github.com/golang/protobuf v1.3.5
 # github.com/golang/protobuf => github.com/golang/protobuf v1.3.5
-# github.com/google/go-cmp => github.com/google/go-cmp v0.2.0
 # github.com/hashicorp/go-immutable-radix => github.com/tonistiigi/go-immutable-radix v0.0.0-20170803185627-826af9ccf0fe
 # github.com/hashicorp/go-immutable-radix => github.com/tonistiigi/go-immutable-radix v0.0.0-20170803185627-826af9ccf0fe
 # github.com/hashicorp/go-msgpack => github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67
 # github.com/hashicorp/go-msgpack => github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67
 # github.com/hashicorp/go-multierror => github.com/hashicorp/go-multierror v1.0.0
 # github.com/hashicorp/go-multierror => github.com/hashicorp/go-multierror v1.0.0