OSDN Git Service

fix log
[bytom/vapor.git] / testutil / deepequal.go
1 package testutil
2
3 import (
4         "reflect"
5         "unsafe"
6 )
7
8 type visit struct {
9         a1, a2 unsafe.Pointer
10         typ    reflect.Type
11 }
12
13 // DeepEqual is similar to reflect.DeepEqual, but treats nil as equal
14 // to empty maps and slices. Some of the implementation is cribbed
15 // from Go's reflect package.
16 func DeepEqual(x, y interface{}) bool {
17         vx := reflect.ValueOf(x)
18         vy := reflect.ValueOf(y)
19         return deepValueEqual(vx, vy, make(map[visit]bool))
20 }
21
22 func deepValueEqual(x, y reflect.Value, visited map[visit]bool) bool {
23         if isEmpty(x) && isEmpty(y) {
24                 return true
25         }
26         if !x.IsValid() {
27                 return !y.IsValid()
28         }
29         if !y.IsValid() {
30                 return false
31         }
32
33         tx := x.Type()
34         ty := y.Type()
35         if tx != ty {
36                 return false
37         }
38
39         switch tx.Kind() {
40         case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
41                 if x.CanAddr() && y.CanAddr() {
42                         a1 := unsafe.Pointer(x.UnsafeAddr())
43                         a2 := unsafe.Pointer(y.UnsafeAddr())
44                         if uintptr(a1) > uintptr(a2) {
45                                 // Canonicalize order to reduce number of entries in visited.
46                                 // Assumes non-moving garbage collector.
47                                 a1, a2 = a2, a1
48                         }
49                         v := visit{a1, a2, tx}
50                         if visited[v] {
51                                 return true
52                         }
53                         visited[v] = true
54                 }
55         }
56
57         switch tx.Kind() {
58         case reflect.Bool:
59                 return x.Bool() == y.Bool()
60
61         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
62                 return x.Int() == y.Int()
63
64         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
65                 return x.Uint() == y.Uint()
66
67         case reflect.Float32, reflect.Float64:
68                 return x.Float() == y.Float()
69
70         case reflect.Complex64, reflect.Complex128:
71                 return x.Complex() == y.Complex()
72
73         case reflect.String:
74                 return x.String() == y.String()
75
76         case reflect.Array:
77                 for i := 0; i < tx.Len(); i++ {
78                         if !deepValueEqual(x.Index(i), y.Index(i), visited) {
79                                 return false
80                         }
81                 }
82                 return true
83
84         case reflect.Slice:
85                 ttx := tx.Elem()
86                 tty := ty.Elem()
87                 if ttx != tty {
88                         return false
89                 }
90                 if x.Len() != y.Len() {
91                         return false
92                 }
93                 for i := 0; i < x.Len(); i++ {
94                         if !deepValueEqual(x.Index(i), y.Index(i), visited) {
95                                 return false
96                         }
97                 }
98                 return true
99
100         case reflect.Interface:
101                 if x.IsNil() {
102                         return y.IsNil()
103                 }
104                 if y.IsNil() {
105                         return false
106                 }
107                 return deepValueEqual(x.Elem(), y.Elem(), visited)
108
109         case reflect.Ptr:
110                 if x.Pointer() == y.Pointer() {
111                         return true
112                 }
113                 return deepValueEqual(x.Elem(), y.Elem(), visited)
114
115         case reflect.Struct:
116                 for i := 0; i < tx.NumField(); i++ {
117                         if !deepValueEqual(x.Field(i), y.Field(i), visited) {
118                                 return false
119                         }
120                 }
121                 return true
122
123         case reflect.Map:
124                 if x.Pointer() == y.Pointer() {
125                         return true
126                 }
127                 if x.Len() != y.Len() {
128                         return false
129                 }
130                 for _, k := range x.MapKeys() {
131                         if !deepValueEqual(x.MapIndex(k), y.MapIndex(k), visited) {
132                                 return false
133                         }
134                 }
135                 return true
136
137         case reflect.Func:
138                 return x.IsNil() && y.IsNil()
139         }
140         return false
141 }
142
143 func isEmpty(v reflect.Value) bool {
144         if !v.IsValid() {
145                 return true
146         }
147         switch v.Type().Kind() {
148         case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr:
149                 return v.IsNil()
150
151         case reflect.Slice, reflect.Map:
152                 return v.IsNil() || v.Len() == 0
153         }
154         return false
155 }