diff.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // Copyright (c) 2015 Arista Networks, Inc.
  2. // Use of this source code is governed by the Apache License 2.0
  3. // that can be found in the COPYING file.
  4. package test
  5. import (
  6. "bytes"
  7. "fmt"
  8. "reflect"
  9. "sort"
  10. "strings"
  11. "notabug.org/themusicgod1/goarista/areflect"
  12. "notabug.org/themusicgod1/goarista/key"
  13. )
  14. // diffable types have a method that returns the diff
  15. // of two objects
  16. type diffable interface {
  17. // Diff returns a human readable string of the diff of the two objects
  18. // an empty string means that the two objects are equal
  19. Diff(other interface{}) string
  20. }
  21. // Diff returns the difference of two objects in a human readable format.
  22. // An empty string is returned when there is no difference.
  23. // To avoid confusing diffs, make sure you pass the expected value first.
  24. func Diff(expected, actual interface{}) string {
  25. if DeepEqual(expected, actual) {
  26. return ""
  27. }
  28. return diffImpl(expected, actual, nil)
  29. }
  30. func diffImpl(a, b interface{}, seen map[edge]struct{}) string {
  31. av := reflect.ValueOf(a)
  32. bv := reflect.ValueOf(b)
  33. // Check if nil
  34. if !av.IsValid() {
  35. if !bv.IsValid() {
  36. return "" // Both are "nil" with no type
  37. }
  38. return fmt.Sprintf("expected nil but got a %T: %#v", b, b)
  39. } else if !bv.IsValid() {
  40. return fmt.Sprintf("expected a %T (%#v) but got nil", a, a)
  41. }
  42. if av.Type() != bv.Type() {
  43. return fmt.Sprintf("expected a %T but got a %T", a, b)
  44. }
  45. switch a := a.(type) {
  46. case string, bool,
  47. int8, int16, int32, int64,
  48. uint8, uint16, uint32, uint64,
  49. float32, float64,
  50. complex64, complex128,
  51. int, uint, uintptr:
  52. if a != b {
  53. typ := reflect.TypeOf(a).Name()
  54. return fmt.Sprintf("%s(%v) != %s(%v)", typ, a, typ, b)
  55. }
  56. return ""
  57. case []byte:
  58. if !bytes.Equal(a, b.([]byte)) {
  59. return fmt.Sprintf("[]byte(%q) != []byte(%q)", a, b)
  60. }
  61. }
  62. if ac, ok := a.(diffable); ok {
  63. return ac.Diff(b.(diffable))
  64. }
  65. if ac, ok := a.(key.Comparable); ok {
  66. if ac.Equal(b.(key.Comparable)) {
  67. return ""
  68. }
  69. return fmt.Sprintf("Comparable types are different: %s vs %s",
  70. PrettyPrint(a), PrettyPrint(b))
  71. }
  72. switch av.Kind() {
  73. case reflect.Array, reflect.Slice:
  74. l := av.Len()
  75. if l != bv.Len() {
  76. return fmt.Sprintf("Expected an array of size %d but got %d",
  77. l, bv.Len())
  78. }
  79. for i := 0; i < l; i++ {
  80. diff := diffImpl(av.Index(i).Interface(), bv.Index(i).Interface(),
  81. seen)
  82. if len(diff) > 0 {
  83. return fmt.Sprintf("In arrays, values are different at index %d: %s", i, diff)
  84. }
  85. }
  86. case reflect.Map:
  87. if c, d := isNilCheck(av, bv); c {
  88. return d
  89. }
  90. if av.Len() != bv.Len() {
  91. return fmt.Sprintf("Maps have different size: %d != %d (%s)",
  92. av.Len(), bv.Len(), diffMapKeys(av, bv))
  93. }
  94. for _, ka := range av.MapKeys() {
  95. ae := av.MapIndex(ka)
  96. if k := ka.Kind(); k == reflect.Ptr || k == reflect.Interface {
  97. return diffComplexKeyMap(av, bv, seen)
  98. }
  99. be := bv.MapIndex(ka)
  100. if !be.IsValid() {
  101. return fmt.Sprintf(
  102. "key %s in map is missing in the actual map",
  103. prettyPrint(ka, ptrSet{}, prettyPrintDepth))
  104. }
  105. if !ae.CanInterface() {
  106. return fmt.Sprintf(
  107. "for key %s in map, value can't become an interface: %s",
  108. prettyPrint(ka, ptrSet{}, prettyPrintDepth),
  109. prettyPrint(ae, ptrSet{}, prettyPrintDepth))
  110. }
  111. if !be.CanInterface() {
  112. return fmt.Sprintf(
  113. "for key %s in map, value can't become an interface: %s",
  114. prettyPrint(ka, ptrSet{}, prettyPrintDepth),
  115. prettyPrint(be, ptrSet{}, prettyPrintDepth))
  116. }
  117. if diff := diffImpl(ae.Interface(), be.Interface(), seen); len(diff) > 0 {
  118. return fmt.Sprintf(
  119. "for key %s in map, values are different: %s",
  120. prettyPrint(ka, ptrSet{}, prettyPrintDepth), diff)
  121. }
  122. }
  123. case reflect.Ptr, reflect.Interface:
  124. if c, d := isNilCheck(av, bv); c {
  125. return d
  126. }
  127. av = av.Elem()
  128. bv = bv.Elem()
  129. if av.CanAddr() && bv.CanAddr() {
  130. e := edge{from: av.UnsafeAddr(), to: bv.UnsafeAddr()}
  131. // Detect and prevent cycles.
  132. if seen == nil {
  133. seen = make(map[edge]struct{})
  134. } else if _, ok := seen[e]; ok {
  135. return ""
  136. }
  137. seen[e] = struct{}{}
  138. }
  139. return diffImpl(av.Interface(), bv.Interface(), seen)
  140. case reflect.Struct:
  141. typ := av.Type()
  142. for i, n := 0, av.NumField(); i < n; i++ {
  143. if typ.Field(i).Tag.Get("deepequal") == "ignore" {
  144. continue
  145. }
  146. af := areflect.ForceExport(av.Field(i))
  147. bf := areflect.ForceExport(bv.Field(i))
  148. if diff := diffImpl(af.Interface(), bf.Interface(), seen); len(diff) > 0 {
  149. return fmt.Sprintf("attributes %q are different: %s",
  150. av.Type().Field(i).Name, diff)
  151. }
  152. }
  153. // The following cases are here to handle named types (aka type aliases).
  154. case reflect.String:
  155. if as, bs := av.String(), bv.String(); as != bs {
  156. return fmt.Sprintf("%s(%q) != %s(%q)", av.Type().Name(), as, bv.Type().Name(), bs)
  157. }
  158. case reflect.Bool:
  159. if ab, bb := av.Bool(), bv.Bool(); ab != bb {
  160. return fmt.Sprintf("%s(%t) != %s(%t)", av.Type().Name(), ab, bv.Type().Name(), bb)
  161. }
  162. case reflect.Uint, reflect.Uintptr,
  163. reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  164. if ai, bi := av.Uint(), bv.Uint(); ai != bi {
  165. return fmt.Sprintf("%s(%d) != %s(%d)", av.Type().Name(), ai, bv.Type().Name(), bi)
  166. }
  167. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  168. if ai, bi := av.Int(), bv.Int(); ai != bi {
  169. return fmt.Sprintf("%s(%d) != %s(%d)", av.Type().Name(), ai, bv.Type().Name(), bi)
  170. }
  171. case reflect.Float32, reflect.Float64:
  172. if af, bf := av.Float(), bv.Float(); af != bf {
  173. return fmt.Sprintf("%s(%f) != %s(%f)", av.Type().Name(), af, bv.Type().Name(), bf)
  174. }
  175. case reflect.Complex64, reflect.Complex128:
  176. if ac, bc := av.Complex(), bv.Complex(); ac != bc {
  177. return fmt.Sprintf("%s(%f) != %s(%f)", av.Type().Name(), ac, bv.Type().Name(), bc)
  178. }
  179. default:
  180. return fmt.Sprintf("Unknown or unsupported type: %T: %#v", a, a)
  181. }
  182. return ""
  183. }
  184. func diffComplexKeyMap(av, bv reflect.Value, seen map[edge]struct{}) string {
  185. ok, ka, be := complexKeyMapEqual(av, bv, seen)
  186. if ok {
  187. return ""
  188. } else if be.IsValid() {
  189. return fmt.Sprintf("for complex key %s in map, values are different: %s",
  190. prettyPrint(ka, ptrSet{}, prettyPrintDepth),
  191. diffImpl(av.MapIndex(ka).Interface(), be.Interface(), seen))
  192. }
  193. return fmt.Sprintf("complex key %s in map is missing in the actual map",
  194. prettyPrint(ka, ptrSet{}, prettyPrintDepth))
  195. }
  196. func diffMapKeys(av, bv reflect.Value) string {
  197. var diffs []string
  198. // TODO: We produce extraneous diffs for composite keys.
  199. for _, ka := range av.MapKeys() {
  200. be := bv.MapIndex(ka)
  201. if !be.IsValid() {
  202. diffs = append(diffs, fmt.Sprintf("missing key: %s",
  203. PrettyPrint(ka.Interface())))
  204. }
  205. }
  206. for _, kb := range bv.MapKeys() {
  207. ae := av.MapIndex(kb)
  208. if !ae.IsValid() {
  209. diffs = append(diffs, fmt.Sprintf("extra key: %s",
  210. PrettyPrint(kb.Interface())))
  211. }
  212. }
  213. sort.Strings(diffs)
  214. return strings.Join(diffs, ", ")
  215. }
  216. func isNilCheck(a, b reflect.Value) (bool /*checked*/, string) {
  217. if a.IsNil() {
  218. if b.IsNil() {
  219. return true, ""
  220. }
  221. return true, fmt.Sprintf("expected nil but got %s",
  222. prettyPrint(b, ptrSet{}, prettyPrintDepth))
  223. } else if b.IsNil() {
  224. return true, fmt.Sprintf("got nil instead of %s",
  225. prettyPrint(a, ptrSet{}, prettyPrintDepth))
  226. }
  227. return false, ""
  228. }
  229. type mapEntry struct {
  230. k, v string
  231. }
  232. type mapEntries struct {
  233. entries []*mapEntry
  234. }
  235. func (t *mapEntries) Len() int {
  236. return len(t.entries)
  237. }
  238. func (t *mapEntries) Less(i, j int) bool {
  239. if t.entries[i].k > t.entries[j].k {
  240. return false
  241. } else if t.entries[i].k < t.entries[j].k {
  242. return true
  243. }
  244. return t.entries[i].v <= t.entries[j].v
  245. }
  246. func (t *mapEntries) Swap(i, j int) {
  247. t.entries[i], t.entries[j] = t.entries[j], t.entries[i]
  248. }