11
func (p *sbuf) Printf(format string, a ...interface{}) {
12
s := fmt.Sprintf(format, a...)
16
// Diff returns a slice where each element describes
17
// a difference between a and b.
18
func Diff(a, b interface{}) (desc []string) {
19
Pdiff((*sbuf)(&desc), a, b)
23
// wprintfer calls Fprintf on w for each Printf call
24
// with a trailing newline.
25
type wprintfer struct{ w io.Writer }
27
func (p *wprintfer) Printf(format string, a ...interface{}) {
28
fmt.Fprintf(p.w, format+"\n", a...)
31
// Fdiff writes to w a description of the differences between a and b.
32
func Fdiff(w io.Writer, a, b interface{}) {
33
Pdiff(&wprintfer{w}, a, b)
36
type Printfer interface {
37
Printf(format string, a ...interface{})
40
// Pdiff prints to p a description of the differences between a and b.
41
// It calls Printf once for each difference, with no trailing newline.
42
// The standard library log.Logger is a Printfer.
43
func Pdiff(p Printfer, a, b interface{}) {
46
aVisited: make(map[visit]visit),
47
bVisited: make(map[visit]visit),
49
d.diff(reflect.ValueOf(a), reflect.ValueOf(b))
52
type Logfer interface {
53
Logf(format string, a ...interface{})
56
// logprintfer calls Fprintf on w for each Printf call
57
// with a trailing newline.
58
type logprintfer struct{ l Logfer }
60
func (p *logprintfer) Printf(format string, a ...interface{}) {
61
p.l.Logf(format, a...)
64
// Ldiff prints to l a description of the differences between a and b.
65
// It calls Logf once for each difference, with no trailing newline.
66
// The standard library testing.T and testing.B are Logfers.
67
func Ldiff(l Logfer, a, b interface{}) {
68
Pdiff(&logprintfer{l}, a, b)
71
type diffPrinter struct {
75
aVisited map[visit]visit
76
bVisited map[visit]visit
79
func (w diffPrinter) printf(f string, a ...interface{}) {
87
func (w diffPrinter) diff(av, bv reflect.Value) {
88
if !av.IsValid() && bv.IsValid() {
89
w.printf("nil != %# v", formatter{v: bv, quote: true})
92
if av.IsValid() && !bv.IsValid() {
93
w.printf("%# v != nil", formatter{v: av, quote: true})
96
if !av.IsValid() && !bv.IsValid() {
103
w.printf("%v != %v", at, bt)
107
if av.CanAddr() && bv.CanAddr() {
108
avis := visit{av.UnsafeAddr(), at}
109
bvis := visit{bv.UnsafeAddr(), bt}
112
// Have we seen this value before?
113
if vis, ok := w.aVisited[avis]; ok {
116
w.printf("%# v (previously visited) != %# v", formatter{v: av, quote: true}, formatter{v: bv, quote: true})
118
} else if _, ok := w.bVisited[bvis]; ok {
120
w.printf("%# v != %# v (previously visited)", formatter{v: av, quote: true}, formatter{v: bv, quote: true})
122
w.aVisited[avis] = bvis
123
w.bVisited[bvis] = avis
129
switch kind := at.Kind(); kind {
131
if a, b := av.Bool(), bv.Bool(); a != b {
132
w.printf("%v != %v", a, b)
134
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
135
if a, b := av.Int(), bv.Int(); a != b {
136
w.printf("%d != %d", a, b)
138
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
139
if a, b := av.Uint(), bv.Uint(); a != b {
140
w.printf("%d != %d", a, b)
142
case reflect.Float32, reflect.Float64:
143
if a, b := av.Float(), bv.Float(); a != b {
144
w.printf("%v != %v", a, b)
146
case reflect.Complex64, reflect.Complex128:
147
if a, b := av.Complex(), bv.Complex(); a != b {
148
w.printf("%v != %v", a, b)
152
for i := 0; i < n; i++ {
153
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
155
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
156
if a, b := av.Pointer(), bv.Pointer(); a != b {
157
w.printf("%#x != %#x", a, b)
159
case reflect.Interface:
160
w.diff(av.Elem(), bv.Elem())
162
ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
163
for _, k := range ak {
164
w := w.relabel(fmt.Sprintf("[%#v]", k))
165
w.printf("%q != (missing)", av.MapIndex(k))
167
for _, k := range both {
168
w := w.relabel(fmt.Sprintf("[%#v]", k))
169
w.diff(av.MapIndex(k), bv.MapIndex(k))
171
for _, k := range bk {
172
w := w.relabel(fmt.Sprintf("[%#v]", k))
173
w.printf("(missing) != %q", bv.MapIndex(k))
177
case av.IsNil() && !bv.IsNil():
178
w.printf("nil != %# v", formatter{v: bv, quote: true})
179
case !av.IsNil() && bv.IsNil():
180
w.printf("%# v != nil", formatter{v: av, quote: true})
181
case !av.IsNil() && !bv.IsNil():
182
w.diff(av.Elem(), bv.Elem())
188
w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB)
191
for i := 0; i < lenA; i++ {
192
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
195
if a, b := av.String(), bv.String(); a != b {
196
w.printf("%q != %q", a, b)
199
for i := 0; i < av.NumField(); i++ {
200
w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
203
panic("unknown reflect Kind: " + kind.String())
207
func (d diffPrinter) relabel(name string) (d1 diffPrinter) {
209
if d.l != "" && name[0] != '[' {
216
// keyEqual compares a and b for equality.
217
// Both a and b must be valid map keys.
218
func keyEqual(av, bv reflect.Value) bool {
219
if !av.IsValid() && !bv.IsValid() {
222
if !av.IsValid() || !bv.IsValid() || av.Type() != bv.Type() {
225
switch kind := av.Kind(); kind {
227
a, b := av.Bool(), bv.Bool()
229
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
230
a, b := av.Int(), bv.Int()
232
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
233
a, b := av.Uint(), bv.Uint()
235
case reflect.Float32, reflect.Float64:
236
a, b := av.Float(), bv.Float()
238
case reflect.Complex64, reflect.Complex128:
239
a, b := av.Complex(), bv.Complex()
242
for i := 0; i < av.Len(); i++ {
243
if !keyEqual(av.Index(i), bv.Index(i)) {
248
case reflect.Chan, reflect.UnsafePointer, reflect.Ptr:
249
a, b := av.Pointer(), bv.Pointer()
251
case reflect.Interface:
252
return keyEqual(av.Elem(), bv.Elem())
254
a, b := av.String(), bv.String()
257
for i := 0; i < av.NumField(); i++ {
258
if !keyEqual(av.Field(i), bv.Field(i)) {
264
panic("invalid map key type " + av.Type().String())
268
func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
269
for _, av := range a {
271
for _, bv := range b {
272
if keyEqual(av, bv) {
274
both = append(both, av)
282
for _, bv := range b {
284
for _, av := range a {
285
if keyEqual(av, bv) {