package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/format" "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph" ) type ConsistOfMatcher struct { Elements []interface{} } func (matcher *ConsistOfMatcher) Match(actual interface{}) (success bool, err error) { if !isArrayOrSlice(actual) && !isMap(actual) { return false, fmt.Errorf("ConsistOf matcher expects an array/slice/map. Got:\n%s", format.Object(actual, 1)) } elements := matcher.Elements if len(matcher.Elements) == 1 && isArrayOrSlice(matcher.Elements[0]) { elements = []interface{}{} value := reflect.ValueOf(matcher.Elements[0]) for i := 0; i < value.Len(); i++ { elements = append(elements, value.Index(i).Interface()) } } matchers := []interface{}{} for _, element := range elements { matcher, isMatcher := element.(omegaMatcher) if !isMatcher { matcher = &EqualMatcher{Expected: element} } matchers = append(matchers, matcher) } values := matcher.valuesOf(actual) if len(values) != len(matchers) { return false, nil } neighbours := func(v, m interface{}) (bool, error) { match, err := m.(omegaMatcher).Match(v) return match && err == nil, nil } bipartiteGraph, err := bipartitegraph.NewBipartiteGraph(values, matchers, neighbours) if err != nil { return false, err } return len(bipartiteGraph.LargestMatching()) == len(values), nil } func (matcher *ConsistOfMatcher) valuesOf(actual interface{}) []interface{} { value := reflect.ValueOf(actual) values := []interface{}{} if isMap(actual) { keys := value.MapKeys() for i := 0; i < value.Len(); i++ { values = append(values, value.MapIndex(keys[i]).Interface()) } } else { for i := 0; i < value.Len(); i++ { values = append(values, value.Index(i).Interface()) } } return values } func (matcher *ConsistOfMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to consist of", matcher.Elements) } func (matcher *ConsistOfMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to consist of", matcher.Elements) }