-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathteq.go
110 lines (99 loc) · 2.5 KB
/
teq.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package teq
import (
"reflect"
)
type Teq struct {
MaxDepth int
transforms map[reflect.Type]func(reflect.Value) reflect.Value
formats map[reflect.Type]func(reflect.Value) string
}
func New() Teq {
return Teq{
MaxDepth: 1_000,
transforms: make(map[reflect.Type]func(reflect.Value) reflect.Value),
formats: make(map[reflect.Type]func(reflect.Value) string),
}
}
func (teq Teq) Equal(t TestingT, expected, actual any) bool {
t.Helper()
defer func() {
if r := recover(); r != nil {
t.Errorf("panic in github.com/seiyab/teq. please report issue. message: %v", r)
}
}()
ok := teq.equal(expected, actual)
if !ok {
t.Errorf(teq.report(expected, actual))
}
return ok
}
func (teq Teq) NotEqual(t TestingT, expected, actual any) bool {
t.Helper()
defer func() {
if r := recover(); r != nil {
t.Errorf("panic in github.com/seiyab/teq. please report issue. message: %v", r)
}
}()
ok := !teq.equal(expected, actual)
if !ok {
if reflect.DeepEqual(expected, actual) {
t.Error("reflect.DeepEqual(expected, actual) == true.")
} else {
t.Errorf("expected %v != %v", expected, actual)
t.Log("reflect.DeepEqual(expected, actual) == false. maybe transforms made them equal.")
}
}
return ok
}
func (teq *Teq) AddTransform(transform any) {
ty := reflect.TypeOf(transform)
if ty.Kind() != reflect.Func {
panic("transform must be a function")
}
if ty.NumIn() != 1 {
panic("transform must have only one argument")
}
if ty.NumOut() != 1 {
panic("transform must have only one return value")
}
trValue := reflect.ValueOf(transform)
reflectTransform := func(v reflect.Value) reflect.Value {
return trValue.Call([]reflect.Value{v})[0]
}
teq.transforms[ty.In(0)] = reflectTransform
}
func (teq *Teq) AddFormat(format any) {
ty := reflect.TypeOf(format)
if ty.Kind() != reflect.Func {
panic("format must be a function")
}
if ty.NumIn() != 1 {
panic("format must have only one argument")
}
if ty.NumOut() != 1 {
panic("format must have only one return value")
}
if ty.Out(0).Kind() != reflect.String {
panic("format must return string")
}
formatValue := reflect.ValueOf(format)
reflectFormat := func(v reflect.Value) string {
return formatValue.Call([]reflect.Value{v})[0].String()
}
teq.formats[ty.In(0)] = reflectFormat
}
func (teq Teq) equal(x, y any) bool {
if x == nil || y == nil {
return x == y
}
v1 := reflect.ValueOf(x)
v2 := reflect.ValueOf(y)
if v1.Type() != v2.Type() {
return false
}
return teq.deepValueEqual(
v1, v2,
make(map[visit]bool),
0,
)
}