@@ -9,36 +9,46 @@ import (
9
9
10
10
// compareJSONFields is the entry point for comparing two interface values
11
11
// handle string with special cases, map[string]interface{} and []interface{} or any other primitive type
12
- func compareJSONFields (requestValue , cassetteValue interface {} ) bool {
12
+ func compareJSONFields (requestValue , cassetteValue any , strict bool ) bool {
13
13
switch requestValue := requestValue .(type ) {
14
14
case string :
15
15
return compareFieldsStrings (requestValue , cassetteValue .(string ))
16
- case map [string ]interface {} :
17
- return compareJSONBodies (requestValue , cassetteValue .(map [string ]interface {}) )
18
- case []interface {} :
19
- return compareSlices (requestValue , cassetteValue .([]interface {} ))
16
+ case map [string ]any :
17
+ return compareJSONBodies (requestValue , cassetteValue .(map [string ]any ), strict )
18
+ case []any :
19
+ return compareSlices (requestValue , cassetteValue .([]any ))
20
20
default :
21
21
return reflect .DeepEqual (requestValue , cassetteValue )
22
22
}
23
23
}
24
24
25
25
// compareJSONBodies compare two given maps that represent json bodies
26
26
// returns true if both json are equivalent
27
- func compareJSONBodies (request , cassette map [string ]interface {} ) bool {
27
+ func compareJSONBodies (request , cassette map [string ]any , strict bool ) bool {
28
28
for key , requestValue := range request {
29
29
cassetteValue , ok := cassette [key ]
30
30
if ! ok {
31
- // Actual request may contain a field that does not exist in cassette
32
- // New fields can appear in requests with new api features
33
- // We do not want to generate new cassettes for each new features
31
+ if strict {
32
+ return false
33
+ }
34
+
34
35
continue
35
36
}
36
37
37
38
if reflect .TypeOf (cassetteValue ) != reflect .TypeOf (requestValue ) {
38
39
return false
39
40
}
40
41
41
- if ! compareJSONFields (requestValue , cassetteValue ) {
42
+ if ! compareJSONFields (requestValue , cassetteValue , strict ) {
43
+ return false
44
+ }
45
+ }
46
+
47
+ for key , cassetteValue := range cassette {
48
+ if _ , ok := request [key ]; ! ok && cassetteValue != nil {
49
+ // Fails match if cassettes contains a field not in actual requests
50
+ // Fields should not disappear from requests unless a sdk breaking change
51
+ // We ignore if field is nil in cassette as it could be an old deprecated and unused field
42
52
return false
43
53
}
44
54
}
@@ -141,7 +151,7 @@ func compareStringSlices(request, cassette []string) bool {
141
151
142
152
// compareSlices compares two slices of interface{}
143
153
// in case of slice of map[string]interface{}, it will attempt to find a match in the other slice without taking into account the order
144
- func compareSlices (request , cassette []interface {} ) bool {
154
+ func compareSlices (request , cassette []any ) bool {
145
155
if len (request ) != len (cassette ) {
146
156
return false
147
157
}
@@ -178,10 +188,31 @@ func compareSlices(request, cassette []interface{}) bool {
178
188
}
179
189
180
190
return true
181
- case map [string ]interface {} :
191
+ case map [string ]any :
182
192
// compare list of maps[string]interface{} without order and without ignored keys
183
193
matched := 0
184
194
195
+ for i := range request {
196
+ // cleanup ignored keys
197
+ for _ , key := range BodyMatcherIgnore {
198
+ removeKeyRecursive (request [i ].(map [string ]any ), key )
199
+ }
200
+
201
+ for _ , key := range BodyMatcherIgnore {
202
+ removeKeyRecursive (cassette [i ].(map [string ]any ), key )
203
+ }
204
+
205
+ if compareJSONFields (request [i ], cassette [i ], false ) {
206
+ matched ++
207
+ }
208
+ }
209
+
210
+ if matched == len (request ) {
211
+ return true
212
+ }
213
+
214
+ // if no match try to compare out of order
215
+ matched = 0
185
216
reqVisited := make ([]bool , len (request ))
186
217
casVisited := make ([]bool , len (cassette ))
187
218
@@ -190,22 +221,12 @@ func compareSlices(request, cassette []interface{}) bool {
190
221
continue
191
222
}
192
223
193
- // cleanup ignored keys
194
- for _ , key := range BodyMatcherIgnore {
195
- removeKeyRecursive (request [i ].(map [string ]interface {}), key )
196
- }
197
-
198
224
for j := range cassette {
199
225
if casVisited [j ] {
200
226
continue
201
227
}
202
228
203
- // cleanup ignored keys
204
- for _ , key := range BodyMatcherIgnore {
205
- removeKeyRecursive (cassette [j ].(map [string ]interface {}), key )
206
- }
207
-
208
- if compareJSONFields (request [i ], cassette [j ]) {
229
+ if compareJSONFields (request [i ], cassette [j ], true ) {
209
230
matched ++
210
231
reqVisited [i ] = true
211
232
casVisited [j ] = true
0 commit comments