1*88d15eacSSasha Smundak// Copyright 2019, The Go Authors. All rights reserved. 2*88d15eacSSasha Smundak// Use of this source code is governed by a BSD-style 3*88d15eacSSasha Smundak// license that can be found in the LICENSE file. 4*88d15eacSSasha Smundak 5*88d15eacSSasha Smundakpackage cmp 6*88d15eacSSasha Smundak 7*88d15eacSSasha Smundakimport "reflect" 8*88d15eacSSasha Smundak 9*88d15eacSSasha Smundak// valueNode represents a single node within a report, which is a 10*88d15eacSSasha Smundak// structured representation of the value tree, containing information 11*88d15eacSSasha Smundak// regarding which nodes are equal or not. 12*88d15eacSSasha Smundaktype valueNode struct { 13*88d15eacSSasha Smundak parent *valueNode 14*88d15eacSSasha Smundak 15*88d15eacSSasha Smundak Type reflect.Type 16*88d15eacSSasha Smundak ValueX reflect.Value 17*88d15eacSSasha Smundak ValueY reflect.Value 18*88d15eacSSasha Smundak 19*88d15eacSSasha Smundak // NumSame is the number of leaf nodes that are equal. 20*88d15eacSSasha Smundak // All descendants are equal only if NumDiff is 0. 21*88d15eacSSasha Smundak NumSame int 22*88d15eacSSasha Smundak // NumDiff is the number of leaf nodes that are not equal. 23*88d15eacSSasha Smundak NumDiff int 24*88d15eacSSasha Smundak // NumIgnored is the number of leaf nodes that are ignored. 25*88d15eacSSasha Smundak NumIgnored int 26*88d15eacSSasha Smundak // NumCompared is the number of leaf nodes that were compared 27*88d15eacSSasha Smundak // using an Equal method or Comparer function. 28*88d15eacSSasha Smundak NumCompared int 29*88d15eacSSasha Smundak // NumTransformed is the number of non-leaf nodes that were transformed. 30*88d15eacSSasha Smundak NumTransformed int 31*88d15eacSSasha Smundak // NumChildren is the number of transitive descendants of this node. 32*88d15eacSSasha Smundak // This counts from zero; thus, leaf nodes have no descendants. 33*88d15eacSSasha Smundak NumChildren int 34*88d15eacSSasha Smundak // MaxDepth is the maximum depth of the tree. This counts from zero; 35*88d15eacSSasha Smundak // thus, leaf nodes have a depth of zero. 36*88d15eacSSasha Smundak MaxDepth int 37*88d15eacSSasha Smundak 38*88d15eacSSasha Smundak // Records is a list of struct fields, slice elements, or map entries. 39*88d15eacSSasha Smundak Records []reportRecord // If populated, implies Value is not populated 40*88d15eacSSasha Smundak 41*88d15eacSSasha Smundak // Value is the result of a transformation, pointer indirect, of 42*88d15eacSSasha Smundak // type assertion. 43*88d15eacSSasha Smundak Value *valueNode // If populated, implies Records is not populated 44*88d15eacSSasha Smundak 45*88d15eacSSasha Smundak // TransformerName is the name of the transformer. 46*88d15eacSSasha Smundak TransformerName string // If non-empty, implies Value is populated 47*88d15eacSSasha Smundak} 48*88d15eacSSasha Smundaktype reportRecord struct { 49*88d15eacSSasha Smundak Key reflect.Value // Invalid for slice element 50*88d15eacSSasha Smundak Value *valueNode 51*88d15eacSSasha Smundak} 52*88d15eacSSasha Smundak 53*88d15eacSSasha Smundakfunc (parent *valueNode) PushStep(ps PathStep) (child *valueNode) { 54*88d15eacSSasha Smundak vx, vy := ps.Values() 55*88d15eacSSasha Smundak child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy} 56*88d15eacSSasha Smundak switch s := ps.(type) { 57*88d15eacSSasha Smundak case StructField: 58*88d15eacSSasha Smundak assert(parent.Value == nil) 59*88d15eacSSasha Smundak parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child}) 60*88d15eacSSasha Smundak case SliceIndex: 61*88d15eacSSasha Smundak assert(parent.Value == nil) 62*88d15eacSSasha Smundak parent.Records = append(parent.Records, reportRecord{Value: child}) 63*88d15eacSSasha Smundak case MapIndex: 64*88d15eacSSasha Smundak assert(parent.Value == nil) 65*88d15eacSSasha Smundak parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child}) 66*88d15eacSSasha Smundak case Indirect: 67*88d15eacSSasha Smundak assert(parent.Value == nil && parent.Records == nil) 68*88d15eacSSasha Smundak parent.Value = child 69*88d15eacSSasha Smundak case TypeAssertion: 70*88d15eacSSasha Smundak assert(parent.Value == nil && parent.Records == nil) 71*88d15eacSSasha Smundak parent.Value = child 72*88d15eacSSasha Smundak case Transform: 73*88d15eacSSasha Smundak assert(parent.Value == nil && parent.Records == nil) 74*88d15eacSSasha Smundak parent.Value = child 75*88d15eacSSasha Smundak parent.TransformerName = s.Name() 76*88d15eacSSasha Smundak parent.NumTransformed++ 77*88d15eacSSasha Smundak default: 78*88d15eacSSasha Smundak assert(parent == nil) // Must be the root step 79*88d15eacSSasha Smundak } 80*88d15eacSSasha Smundak return child 81*88d15eacSSasha Smundak} 82*88d15eacSSasha Smundak 83*88d15eacSSasha Smundakfunc (r *valueNode) Report(rs Result) { 84*88d15eacSSasha Smundak assert(r.MaxDepth == 0) // May only be called on leaf nodes 85*88d15eacSSasha Smundak 86*88d15eacSSasha Smundak if rs.ByIgnore() { 87*88d15eacSSasha Smundak r.NumIgnored++ 88*88d15eacSSasha Smundak } else { 89*88d15eacSSasha Smundak if rs.Equal() { 90*88d15eacSSasha Smundak r.NumSame++ 91*88d15eacSSasha Smundak } else { 92*88d15eacSSasha Smundak r.NumDiff++ 93*88d15eacSSasha Smundak } 94*88d15eacSSasha Smundak } 95*88d15eacSSasha Smundak assert(r.NumSame+r.NumDiff+r.NumIgnored == 1) 96*88d15eacSSasha Smundak 97*88d15eacSSasha Smundak if rs.ByMethod() { 98*88d15eacSSasha Smundak r.NumCompared++ 99*88d15eacSSasha Smundak } 100*88d15eacSSasha Smundak if rs.ByFunc() { 101*88d15eacSSasha Smundak r.NumCompared++ 102*88d15eacSSasha Smundak } 103*88d15eacSSasha Smundak assert(r.NumCompared <= 1) 104*88d15eacSSasha Smundak} 105*88d15eacSSasha Smundak 106*88d15eacSSasha Smundakfunc (child *valueNode) PopStep() (parent *valueNode) { 107*88d15eacSSasha Smundak if child.parent == nil { 108*88d15eacSSasha Smundak return nil 109*88d15eacSSasha Smundak } 110*88d15eacSSasha Smundak parent = child.parent 111*88d15eacSSasha Smundak parent.NumSame += child.NumSame 112*88d15eacSSasha Smundak parent.NumDiff += child.NumDiff 113*88d15eacSSasha Smundak parent.NumIgnored += child.NumIgnored 114*88d15eacSSasha Smundak parent.NumCompared += child.NumCompared 115*88d15eacSSasha Smundak parent.NumTransformed += child.NumTransformed 116*88d15eacSSasha Smundak parent.NumChildren += child.NumChildren + 1 117*88d15eacSSasha Smundak if parent.MaxDepth < child.MaxDepth+1 { 118*88d15eacSSasha Smundak parent.MaxDepth = child.MaxDepth + 1 119*88d15eacSSasha Smundak } 120*88d15eacSSasha Smundak return parent 121*88d15eacSSasha Smundak} 122