@@ -1,3 +0,0 @@
 | 
				
			|||||||
language: go
 | 
					 | 
				
			||||||
go:
 | 
					 | 
				
			||||||
  - "1.15"
 | 
					 | 
				
			||||||
@@ -1,7 +1,5 @@
 | 
				
			|||||||
# REST API 2.0 Discogs.com client
 | 
					# REST API 2.0 Discogs.com client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://travis-ci.org/irlndts/go-discogs)[](https://goreportcard.com/report/github.com/irlndts/go-discogs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
go-discogs is a Go client library for the [Discogs API](https://www.discogs.com/developers/). Check the usage section to see how to access the Discogs API.
 | 
					go-discogs is a Go client library for the [Discogs API](https://www.discogs.com/developers/). Check the usage section to see how to access the Discogs API.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The lib is under MIT but be sure you are familiar with [Discogs API Terms of Use](https://support.discogs.com/hc/en-us/articles/360009334593-API-Terms-of-Use).
 | 
					The lib is under MIT but be sure you are familiar with [Discogs API Terms of Use](https://support.discogs.com/hc/en-us/articles/360009334593-API-Terms-of-Use).
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
module github.com/irlndts/go-discogs
 | 
					module github.com/irlndts/go-discogs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go 1.15
 | 
					go 1.16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require github.com/google/go-cmp v0.4.1
 | 
					require github.com/google/go-cmp v0.5.4
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
				
			|||||||
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
 | 
					github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 | 
				
			||||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 | 
					golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
					golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										81
									
								
								vendor/github.com/google/go-cmp/cmp/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										81
									
								
								vendor/github.com/google/go-cmp/cmp/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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 determines equality of values.
 | 
					// Package cmp determines equality of values.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
@@ -90,6 +90,52 @@ import (
 | 
				
			|||||||
// If there is a cycle, then the pointed at values are considered equal
 | 
					// 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.
 | 
					// 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.compareAny(rootStep(x, y))
 | 
				
			||||||
 | 
						return s.result.Equal()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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. If you need the ability to
 | 
				
			||||||
 | 
					// programmatically interpret the difference, consider using a custom Reporter.
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
						s.reporters = append(s.reporters, reporter{r})
 | 
				
			||||||
 | 
						s.compareAny(rootStep(x, y))
 | 
				
			||||||
 | 
						d := r.String()
 | 
				
			||||||
 | 
						if (d == "") != s.result.Equal() {
 | 
				
			||||||
 | 
							panic("inconsistent difference and equality results")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						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)
 | 
						vx := reflect.ValueOf(x)
 | 
				
			||||||
	vy := reflect.ValueOf(y)
 | 
						vy := reflect.ValueOf(y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,33 +158,7 @@ func Equal(x, y interface{}, opts ...Option) bool {
 | 
				
			|||||||
		t = vx.Type()
 | 
							t = vx.Type()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s := newState(opts)
 | 
						return &pathStep{t, vx, vy}
 | 
				
			||||||
	s.compareAny(&pathStep{t, vx, vy})
 | 
					 | 
				
			||||||
	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 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 to 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. If you need the ability to
 | 
					 | 
				
			||||||
// programmatically interpret the difference, consider using a custom Reporter.
 | 
					 | 
				
			||||||
func Diff(x, y interface{}, opts ...Option) string {
 | 
					 | 
				
			||||||
	r := new(defaultReporter)
 | 
					 | 
				
			||||||
	eq := Equal(x, y, Options(opts), Reporter(r))
 | 
					 | 
				
			||||||
	d := r.String()
 | 
					 | 
				
			||||||
	if (d == "") != eq {
 | 
					 | 
				
			||||||
		panic("inconsistent difference and equality results")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return d
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type state struct {
 | 
					type state struct {
 | 
				
			||||||
@@ -356,7 +376,7 @@ 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): Workaround for reflect bug (https://golang.org/issue/22143).
 | 
						// TODO(≥go1.10): Workaround for reflect bug (https://golang.org/issue/22143).
 | 
				
			||||||
	if !flags.AtLeastGo110 {
 | 
						if !flags.AtLeastGo110 {
 | 
				
			||||||
		if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t {
 | 
							if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t {
 | 
				
			||||||
			return reflect.New(t).Elem()
 | 
								return reflect.New(t).Elem()
 | 
				
			||||||
@@ -366,6 +386,7 @@ func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
 | 
					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
 | 
						var vax, vay reflect.Value // Addressable versions of vx and vy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var mayForce, mayForceInit bool
 | 
						var mayForce, mayForceInit bool
 | 
				
			||||||
@@ -387,6 +408,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
 | 
				
			|||||||
				// For retrieveUnexportedField to work, the parent struct must
 | 
									// For retrieveUnexportedField to work, the parent struct must
 | 
				
			||||||
				// be addressable. Create a new copy of the values if
 | 
									// be addressable. Create a new copy of the values if
 | 
				
			||||||
				// necessary to make them addressable.
 | 
									// necessary to make them addressable.
 | 
				
			||||||
 | 
									addr = vx.CanAddr() || vy.CanAddr()
 | 
				
			||||||
				vax = makeAddressable(vx)
 | 
									vax = makeAddressable(vx)
 | 
				
			||||||
				vay = makeAddressable(vy)
 | 
									vay = makeAddressable(vy)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -397,6 +419,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
 | 
				
			|||||||
				mayForceInit = true
 | 
									mayForceInit = true
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			step.mayForce = mayForce
 | 
								step.mayForce = mayForce
 | 
				
			||||||
 | 
								step.paddr = addr
 | 
				
			||||||
			step.pvx = vax
 | 
								step.pvx = vax
 | 
				
			||||||
			step.pvy = vay
 | 
								step.pvy = vay
 | 
				
			||||||
			step.field = t.Field(i)
 | 
								step.field = t.Field(i)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/github.com/google/go-cmp/cmp/export_panic.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/google/go-cmp/cmp/export_panic.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +build purego
 | 
					// +build purego
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -10,6 +10,6 @@ import "reflect"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const supportExporters = false
 | 
					const supportExporters = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value {
 | 
					func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value {
 | 
				
			||||||
	panic("no support for forcibly accessing unexported fields")
 | 
						panic("no support for forcibly accessing unexported fields")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								vendor/github.com/google/go-cmp/cmp/export_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/google/go-cmp/cmp/export_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +build !purego
 | 
					// +build !purego
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,9 +17,19 @@ const supportExporters = true
 | 
				
			|||||||
// a struct such that the value has read-write permissions.
 | 
					// a struct such that the value has read-write permissions.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// The parent struct, v, must be addressable, while f must be a StructField
 | 
					// The parent struct, v, must be addressable, while f must be a StructField
 | 
				
			||||||
// describing the field to retrieve.
 | 
					// describing the field to retrieve. If addr is false,
 | 
				
			||||||
func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value {
 | 
					// then the returned value will be shallowed copied to be non-addressable.
 | 
				
			||||||
	// See https://github.com/google/go-cmp/issues/167 for discussion of the
 | 
					func retrieveUnexportedField(v reflect.Value, f reflect.StructField, addr bool) reflect.Value {
 | 
				
			||||||
	// following expression.
 | 
						ve := reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem()
 | 
				
			||||||
	return 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
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +build !cmp_debug
 | 
					// +build !cmp_debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +build cmp_debug
 | 
					// +build cmp_debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,6 +119,8 @@ func (r Result) Similar() bool {
 | 
				
			|||||||
	return r.NumSame+1 >= r.NumDiff
 | 
						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.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
@@ -177,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.
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
@@ -194,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 "cmp_debug" build tag prints a visualization
 | 
						// Non-deterministically start with either the forward or reverse direction
 | 
				
			||||||
	// of the algorithm running in real-time. This is educational for
 | 
						// to introduce some deliberate instability so that we have the flexibility
 | 
				
			||||||
	// understanding how the algorithm works. See debug_enable.go.
 | 
						// to change this algorithm in the future.
 | 
				
			||||||
	f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es)
 | 
						if flags.Deterministic || randBool {
 | 
				
			||||||
	for {
 | 
							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.
 | 
				
			||||||
@@ -242,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.
 | 
				
			||||||
@@ -280,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-- {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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 flags
 | 
					package flags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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 !go1.10
 | 
					// +build !go1.10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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 go1.10
 | 
					// +build go1.10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/function/func.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/function/func.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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 function provides functionality for identifying function types.
 | 
					// Package function provides functionality for identifying function types.
 | 
				
			||||||
package function
 | 
					package function
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										157
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/name.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/name.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2018, The Go Authors. All rights reserved.
 | 
					// Copyright 2018, 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 purego
 | 
					// +build purego
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,3 +21,13 @@ func PointerOf(v reflect.Value) Pointer {
 | 
				
			|||||||
	// assumes that the GC implementation does not use a moving collector.
 | 
						// assumes that the GC implementation does not use a moving collector.
 | 
				
			||||||
	return Pointer{v.Pointer(), v.Type()}
 | 
						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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2018, The Go Authors. All rights reserved.
 | 
					// Copyright 2018, 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 !purego
 | 
					// +build !purego
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,3 +24,13 @@ func PointerOf(v reflect.Value) Pointer {
 | 
				
			|||||||
	// which is necessary if the GC ever uses a moving collector.
 | 
						// which is necessary if the GC ever uses a moving collector.
 | 
				
			||||||
	return Pointer{unsafe.Pointer(v.Pointer()), v.Type()}
 | 
						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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/zero.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/internal/value/zero.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								vendor/github.com/google/go-cmp/cmp/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/google/go-cmp/cmp/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -225,11 +225,14 @@ func (validator) apply(s *state, vx, vy reflect.Value) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Unable to Interface implies unexported field without visibility access.
 | 
						// Unable to Interface implies unexported field without visibility access.
 | 
				
			||||||
	if !vx.CanInterface() || !vy.CanInterface() {
 | 
						if !vx.CanInterface() || !vy.CanInterface() {
 | 
				
			||||||
		const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported"
 | 
							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
 | 
							var name string
 | 
				
			||||||
		if t := s.curPath.Index(-2).Type(); t.Name() != "" {
 | 
							if t := s.curPath.Index(-2).Type(); t.Name() != "" {
 | 
				
			||||||
			// Named type with unexported fields.
 | 
								// Named type with unexported fields.
 | 
				
			||||||
			name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType
 | 
								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 {
 | 
							} else {
 | 
				
			||||||
			// Unnamed type with unexported fields. Derive PkgPath from field.
 | 
								// Unnamed type with unexported fields. Derive PkgPath from field.
 | 
				
			||||||
			var pkgPath string
 | 
								var pkgPath string
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								vendor/github.com/google/go-cmp/cmp/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/google/go-cmp/cmp/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -177,7 +177,8 @@ type structField struct {
 | 
				
			|||||||
	// pvx, pvy, and field are only valid if unexported is true.
 | 
						// pvx, pvy, and field are only valid if unexported is true.
 | 
				
			||||||
	unexported bool
 | 
						unexported bool
 | 
				
			||||||
	mayForce   bool                // Forcibly allow visibility
 | 
						mayForce   bool                // Forcibly allow visibility
 | 
				
			||||||
	pvx, pvy   reflect.Value       // Parent values
 | 
						paddr      bool                // Was parent addressable?
 | 
				
			||||||
 | 
						pvx, pvy   reflect.Value       // Parent values (always addressible)
 | 
				
			||||||
	field      reflect.StructField // Field information
 | 
						field      reflect.StructField // Field information
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -189,8 +190,8 @@ func (sf StructField) Values() (vx, vy reflect.Value) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Forcibly obtain read-write access to an unexported struct field.
 | 
						// Forcibly obtain read-write access to an unexported struct field.
 | 
				
			||||||
	if sf.mayForce {
 | 
						if sf.mayForce {
 | 
				
			||||||
		vx = retrieveUnexportedField(sf.pvx, sf.field)
 | 
							vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr)
 | 
				
			||||||
		vy = retrieveUnexportedField(sf.pvy, sf.field)
 | 
							vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr)
 | 
				
			||||||
		return vx, vy // CanInterface reports true
 | 
							return vx, vy // CanInterface reports true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return sf.vx, sf.vy // CanInterface reports false
 | 
						return sf.vx, sf.vy // CanInterface reports false
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								vendor/github.com/google/go-cmp/cmp/report.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/google/go-cmp/cmp/report.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,7 +41,10 @@ func (r *defaultReporter) String() string {
 | 
				
			|||||||
	if r.root.NumDiff == 0 {
 | 
						if r.root.NumDiff == 0 {
 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return formatOptions{}.FormatDiff(r.root).String()
 | 
						ptrs := new(pointerReferences)
 | 
				
			||||||
 | 
						text := formatOptions{}.FormatDiff(r.root, ptrs)
 | 
				
			||||||
 | 
						resolveReferences(text)
 | 
				
			||||||
 | 
						return text.String()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func assert(ok bool) {
 | 
					func assert(ok bool) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										201
									
								
								vendor/github.com/google/go-cmp/cmp/report_compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										201
									
								
								vendor/github.com/google/go-cmp/cmp/report_compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -11,14 +11,6 @@ import (
 | 
				
			|||||||
	"github.com/google/go-cmp/cmp/internal/value"
 | 
						"github.com/google/go-cmp/cmp/internal/value"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Enforce limits?
 | 
					 | 
				
			||||||
//	* Enforce maximum number of records to print per node?
 | 
					 | 
				
			||||||
//	* Enforce maximum size in bytes allowed?
 | 
					 | 
				
			||||||
//	* As a heuristic, use less verbosity for equal nodes than unequal nodes.
 | 
					 | 
				
			||||||
// TODO: Enforce unique outputs?
 | 
					 | 
				
			||||||
//	* Avoid Stringer methods if it results in same output?
 | 
					 | 
				
			||||||
//	* Print pointer address if outputs still equal?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// numContextRecords is the number of surrounding equal records to print.
 | 
					// numContextRecords is the number of surrounding equal records to print.
 | 
				
			||||||
const numContextRecords = 2
 | 
					const numContextRecords = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -71,19 +63,56 @@ func (opts formatOptions) WithTypeMode(t typeMode) formatOptions {
 | 
				
			|||||||
	opts.TypeMode = t
 | 
						opts.TypeMode = t
 | 
				
			||||||
	return opts
 | 
						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 = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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
 | 
					// FormatDiff converts a valueNode tree into a textNode tree, where the later
 | 
				
			||||||
// is a textual representation of the differences detected in the former.
 | 
					// is a textual representation of the differences detected in the former.
 | 
				
			||||||
func (opts formatOptions) FormatDiff(v *valueNode) textNode {
 | 
					func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) {
 | 
				
			||||||
 | 
						if opts.DiffMode == diffIdentical {
 | 
				
			||||||
 | 
							opts = opts.WithVerbosity(1)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							opts = opts.WithVerbosity(3)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check whether we have specialized formatting for this node.
 | 
						// Check whether we have specialized formatting for this node.
 | 
				
			||||||
	// This is not necessary, but helpful for producing more readable outputs.
 | 
						// This is not necessary, but helpful for producing more readable outputs.
 | 
				
			||||||
	if opts.CanFormatDiffSlice(v) {
 | 
						if opts.CanFormatDiffSlice(v) {
 | 
				
			||||||
		return opts.FormatDiffSlice(v)
 | 
							return opts.FormatDiffSlice(v)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var withinSlice bool
 | 
						var parentKind reflect.Kind
 | 
				
			||||||
	if v.parent != nil && (v.parent.Type.Kind() == reflect.Slice || v.parent.Type.Kind() == reflect.Array) {
 | 
						if v.parent != nil && v.parent.TransformerName == "" {
 | 
				
			||||||
		withinSlice = true
 | 
							parentKind = v.parent.Type.Kind()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// For leaf nodes, format the value based on the reflect.Values alone.
 | 
						// For leaf nodes, format the value based on the reflect.Values alone.
 | 
				
			||||||
@@ -92,8 +121,8 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
 | 
				
			|||||||
		case diffUnknown, diffIdentical:
 | 
							case diffUnknown, diffIdentical:
 | 
				
			||||||
			// Format Equal.
 | 
								// Format Equal.
 | 
				
			||||||
			if v.NumDiff == 0 {
 | 
								if v.NumDiff == 0 {
 | 
				
			||||||
				outx := opts.FormatValue(v.ValueX, withinSlice, visitedPointers{})
 | 
									outx := opts.FormatValue(v.ValueX, parentKind, ptrs)
 | 
				
			||||||
				outy := opts.FormatValue(v.ValueY, withinSlice, visitedPointers{})
 | 
									outy := opts.FormatValue(v.ValueY, parentKind, ptrs)
 | 
				
			||||||
				if v.NumIgnored > 0 && v.NumSame == 0 {
 | 
									if v.NumIgnored > 0 && v.NumSame == 0 {
 | 
				
			||||||
					return textEllipsis
 | 
										return textEllipsis
 | 
				
			||||||
				} else if outx.Len() < outy.Len() {
 | 
									} else if outx.Len() < outy.Len() {
 | 
				
			||||||
@@ -106,8 +135,13 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
 | 
				
			|||||||
			// Format unequal.
 | 
								// Format unequal.
 | 
				
			||||||
			assert(opts.DiffMode == diffUnknown)
 | 
								assert(opts.DiffMode == diffUnknown)
 | 
				
			||||||
			var list textList
 | 
								var list textList
 | 
				
			||||||
			outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, withinSlice, visitedPointers{})
 | 
								outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs)
 | 
				
			||||||
			outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, withinSlice, visitedPointers{})
 | 
								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 {
 | 
								if outx != nil {
 | 
				
			||||||
				list = append(list, textRecord{Diff: '-', Value: outx})
 | 
									list = append(list, textRecord{Diff: '-', Value: outx})
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -116,34 +150,57 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			return opts.WithTypeMode(emitType).FormatType(v.Type, list)
 | 
								return opts.WithTypeMode(emitType).FormatType(v.Type, list)
 | 
				
			||||||
		case diffRemoved:
 | 
							case diffRemoved:
 | 
				
			||||||
			return opts.FormatValue(v.ValueX, withinSlice, visitedPointers{})
 | 
								return opts.FormatValue(v.ValueX, parentKind, ptrs)
 | 
				
			||||||
		case diffInserted:
 | 
							case diffInserted:
 | 
				
			||||||
			return opts.FormatValue(v.ValueY, withinSlice, visitedPointers{})
 | 
								return opts.FormatValue(v.ValueY, parentKind, ptrs)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			panic("invalid diff mode")
 | 
								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.
 | 
						// Descend into the child value node.
 | 
				
			||||||
	if v.TransformerName != "" {
 | 
						if v.TransformerName != "" {
 | 
				
			||||||
		out := opts.WithTypeMode(emitType).FormatDiff(v.Value)
 | 
							out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
 | 
				
			||||||
		out = textWrap{"Inverse(" + v.TransformerName + ", ", out, ")"}
 | 
							out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"}
 | 
				
			||||||
		return opts.FormatType(v.Type, out)
 | 
							return opts.FormatType(v.Type, out)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		switch k := v.Type.Kind(); k {
 | 
							switch k := v.Type.Kind(); k {
 | 
				
			||||||
		case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map:
 | 
							case reflect.Struct, reflect.Array, reflect.Slice:
 | 
				
			||||||
			return opts.FormatType(v.Type, opts.formatDiffList(v.Records, k))
 | 
								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:
 | 
							case reflect.Ptr:
 | 
				
			||||||
			return textWrap{"&", opts.FormatDiff(v.Value), ""}
 | 
								// 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:
 | 
							case reflect.Interface:
 | 
				
			||||||
			return opts.WithTypeMode(emitType).FormatDiff(v.Value)
 | 
								out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			panic(fmt.Sprintf("%v cannot have children", k))
 | 
								panic(fmt.Sprintf("%v cannot have children", k))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return out
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) textNode {
 | 
					func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode {
 | 
				
			||||||
	// Derive record name based on the data structure kind.
 | 
						// Derive record name based on the data structure kind.
 | 
				
			||||||
	var name string
 | 
						var name string
 | 
				
			||||||
	var formatKey func(reflect.Value) string
 | 
						var formatKey func(reflect.Value) string
 | 
				
			||||||
@@ -159,7 +216,17 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
 | 
				
			|||||||
	case reflect.Map:
 | 
						case reflect.Map:
 | 
				
			||||||
		name = "entry"
 | 
							name = "entry"
 | 
				
			||||||
		opts = opts.WithTypeMode(elideType)
 | 
							opts = opts.WithTypeMode(elideType)
 | 
				
			||||||
		formatKey = formatMapKey
 | 
							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.
 | 
						// Handle unification.
 | 
				
			||||||
@@ -168,6 +235,11 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
 | 
				
			|||||||
		var list textList
 | 
							var list textList
 | 
				
			||||||
		var deferredEllipsis bool // Add final "..." to indicate records were dropped
 | 
							var deferredEllipsis bool // Add final "..." to indicate records were dropped
 | 
				
			||||||
		for _, r := range recs {
 | 
							for _, r := range recs {
 | 
				
			||||||
 | 
								if len(list) == maxLen {
 | 
				
			||||||
 | 
									deferredEllipsis = true
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Elide struct fields that are zero value.
 | 
								// Elide struct fields that are zero value.
 | 
				
			||||||
			if k == reflect.Struct {
 | 
								if k == reflect.Struct {
 | 
				
			||||||
				var isZero bool
 | 
									var isZero bool
 | 
				
			||||||
@@ -191,23 +263,31 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if out := opts.FormatDiff(r.Value); out != nil {
 | 
								if out := opts.FormatDiff(r.Value, ptrs); out != nil {
 | 
				
			||||||
				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
									list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if deferredEllipsis {
 | 
							if deferredEllipsis {
 | 
				
			||||||
			list.AppendEllipsis(diffStats{})
 | 
								list.AppendEllipsis(diffStats{})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return textWrap{"{", list, "}"}
 | 
							return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
 | 
				
			||||||
	case diffUnknown:
 | 
						case diffUnknown:
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		panic("invalid diff mode")
 | 
							panic("invalid diff mode")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Handle differencing.
 | 
						// Handle differencing.
 | 
				
			||||||
 | 
						var numDiffs int
 | 
				
			||||||
	var list textList
 | 
						var list textList
 | 
				
			||||||
 | 
						var keys []reflect.Value // invariant: len(list) == len(keys)
 | 
				
			||||||
	groups := coalesceAdjacentRecords(name, recs)
 | 
						groups := coalesceAdjacentRecords(name, recs)
 | 
				
			||||||
 | 
						maxGroup := diffStats{Name: name}
 | 
				
			||||||
	for i, ds := range groups {
 | 
						for i, ds := range groups {
 | 
				
			||||||
 | 
							if maxLen >= 0 && numDiffs >= maxLen {
 | 
				
			||||||
 | 
								maxGroup = maxGroup.Append(ds)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Handle equal records.
 | 
							// Handle equal records.
 | 
				
			||||||
		if ds.NumDiff() == 0 {
 | 
							if ds.NumDiff() == 0 {
 | 
				
			||||||
			// Compute the number of leading and trailing records to print.
 | 
								// Compute the number of leading and trailing records to print.
 | 
				
			||||||
@@ -231,16 +311,21 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Format the equal values.
 | 
								// Format the equal values.
 | 
				
			||||||
			for _, r := range recs[:numLo] {
 | 
								for _, r := range recs[:numLo] {
 | 
				
			||||||
				out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value)
 | 
									out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
 | 
				
			||||||
				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
									list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
				
			||||||
 | 
									keys = append(keys, r.Key)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if numEqual > numLo+numHi {
 | 
								if numEqual > numLo+numHi {
 | 
				
			||||||
				ds.NumIdentical -= numLo + numHi
 | 
									ds.NumIdentical -= numLo + numHi
 | 
				
			||||||
				list.AppendEllipsis(ds)
 | 
									list.AppendEllipsis(ds)
 | 
				
			||||||
 | 
									for len(keys) < len(list) {
 | 
				
			||||||
 | 
										keys = append(keys, reflect.Value{})
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			for _, r := range recs[numEqual-numHi : numEqual] {
 | 
								for _, r := range recs[numEqual-numHi : numEqual] {
 | 
				
			||||||
				out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value)
 | 
									out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
 | 
				
			||||||
				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
									list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
				
			||||||
 | 
									keys = append(keys, r.Key)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			recs = recs[numEqual:]
 | 
								recs = recs[numEqual:]
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
@@ -252,24 +337,70 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
 | 
				
			|||||||
			case opts.CanFormatDiffSlice(r.Value):
 | 
								case opts.CanFormatDiffSlice(r.Value):
 | 
				
			||||||
				out := opts.FormatDiffSlice(r.Value)
 | 
									out := opts.FormatDiffSlice(r.Value)
 | 
				
			||||||
				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
									list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
				
			||||||
 | 
									keys = append(keys, r.Key)
 | 
				
			||||||
			case r.Value.NumChildren == r.Value.MaxDepth:
 | 
								case r.Value.NumChildren == r.Value.MaxDepth:
 | 
				
			||||||
				outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value)
 | 
									outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs)
 | 
				
			||||||
				outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value)
 | 
									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 {
 | 
									if outx != nil {
 | 
				
			||||||
					list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx})
 | 
										list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx})
 | 
				
			||||||
 | 
										keys = append(keys, r.Key)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if outy != nil {
 | 
									if outy != nil {
 | 
				
			||||||
					list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy})
 | 
										list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy})
 | 
				
			||||||
 | 
										keys = append(keys, r.Key)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				out := opts.FormatDiff(r.Value)
 | 
									out := opts.FormatDiff(r.Value, ptrs)
 | 
				
			||||||
				list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
									list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
 | 
				
			||||||
 | 
									keys = append(keys, r.Key)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		recs = recs[ds.NumDiff():]
 | 
							recs = recs[ds.NumDiff():]
 | 
				
			||||||
 | 
							numDiffs += ds.NumDiff()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if maxGroup.IsZero() {
 | 
				
			||||||
		assert(len(recs) == 0)
 | 
							assert(len(recs) == 0)
 | 
				
			||||||
	return textWrap{"{", list, "}"}
 | 
						} 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
 | 
					// coalesceAdjacentRecords coalesces the list of records into groups of
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										264
									
								
								vendor/github.com/google/go-cmp/cmp/report_references.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								vendor/github.com/google/go-cmp/cmp/report_references.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										285
									
								
								vendor/github.com/google/go-cmp/cmp/report_reflect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										285
									
								
								vendor/github.com/google/go-cmp/cmp/report_reflect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,17 +1,18 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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 (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"unicode"
 | 
						"unicode"
 | 
				
			||||||
 | 
						"unicode/utf8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/google/go-cmp/cmp/internal/flags"
 | 
					 | 
				
			||||||
	"github.com/google/go-cmp/cmp/internal/value"
 | 
						"github.com/google/go-cmp/cmp/internal/value"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,14 +21,22 @@ type formatValueOptions struct {
 | 
				
			|||||||
	// methods like error.Error or fmt.Stringer.String.
 | 
						// methods like error.Error or fmt.Stringer.String.
 | 
				
			||||||
	AvoidStringer bool
 | 
						AvoidStringer bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ShallowPointers controls whether to avoid descending into pointers.
 | 
					 | 
				
			||||||
	// Useful when printing map keys, where pointer comparison is performed
 | 
					 | 
				
			||||||
	// on the pointer address rather than the pointed-at value.
 | 
					 | 
				
			||||||
	ShallowPointers bool
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// PrintAddresses controls whether to print the address of all pointers,
 | 
						// PrintAddresses controls whether to print the address of all pointers,
 | 
				
			||||||
	// slice elements, and maps.
 | 
						// slice elements, and maps.
 | 
				
			||||||
	PrintAddresses bool
 | 
						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.
 | 
					// FormatType prints the type as if it were wrapping s.
 | 
				
			||||||
@@ -44,12 +53,15 @@ func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode {
 | 
				
			|||||||
		default:
 | 
							default:
 | 
				
			||||||
			return s
 | 
								return s
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if opts.DiffMode == diffIdentical {
 | 
				
			||||||
 | 
								return s // elide type for identical nodes
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	case elideType:
 | 
						case elideType:
 | 
				
			||||||
		return s
 | 
							return s
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Determine the type label, applying special handling for unnamed types.
 | 
						// Determine the type label, applying special handling for unnamed types.
 | 
				
			||||||
	typeName := t.String()
 | 
						typeName := value.TypeString(t, opts.QualifiedNames)
 | 
				
			||||||
	if t.Name() == "" {
 | 
						if t.Name() == "" {
 | 
				
			||||||
		// According to Go grammar, certain type literals contain symbols that
 | 
							// According to Go grammar, certain type literals contain symbols that
 | 
				
			||||||
		// do not strongly bind to the next lexicographical token (e.g., *T).
 | 
							// do not strongly bind to the next lexicographical token (e.g., *T).
 | 
				
			||||||
@@ -57,39 +69,77 @@ func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode {
 | 
				
			|||||||
		case reflect.Chan, reflect.Func, reflect.Ptr:
 | 
							case reflect.Chan, reflect.Func, reflect.Ptr:
 | 
				
			||||||
			typeName = "(" + typeName + ")"
 | 
								typeName = "(" + typeName + ")"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		typeName = strings.Replace(typeName, "struct {", "struct{", -1)
 | 
						}
 | 
				
			||||||
		typeName = strings.Replace(typeName, "interface {", "interface{", -1)
 | 
						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
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Avoid wrap the value in parenthesis if unnecessary.
 | 
							// Already has delimiters that make parenthesis unnecessary.
 | 
				
			||||||
	if s, ok := s.(textWrap); ok {
 | 
							hasParens := strings.HasPrefix(s2.Prefix, "(") && strings.HasSuffix(s2.Suffix, ")")
 | 
				
			||||||
		hasParens := strings.HasPrefix(s.Prefix, "(") && strings.HasSuffix(s.Suffix, ")")
 | 
							hasBraces := strings.HasPrefix(s2.Prefix, "{") && strings.HasSuffix(s2.Suffix, "}")
 | 
				
			||||||
		hasBraces := strings.HasPrefix(s.Prefix, "{") && strings.HasSuffix(s.Suffix, "}")
 | 
					 | 
				
			||||||
		if hasParens || hasBraces {
 | 
							if hasParens || hasBraces {
 | 
				
			||||||
			return textWrap{typeName, s, ""}
 | 
								return s
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return textWrap{typeName + "(", 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
 | 
					// FormatValue prints the reflect.Value, taking extra care to avoid descending
 | 
				
			||||||
// into pointers already in m. As pointers are visited, m is also updated.
 | 
					// into pointers already in ptrs. As pointers are visited, ptrs is also updated.
 | 
				
			||||||
func (opts formatOptions) FormatValue(v reflect.Value, withinSlice bool, m visitedPointers) (out textNode) {
 | 
					func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, ptrs *pointerReferences) (out textNode) {
 | 
				
			||||||
	if !v.IsValid() {
 | 
						if !v.IsValid() {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t := v.Type()
 | 
						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.
 | 
						// Check whether there is an Error or String method to call.
 | 
				
			||||||
	if !opts.AvoidStringer && v.CanInterface() {
 | 
						if !opts.AvoidStringer && v.CanInterface() {
 | 
				
			||||||
		// Avoid calling Error or String methods on nil receivers since many
 | 
							// Avoid calling Error or String methods on nil receivers since many
 | 
				
			||||||
		// implementations crash when doing so.
 | 
							// implementations crash when doing so.
 | 
				
			||||||
		if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() {
 | 
							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) {
 | 
									switch v := v.Interface().(type) {
 | 
				
			||||||
				case error:
 | 
									case error:
 | 
				
			||||||
				return textLine("e" + formatString(v.Error()))
 | 
										strVal = v.Error()
 | 
				
			||||||
 | 
										prefix = "e"
 | 
				
			||||||
				case fmt.Stringer:
 | 
									case fmt.Stringer:
 | 
				
			||||||
				return textLine("s" + formatString(v.String()))
 | 
										strVal = v.String()
 | 
				
			||||||
 | 
										prefix = "s"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
								if prefix != "" {
 | 
				
			||||||
 | 
									return opts.formatString(prefix, strVal)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -102,7 +152,6 @@ func (opts formatOptions) FormatValue(v reflect.Value, withinSlice bool, m visit
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var ptr string
 | 
					 | 
				
			||||||
	switch t.Kind() {
 | 
						switch t.Kind() {
 | 
				
			||||||
	case reflect.Bool:
 | 
						case reflect.Bool:
 | 
				
			||||||
		return textLine(fmt.Sprint(v.Bool()))
 | 
							return textLine(fmt.Sprint(v.Bool()))
 | 
				
			||||||
@@ -111,7 +160,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, withinSlice bool, m visit
 | 
				
			|||||||
	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
						case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
				
			||||||
		return textLine(fmt.Sprint(v.Uint()))
 | 
							return textLine(fmt.Sprint(v.Uint()))
 | 
				
			||||||
	case reflect.Uint8:
 | 
						case reflect.Uint8:
 | 
				
			||||||
		if withinSlice {
 | 
							if parentKind == reflect.Slice || parentKind == reflect.Array {
 | 
				
			||||||
			return textLine(formatHex(v.Uint()))
 | 
								return textLine(formatHex(v.Uint()))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return textLine(fmt.Sprint(v.Uint()))
 | 
							return textLine(fmt.Sprint(v.Uint()))
 | 
				
			||||||
@@ -122,77 +171,121 @@ func (opts formatOptions) FormatValue(v reflect.Value, withinSlice bool, m visit
 | 
				
			|||||||
	case reflect.Complex64, reflect.Complex128:
 | 
						case reflect.Complex64, reflect.Complex128:
 | 
				
			||||||
		return textLine(fmt.Sprint(v.Complex()))
 | 
							return textLine(fmt.Sprint(v.Complex()))
 | 
				
			||||||
	case reflect.String:
 | 
						case reflect.String:
 | 
				
			||||||
		return textLine(formatString(v.String()))
 | 
							return opts.formatString("", v.String())
 | 
				
			||||||
	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
 | 
						case reflect.UnsafePointer, reflect.Chan, reflect.Func:
 | 
				
			||||||
		return textLine(formatPointer(v))
 | 
							return textLine(formatPointer(value.PointerOf(v), true))
 | 
				
			||||||
	case reflect.Struct:
 | 
						case reflect.Struct:
 | 
				
			||||||
		var list textList
 | 
							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++ {
 | 
							for i := 0; i < v.NumField(); i++ {
 | 
				
			||||||
			vv := v.Field(i)
 | 
								vv := v.Field(i)
 | 
				
			||||||
			if value.IsZero(vv) {
 | 
								if value.IsZero(vv) {
 | 
				
			||||||
				continue // Elide fields with zero values
 | 
									continue // Elide fields with zero values
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			s := opts.WithTypeMode(autoType).FormatValue(vv, false, m)
 | 
								if len(list) == maxLen {
 | 
				
			||||||
			list = append(list, textRecord{Key: t.Field(i).Name, Value: s})
 | 
									list.AppendEllipsis(diffStats{})
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		return textWrap{"{", list, "}"}
 | 
								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:
 | 
						case reflect.Slice:
 | 
				
			||||||
		if v.IsNil() {
 | 
							if v.IsNil() {
 | 
				
			||||||
			return textNil
 | 
								return textNil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if opts.PrintAddresses {
 | 
					
 | 
				
			||||||
			ptr = formatPointer(v)
 | 
							// 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
 | 
							fallthrough
 | 
				
			||||||
	case reflect.Array:
 | 
						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
 | 
							var list textList
 | 
				
			||||||
		for i := 0; i < v.Len(); i++ {
 | 
							for i := 0; i < v.Len(); i++ {
 | 
				
			||||||
			vi := v.Index(i)
 | 
								if len(list) == maxLen {
 | 
				
			||||||
			if vi.CanAddr() { // Check for cyclic elements
 | 
									list.AppendEllipsis(diffStats{})
 | 
				
			||||||
				p := vi.Addr()
 | 
									break
 | 
				
			||||||
				if m.Visit(p) {
 | 
					 | 
				
			||||||
					var out textNode
 | 
					 | 
				
			||||||
					out = textLine(formatPointer(p))
 | 
					 | 
				
			||||||
					out = opts.WithTypeMode(emitType).FormatType(p.Type(), out)
 | 
					 | 
				
			||||||
					out = textWrap{"*", out, ""}
 | 
					 | 
				
			||||||
					list = append(list, textRecord{Value: out})
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			}
 | 
								s := opts.WithTypeMode(elideType).FormatValue(v.Index(i), t.Kind(), ptrs)
 | 
				
			||||||
			s := opts.WithTypeMode(elideType).FormatValue(vi, true, m)
 | 
					 | 
				
			||||||
			list = append(list, textRecord{Value: s})
 | 
								list = append(list, textRecord{Value: s})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return textWrap{ptr + "{", list, "}"}
 | 
					
 | 
				
			||||||
 | 
							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:
 | 
						case reflect.Map:
 | 
				
			||||||
		if v.IsNil() {
 | 
							if v.IsNil() {
 | 
				
			||||||
			return textNil
 | 
								return textNil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if m.Visit(v) {
 | 
					 | 
				
			||||||
			return textLine(formatPointer(v))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 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
 | 
							var list textList
 | 
				
			||||||
		for _, k := range value.SortKeys(v.MapKeys()) {
 | 
							for _, k := range value.SortKeys(v.MapKeys()) {
 | 
				
			||||||
			sk := formatMapKey(k)
 | 
								if len(list) == maxLen {
 | 
				
			||||||
			sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), false, m)
 | 
									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})
 | 
								list = append(list, textRecord{Key: sk, Value: sv})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if opts.PrintAddresses {
 | 
					
 | 
				
			||||||
			ptr = formatPointer(v)
 | 
							out = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
 | 
				
			||||||
		}
 | 
							out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
 | 
				
			||||||
		return textWrap{ptr + "{", list, "}"}
 | 
							return out
 | 
				
			||||||
	case reflect.Ptr:
 | 
						case reflect.Ptr:
 | 
				
			||||||
		if v.IsNil() {
 | 
							if v.IsNil() {
 | 
				
			||||||
			return textNil
 | 
								return textNil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if m.Visit(v) || opts.ShallowPointers {
 | 
					
 | 
				
			||||||
			return textLine(formatPointer(v))
 | 
							// Check pointer for cycles.
 | 
				
			||||||
		}
 | 
							ptrRef, visited := ptrs.Push(v)
 | 
				
			||||||
		if opts.PrintAddresses {
 | 
							if visited {
 | 
				
			||||||
			ptr = formatPointer(v)
 | 
								out = makeLeafReference(ptrRef, opts.PrintAddresses)
 | 
				
			||||||
 | 
								return &textWrap{Prefix: "&", Value: out}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							defer ptrs.Pop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		skipType = true // Let the underlying value print the type instead
 | 
							skipType = true // Let the underlying value print the type instead
 | 
				
			||||||
		return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), false, m), ""}
 | 
							out = opts.FormatValue(v.Elem(), t.Kind(), ptrs)
 | 
				
			||||||
 | 
							out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
 | 
				
			||||||
 | 
							out = &textWrap{Prefix: "&", Value: out}
 | 
				
			||||||
 | 
							return out
 | 
				
			||||||
	case reflect.Interface:
 | 
						case reflect.Interface:
 | 
				
			||||||
		if v.IsNil() {
 | 
							if v.IsNil() {
 | 
				
			||||||
			return textNil
 | 
								return textNil
 | 
				
			||||||
@@ -200,19 +293,67 @@ func (opts formatOptions) FormatValue(v reflect.Value, withinSlice bool, m visit
 | 
				
			|||||||
		// Interfaces accept different concrete types,
 | 
							// Interfaces accept different concrete types,
 | 
				
			||||||
		// so configure the underlying value to explicitly print the type.
 | 
							// so configure the underlying value to explicitly print the type.
 | 
				
			||||||
		skipType = true // Print the concrete type instead
 | 
							skipType = true // Print the concrete type instead
 | 
				
			||||||
		return opts.WithTypeMode(emitType).FormatValue(v.Elem(), false, m)
 | 
							return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs)
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		panic(fmt.Sprintf("%v kind not handled", v.Kind()))
 | 
							panic(fmt.Sprintf("%v kind not handled", v.Kind()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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.
 | 
					// formatMapKey formats v as if it were a map key.
 | 
				
			||||||
// The result is guaranteed to be a single line.
 | 
					// The result is guaranteed to be a single line.
 | 
				
			||||||
func formatMapKey(v reflect.Value) string {
 | 
					func formatMapKey(v reflect.Value, disambiguate bool, ptrs *pointerReferences) string {
 | 
				
			||||||
	var opts formatOptions
 | 
						var opts formatOptions
 | 
				
			||||||
 | 
						opts.DiffMode = diffIdentical
 | 
				
			||||||
	opts.TypeMode = elideType
 | 
						opts.TypeMode = elideType
 | 
				
			||||||
	opts.ShallowPointers = true
 | 
						opts.PrintAddresses = disambiguate
 | 
				
			||||||
	s := opts.FormatValue(v, false, visitedPointers{}).String()
 | 
						opts.AvoidStringer = disambiguate
 | 
				
			||||||
 | 
						opts.QualifiedNames = disambiguate
 | 
				
			||||||
 | 
						opts.VerbosityLevel = maxVerbosityPreset
 | 
				
			||||||
 | 
						opts.LimitVerbosity = true
 | 
				
			||||||
 | 
						s := opts.FormatValue(v, reflect.Map, ptrs).String()
 | 
				
			||||||
	return strings.TrimSpace(s)
 | 
						return strings.TrimSpace(s)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -230,7 +371,7 @@ func formatString(s string) string {
 | 
				
			|||||||
	rawInvalid := func(r rune) bool {
 | 
						rawInvalid := func(r rune) bool {
 | 
				
			||||||
		return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t')
 | 
							return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if strings.IndexFunc(s, rawInvalid) < 0 {
 | 
						if utf8.ValidString(s) && strings.IndexFunc(s, rawInvalid) < 0 {
 | 
				
			||||||
		return "`" + s + "`"
 | 
							return "`" + s + "`"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return qs
 | 
						return qs
 | 
				
			||||||
@@ -259,23 +400,3 @@ func formatHex(u uint64) string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return fmt.Sprintf(f, u)
 | 
						return fmt.Sprintf(f, u)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// formatPointer prints the address of the pointer.
 | 
					 | 
				
			||||||
func formatPointer(v reflect.Value) string {
 | 
					 | 
				
			||||||
	p := v.Pointer()
 | 
					 | 
				
			||||||
	if flags.Deterministic {
 | 
					 | 
				
			||||||
		p = 0xdeadf00f // Only used for stable testing purposes
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return fmt.Sprintf("⟪0x%x⟫", p)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type visitedPointers map[value.Pointer]struct{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Visit inserts pointer v into the visited map and reports whether it had
 | 
					 | 
				
			||||||
// already been visited before.
 | 
					 | 
				
			||||||
func (m visitedPointers) Visit(v reflect.Value) bool {
 | 
					 | 
				
			||||||
	p := value.PointerOf(v)
 | 
					 | 
				
			||||||
	_, visited := m[p]
 | 
					 | 
				
			||||||
	m[p] = struct{}{}
 | 
					 | 
				
			||||||
	return visited
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										131
									
								
								vendor/github.com/google/go-cmp/cmp/report_slices.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										131
									
								
								vendor/github.com/google/go-cmp/cmp/report_slices.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"unicode"
 | 
						"unicode"
 | 
				
			||||||
	"unicode/utf8"
 | 
						"unicode/utf8"
 | 
				
			||||||
@@ -23,11 +24,25 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
 | 
				
			|||||||
		return false // Must be formatting in diff mode
 | 
							return false // Must be formatting in diff mode
 | 
				
			||||||
	case v.NumDiff == 0:
 | 
						case v.NumDiff == 0:
 | 
				
			||||||
		return false // No differences detected
 | 
							return false // No differences detected
 | 
				
			||||||
	case v.NumIgnored+v.NumCompared+v.NumTransformed > 0:
 | 
					 | 
				
			||||||
		// TODO: Handle the case where someone uses bytes.Equal on a large slice.
 | 
					 | 
				
			||||||
		return false // Some custom option was used to determined equality
 | 
					 | 
				
			||||||
	case !v.ValueX.IsValid() || !v.ValueY.IsValid():
 | 
						case !v.ValueX.IsValid() || !v.ValueY.IsValid():
 | 
				
			||||||
		return false // Both values must be valid
 | 
							return false // Both values must be valid
 | 
				
			||||||
 | 
						case v.Type.Kind() == reflect.Slice && (v.ValueX.Len() == 0 || v.ValueY.Len() == 0):
 | 
				
			||||||
 | 
							return false // Both slice values have to be non-empty
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch t := v.Type; t.Kind() {
 | 
						switch t := v.Type; t.Kind() {
 | 
				
			||||||
@@ -82,7 +97,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if isText || isBinary {
 | 
						if isText || isBinary {
 | 
				
			||||||
		var numLines, lastLineIdx, maxLineLen int
 | 
							var numLines, lastLineIdx, maxLineLen int
 | 
				
			||||||
		isBinary = false
 | 
							isBinary = !utf8.ValidString(sx) || !utf8.ValidString(sy)
 | 
				
			||||||
		for i, r := range sx + sy {
 | 
							for i, r := range sx + sy {
 | 
				
			||||||
			if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError {
 | 
								if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError {
 | 
				
			||||||
				isBinary = true
 | 
									isBinary = true
 | 
				
			||||||
@@ -97,7 +112,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		isText = !isBinary
 | 
							isText = !isBinary
 | 
				
			||||||
		isLinedText = isText && numLines >= 4 && maxLineLen <= 256
 | 
							isLinedText = isText && numLines >= 4 && maxLineLen <= 1024
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Format the string into printable records.
 | 
						// Format the string into printable records.
 | 
				
			||||||
@@ -117,6 +132,83 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		delim = "\n"
 | 
							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,
 | 
						// If the text appears to be single-lined text,
 | 
				
			||||||
	// then perform differencing in approximately fixed-sized chunks.
 | 
						// then perform differencing in approximately fixed-sized chunks.
 | 
				
			||||||
	// The output is printed as quoted strings.
 | 
						// The output is printed as quoted strings.
 | 
				
			||||||
@@ -129,6 +221,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		delim = ""
 | 
							delim = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If the text appears to be binary data,
 | 
						// If the text appears to be binary data,
 | 
				
			||||||
	// then perform differencing in approximately fixed-sized chunks.
 | 
						// then perform differencing in approximately fixed-sized chunks.
 | 
				
			||||||
	// The output is inspired by hexdump.
 | 
						// The output is inspired by hexdump.
 | 
				
			||||||
@@ -145,6 +238,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 | 
				
			|||||||
				return textRecord{Diff: d, Value: textLine(s), Comment: comment}
 | 
									return textRecord{Diff: d, Value: textLine(s), Comment: comment}
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// For all other slices of primitive types,
 | 
						// For all other slices of primitive types,
 | 
				
			||||||
	// then perform differencing in approximately fixed-sized chunks.
 | 
						// then perform differencing in approximately fixed-sized chunks.
 | 
				
			||||||
	// The size of each chunk depends on the width of the element kind.
 | 
						// The size of each chunk depends on the width of the element kind.
 | 
				
			||||||
@@ -187,7 +281,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Wrap the output with appropriate type information.
 | 
						// Wrap the output with appropriate type information.
 | 
				
			||||||
	var out textNode = textWrap{"{", list, "}"}
 | 
						var out textNode = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
 | 
				
			||||||
	if !isText {
 | 
						if !isText {
 | 
				
			||||||
		// The "{...}" byte-sequence literal is not valid Go syntax for strings.
 | 
							// The "{...}" byte-sequence literal is not valid Go syntax for strings.
 | 
				
			||||||
		// Emit the type for extra clarity (e.g. "string{...}").
 | 
							// Emit the type for extra clarity (e.g. "string{...}").
 | 
				
			||||||
@@ -198,12 +292,12 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	switch t.Kind() {
 | 
						switch t.Kind() {
 | 
				
			||||||
	case reflect.String:
 | 
						case reflect.String:
 | 
				
			||||||
		out = textWrap{"strings.Join(", out, fmt.Sprintf(", %q)", delim)}
 | 
							out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
 | 
				
			||||||
		if t != reflect.TypeOf(string("")) {
 | 
							if t != reflect.TypeOf(string("")) {
 | 
				
			||||||
			out = opts.FormatType(t, out)
 | 
								out = opts.FormatType(t, out)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Slice:
 | 
						case reflect.Slice:
 | 
				
			||||||
		out = textWrap{"bytes.Join(", out, fmt.Sprintf(", %q)", delim)}
 | 
							out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
 | 
				
			||||||
		if t != reflect.TypeOf([]byte(nil)) {
 | 
							if t != reflect.TypeOf([]byte(nil)) {
 | 
				
			||||||
			out = opts.FormatType(t, out)
 | 
								out = opts.FormatType(t, out)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -244,9 +338,22 @@ func (opts formatOptions) formatDiffSlice(
 | 
				
			|||||||
		return n0 - 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 := coalesceAdjacentEdits(name, es)
 | 
				
			||||||
	groups = coalesceInterveningIdentical(groups, chunkSize/4)
 | 
						groups = coalesceInterveningIdentical(groups, chunkSize/4)
 | 
				
			||||||
 | 
						maxGroup := diffStats{Name: name}
 | 
				
			||||||
	for i, ds := range groups {
 | 
						for i, ds := range groups {
 | 
				
			||||||
 | 
							if maxLen >= 0 && numDiffs >= maxLen {
 | 
				
			||||||
 | 
								maxGroup = maxGroup.Append(ds)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Print equal.
 | 
							// Print equal.
 | 
				
			||||||
		if ds.NumDiff() == 0 {
 | 
							if ds.NumDiff() == 0 {
 | 
				
			||||||
			// Compute the number of leading and trailing equal bytes to print.
 | 
								// Compute the number of leading and trailing equal bytes to print.
 | 
				
			||||||
@@ -275,12 +382,18 @@ func (opts formatOptions) formatDiffSlice(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Print unequal.
 | 
							// Print unequal.
 | 
				
			||||||
 | 
							len0 := len(list)
 | 
				
			||||||
		nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved)
 | 
							nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved)
 | 
				
			||||||
		vx = vx.Slice(nx, vx.Len())
 | 
							vx = vx.Slice(nx, vx.Len())
 | 
				
			||||||
		ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted)
 | 
							ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted)
 | 
				
			||||||
		vy = vy.Slice(ny, vy.Len())
 | 
							vy = vy.Slice(ny, vy.Len())
 | 
				
			||||||
 | 
							numDiffs += len(list) - len0
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if maxGroup.IsZero() {
 | 
				
			||||||
		assert(vx.Len() == 0 && vy.Len() == 0)
 | 
							assert(vx.Len() == 0 && vy.Len() == 0)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							list.AppendEllipsis(maxGroup)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return list
 | 
						return list
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										74
									
								
								vendor/github.com/google/go-cmp/cmp/report_text.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/google/go-cmp/cmp/report_text.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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,12 +10,15 @@ import (
 | 
				
			|||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
						"unicode/utf8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/google/go-cmp/cmp/internal/flags"
 | 
						"github.com/google/go-cmp/cmp/internal/flags"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
 | 
					var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const maxColumnLength = 80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type indentMode int
 | 
					type indentMode int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (n indentMode) appendIndent(b []byte, d diffMode) []byte {
 | 
					func (n indentMode) appendIndent(b []byte, d diffMode) []byte {
 | 
				
			||||||
@@ -94,18 +97,19 @@ type textWrap struct {
 | 
				
			|||||||
	Prefix   string      // e.g., "bytes.Buffer{"
 | 
						Prefix   string      // e.g., "bytes.Buffer{"
 | 
				
			||||||
	Value    textNode    // textWrap | textList | textLine
 | 
						Value    textNode    // textWrap | textList | textLine
 | 
				
			||||||
	Suffix   string      // e.g., "}"
 | 
						Suffix   string      // e.g., "}"
 | 
				
			||||||
 | 
						Metadata interface{} // arbitrary metadata; has no effect on formatting
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s textWrap) Len() int {
 | 
					func (s *textWrap) Len() int {
 | 
				
			||||||
	return len(s.Prefix) + s.Value.Len() + len(s.Suffix)
 | 
						return len(s.Prefix) + s.Value.Len() + len(s.Suffix)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (s1 textWrap) Equal(s2 textNode) bool {
 | 
					func (s1 *textWrap) Equal(s2 textNode) bool {
 | 
				
			||||||
	if s2, ok := s2.(textWrap); ok {
 | 
						if s2, ok := s2.(*textWrap); ok {
 | 
				
			||||||
		return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix
 | 
							return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (s textWrap) String() string {
 | 
					func (s *textWrap) String() string {
 | 
				
			||||||
	var d diffMode
 | 
						var d diffMode
 | 
				
			||||||
	var n indentMode
 | 
						var n indentMode
 | 
				
			||||||
	_, s2 := s.formatCompactTo(nil, d)
 | 
						_, s2 := s.formatCompactTo(nil, d)
 | 
				
			||||||
@@ -114,7 +118,7 @@ func (s textWrap) String() string {
 | 
				
			|||||||
	b = append(b, '\n')              // Trailing newline
 | 
						b = append(b, '\n')              // Trailing newline
 | 
				
			||||||
	return string(b)
 | 
						return string(b)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
 | 
					func (s *textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
 | 
				
			||||||
	n0 := len(b) // Original buffer length
 | 
						n0 := len(b) // Original buffer length
 | 
				
			||||||
	b = append(b, s.Prefix...)
 | 
						b = append(b, s.Prefix...)
 | 
				
			||||||
	b, s.Value = s.Value.formatCompactTo(b, d)
 | 
						b, s.Value = s.Value.formatCompactTo(b, d)
 | 
				
			||||||
@@ -124,7 +128,7 @@ func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return b, s
 | 
						return b, s
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
 | 
					func (s *textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
 | 
				
			||||||
	b = append(b, s.Prefix...)
 | 
						b = append(b, s.Prefix...)
 | 
				
			||||||
	b = s.Value.formatExpandedTo(b, d, n)
 | 
						b = s.Value.formatExpandedTo(b, d, n)
 | 
				
			||||||
	b = append(b, s.Suffix...)
 | 
						b = append(b, s.Suffix...)
 | 
				
			||||||
@@ -139,6 +143,7 @@ type textRecord struct {
 | 
				
			|||||||
	Diff       diffMode     // e.g., 0 or '-' or '+'
 | 
						Diff       diffMode     // e.g., 0 or '-' or '+'
 | 
				
			||||||
	Key        string       // e.g., "MyField"
 | 
						Key        string       // e.g., "MyField"
 | 
				
			||||||
	Value      textNode     // textWrap | textLine
 | 
						Value      textNode     // textWrap | textLine
 | 
				
			||||||
 | 
						ElideComma bool         // avoid trailing comma
 | 
				
			||||||
	Comment    fmt.Stringer // e.g., "6 identical fields"
 | 
						Comment    fmt.Stringer // e.g., "6 identical fields"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,12 +151,12 @@ type textRecord struct {
 | 
				
			|||||||
// exists at the end. If cs is non-zero it coalesces the statistics with the
 | 
					// exists at the end. If cs is non-zero it coalesces the statistics with the
 | 
				
			||||||
// previous diffStats.
 | 
					// previous diffStats.
 | 
				
			||||||
func (s *textList) AppendEllipsis(ds diffStats) {
 | 
					func (s *textList) AppendEllipsis(ds diffStats) {
 | 
				
			||||||
	hasStats := ds != diffStats{}
 | 
						hasStats := !ds.IsZero()
 | 
				
			||||||
	if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) {
 | 
						if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) {
 | 
				
			||||||
		if hasStats {
 | 
							if hasStats {
 | 
				
			||||||
			*s = append(*s, textRecord{Value: textEllipsis, Comment: ds})
 | 
								*s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds})
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			*s = append(*s, textRecord{Value: textEllipsis})
 | 
								*s = append(*s, textRecord{Value: textEllipsis, ElideComma: true})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -191,7 +196,7 @@ func (s1 textList) Equal(s2 textNode) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s textList) String() string {
 | 
					func (s textList) String() string {
 | 
				
			||||||
	return textWrap{"{", s, "}"}.String()
 | 
						return (&textWrap{Prefix: "{", Value: s, Suffix: "}"}).String()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
 | 
					func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
 | 
				
			||||||
@@ -221,7 +226,7 @@ func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	// Force multi-lined output when printing a removed/inserted node that
 | 
						// Force multi-lined output when printing a removed/inserted node that
 | 
				
			||||||
	// is sufficiently long.
 | 
						// is sufficiently long.
 | 
				
			||||||
	if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > 80 {
 | 
						if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > maxColumnLength {
 | 
				
			||||||
		multiLine = true
 | 
							multiLine = true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !multiLine {
 | 
						if !multiLine {
 | 
				
			||||||
@@ -236,16 +241,50 @@ func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
 | 
				
			|||||||
			_, isLine := r.Value.(textLine)
 | 
								_, isLine := r.Value.(textLine)
 | 
				
			||||||
			return r.Key == "" || !isLine
 | 
								return r.Key == "" || !isLine
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		func(r textRecord) int { return len(r.Key) },
 | 
							func(r textRecord) int { return utf8.RuneCountInString(r.Key) },
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	alignValueLens := s.alignLens(
 | 
						alignValueLens := s.alignLens(
 | 
				
			||||||
		func(r textRecord) bool {
 | 
							func(r textRecord) bool {
 | 
				
			||||||
			_, isLine := r.Value.(textLine)
 | 
								_, isLine := r.Value.(textLine)
 | 
				
			||||||
			return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil
 | 
								return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		func(r textRecord) int { return len(r.Value.(textLine)) },
 | 
							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.
 | 
						// Format the list as a multi-lined output.
 | 
				
			||||||
	n++
 | 
						n++
 | 
				
			||||||
	for i, r := range s {
 | 
						for i, r := range s {
 | 
				
			||||||
@@ -256,7 +295,7 @@ func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
 | 
				
			|||||||
		b = alignKeyLens[i].appendChar(b, ' ')
 | 
							b = alignKeyLens[i].appendChar(b, ' ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		b = r.Value.formatExpandedTo(b, d|r.Diff, n)
 | 
							b = r.Value.formatExpandedTo(b, d|r.Diff, n)
 | 
				
			||||||
		if !r.Value.Equal(textEllipsis) {
 | 
							if !r.ElideComma {
 | 
				
			||||||
			b = append(b, ',')
 | 
								b = append(b, ',')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		b = alignValueLens[i].appendChar(b, ' ')
 | 
							b = alignValueLens[i].appendChar(b, ' ')
 | 
				
			||||||
@@ -332,6 +371,11 @@ type diffStats struct {
 | 
				
			|||||||
	NumModified  int
 | 
						NumModified  int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s diffStats) IsZero() bool {
 | 
				
			||||||
 | 
						s.Name = ""
 | 
				
			||||||
 | 
						return s == diffStats{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s diffStats) NumDiff() int {
 | 
					func (s diffStats) NumDiff() int {
 | 
				
			||||||
	return s.NumRemoved + s.NumInserted + s.NumModified
 | 
						return s.NumRemoved + s.NumInserted + s.NumModified
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/report_value.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/google/go-cmp/cmp/report_value.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
// Copyright 2019, The Go Authors. All rights reserved.
 | 
					// Copyright 2019, 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,4 @@
 | 
				
			|||||||
# github.com/google/go-cmp v0.4.1
 | 
					# github.com/google/go-cmp v0.5.4
 | 
				
			||||||
## explicit
 | 
					## explicit
 | 
				
			||||||
github.com/google/go-cmp/cmp
 | 
					github.com/google/go-cmp/cmp
 | 
				
			||||||
github.com/google/go-cmp/cmp/internal/diff
 | 
					github.com/google/go-cmp/cmp/internal/diff
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user