DSCGS-36 Go mod updated, test updated (#38)
This commit is contained in:
		
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
module github.com/irlndts/go-discogs
 | 
			
		||||
 | 
			
		||||
go 1.13.4
 | 
			
		||||
go 1.14
 | 
			
		||||
 | 
			
		||||
require github.com/google/go-cmp v0.3.1
 | 
			
		||||
require github.com/google/go-cmp v0.4.0
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,2 +1,4 @@
 | 
			
		||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
 | 
			
		||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
			
		||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 | 
			
		||||
github.com/google/go-cmp v0.4.0/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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ type Series struct {
 | 
			
		||||
	ID             int    `json:"id"`
 | 
			
		||||
	Name           string `json:"name"`
 | 
			
		||||
	ResourceURL    string `json:"resource_url"`
 | 
			
		||||
	ThumbnailURL   string `json:"thumbnail_url"`
 | 
			
		||||
	ThumbnailURL   string `json:"thumbnail_url,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ArtistSource ...
 | 
			
		||||
@@ -68,7 +68,7 @@ type LabelSource struct {
 | 
			
		||||
 | 
			
		||||
// Identifier ...
 | 
			
		||||
type Identifier struct {
 | 
			
		||||
	Description string `json:"description"`
 | 
			
		||||
	Description string `json:"description,omitempty"`
 | 
			
		||||
	Type        string `json:"type"`
 | 
			
		||||
	Value       string `json:"value"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										81
									
								
								vendor/github.com/google/go-cmp/cmp/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										81
									
								
								vendor/github.com/google/go-cmp/cmp/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -22,8 +22,8 @@
 | 
			
		||||
// equality is determined by recursively comparing the primitive kinds on both
 | 
			
		||||
// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
 | 
			
		||||
// fields are not compared by default; they result in panics unless suppressed
 | 
			
		||||
// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly compared
 | 
			
		||||
// using the AllowUnexported option.
 | 
			
		||||
// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly
 | 
			
		||||
// compared using the Exporter option.
 | 
			
		||||
package cmp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@@ -62,8 +62,8 @@ import (
 | 
			
		||||
//
 | 
			
		||||
// Structs are equal if recursively calling Equal on all fields report equal.
 | 
			
		||||
// If a struct contains unexported fields, Equal panics unless an Ignore option
 | 
			
		||||
// (e.g., cmpopts.IgnoreUnexported) ignores that field or the AllowUnexported
 | 
			
		||||
// option explicitly permits comparing the unexported field.
 | 
			
		||||
// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option
 | 
			
		||||
// explicitly permits comparing the unexported field.
 | 
			
		||||
//
 | 
			
		||||
// Slices are equal if they are both nil or both non-nil, where recursively
 | 
			
		||||
// calling Equal on all non-ignored slice or array elements report equal.
 | 
			
		||||
@@ -80,6 +80,11 @@ import (
 | 
			
		||||
// Pointers and interfaces are equal if they are both nil or both non-nil,
 | 
			
		||||
// where they have the same underlying concrete type and recursively
 | 
			
		||||
// calling Equal on the underlying values reports equal.
 | 
			
		||||
//
 | 
			
		||||
// Before recursing into a pointer, slice element, or map, the current path
 | 
			
		||||
// is checked to detect whether the address has already been visited.
 | 
			
		||||
// If there is a cycle, then the pointed at values are considered equal
 | 
			
		||||
// only if both addresses were previously visited in the same path step.
 | 
			
		||||
func Equal(x, y interface{}, opts ...Option) bool {
 | 
			
		||||
	vx := reflect.ValueOf(x)
 | 
			
		||||
	vy := reflect.ValueOf(y)
 | 
			
		||||
@@ -137,6 +142,7 @@ type state struct {
 | 
			
		||||
	// Calling statelessCompare must not result in observable changes to these.
 | 
			
		||||
	result    diff.Result // The current result of comparison
 | 
			
		||||
	curPath   Path        // The current path in the value tree
 | 
			
		||||
	curPtrs   pointerPath // The current set of visited pointers
 | 
			
		||||
	reporters []reporter  // Optional reporters
 | 
			
		||||
 | 
			
		||||
	// recChecker checks for infinite cycles applying the same set of
 | 
			
		||||
@@ -148,13 +154,14 @@ type state struct {
 | 
			
		||||
	dynChecker dynChecker
 | 
			
		||||
 | 
			
		||||
	// These fields, once set by processOption, will not change.
 | 
			
		||||
	exporters map[reflect.Type]bool // Set of structs with unexported field visibility
 | 
			
		||||
	exporters []exporter // List of exporters for structs with unexported fields
 | 
			
		||||
	opts      Options    // List of all fundamental and filter options
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newState(opts []Option) *state {
 | 
			
		||||
	// Always ensure a validator option exists to validate the inputs.
 | 
			
		||||
	s := &state{opts: Options{validator{}}}
 | 
			
		||||
	s.curPtrs.Init()
 | 
			
		||||
	s.processOption(Options(opts))
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
@@ -174,13 +181,8 @@ func (s *state) processOption(opt Option) {
 | 
			
		||||
			panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt))
 | 
			
		||||
		}
 | 
			
		||||
		s.opts = append(s.opts, opt)
 | 
			
		||||
	case visibleStructs:
 | 
			
		||||
		if s.exporters == nil {
 | 
			
		||||
			s.exporters = make(map[reflect.Type]bool)
 | 
			
		||||
		}
 | 
			
		||||
		for t := range opt {
 | 
			
		||||
			s.exporters[t] = true
 | 
			
		||||
		}
 | 
			
		||||
	case exporter:
 | 
			
		||||
		s.exporters = append(s.exporters, opt)
 | 
			
		||||
	case reporter:
 | 
			
		||||
		s.reporters = append(s.reporters, opt)
 | 
			
		||||
	default:
 | 
			
		||||
@@ -192,9 +194,9 @@ func (s *state) processOption(opt Option) {
 | 
			
		||||
// This function is stateless in that it does not alter the current result,
 | 
			
		||||
// or output to any registered reporters.
 | 
			
		||||
func (s *state) statelessCompare(step PathStep) diff.Result {
 | 
			
		||||
	// We do not save and restore the curPath because all of the compareX
 | 
			
		||||
	// methods should properly push and pop from the path.
 | 
			
		||||
	// It is an implementation bug if the contents of curPath differs from
 | 
			
		||||
	// We do not save and restore curPath and curPtrs because all of the
 | 
			
		||||
	// compareX methods should properly push and pop from them.
 | 
			
		||||
	// It is an implementation bug if the contents of the paths differ from
 | 
			
		||||
	// when calling this function to when returning from it.
 | 
			
		||||
 | 
			
		||||
	oldResult, oldReporters := s.result, s.reporters
 | 
			
		||||
@@ -216,9 +218,17 @@ func (s *state) compareAny(step PathStep) {
 | 
			
		||||
	}
 | 
			
		||||
	s.recChecker.Check(s.curPath)
 | 
			
		||||
 | 
			
		||||
	// Obtain the current type and values.
 | 
			
		||||
	// Cycle-detection for slice elements (see NOTE in compareSlice).
 | 
			
		||||
	t := step.Type()
 | 
			
		||||
	vx, vy := step.Values()
 | 
			
		||||
	if si, ok := step.(SliceIndex); ok && si.isSlice && vx.IsValid() && vy.IsValid() {
 | 
			
		||||
		px, py := vx.Addr(), vy.Addr()
 | 
			
		||||
		if eq, visited := s.curPtrs.Push(px, py); visited {
 | 
			
		||||
			s.report(eq, reportByCycle)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		defer s.curPtrs.Pop(px, py)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Rule 1: Check whether an option applies on this node in the value tree.
 | 
			
		||||
	if s.tryOptions(t, vx, vy) {
 | 
			
		||||
@@ -354,6 +364,7 @@ func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
 | 
			
		||||
func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
 | 
			
		||||
	var vax, vay reflect.Value // Addressable versions of vx and vy
 | 
			
		||||
 | 
			
		||||
	var mayForce, mayForceInit bool
 | 
			
		||||
	step := StructField{&structField{}}
 | 
			
		||||
	for i := 0; i < t.NumField(); i++ {
 | 
			
		||||
		step.typ = t.Field(i).Type
 | 
			
		||||
@@ -375,7 +386,13 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
 | 
			
		||||
				vax = makeAddressable(vx)
 | 
			
		||||
				vay = makeAddressable(vy)
 | 
			
		||||
			}
 | 
			
		||||
			step.mayForce = s.exporters[t]
 | 
			
		||||
			if !mayForceInit {
 | 
			
		||||
				for _, xf := range s.exporters {
 | 
			
		||||
					mayForce = mayForce || xf(t)
 | 
			
		||||
				}
 | 
			
		||||
				mayForceInit = true
 | 
			
		||||
			}
 | 
			
		||||
			step.mayForce = mayForce
 | 
			
		||||
			step.pvx = vax
 | 
			
		||||
			step.pvy = vay
 | 
			
		||||
			step.field = t.Field(i)
 | 
			
		||||
@@ -391,9 +408,21 @@ func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: Support cyclic data structures.
 | 
			
		||||
	// NOTE: It is incorrect to call curPtrs.Push on the slice header pointer
 | 
			
		||||
	// since slices represents a list of pointers, rather than a single pointer.
 | 
			
		||||
	// The pointer checking logic must be handled on a per-element basis
 | 
			
		||||
	// in compareAny.
 | 
			
		||||
	//
 | 
			
		||||
	// A slice header (see reflect.SliceHeader) in Go is a tuple of a starting
 | 
			
		||||
	// pointer P, a length N, and a capacity C. Supposing each slice element has
 | 
			
		||||
	// a memory size of M, then the slice is equivalent to the list of pointers:
 | 
			
		||||
	//	[P+i*M for i in range(N)]
 | 
			
		||||
	//
 | 
			
		||||
	// For example, v[:0] and v[:1] are slices with the same starting pointer,
 | 
			
		||||
	// but they are clearly different values. Using the slice pointer alone
 | 
			
		||||
	// violates the assumption that equal pointers implies equal values.
 | 
			
		||||
 | 
			
		||||
	step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}}}
 | 
			
		||||
	step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}, isSlice: isSlice}}
 | 
			
		||||
	withIndexes := func(ix, iy int) SliceIndex {
 | 
			
		||||
		if ix >= 0 {
 | 
			
		||||
			step.vx, step.xkey = vx.Index(ix), ix
 | 
			
		||||
@@ -470,7 +499,12 @@ func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: Support cyclic data structures.
 | 
			
		||||
	// Cycle-detection for maps.
 | 
			
		||||
	if eq, visited := s.curPtrs.Push(vx, vy); visited {
 | 
			
		||||
		s.report(eq, reportByCycle)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer s.curPtrs.Pop(vx, vy)
 | 
			
		||||
 | 
			
		||||
	// We combine and sort the two map keys so that we can perform the
 | 
			
		||||
	// comparisons in a deterministic order.
 | 
			
		||||
@@ -507,7 +541,12 @@ func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: Support cyclic data structures.
 | 
			
		||||
	// Cycle-detection for pointers.
 | 
			
		||||
	if eq, visited := s.curPtrs.Push(vx, vy); visited {
 | 
			
		||||
		s.report(eq, reportByCycle)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer s.curPtrs.Pop(vx, vy)
 | 
			
		||||
 | 
			
		||||
	vx, vy = vx.Elem(), vy.Elem()
 | 
			
		||||
	s.compareAny(Indirect{&indirect{pathStep{t.Elem(), vx, vy}}})
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
									
									
								
							@@ -8,8 +8,8 @@ package cmp
 | 
			
		||||
 | 
			
		||||
import "reflect"
 | 
			
		||||
 | 
			
		||||
const supportAllowUnexported = false
 | 
			
		||||
const supportExporters = false
 | 
			
		||||
 | 
			
		||||
func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value {
 | 
			
		||||
	panic("retrieveUnexportedField is not implemented")
 | 
			
		||||
	panic("no support for forcibly accessing unexported fields")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/google/go-cmp/cmp/export_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/google/go-cmp/cmp/export_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -11,7 +11,7 @@ import (
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const supportAllowUnexported = true
 | 
			
		||||
const supportExporters = true
 | 
			
		||||
 | 
			
		||||
// retrieveUnexportedField uses unsafe to forcibly retrieve any field from
 | 
			
		||||
// a struct such that the value has read-write permissions.
 | 
			
		||||
@@ -19,5 +19,7 @@ const supportAllowUnexported = true
 | 
			
		||||
// The parent struct, v, must be addressable, while f must be a StructField
 | 
			
		||||
// describing the field to retrieve.
 | 
			
		||||
func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value {
 | 
			
		||||
	return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem()
 | 
			
		||||
	// See https://github.com/google/go-cmp/issues/167 for discussion of the
 | 
			
		||||
	// following expression.
 | 
			
		||||
	return reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								vendor/github.com/google/go-cmp/cmp/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/google/go-cmp/cmp/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -225,8 +225,20 @@ func (validator) apply(s *state, vx, vy reflect.Value) {
 | 
			
		||||
 | 
			
		||||
	// Unable to Interface implies unexported field without visibility access.
 | 
			
		||||
	if !vx.CanInterface() || !vy.CanInterface() {
 | 
			
		||||
		const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider AllowUnexported or cmpopts.IgnoreUnexported"
 | 
			
		||||
		panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help))
 | 
			
		||||
		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"
 | 
			
		||||
		var name string
 | 
			
		||||
		if t := s.curPath.Index(-2).Type(); t.Name() != "" {
 | 
			
		||||
			// Named type with unexported fields.
 | 
			
		||||
			name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType
 | 
			
		||||
		} else {
 | 
			
		||||
			// Unnamed type with unexported fields. Derive PkgPath from field.
 | 
			
		||||
			var pkgPath string
 | 
			
		||||
			for i := 0; i < t.NumField() && pkgPath == ""; i++ {
 | 
			
		||||
				pkgPath = t.Field(i).PkgPath
 | 
			
		||||
			}
 | 
			
		||||
			name = fmt.Sprintf("%q.(%v)", pkgPath, t.String()) // e.g., "path/to/package".(struct { a int })
 | 
			
		||||
		}
 | 
			
		||||
		panic(fmt.Sprintf("cannot handle unexported field at %#v:\n\t%v\n%s", s.curPath, name, help))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	panic("not reachable")
 | 
			
		||||
@@ -360,9 +372,8 @@ func (cm comparer) String() string {
 | 
			
		||||
	return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllowUnexported returns an Option that forcibly allows operations on
 | 
			
		||||
// unexported fields in certain structs, which are specified by passing in a
 | 
			
		||||
// value of each struct type.
 | 
			
		||||
// Exporter returns an Option that specifies whether Equal is allowed to
 | 
			
		||||
// introspect into the unexported fields of certain struct types.
 | 
			
		||||
//
 | 
			
		||||
// Users of this option must understand that comparing on unexported fields
 | 
			
		||||
// from external packages is not safe since changes in the internal
 | 
			
		||||
@@ -386,10 +397,24 @@ func (cm comparer) String() string {
 | 
			
		||||
//
 | 
			
		||||
// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore
 | 
			
		||||
// all unexported fields on specified struct types.
 | 
			
		||||
func AllowUnexported(types ...interface{}) Option {
 | 
			
		||||
	if !supportAllowUnexported {
 | 
			
		||||
		panic("AllowUnexported is not supported on purego builds, Google App Engine Standard, or GopherJS")
 | 
			
		||||
func Exporter(f func(reflect.Type) bool) Option {
 | 
			
		||||
	if !supportExporters {
 | 
			
		||||
		panic("Exporter is not supported on purego builds")
 | 
			
		||||
	}
 | 
			
		||||
	return exporter(f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type exporter func(reflect.Type) bool
 | 
			
		||||
 | 
			
		||||
func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
 | 
			
		||||
	panic("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllowUnexported returns an Options that allows Equal to forcibly introspect
 | 
			
		||||
// unexported fields of the specified struct types.
 | 
			
		||||
//
 | 
			
		||||
// See Exporter for the proper use of this option.
 | 
			
		||||
func AllowUnexported(types ...interface{}) Option {
 | 
			
		||||
	m := make(map[reflect.Type]bool)
 | 
			
		||||
	for _, typ := range types {
 | 
			
		||||
		t := reflect.TypeOf(typ)
 | 
			
		||||
@@ -398,13 +423,7 @@ func AllowUnexported(types ...interface{}) Option {
 | 
			
		||||
		}
 | 
			
		||||
		m[t] = true
 | 
			
		||||
	}
 | 
			
		||||
	return visibleStructs(m)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type visibleStructs map[reflect.Type]bool
 | 
			
		||||
 | 
			
		||||
func (visibleStructs) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
 | 
			
		||||
	panic("not implemented")
 | 
			
		||||
	return exporter(func(t reflect.Type) bool { return m[t] })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Result represents the comparison result for a single node and
 | 
			
		||||
@@ -436,6 +455,11 @@ func (r Result) ByFunc() bool {
 | 
			
		||||
	return r.flags&reportByFunc != 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ByCycle reports whether a reference cycle was detected.
 | 
			
		||||
func (r Result) ByCycle() bool {
 | 
			
		||||
	return r.flags&reportByCycle != 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type resultFlags uint
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -446,6 +470,7 @@ const (
 | 
			
		||||
	reportByIgnore
 | 
			
		||||
	reportByMethod
 | 
			
		||||
	reportByFunc
 | 
			
		||||
	reportByCycle
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Reporter is an Option that can be passed to Equal. When Equal traverses
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								vendor/github.com/google/go-cmp/cmp/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/google/go-cmp/cmp/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -10,6 +10,8 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp/internal/value"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Path is a list of PathSteps describing the sequence of operations to get
 | 
			
		||||
@@ -41,7 +43,7 @@ type PathStep interface {
 | 
			
		||||
	// In some cases, one or both may be invalid or have restrictions:
 | 
			
		||||
	//	• For StructField, both are not interface-able if the current field
 | 
			
		||||
	//	is unexported and the struct type is not explicitly permitted by
 | 
			
		||||
	//	AllowUnexported to traverse unexported fields.
 | 
			
		||||
	//	an Exporter to traverse unexported fields.
 | 
			
		||||
	//	• For SliceIndex, one may be invalid if an element is missing from
 | 
			
		||||
	//	either the x or y slice.
 | 
			
		||||
	//	• For MapIndex, one may be invalid if an entry is missing from
 | 
			
		||||
@@ -207,6 +209,7 @@ type SliceIndex struct{ *sliceIndex }
 | 
			
		||||
type sliceIndex struct {
 | 
			
		||||
	pathStep
 | 
			
		||||
	xkey, ykey int
 | 
			
		||||
	isSlice    bool // False for reflect.Array
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (si SliceIndex) Type() reflect.Type             { return si.typ }
 | 
			
		||||
@@ -301,6 +304,72 @@ func (tf Transform) Func() reflect.Value { return tf.trans.fnc }
 | 
			
		||||
// The == operator can be used to detect the exact option used.
 | 
			
		||||
func (tf Transform) Option() Option { return tf.trans }
 | 
			
		||||
 | 
			
		||||
// pointerPath represents a dual-stack of pointers encountered when
 | 
			
		||||
// recursively traversing the x and y values. This data structure supports
 | 
			
		||||
// detection of cycles and determining whether the cycles are equal.
 | 
			
		||||
// In Go, cycles can occur via pointers, slices, and maps.
 | 
			
		||||
//
 | 
			
		||||
// The pointerPath uses a map to represent a stack; where descension into a
 | 
			
		||||
// pointer pushes the address onto the stack, and ascension from a pointer
 | 
			
		||||
// pops the address from the stack. Thus, when traversing into a pointer from
 | 
			
		||||
// reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles
 | 
			
		||||
// by checking whether the pointer has already been visited. The cycle detection
 | 
			
		||||
// uses a seperate stack for the x and y values.
 | 
			
		||||
//
 | 
			
		||||
// If a cycle is detected we need to determine whether the two pointers
 | 
			
		||||
// should be considered equal. The definition of equality chosen by Equal
 | 
			
		||||
// requires two graphs to have the same structure. To determine this, both the
 | 
			
		||||
// x and y values must have a cycle where the previous pointers were also
 | 
			
		||||
// encountered together as a pair.
 | 
			
		||||
//
 | 
			
		||||
// Semantically, this is equivalent to augmenting Indirect, SliceIndex, and
 | 
			
		||||
// MapIndex with pointer information for the x and y values.
 | 
			
		||||
// Suppose px and py are two pointers to compare, we then search the
 | 
			
		||||
// Path for whether px was ever encountered in the Path history of x, and
 | 
			
		||||
// similarly so with py. If either side has a cycle, the comparison is only
 | 
			
		||||
// equal if both px and py have a cycle resulting from the same PathStep.
 | 
			
		||||
//
 | 
			
		||||
// Using a map as a stack is more performant as we can perform cycle detection
 | 
			
		||||
// in O(1) instead of O(N) where N is len(Path).
 | 
			
		||||
type pointerPath struct {
 | 
			
		||||
	// mx is keyed by x pointers, where the value is the associated y pointer.
 | 
			
		||||
	mx map[value.Pointer]value.Pointer
 | 
			
		||||
	// my is keyed by y pointers, where the value is the associated x pointer.
 | 
			
		||||
	my map[value.Pointer]value.Pointer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *pointerPath) Init() {
 | 
			
		||||
	p.mx = make(map[value.Pointer]value.Pointer)
 | 
			
		||||
	p.my = make(map[value.Pointer]value.Pointer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Push indicates intent to descend into pointers vx and vy where
 | 
			
		||||
// visited reports whether either has been seen before. If visited before,
 | 
			
		||||
// equal reports whether both pointers were encountered together.
 | 
			
		||||
// Pop must be called if and only if the pointers were never visited.
 | 
			
		||||
//
 | 
			
		||||
// The pointers vx and vy must be a reflect.Ptr, reflect.Slice, or reflect.Map
 | 
			
		||||
// and be non-nil.
 | 
			
		||||
func (p pointerPath) Push(vx, vy reflect.Value) (equal, visited bool) {
 | 
			
		||||
	px := value.PointerOf(vx)
 | 
			
		||||
	py := value.PointerOf(vy)
 | 
			
		||||
	_, ok1 := p.mx[px]
 | 
			
		||||
	_, ok2 := p.my[py]
 | 
			
		||||
	if ok1 || ok2 {
 | 
			
		||||
		equal = p.mx[px] == py && p.my[py] == px // Pointers paired together
 | 
			
		||||
		return equal, true
 | 
			
		||||
	}
 | 
			
		||||
	p.mx[px] = py
 | 
			
		||||
	p.my[py] = px
 | 
			
		||||
	return false, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pop ascends from pointers vx and vy.
 | 
			
		||||
func (p pointerPath) Pop(vx, vy reflect.Value) {
 | 
			
		||||
	delete(p.mx, value.PointerOf(vx))
 | 
			
		||||
	delete(p.my, value.PointerOf(vy))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isExported reports whether the identifier is exported.
 | 
			
		||||
func isExported(id string) bool {
 | 
			
		||||
	r, _ := utf8.DecodeRuneInString(id)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,5 @@
 | 
			
		||||
# github.com/google/go-cmp v0.3.1
 | 
			
		||||
# github.com/google/go-cmp v0.4.0
 | 
			
		||||
## explicit
 | 
			
		||||
github.com/google/go-cmp/cmp
 | 
			
		||||
github.com/google/go-cmp/cmp/internal/diff
 | 
			
		||||
github.com/google/go-cmp/cmp/internal/flags
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user