Matthias Andreas Benkard | 832a54e | 2019-01-29 09:27:38 +0100 | [diff] [blame] | 1 | package matchers |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "reflect" |
| 6 | |
| 7 | "github.com/onsi/gomega/format" |
| 8 | "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph" |
| 9 | ) |
| 10 | |
| 11 | type ConsistOfMatcher struct { |
| 12 | Elements []interface{} |
| 13 | } |
| 14 | |
| 15 | func (matcher *ConsistOfMatcher) Match(actual interface{}) (success bool, err error) { |
| 16 | if !isArrayOrSlice(actual) && !isMap(actual) { |
| 17 | return false, fmt.Errorf("ConsistOf matcher expects an array/slice/map. Got:\n%s", format.Object(actual, 1)) |
| 18 | } |
| 19 | |
| 20 | elements := matcher.Elements |
| 21 | if len(matcher.Elements) == 1 && isArrayOrSlice(matcher.Elements[0]) { |
| 22 | elements = []interface{}{} |
| 23 | value := reflect.ValueOf(matcher.Elements[0]) |
| 24 | for i := 0; i < value.Len(); i++ { |
| 25 | elements = append(elements, value.Index(i).Interface()) |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | matchers := []interface{}{} |
| 30 | for _, element := range elements { |
| 31 | matcher, isMatcher := element.(omegaMatcher) |
| 32 | if !isMatcher { |
| 33 | matcher = &EqualMatcher{Expected: element} |
| 34 | } |
| 35 | matchers = append(matchers, matcher) |
| 36 | } |
| 37 | |
| 38 | values := matcher.valuesOf(actual) |
| 39 | |
| 40 | if len(values) != len(matchers) { |
| 41 | return false, nil |
| 42 | } |
| 43 | |
| 44 | neighbours := func(v, m interface{}) (bool, error) { |
| 45 | match, err := m.(omegaMatcher).Match(v) |
| 46 | return match && err == nil, nil |
| 47 | } |
| 48 | |
| 49 | bipartiteGraph, err := bipartitegraph.NewBipartiteGraph(values, matchers, neighbours) |
| 50 | if err != nil { |
| 51 | return false, err |
| 52 | } |
| 53 | |
| 54 | return len(bipartiteGraph.LargestMatching()) == len(values), nil |
| 55 | } |
| 56 | |
| 57 | func (matcher *ConsistOfMatcher) valuesOf(actual interface{}) []interface{} { |
| 58 | value := reflect.ValueOf(actual) |
| 59 | values := []interface{}{} |
| 60 | if isMap(actual) { |
| 61 | keys := value.MapKeys() |
| 62 | for i := 0; i < value.Len(); i++ { |
| 63 | values = append(values, value.MapIndex(keys[i]).Interface()) |
| 64 | } |
| 65 | } else { |
| 66 | for i := 0; i < value.Len(); i++ { |
| 67 | values = append(values, value.Index(i).Interface()) |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | return values |
| 72 | } |
| 73 | |
| 74 | func (matcher *ConsistOfMatcher) FailureMessage(actual interface{}) (message string) { |
| 75 | return format.Message(actual, "to consist of", matcher.Elements) |
| 76 | } |
| 77 | |
| 78 | func (matcher *ConsistOfMatcher) NegatedFailureMessage(actual interface{}) (message string) { |
| 79 | return format.Message(actual, "not to consist of", matcher.Elements) |
| 80 | } |