-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathequal.go
147 lines (124 loc) · 3.43 KB
/
equal.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package main
import (
"bytes"
"encoding/json"
"fmt"
"math"
"strconv"
"github.com/buger/jsonparser"
)
func equalResponseBodies(bodyResponse, bodyBullet []byte) bool {
return jsEqualObjects(bodyResponse, bodyBullet)
}
func jsEqual(dataType jsonparser.ValueType, smthResponse, smthBullet []byte) bool {
switch dataType {
case jsonparser.Number:
return jsEqualNumbers(smthResponse, smthBullet)
case jsonparser.String:
return jsEqualStrings(smthResponse, smthBullet)
case jsonparser.Array:
return jsEqualArrays(smthResponse, smthBullet)
case jsonparser.Object:
return jsEqualObjects(smthResponse, smthBullet)
case jsonparser.Null:
if !argv.allowNulls {
return false
}
return bytes.Equal(smthResponse, bytesNull) && bytes.Equal(smthResponse, smthBullet)
default:
// не поддерживаемый тип
return false
}
}
func jsEqualObjects(objResponse, objBullet []byte) bool {
return nil == jsonparser.ObjectEach(
objBullet,
func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
valueResponse, dataTypeResponse, _, err := jsonparser.Get(objResponse, string(key))
if err != nil {
return err
} else if dataType != dataTypeResponse {
return ErrResponseDiff
} else if !jsEqual(dataType, valueResponse, value) {
return ErrResponseDiff
}
return nil
},
)
}
func jsEqualNumbers(numberResponse, numberBullet []byte) bool {
if numBullet, err := strconv.ParseFloat(string(numberBullet), 64); err != nil {
return false
} else if numResponse, err := strconv.ParseFloat(string(numberResponse), 64); err != nil {
return false
} else {
return math.Abs(numBullet-numResponse) < 1e-5
}
}
func jsEqualStrings(stringResponse, stringBullet []byte) bool {
return bytes.Equal(stringBullet, stringResponse) || bytes.Equal(utf8Unescaped(stringBullet), utf8Unescaped(stringResponse))
}
func jsEqualArrays(arrayResponse, arrayBullet []byte) bool {
var err error
type arrayItem struct {
dataType jsonparser.ValueType
value []byte
}
var itemsResponse, itemsBullet []arrayItem
_, err = jsonparser.ArrayEach(
arrayBullet,
func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
if err != nil {
return
}
itemsResponse = append(itemsResponse, arrayItem{dataType: dataType, value: value})
},
)
if err != nil {
return false
}
_, err = jsonparser.ArrayEach(
arrayResponse,
func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
if err != nil {
return
}
itemsBullet = append(itemsBullet, arrayItem{dataType: dataType, value: value})
},
)
if err != nil {
return false
}
if len(itemsResponse) != len(itemsBullet) {
return false
}
for i, itemBullet := range itemsBullet {
if itemBullet.dataType != itemsResponse[i].dataType {
return false
} else if !jsEqual(itemBullet.dataType, itemsResponse[i].value, itemBullet.value) {
return false
}
}
return true
}
// хак для перевода экранированных строк вида "\u1234\u5678" в нормальный юникод
func utf8Unescaped(b []byte) []byte {
var buf bytes.Buffer
buf.WriteByte('"')
buf.Write(b)
buf.WriteByte('"')
var s string
json.Unmarshal(buf.Bytes(), &s)
return []byte(s)
}
func utf8MixedUnescaped(b []byte) []byte {
if len(b) == 0 {
return bytesEmpty
}
unescaped, err := jsonparser.Unescape(b, nil)
if err != nil {
fmt.Printf("Failed to unescape: %v", err)
return b
}
return unescaped
}