report_value.go 3.5 KB

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