The cmp package provides types for navigating the comparison tree and implementing custom reporting of comparison results.
import (
"reflect"
"github.com/google/go-cmp/cmp"
)type Path []PathStepPath is a list of PathStep describing the sequence of operations to get from some root type to the current position in the value tree. The first Path element is always an operation-less PathStep that exists simply to identify the initial type.
Note: When traversing structs with embedded structs, the embedded struct is always accessed as a field before traversing its fields.
Methods:
func (pa Path) String() stringString returns the simplified path to a node. The simplified path only contains struct field accesses.
Example output: MyMap.MySlices.MyField
func (pa Path) GoString() stringGoString returns the path to a specific node using Go syntax.
Example output: (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
func (pa Path) Index(i int) PathStepIndex returns the ith step in the Path and supports negative indexing. A negative index starts counting from the tail (-1 is last step, -2 is second-to-last, etc.). If index is invalid, returns a non-nil PathStep that reports a nil Type.
Parameters:
i int - Index of step to retrieve (supports negative indexing)Returns:
PathStep - The path step at the specified indexfunc (pa Path) Last() PathStepLast returns the last PathStep in the Path. If the path is empty, returns a non-nil PathStep that reports a nil Type.
Returns:
PathStep - The last path steptype PathStep interface {
String() string
Type() reflect.Type
Values() (vx, vy reflect.Value)
}PathStep is a union-type for specific operations to traverse a value's tree structure. Users never need to implement these types as values are returned by this package.
Implementations:
Methods:
String() string - Returns string representation of the stepType() reflect.Type - Returns resulting type after performing the path stepValues() (vx, vy reflect.Value) - Returns resulting values after performing the path step. Type of each valid value is guaranteed identical to Type. In some cases, one or both may be invalid or have restrictions (see specific PathStep implementations).type StructField struct {
// Has unexported fields
}StructField is a PathStep that represents a struct field access.
Methods:
func (sf StructField) Name() stringName returns the field name.
func (sf StructField) Index() intIndex returns the index of the field in the parent struct type. See reflect.Type.Field.
func (sf StructField) String() stringfunc (sf StructField) Type() reflect.Typefunc (sf StructField) Values() (vx, vy reflect.Value)Values returns the field values. Both are not interface-able if the current field is unexported and the struct type is not explicitly permitted by an Exporter to traverse unexported fields.
type SliceIndex struct {
// Has unexported fields
}SliceIndex is a PathStep that represents an index operation on a slice or array.
Methods:
func (si SliceIndex) Key() intKey returns the index key. May return -1 if in a split state.
func (si SliceIndex) SplitKeys() (ix, iy int)SplitKeys returns the indexes for indexing into slices in the x and y values, respectively. These indexes may differ due to insertion or removal of an element, causing all indexes to shift. If an index is -1, the element does not exist in the associated slice.
SliceIndex.Key is guaranteed to return -1 if and only if the indexes returned by SplitKeys are not the same. SplitKeys will never return -1 for both indexes.
Returns:
ix int - Index in x sliceiy int - Index in y slicefunc (si SliceIndex) String() stringfunc (si SliceIndex) Type() reflect.Typefunc (si SliceIndex) Values() (vx, vy reflect.Value)Values returns the element values. One may be invalid if an element is missing from either the x or y slice.
type MapIndex struct {
// Has unexported fields
}MapIndex is a PathStep that represents an index operation on a map at some index Key.
Methods:
func (mi MapIndex) Key() reflect.ValueKey returns the value of the map key.
func (mi MapIndex) String() stringfunc (mi MapIndex) Type() reflect.Typefunc (mi MapIndex) Values() (vx, vy reflect.Value)Values returns the map entry values. One may be invalid if an entry is missing from either the x or y map.
type Indirect struct {
// Has unexported fields
}Indirect is a PathStep that represents pointer indirection on the parent type.
Methods:
func (in Indirect) String() stringfunc (in Indirect) Type() reflect.Typefunc (in Indirect) Values() (vx, vy reflect.Value)type TypeAssertion struct {
// Has unexported fields
}TypeAssertion is a PathStep that represents a type assertion on an interface.
Methods:
func (ta TypeAssertion) String() stringfunc (ta TypeAssertion) Type() reflect.Typefunc (ta TypeAssertion) Values() (vx, vy reflect.Value)type Transform struct {
// Has unexported fields
}Transform is a PathStep that represents a transformation from the parent type to the current type.
Methods:
func (tf Transform) Name() stringName returns the name of the Transformer.
func (tf Transform) Func() reflect.ValueFunc returns the function pointer to the transformer function.
func (tf Transform) Option() OptionOption returns the originally constructed Transformer option. The == operator can be used to detect the exact option used.
func (tf Transform) String() stringfunc (tf Transform) Type() reflect.Typefunc (tf Transform) Values() (vx, vy reflect.Value)func Reporter(r interface {
PushStep(PathStep)
Report(Result)
PopStep()
}) OptionReporter is an Option that can be passed to Equal. When Equal traverses the value trees, it calls PushStep as it descends into each node and PopStep as it ascends out. Leaf nodes are either compared (equal or not equal) or ignored, reported via the Report method.
Parameters:
r interface{} - Must implement the reporter interface with three methods:
PushStep(PathStep) - Called when a tree-traversal operation is performed. The PathStep itself is only valid until popped. The PathStep.Values are valid for entire traversal and must not be mutated. Equal always calls PushStep at start with operation-less PathStep for root values. Within a slice, exact set of inserted/removed/modified elements is unspecified. Map entries are iterated in unspecified order.Report(Result) - Called exactly once on leaf nodes to report whether comparison identified the node as equal, unequal, or ignored. A leaf node is immediately preceded and followed by PushStep/PopStep calls.PopStep() - Ascends back up the value tree. Always a matching pop for every push.Returns:
Option - Configuration optionExample:
type DiffReporter struct {
path cmp.Path
diffs []string
}
func (r *DiffReporter) PushStep(ps cmp.PathStep) {
r.path = append(r.path, ps)
}
func (r *DiffReporter) Report(rs cmp.Result) {
if !rs.Equal() {
vx, vy := r.path.Last().Values()
r.diffs = append(r.diffs, fmt.Sprintf("%s: %v != %v", r.path, vx, vy))
}
}
func (r *DiffReporter) PopStep() {
r.path = r.path[:len(r.path)-1]
}
// Usage
reporter := &DiffReporter{}
cmp.Equal(x, y, cmp.Reporter(reporter))
for _, diff := range reporter.diffs {
fmt.Println(diff)
}type Result struct {
// Has unexported fields
}Result represents the comparison result for a single node. Provided by cmp when calling Report (see Reporter).
Methods:
func (r Result) Equal() boolEqual reports whether the node was determined to be equal or not. As a special case, ignored nodes are considered equal.
func (r Result) ByIgnore() boolByIgnore reports whether the node is equal because it was ignored. Never reports true if Result.Equal reports false.
func (r Result) ByFunc() boolByFunc reports whether a Comparer function determined equality.
func (r Result) ByMethod() boolByMethod reports whether the Equal method determined equality.
func (r Result) ByCycle() boolByCycle reports whether a reference cycle was detected.