| 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) |
| } |