...

Source file src/github.com/onsi/gomega/matchers/consist_of.go

Documentation: github.com/onsi/gomega/matchers

     1  // untested sections: 3
     2  
     3  package matchers
     4  
     5  import (
     6  	"fmt"
     7  	"reflect"
     8  
     9  	"github.com/onsi/gomega/format"
    10  	"github.com/onsi/gomega/matchers/support/goraph/bipartitegraph"
    11  )
    12  
    13  type ConsistOfMatcher struct {
    14  	Elements        []interface{}
    15  	missingElements []interface{}
    16  	extraElements   []interface{}
    17  }
    18  
    19  func (matcher *ConsistOfMatcher) Match(actual interface{}) (success bool, err error) {
    20  	if !isArrayOrSlice(actual) && !isMap(actual) {
    21  		return false, fmt.Errorf("ConsistOf matcher expects an array/slice/map.  Got:\n%s", format.Object(actual, 1))
    22  	}
    23  
    24  	matchers := matchers(matcher.Elements)
    25  	values := valuesOf(actual)
    26  
    27  	bipartiteGraph, err := bipartitegraph.NewBipartiteGraph(values, matchers, neighbours)
    28  	if err != nil {
    29  		return false, err
    30  	}
    31  
    32  	edges := bipartiteGraph.LargestMatching()
    33  	if len(edges) == len(values) && len(edges) == len(matchers) {
    34  		return true, nil
    35  	}
    36  
    37  	var missingMatchers []interface{}
    38  	matcher.extraElements, missingMatchers = bipartiteGraph.FreeLeftRight(edges)
    39  	matcher.missingElements = equalMatchersToElements(missingMatchers)
    40  
    41  	return false, nil
    42  }
    43  
    44  func neighbours(value, matcher interface{}) (bool, error) {
    45  	match, err := matcher.(omegaMatcher).Match(value)
    46  	return match && err == nil, nil
    47  }
    48  
    49  func equalMatchersToElements(matchers []interface{}) (elements []interface{}) {
    50  	for _, matcher := range matchers {
    51  		if equalMatcher, ok := matcher.(*EqualMatcher); ok {
    52  			elements = append(elements, equalMatcher.Expected)
    53  		} else if _, ok := matcher.(*BeNilMatcher); ok {
    54  			elements = append(elements, nil)
    55  		} else {
    56  			elements = append(elements, matcher)
    57  		}
    58  	}
    59  	return
    60  }
    61  
    62  func flatten(elems []interface{}) []interface{} {
    63  	if len(elems) != 1 || !isArrayOrSlice(elems[0]) {
    64  		return elems
    65  	}
    66  
    67  	value := reflect.ValueOf(elems[0])
    68  	flattened := make([]interface{}, value.Len())
    69  	for i := 0; i < value.Len(); i++ {
    70  		flattened[i] = value.Index(i).Interface()
    71  	}
    72  	return flattened
    73  }
    74  
    75  func matchers(expectedElems []interface{}) (matchers []interface{}) {
    76  	for _, e := range flatten(expectedElems) {
    77  		if e == nil {
    78  			matchers = append(matchers, &BeNilMatcher{})
    79  		} else if matcher, isMatcher := e.(omegaMatcher); isMatcher {
    80  			matchers = append(matchers, matcher)
    81  		} else {
    82  			matchers = append(matchers, &EqualMatcher{Expected: e})
    83  		}
    84  	}
    85  	return
    86  }
    87  
    88  func presentable(elems []interface{}) interface{} {
    89  	elems = flatten(elems)
    90  
    91  	if len(elems) == 0 {
    92  		return []interface{}{}
    93  	}
    94  
    95  	sv := reflect.ValueOf(elems)
    96  	firstEl := sv.Index(0)
    97  	if firstEl.IsNil() {
    98  		return elems
    99  	}
   100  	tt := firstEl.Elem().Type()
   101  	for i := 1; i < sv.Len(); i++ {
   102  		el := sv.Index(i)
   103  		if el.IsNil() || (sv.Index(i).Elem().Type() != tt) {
   104  			return elems
   105  		}
   106  	}
   107  
   108  	ss := reflect.MakeSlice(reflect.SliceOf(tt), sv.Len(), sv.Len())
   109  	for i := 0; i < sv.Len(); i++ {
   110  		ss.Index(i).Set(sv.Index(i).Elem())
   111  	}
   112  
   113  	return ss.Interface()
   114  }
   115  
   116  func valuesOf(actual interface{}) []interface{} {
   117  	value := reflect.ValueOf(actual)
   118  	values := []interface{}{}
   119  	if isMap(actual) {
   120  		keys := value.MapKeys()
   121  		for i := 0; i < value.Len(); i++ {
   122  			values = append(values, value.MapIndex(keys[i]).Interface())
   123  		}
   124  	} else {
   125  		for i := 0; i < value.Len(); i++ {
   126  			values = append(values, value.Index(i).Interface())
   127  		}
   128  	}
   129  
   130  	return values
   131  }
   132  
   133  func (matcher *ConsistOfMatcher) FailureMessage(actual interface{}) (message string) {
   134  	message = format.Message(actual, "to consist of", presentable(matcher.Elements))
   135  	message = appendMissingElements(message, matcher.missingElements)
   136  	if len(matcher.extraElements) > 0 {
   137  		message = fmt.Sprintf("%s\nthe extra elements were\n%s", message,
   138  			format.Object(presentable(matcher.extraElements), 1))
   139  	}
   140  	return
   141  }
   142  
   143  func appendMissingElements(message string, missingElements []interface{}) string {
   144  	if len(missingElements) == 0 {
   145  		return message
   146  	}
   147  	return fmt.Sprintf("%s\nthe missing elements were\n%s", message,
   148  		format.Object(presentable(missingElements), 1))
   149  }
   150  
   151  func (matcher *ConsistOfMatcher) NegatedFailureMessage(actual interface{}) (message string) {
   152  	return format.Message(actual, "not to consist of", presentable(matcher.Elements))
   153  }
   154  

View as plain text