Is there any support for matching ordered slice?
rickyson96 opened this issue · comments
Hi! Thanks for the awesome matcher package!
I know that currently we can use Equal
and friends to have exact matching of ordered slice.
But what if I want to match the slice, in an ordered manner, with custom equality matcher?
Something like this
tc := []string{"aaa", "bbb", "ccc"}
Expect(tc).To(ConsistOf(
ContainsSubstring("a"), // "aaa"
Equal("bbb"), // "bbb"
BeEquivalentTo("ccc"), // "ccc"
))
My current use case is that I have list of proto message which I can't use exact equality. I'm using the gproto package to do the equality. Something similar to the snippet below.
tc := []proto.Message{...}
expectation := []proto.Message{...}
matchers := []types.GomegaMatcher{}
for _, ex := range expectations {
matchers := append(matchers, gproto.Equal(ex))
}
Expect(tc).To(ConsistOf(matchers)) // but no ordering
Currently, I'm using loop to match the index with matcher's index to get the ordering. Is it expected that way or is there something I am missing?
hey @rickyson96 -- you're right (and I'm somewhat surprised, all these years later!) that we still don't have a simple matcher matcher to perform an ordered per-element assertion on a slice/array. If you'd be interested in working on a PR that would be wonderful!
In the meantime, you can use the gstruct
package to solve for this problem - though there's a bit more complexity involved. You'll want to do something like:
import "github.com/onsi/gomega/gstruct"
var _ = It("is the correct, ordered, set of messages", func() {
tc := []proto.Message{...}
expectation := []proto.Message{...}
// gstruct.Elements is a map[string]GomegaMatcher
elements := gstruct.Elements{}
for idx, ex := range expectations {
elements[strconv.Itoa(idx)] = gproto.Equal(ex) //note the index is used as a string key
}
//gstruct.MatchAllElements will iterate over tc and use gstruct.IndexIdentity to get the key for each element (in this case, a string version of the index). It will then look up the matcher from elements and match it against the value in tc.
Expect(tc).To(gstruct.MatchAllElementsWithIndex(gstruct.IndexIdentity, elements))
})
this will give you an ordered assertion (and will fail if there are extra things in tc
and/or missing things in tc
). You can learn more in the gstruct docs here
Wow, I didn't think of the gstruct
solution despite already using it for struct
and maps
.
Thanks for the information!