// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package cmp determines equality of values. // // This package is intended to be a more powerful and safer alternative to // reflect.DeepEqual for comparing whether two values are semantically equal. // It is intended to only be used in tests, as performance is not a goal and // it may panic if it cannot compare the values. Its propensity towards // panicking means that its unsuitable for production environments where a // spurious panic may be fatal. // // The primary features of cmp are: // // - When the default behavior of equality does not suit the test's needs, // custom equality functions can override the equality operation. // For example, an equality function may report floats as equal so long as // they are within some tolerance of each other. // // - Types with an Equal method may use that method to determine equality. // This allows package authors to determine the equality operation // for the types that they define. // // - If no custom equality functions are used and no Equal method is defined, // 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 Exporter option.
package cmp import ( ) // TODO(≥go1.18): Use any instead of interface{}. // 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., cmpopts.IgnoreUnexported) ignores that field or the Exporter option // explicitly permits comparing the unexported field. // // Slices are equal if they are both nil or both non-nil, where recursively // calling Equal on all non-ignored slice or array elements report equal. // Empty non-nil slices and nil slices are not equal; to equate empty slices, // consider using cmpopts.EquateEmpty. // // 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 cmpopts.SortMaps. // Empty non-nil maps and nil maps are not equal; to equate empty maps, // consider using cmpopts.EquateEmpty. // // Pointers and interfaces are equal if they are both nil or both non-nil, // where they have the same underlying concrete type and recursively // calling Equal on the underlying values reports equal. // // Before recursing into a pointer, slice element, or map, the current path // is checked to detect whether the address has already been visited. // If there is a cycle, then the pointed at values are considered equal // only if both addresses were previously visited in the same path step. func (, interface{}, ...Option) bool { := newState() .compareAny(rootStep(, )) return .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 (, interface{}, ...Option) string { := newState() // 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(.reporters) == 0 { .compareAny(rootStep(, )) if .result.Equal() { return "" } .result = diff.Result{} // Reset results } := new(defaultReporter) .reporters = append(.reporters, reporter{}) .compareAny(rootStep(, )) := .String() if ( == "") != .result.Equal() { panic("inconsistent difference and equality results") } return } // rootStep constructs the first path step. If x and y have differing types, // then they are stored within an empty interface type. func (, interface{}) PathStep { := reflect.ValueOf() := reflect.ValueOf() // If the inputs are different types, auto-wrap them in an empty interface // so that they have the same parent type. var reflect.Type if !.IsValid() || !.IsValid() || .Type() != .Type() { = anyType if .IsValid() { := reflect.New().Elem() .Set() = } if .IsValid() { := reflect.New().Elem() .Set() = } } else { = .Type() } return &pathStep{, , } } type state struct { // These fields represent the "comparison state". // 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 // transformers upon the output of itself. recChecker recChecker // dynChecker triggers pseudo-random checks for option correctness. // It is safe for statelessCompare to mutate this value. dynChecker dynChecker // These fields, once set by processOption, will not change. exporters []exporter // List of exporters for structs with unexported fields opts Options // List of all fundamental and filter options } func ( []Option) *state { // Always ensure a validator option exists to validate the inputs. := &state{opts: Options{validator{}}} .curPtrs.Init() .processOption(Options()) return } func ( *state) ( Option) { switch opt := .(type) { case nil: case Options: for , := range { .() } case coreOption: type interface { () bool } if , := .(); && !.() { panic(fmt.Sprintf("cannot use an unfiltered option: %v", )) } .opts = append(.opts, ) case exporter: .exporters = append(.exporters, ) case reporter: .reporters = append(.reporters, ) default: panic(fmt.Sprintf("unknown option %T", )) } } // 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 ( *state) ( PathStep) diff.Result { // We do not save and restore curPath and curPtrs because all of the // compareX methods should properly push and pop from them. // It is an implementation bug if the contents of the paths differ from // when calling this function to when returning from it. , := .result, .reporters .result = diff.Result{} // Reset result .reporters = nil // Remove reporters to avoid spurious printouts .compareAny() := .result .result, .reporters = , return } func ( *state) ( PathStep) { // Update the path stack. .curPath.push() defer .curPath.pop() for , := range .reporters { .PushStep() defer .PopStep() } .recChecker.Check(.curPath) // Cycle-detection for slice elements (see NOTE in compareSlice). := .Type() , := .Values() if , := .(SliceIndex); && .isSlice && .IsValid() && .IsValid() { , := .Addr(), .Addr() if , := .curPtrs.Push(, ); { .report(, reportByCycle) return } defer .curPtrs.Pop(, ) } // Rule 1: Check whether an option applies on this node in the value tree. if .tryOptions(, , ) { return } // Rule 2: Check whether the type has a valid Equal method. if .tryMethod(, , ) { return } // Rule 3: Compare based on the underlying kind. switch .Kind() { case reflect.Bool: .report(.Bool() == .Bool(), 0) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: .report(.Int() == .Int(), 0) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: .report(.Uint() == .Uint(), 0) case reflect.Float32, reflect.Float64: .report(.Float() == .Float(), 0) case reflect.Complex64, reflect.Complex128: .report(.Complex() == .Complex(), 0) case reflect.String: .report(.String() == .String(), 0) case reflect.Chan, reflect.UnsafePointer: .report(.Pointer() == .Pointer(), 0) case reflect.Func: .report(.IsNil() && .IsNil(), 0) case reflect.Struct: .compareStruct(, , ) case reflect.Slice, reflect.Array: .compareSlice(, , ) case reflect.Map: .compareMap(, , ) case reflect.Ptr: .comparePtr(, , ) case reflect.Interface: .compareInterface(, , ) default: panic(fmt.Sprintf("%v kind not handled", .Kind())) } } func ( *state) ( reflect.Type, , reflect.Value) bool { // Evaluate all filters and apply the remaining options. if := .opts.filter(, , , ); != nil { .apply(, , ) return true } return false } func ( *state) ( reflect.Type, , reflect.Value) bool { // Check if this type even has an Equal method. , := .MethodByName("Equal") if ! || !function.IsType(.Type, function.EqualAssignable) { return false } := .callTTBFunc(.Func, , ) .report(, reportByMethod) return true } func ( *state) (, reflect.Value, Transform) reflect.Value { if !.dynChecker.Next() { return .Call([]reflect.Value{})[0] } // Run the function twice and ensure that we get the same results back. // We run in goroutines so that the race detector (if enabled) can detect // unsafe mutations to the input. := make(chan reflect.Value) go detectRaces(, , ) := <- := .Call([]reflect.Value{})[0] if .vx, .vy = , ; !.statelessCompare().Equal() { // To avoid false-positives with non-reflexive equality operations, // we sanity check whether a value is equal to itself. if .vx, .vy = , ; !.statelessCompare().Equal() { return } panic(fmt.Sprintf("non-deterministic function detected: %s", function.NameOf())) } return } func ( *state) (, , reflect.Value) bool { if !.dynChecker.Next() { return .Call([]reflect.Value{, })[0].Bool() } // Swapping the input arguments is sufficient to check that // f is symmetric and deterministic. // We run in goroutines so that the race detector (if enabled) can detect // unsafe mutations to the input. := make(chan reflect.Value) go detectRaces(, , , ) := <- := .Call([]reflect.Value{, })[0].Bool() if !.IsValid() || .Bool() != { panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", function.NameOf())) } return } func ( chan<- reflect.Value, reflect.Value, ...reflect.Value) { var reflect.Value defer func() { recover() // Ignore panics, let the other call to f panic instead <- }() = .Call()[0] } func ( *state) ( reflect.Type, , reflect.Value) { var bool var , reflect.Value // Addressable versions of vx and vy var , bool := StructField{&structField{}} for := 0; < .NumField(); ++ { .typ = .Field().Type .vx = .Field() .vy = .Field() .name = .Field().Name .idx = .unexported = !isExported(.name) if .unexported { if .name == "_" { continue } // Defer checking of unexported fields until later to give an // Ignore a chance to ignore the field. if !.IsValid() || !.IsValid() { // For retrieveUnexportedField to work, the parent struct must // be addressable. Create a new copy of the values if // necessary to make them addressable. = .CanAddr() || .CanAddr() = makeAddressable() = makeAddressable() } if ! { for , := range .exporters { = || () } = true } .mayForce = .paddr = .pvx = .pvy = .field = .Field() } .compareAny() } } func ( *state) ( reflect.Type, , reflect.Value) { := .Kind() == reflect.Slice if && (.IsNil() || .IsNil()) { .report(.IsNil() && .IsNil(), 0) return } // 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. := SliceIndex{&sliceIndex{pathStep: pathStep{typ: .Elem()}, isSlice: }} := func(, int) SliceIndex { if >= 0 { .vx, .xkey = .Index(), } else { .vx, .xkey = reflect.Value{}, -1 } if >= 0 { .vy, .ykey = .Index(), } else { .vy, .ykey = reflect.Value{}, -1 } return } // Ignore options are able to ignore missing elements in a slice. // However, detecting these reliably requires an optimal differencing // algorithm, for which diff.Difference is not. // // Instead, we first iterate through both slices to detect which elements // would be ignored if standing alone. The index of non-discarded elements // are stored in a separate slice, which diffing is then performed on. var , []int var , []bool for := 0; < .Len(); ++ { := .statelessCompare((, -1)).NumDiff == 0 if ! { = append(, ) } = append(, ) } for := 0; < .Len(); ++ { := .statelessCompare((-1, )).NumDiff == 0 if ! { = append(, ) } = append(, ) } // Compute an edit-script for slices vx and vy (excluding ignored elements). := diff.Difference(len(), len(), func(, int) diff.Result { return .statelessCompare(([], [])) }) // Replay the ignore-scripts and the edit-script. var , int for < .Len() || < .Len() { var diff.EditType switch { case < len() && []: = diff.UniqueX case < len() && []: = diff.UniqueY default: , = [0], [1:] } switch { case diff.UniqueX: .compareAny((, -1)) ++ case diff.UniqueY: .compareAny((-1, )) ++ default: .compareAny((, )) ++ ++ } } } func ( *state) ( reflect.Type, , reflect.Value) { if .IsNil() || .IsNil() { .report(.IsNil() && .IsNil(), 0) return } // Cycle-detection for maps. if , := .curPtrs.Push(, ); { .report(, reportByCycle) return } defer .curPtrs.Pop(, ) // We combine and sort the two map keys so that we can perform the // comparisons in a deterministic order. := MapIndex{&mapIndex{pathStep: pathStep{typ: .Elem()}}} for , := range value.SortKeys(append(.MapKeys(), .MapKeys()...)) { .vx = .MapIndex() .vy = .MapIndex() .key = if !.vx.IsValid() && !.vy.IsValid() { // It is possible for both vx and vy to be invalid if the // key contained a NaN value in it. // // Even with the ability to retrieve NaN keys in Go 1.12, // there still isn't a sensible way to compare the values since // a NaN key may map to multiple unordered values. // The most reasonable way to compare NaNs would be to compare the // set of values. However, this is impossible to do efficiently // since set equality is provably an O(n^2) operation given only // an Equal function. If we had a Less function or Hash function, // this could be done in O(n*log(n)) or O(n), respectively. // // Rather than adding complex logic to deal with NaNs, make it // the user's responsibility to compare such obscure maps. const = "consider providing a Comparer to compare the map" panic(fmt.Sprintf("%#v has map key with NaNs\n%s", .curPath, )) } .compareAny() } } func ( *state) ( reflect.Type, , reflect.Value) { if .IsNil() || .IsNil() { .report(.IsNil() && .IsNil(), 0) return } // Cycle-detection for pointers. if , := .curPtrs.Push(, ); { .report(, reportByCycle) return } defer .curPtrs.Pop(, ) , = .Elem(), .Elem() .compareAny(Indirect{&indirect{pathStep{.Elem(), , }}}) } func ( *state) ( reflect.Type, , reflect.Value) { if .IsNil() || .IsNil() { .report(.IsNil() && .IsNil(), 0) return } , = .Elem(), .Elem() if .Type() != .Type() { .report(false, 0) return } .compareAny(TypeAssertion{&typeAssertion{pathStep{.Type(), , }}}) } func ( *state) ( bool, resultFlags) { if &reportByIgnore == 0 { if { .result.NumSame++ |= reportEqual } else { .result.NumDiff++ |= reportUnequal } } for , := range .reporters { .Report(Result{flags: }) } } // recChecker tracks the state needed to periodically perform checks that // user provided transformers are not stuck in an infinitely recursive cycle. type recChecker struct{ next int } // Check scans the Path for any recursive transformers and panics when any // recursive transformers are detected. Note that the presence of a // recursive Transformer does not necessarily imply an infinite cycle. // As such, this check only activates after some minimal number of path steps. func ( *recChecker) ( Path) { const = 1 << 16 if .next == 0 { .next = } if len() < .next { return } .next <<= 1 // Check whether the same transformer has appeared at least twice. var []string := map[Option]int{} for , := range { if , := .(Transform); { := .Option() if [] == 1 { // Transformer was used exactly once before := .(*transformer).fnc.Type() = append(, fmt.Sprintf("%v: %v => %v", , .In(0), .Out(0))) } []++ } } if len() > 0 { const = "recursive set of Transformers detected" const = "consider using cmpopts.AcyclicTransformer" := strings.Join(, "\n\t") panic(fmt.Sprintf("%s:\n\t%s\n%s", , , )) } } // dynChecker tracks the state needed to periodically perform checks that // user provided functions are symmetric and deterministic. // The zero value is safe for immediate use. type dynChecker struct{ curr, next int } // 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 ( *dynChecker) () bool { := .curr == .next if { .curr = 0 .next++ } .curr++ return } // 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 ( reflect.Value) reflect.Value { if .CanAddr() { return } := reflect.New(.Type()).Elem() .Set() return }