Skip to content

Commit 4b25963

Browse files
committed
fix <3
1 parent 397987c commit 4b25963

File tree

2 files changed

+39
-120
lines changed

2 files changed

+39
-120
lines changed

internal/acctest/compare.go

Lines changed: 27 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11
package acctest
22

33
import (
4-
"errors"
5-
"fmt"
64
"net/url"
75
"reflect"
86
"sort"
97
"strings"
108
)
119

12-
var (
13-
ErrKeyIndex = errors.New("key index not found")
14-
ErrValueIndex = errors.New("value index not found")
15-
ErrNotComparable = errors.New("not comparable")
16-
supportedMapKeys = []string{"key", "name"}
17-
supportedMapValues = []string{"value", "values"}
18-
)
19-
2010
// compareJSONFields is the entry point for comparing two interface values
2111
// handle string with special cases, map[string]interface{} and []interface{} or any other primitive type
2212
func compareJSONFields(requestValue, cassetteValue interface{}) bool {
@@ -201,115 +191,44 @@ func compareSlices(request, cassette []interface{}) bool {
201191

202192
return true
203193
case map[string]interface{}:
204-
// potential corner cases:
205-
// - the maps have the same structure to identify key value pairs: we normalize and compare them
206-
// - the maps have different structure: we recurse on compareJSONFields to individually compare them
207-
requestMap, cassetteMap, err := normalizeMaps(request, cassette)
208-
if err != nil {
209-
for i, v := range request {
210-
// remove keys that are not relevant for comparison
211-
// like project_id, organization_id, etc.
212-
for _, key := range BodyMatcherIgnore {
213-
removeKeyRecursive(cassette[i].(map[string]interface{}), key)
214-
removeKeyRecursive(v.(map[string]interface{}), key)
215-
}
216-
217-
if !compareJSONFields(v, cassette[i]) {
218-
return false
219-
}
220-
}
194+
// compare list of maps[string]interface{} without order and without ignored keys
195+
matched := 0
221196

222-
return true
223-
}
224-
225-
for k := range requestMap {
226-
if _, ok := cassetteMap[k]; !ok {
227-
return false
228-
}
197+
reqVisited := make([]bool, len(request))
198+
casVisited := make([]bool, len(cassette))
229199

230-
if !compareJSONFields(requestMap[k], cassetteMap[k]) {
231-
return false
232-
}
233-
}
234-
235-
return true
236-
default:
237-
return reflect.DeepEqual(request, cassette)
238-
}
239-
}
240-
241-
// normalizeMaps normalize 2 lists of simple maps
242-
// from [{ "name": "foo", "value": "bar" }, { "name": "baz", "value": "qux" }] to { "foo": "bar", "baz": "qux" }
243-
// returns KeyIndex and ValueIndex errors if the supported key or value are not found
244-
func normalizeMaps(request, cassette []interface{}) (requestMap, cassetteMap map[string]interface{}, err error) {
245-
requestMap = make(map[string]interface{})
246-
cassetteMap = make(map[string]interface{})
247-
248-
for _, v := range request {
249-
rmap, ok := v.(map[string]interface{})
250-
if !ok {
251-
return nil, nil, ErrNotComparable
252-
}
253-
254-
var keyIndex, key string
255-
for _, key = range supportedMapKeys {
256-
if keyIndex, ok = rmap[key].(string); ok {
257-
break
200+
for i := range request {
201+
if reqVisited[i] {
202+
continue
258203
}
259-
}
260204

261-
if !ok {
262-
return nil, nil, fmt.Errorf("%w: %s", ErrKeyIndex, key)
263-
}
264-
265-
var value interface{}
266-
267-
var valueKey string
268-
for _, valueKey = range supportedMapValues {
269-
if value, ok = rmap[valueKey]; ok {
270-
break
205+
// cleanup ignored keys
206+
for _, key := range BodyMatcherIgnore {
207+
removeKeyRecursive(request[i].(map[string]interface{}), key)
271208
}
272-
}
273-
274-
if !ok {
275-
return nil, nil, fmt.Errorf("%w: %s", ErrValueIndex, valueKey)
276-
}
277-
278-
requestMap[keyIndex] = value
279-
}
280209

281-
for _, v := range cassette {
282-
cmap, ok := v.(map[string]interface{})
283-
if !ok {
284-
return nil, nil, ErrNotComparable
285-
}
286-
287-
var keyIndex, key string
288-
for _, key = range supportedMapKeys {
289-
if keyIndex, ok = cmap[key].(string); ok {
290-
break
291-
}
292-
}
210+
for j := range cassette {
211+
if casVisited[j] {
212+
continue
213+
}
293214

294-
if !ok {
295-
return nil, nil, fmt.Errorf("%w: %s", ErrKeyIndex, key)
296-
}
215+
// cleanup ignored keys
216+
for _, key := range BodyMatcherIgnore {
217+
removeKeyRecursive(cassette[j].(map[string]interface{}), key)
218+
}
297219

298-
var value interface{}
220+
if compareJSONFields(request[i], cassette[j]) {
221+
matched++
222+
reqVisited[i] = true
223+
casVisited[j] = true
299224

300-
var valueKey string
301-
for _, valueKey = range supportedMapValues {
302-
if value, ok = cmap[valueKey]; ok {
303-
break
225+
break
226+
}
304227
}
305228
}
306229

307-
if !ok {
308-
return nil, nil, fmt.Errorf("%w: %s", ErrValueIndex, valueKey)
309-
}
310-
311-
cassetteMap[keyIndex] = value
230+
return matched == len(request)
231+
default:
232+
return reflect.DeepEqual(request, cassette)
312233
}
313-
314-
return requestMap, cassetteMap, nil
315234
}

internal/acctest/vcr.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ var BodyMatcherIgnore = []string{
5050
"mnq_nats_subject",
5151
}
5252

53+
// removeKeyRecursive removes a key from a map and all its nested maps
54+
func removeKeyRecursive(m map[string]interface{}, key string) {
55+
delete(m, key)
56+
57+
for _, v := range m {
58+
if v, ok := v.(map[string]interface{}); ok {
59+
removeKeyRecursive(v, key)
60+
}
61+
}
62+
}
63+
5364
// getTestFilePath returns a valid filename path based on the go test name and suffix. (Take care of non fs friendly char)
5465
func getTestFilePath(t *testing.T, pkgFolder string, suffix string) string {
5566
t.Helper()
@@ -132,8 +143,7 @@ func cassetteBodyMatcher(request *http.Request, cassette cassette.Request) bool
132143
// actualRequest contains JSON but cassette may not contain JSON, this doesn't match in this case
133144
return false
134145
}
135-
136-
// Remove keys that should be ignored during comparison
146+
// remove keys that should be ignored during comparison
137147
for _, key := range BodyMatcherIgnore {
138148
removeKeyRecursive(requestJSON, key)
139149
removeKeyRecursive(cassetteJSON, key)
@@ -142,16 +152,6 @@ func cassetteBodyMatcher(request *http.Request, cassette cassette.Request) bool
142152
return compareJSONBodies(requestJSON, cassetteJSON)
143153
}
144154

145-
func removeKeyRecursive(m map[string]interface{}, key string) {
146-
delete(m, key)
147-
148-
for _, v := range m {
149-
if v, ok := v.(map[string]interface{}); ok {
150-
removeKeyRecursive(v, key)
151-
}
152-
}
153-
}
154-
155155
// CassetteMatcher is a custom matcher that check equivalence of a played request against a recorded one
156156
// It compares method, path and query but will remove unwanted values from query
157157
func CassetteMatcher(request *http.Request, cassette cassette.Request) bool {

0 commit comments

Comments
 (0)