// Equal reports whether x and y are equal by recursively applying the // following rules in the given order to x and y and all of their sub-values: // // - Let S be the set of all [Ignore], [Transformer], and [Comparer] options that // remain after applying all path filters, value filters, and type filters. // If at least one [Ignore] exists in S, then the comparison is ignored. // If the number of [Transformer] and [Comparer] options in S is non-zero, // then Equal panics because it is ambiguous which option to use. // If S contains a single [Transformer], then use that to transform // the current values and recursively call Equal on the output values. // If S contains a single [Comparer], then use that to compare the current values. // Otherwise, evaluation proceeds to the next rule. // // - If the values have an Equal method of the form "(T) Equal(T) bool" or // "(T) Equal(I) bool" where T is assignable to I, then use the result of // x.Equal(y) even if x or y is nil. Otherwise, no such method exists and // evaluation proceeds to the next rule. // // - Lastly, try to compare x and y based on their basic kinds. // Simple kinds like booleans, integers, floats, complex numbers, strings, // and channels are compared using the equivalent of the == operator in Go. // Functions are only equal if they are both nil, otherwise they are unequal. // // 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., [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported]) ignores that field // or the [Exporter] option explicitly permits comparing the unexported field. // // Slices are equal if they are both nil or both non-nil, where recursively // calling Equal on all non-ignored slice or array elements report equal. // Empty non-nil slices and nil slices are not equal; to equate empty slices, // consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty]. // // Maps are equal if they are both nil or both non-nil, where recursively // calling Equal on all non-ignored map entries report equal. // Map keys are equal according to the == operator. // To use custom comparisons for map keys, consider using // [github.com/google/go-cmp/cmp/cmpopts.SortMaps]. // Empty non-nil maps and nil maps are not equal; to equate empty maps, // consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty]. // // Pointers and interfaces are equal if they are both nil or both non-nil, // where they have the same underlying concrete type and recursively // calling Equal on the underlying values reports equal. // // Before recursing into a pointer, slice element, or map, the current path // is checked to detect whether the address has already been visited. // If there is a cycle, then the pointed at values are considered equal // only if both addresses were previously visited in the same path step. func Equal(x, y interface{ … } // 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{ … } // 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{ … } type state … func newState(opts []Option) *state { … } func (s *state) processOption(opt Option) { … } // statelessCompare compares two values and returns the result. // 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 { … } func (s *state) compareAny(step PathStep) { … } func (s *state) tryOptions(t reflect.Type, vx, vy reflect.Value) bool { … } func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool { … } func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value { … } func (s *state) callTTBFunc(f, x, y reflect.Value) bool { … } func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) { … } func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { … } func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) { … } func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) { … } func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) { … } func (s *state) compareInterface(t reflect.Type, vx, vy reflect.Value) { … } func (s *state) report(eq bool, rf resultFlags) { … } type recChecker … // Check scans the Path for any recursive transformers and panics when any // recursive transformers are detected. Note that the presence of a // recursive Transformer does not necessarily imply an infinite cycle. // As such, this check only activates after some minimal number of path steps. func (rc *recChecker) Check(p Path) { … } type dynChecker … // Next increments the state and reports whether a check should be performed. // // Checks occur every Nth function call, where N is a triangular number: // // 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ... // // See https://en.wikipedia.org/wiki/Triangular_number // // This sequence ensures that the cost of checks drops significantly as // the number of functions calls grows larger. func (dc *dynChecker) Next() bool { … } // makeAddressable returns a value that is always addressable. // It returns the input verbatim if it is already addressable, // otherwise it creates a new value and returns an addressable copy. func makeAddressable(v reflect.Value) reflect.Value { … }