diff.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package pretty
  2. import (
  3. "fmt"
  4. "io"
  5. "reflect"
  6. )
  7. type sbuf []string
  8. func (s *sbuf) Write(b []byte) (int, error) {
  9. *s = append(*s, string(b))
  10. return len(b), nil
  11. }
  12. // Diff returns a slice where each element describes
  13. // a difference between a and b.
  14. func Diff(a, b interface{}) (desc []string) {
  15. Fdiff((*sbuf)(&desc), a, b)
  16. return desc
  17. }
  18. // Fdiff writes to w a description of the differences between a and b.
  19. func Fdiff(w io.Writer, a, b interface{}) {
  20. diffWriter{w: w}.diff(reflect.ValueOf(a), reflect.ValueOf(b))
  21. }
  22. type diffWriter struct {
  23. w io.Writer
  24. l string // label
  25. }
  26. func (w diffWriter) printf(f string, a ...interface{}) {
  27. var l string
  28. if w.l != "" {
  29. l = w.l + ": "
  30. }
  31. fmt.Fprintf(w.w, l+f, a...)
  32. }
  33. func (w diffWriter) diff(av, bv reflect.Value) {
  34. if !av.IsValid() && bv.IsValid() {
  35. w.printf("nil != %#v", bv.Interface())
  36. return
  37. }
  38. if av.IsValid() && !bv.IsValid() {
  39. w.printf("%#v != nil", av.Interface())
  40. return
  41. }
  42. if !av.IsValid() && !bv.IsValid() {
  43. return
  44. }
  45. at := av.Type()
  46. bt := bv.Type()
  47. if at != bt {
  48. w.printf("%v != %v", at, bt)
  49. return
  50. }
  51. // numeric types, including bool
  52. if at.Kind() < reflect.Array {
  53. a, b := av.Interface(), bv.Interface()
  54. if a != b {
  55. w.printf("%#v != %#v", a, b)
  56. }
  57. return
  58. }
  59. switch at.Kind() {
  60. case reflect.String:
  61. a, b := av.Interface(), bv.Interface()
  62. if a != b {
  63. w.printf("%q != %q", a, b)
  64. }
  65. case reflect.Ptr:
  66. switch {
  67. case av.IsNil() && !bv.IsNil():
  68. w.printf("nil != %v", bv.Interface())
  69. case !av.IsNil() && bv.IsNil():
  70. w.printf("%v != nil", av.Interface())
  71. case !av.IsNil() && !bv.IsNil():
  72. w.diff(av.Elem(), bv.Elem())
  73. }
  74. case reflect.Struct:
  75. for i := 0; i < av.NumField(); i++ {
  76. w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
  77. }
  78. case reflect.Slice:
  79. lenA := av.Len()
  80. lenB := bv.Len()
  81. if lenA != lenB {
  82. w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB)
  83. break
  84. }
  85. for i := 0; i < lenA; i++ {
  86. w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
  87. }
  88. case reflect.Map:
  89. ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
  90. for _, k := range ak {
  91. w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
  92. w.printf("%q != (missing)", av.MapIndex(k))
  93. }
  94. for _, k := range both {
  95. w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
  96. w.diff(av.MapIndex(k), bv.MapIndex(k))
  97. }
  98. for _, k := range bk {
  99. w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
  100. w.printf("(missing) != %q", bv.MapIndex(k))
  101. }
  102. case reflect.Interface:
  103. w.diff(reflect.ValueOf(av.Interface()), reflect.ValueOf(bv.Interface()))
  104. default:
  105. if !reflect.DeepEqual(av.Interface(), bv.Interface()) {
  106. w.printf("%# v != %# v", Formatter(av.Interface()), Formatter(bv.Interface()))
  107. }
  108. }
  109. }
  110. func (d diffWriter) relabel(name string) (d1 diffWriter) {
  111. d1 = d
  112. if d.l != "" && name[0] != '[' {
  113. d1.l += "."
  114. }
  115. d1.l += name
  116. return d1
  117. }
  118. func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
  119. for _, av := range a {
  120. inBoth := false
  121. for _, bv := range b {
  122. if reflect.DeepEqual(av.Interface(), bv.Interface()) {
  123. inBoth = true
  124. both = append(both, av)
  125. break
  126. }
  127. }
  128. if !inBoth {
  129. ak = append(ak, av)
  130. }
  131. }
  132. for _, bv := range b {
  133. inBoth := false
  134. for _, av := range a {
  135. if reflect.DeepEqual(av.Interface(), bv.Interface()) {
  136. inBoth = true
  137. break
  138. }
  139. }
  140. if !inBoth {
  141. bk = append(bk, bv)
  142. }
  143. }
  144. return
  145. }