@@ -55,25 +55,7 @@ func JSONKeyTypeEqual(wantKey string, wantType gjson.Type) JSON {
5555	}
5656}
5757
58- // JSONCheckOff returns a matcher which will loop over `wantKey` and ensure that the items 
59- // (which can be array elements or object keys) 
60- // are present exactly once in any order in `wantItems`. If there are unexpected items or items 
61- // appear more than once then the match fails. This matcher can be used to check off items in 
62- // an array/object. The `mapper` function should map the item to an interface which will be 
63- // comparable via `reflect.DeepEqual` with items in `wantItems`. The optional `fn` callback 
64- // allows more checks to be performed other than checking off the item from the list. It is 
65- // called with 2 args: the result of the `mapper` function and the element itself (or value if 
66- // it's an object). 
67- // 
68- // Usage: (ensures `events` has these events in any order, with the right event type) 
69- //    JSONCheckOff("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} { 
70- //        return r.Get("event_id").Str 
71- //    }, func(eventID interface{}, eventBody gjson.Result) error { 
72- //        if eventBody.Get("type").Str != "m.room.message" { 
73- //	          return fmt.Errorf("expected event to be 'm.room.message'") 
74- //        } 
75- //    }) 
76- func  JSONCheckOff (wantKey  string , wantItems  []interface {}, mapper  func (gjson.Result ) interface {}, fn  func (interface {}, gjson.Result ) error ) JSON  {
58+ func  jsonCheckOffInternal (wantKey  string , wantItems  []interface {}, allowUnwantedItems  bool , mapper  func (gjson.Result ) interface {}, fn  func (interface {}, gjson.Result ) error ) JSON  {
7759	return  func (body  []byte ) error  {
7860		res  :=  gjson .GetBytes (body , wantKey )
7961		if  ! res .Exists () {
@@ -103,12 +85,15 @@ func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Res
10385					break 
10486				}
10587			}
106- 			if  want  ==  - 1  {
88+ 			if  ! allowUnwantedItems   &&   want  ==  - 1  {
10789				err  =  fmt .Errorf ("JSONCheckOff: unexpected item %s" , item )
10890				return  false 
10991			}
110- 			// delete the wanted item 
111- 			wantItems  =  append (wantItems [:want ], wantItems [want + 1 :]... )
92+ 
93+ 			if  want  !=  - 1  {
94+ 				// delete the wanted item 
95+ 				wantItems  =  append (wantItems [:want ], wantItems [want + 1 :]... )
96+ 			}
11297
11398			// do further checks 
11499			if  fn  !=  nil  {
@@ -130,6 +115,50 @@ func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Res
130115	}
131116}
132117
118+ // JSONCheckOffAllowUnwanted returns a matcher which will loop over `wantKey` and ensure that the items 
119+ // (which can be array elements or object keys) 
120+ // are present exactly once in any order in `wantItems`. Allows unexpected items or items 
121+ // appear that more than once. This matcher can be used to check off items in 
122+ // an array/object. The `mapper` function should map the item to an interface which will be 
123+ // comparable via `reflect.DeepEqual` with items in `wantItems`. The optional `fn` callback 
124+ // allows more checks to be performed other than checking off the item from the list. It is 
125+ // called with 2 args: the result of the `mapper` function and the element itself (or value if 
126+ // it's an object). 
127+ // 
128+ // Usage: (ensures `events` has these events in any order, with the right event type) 
129+ //    JSONCheckOffAllowUnwanted("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} { 
130+ //        return r.Get("event_id").Str 
131+ //    }, func(eventID interface{}, eventBody gjson.Result) error { 
132+ //        if eventBody.Get("type").Str != "m.room.message" { 
133+ //	          return fmt.Errorf("expected event to be 'm.room.message'") 
134+ //        } 
135+ //    }) 
136+ func  JSONCheckOffAllowUnwanted (wantKey  string , wantItems  []interface {}, mapper  func (gjson.Result ) interface {}, fn  func (interface {}, gjson.Result ) error ) JSON  {
137+ 	return  jsonCheckOffInternal (wantKey , wantItems , true , mapper , fn )
138+ }
139+ 
140+ // JSONCheckOff returns a matcher which will loop over `wantKey` and ensure that the items 
141+ // (which can be array elements or object keys) 
142+ // are present exactly once in any order in `wantItems`. If there are unexpected items or items 
143+ // appear more than once then the match fails. This matcher can be used to check off items in 
144+ // an array/object. The `mapper` function should map the item to an interface which will be 
145+ // comparable via `reflect.DeepEqual` with items in `wantItems`. The optional `fn` callback 
146+ // allows more checks to be performed other than checking off the item from the list. It is 
147+ // called with 2 args: the result of the `mapper` function and the element itself (or value if 
148+ // it's an object). 
149+ // 
150+ // Usage: (ensures `events` has these events in any order, with the right event type) 
151+ //    JSONCheckOff("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} { 
152+ //        return r.Get("event_id").Str 
153+ //    }, func(eventID interface{}, eventBody gjson.Result) error { 
154+ //        if eventBody.Get("type").Str != "m.room.message" { 
155+ //	          return fmt.Errorf("expected event to be 'm.room.message'") 
156+ //        } 
157+ //    }) 
158+ func  JSONCheckOff (wantKey  string , wantItems  []interface {}, mapper  func (gjson.Result ) interface {}, fn  func (interface {}, gjson.Result ) error ) JSON  {
159+ 	return  jsonCheckOffInternal (wantKey , wantItems , false , mapper , fn )
160+ }
161+ 
133162// JSONArrayEach returns a matcher which will check that `wantKey` is an array then loops over each 
134163// item calling `fn`. If `fn` returns an error, iterating stops and an error is returned. 
135164func  JSONArrayEach (wantKey  string , fn  func (gjson.Result ) error ) JSON  {
0 commit comments