podman

Форк
0
295 строк · 7.2 Кб
1
package pretty
2

3
import (
4
	"fmt"
5
	"io"
6
	"reflect"
7
)
8

9
type sbuf []string
10

11
func (p *sbuf) Printf(format string, a ...interface{}) {
12
	s := fmt.Sprintf(format, a...)
13
	*p = append(*p, s)
14
}
15

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)
20
	return desc
21
}
22

23
// wprintfer calls Fprintf on w for each Printf call
24
// with a trailing newline.
25
type wprintfer struct{ w io.Writer }
26

27
func (p *wprintfer) Printf(format string, a ...interface{}) {
28
	fmt.Fprintf(p.w, format+"\n", a...)
29
}
30

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)
34
}
35

36
type Printfer interface {
37
	Printf(format string, a ...interface{})
38
}
39

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{}) {
44
	d := diffPrinter{
45
		w:        p,
46
		aVisited: make(map[visit]visit),
47
		bVisited: make(map[visit]visit),
48
	}
49
	d.diff(reflect.ValueOf(a), reflect.ValueOf(b))
50
}
51

52
type Logfer interface {
53
	Logf(format string, a ...interface{})
54
}
55

56
// logprintfer calls Fprintf on w for each Printf call
57
// with a trailing newline.
58
type logprintfer struct{ l Logfer }
59

60
func (p *logprintfer) Printf(format string, a ...interface{}) {
61
	p.l.Logf(format, a...)
62
}
63

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)
69
}
70

71
type diffPrinter struct {
72
	w Printfer
73
	l string // label
74

75
	aVisited map[visit]visit
76
	bVisited map[visit]visit
77
}
78

79
func (w diffPrinter) printf(f string, a ...interface{}) {
80
	var l string
81
	if w.l != "" {
82
		l = w.l + ": "
83
	}
84
	w.w.Printf(l+f, a...)
85
}
86

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})
90
		return
91
	}
92
	if av.IsValid() && !bv.IsValid() {
93
		w.printf("%# v != nil", formatter{v: av, quote: true})
94
		return
95
	}
96
	if !av.IsValid() && !bv.IsValid() {
97
		return
98
	}
99

100
	at := av.Type()
101
	bt := bv.Type()
102
	if at != bt {
103
		w.printf("%v != %v", at, bt)
104
		return
105
	}
106

107
	if av.CanAddr() && bv.CanAddr() {
108
		avis := visit{av.UnsafeAddr(), at}
109
		bvis := visit{bv.UnsafeAddr(), bt}
110
		var cycle bool
111

112
		// Have we seen this value before?
113
		if vis, ok := w.aVisited[avis]; ok {
114
			cycle = true
115
			if vis != bvis {
116
				w.printf("%# v (previously visited) != %# v", formatter{v: av, quote: true}, formatter{v: bv, quote: true})
117
			}
118
		} else if _, ok := w.bVisited[bvis]; ok {
119
			cycle = true
120
			w.printf("%# v != %# v (previously visited)", formatter{v: av, quote: true}, formatter{v: bv, quote: true})
121
		}
122
		w.aVisited[avis] = bvis
123
		w.bVisited[bvis] = avis
124
		if cycle {
125
			return
126
		}
127
	}
128

129
	switch kind := at.Kind(); kind {
130
	case reflect.Bool:
131
		if a, b := av.Bool(), bv.Bool(); a != b {
132
			w.printf("%v != %v", a, b)
133
		}
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)
137
		}
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)
141
		}
142
	case reflect.Float32, reflect.Float64:
143
		if a, b := av.Float(), bv.Float(); a != b {
144
			w.printf("%v != %v", a, b)
145
		}
146
	case reflect.Complex64, reflect.Complex128:
147
		if a, b := av.Complex(), bv.Complex(); a != b {
148
			w.printf("%v != %v", a, b)
149
		}
150
	case reflect.Array:
151
		n := av.Len()
152
		for i := 0; i < n; i++ {
153
			w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
154
		}
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)
158
		}
159
	case reflect.Interface:
160
		w.diff(av.Elem(), bv.Elem())
161
	case reflect.Map:
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))
166
		}
167
		for _, k := range both {
168
			w := w.relabel(fmt.Sprintf("[%#v]", k))
169
			w.diff(av.MapIndex(k), bv.MapIndex(k))
170
		}
171
		for _, k := range bk {
172
			w := w.relabel(fmt.Sprintf("[%#v]", k))
173
			w.printf("(missing) != %q", bv.MapIndex(k))
174
		}
175
	case reflect.Ptr:
176
		switch {
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())
183
		}
184
	case reflect.Slice:
185
		lenA := av.Len()
186
		lenB := bv.Len()
187
		if lenA != lenB {
188
			w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB)
189
			break
190
		}
191
		for i := 0; i < lenA; i++ {
192
			w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
193
		}
194
	case reflect.String:
195
		if a, b := av.String(), bv.String(); a != b {
196
			w.printf("%q != %q", a, b)
197
		}
198
	case reflect.Struct:
199
		for i := 0; i < av.NumField(); i++ {
200
			w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
201
		}
202
	default:
203
		panic("unknown reflect Kind: " + kind.String())
204
	}
205
}
206

207
func (d diffPrinter) relabel(name string) (d1 diffPrinter) {
208
	d1 = d
209
	if d.l != "" && name[0] != '[' {
210
		d1.l += "."
211
	}
212
	d1.l += name
213
	return d1
214
}
215

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() {
220
		return true
221
	}
222
	if !av.IsValid() || !bv.IsValid() || av.Type() != bv.Type() {
223
		return false
224
	}
225
	switch kind := av.Kind(); kind {
226
	case reflect.Bool:
227
		a, b := av.Bool(), bv.Bool()
228
		return a == b
229
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
230
		a, b := av.Int(), bv.Int()
231
		return a == b
232
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
233
		a, b := av.Uint(), bv.Uint()
234
		return a == b
235
	case reflect.Float32, reflect.Float64:
236
		a, b := av.Float(), bv.Float()
237
		return a == b
238
	case reflect.Complex64, reflect.Complex128:
239
		a, b := av.Complex(), bv.Complex()
240
		return a == b
241
	case reflect.Array:
242
		for i := 0; i < av.Len(); i++ {
243
			if !keyEqual(av.Index(i), bv.Index(i)) {
244
				return false
245
			}
246
		}
247
		return true
248
	case reflect.Chan, reflect.UnsafePointer, reflect.Ptr:
249
		a, b := av.Pointer(), bv.Pointer()
250
		return a == b
251
	case reflect.Interface:
252
		return keyEqual(av.Elem(), bv.Elem())
253
	case reflect.String:
254
		a, b := av.String(), bv.String()
255
		return a == b
256
	case reflect.Struct:
257
		for i := 0; i < av.NumField(); i++ {
258
			if !keyEqual(av.Field(i), bv.Field(i)) {
259
				return false
260
			}
261
		}
262
		return true
263
	default:
264
		panic("invalid map key type " + av.Type().String())
265
	}
266
}
267

268
func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
269
	for _, av := range a {
270
		inBoth := false
271
		for _, bv := range b {
272
			if keyEqual(av, bv) {
273
				inBoth = true
274
				both = append(both, av)
275
				break
276
			}
277
		}
278
		if !inBoth {
279
			ak = append(ak, av)
280
		}
281
	}
282
	for _, bv := range b {
283
		inBoth := false
284
		for _, av := range a {
285
			if keyEqual(av, bv) {
286
				inBoth = true
287
				break
288
			}
289
		}
290
		if !inBoth {
291
			bk = append(bk, bv)
292
		}
293
	}
294
	return
295
}
296

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.