Example #1
0
// Matches strings that contain the given substring.
func Contains(substring string) *base.Matcher {
	match := func(s string) *base.Result {
		extra := 8
		if foundStart := strings.Index(s, substring); foundStart >= 0 {
			foundEnd := foundStart + len(substring)
			start, end := foundStart-extra, foundEnd+extra
			prefix, suffix := "", ""
			if start <= 0 {
				start = 0
			} else {
				prefix = "..."
			}
			if end >= len(s) {
				end = len(s)
			} else {
				suffix = "..."
			}
			return base.NewResultf(true,
				"substring \"%v\" appears in \"%v%v[%v]%v%v\"", substring,
				prefix, s[start:foundStart], substring, s[foundEnd:end], suffix)
		}
		return base.NewResultf(false,
			"substring \"%v\" does not appear in \"%v\"",
			substring, s)
	}
	return base.NewMatcherf(match, "Contains(\"%v\")", substring)
}
Example #2
0
// Variant of OnPattern() that uses the given subgroup of the pattern.
func OnPatternGroup(pattern string, group int) func(matcher *base.Matcher) *base.Matcher {
	re := regexp.MustCompile(pattern)
	if num := re.NumSubexp(); num < group {
		println("Illegal group #", group, ": there are only ", num, "groups.")
		panic("Group index out of bounds.")
	}
	return func(matcher *base.Matcher) *base.Matcher {
		match := func(s string) *base.Result {
			loc := re.FindStringSubmatchIndex(s)
			if loc == nil {
				return base.NewResultf(false,
					"No occurrences of pattern \"%v\"", pattern)
			}
			start, end := loc[0], loc[1]
			substart, subend := loc[group*2], loc[group*2+1]
			prefix := s[start:substart]
			substring := s[substart:subend]
			suffix := s[subend:end]
			result := matcher.Match(substring)
			return base.NewResultf(result.Matched(),
				"Found substring[%v:%v], [%v:%v]=\"%v[%v]%v\" for pattern \"%v\"",
				substart, subend, start, end,
				prefix, substring, suffix, pattern).WithCauses(result)
		}
		return base.NewMatcherf(match,
			"OnPatternGroup[\"%v\", %v][%v]", pattern, group, matcher)
	}
}
Example #3
0
// Variant of AnyPattern() that uses the given subgroup of the pattern.
func AnyPatternGroup(pattern string, group int) func(matcher *base.Matcher) *base.Matcher {
	re := regexp.MustCompile(pattern)
	if num := re.NumSubexp(); num < group {
		println("Illegal group #", group, ": there are only ", num, "groups.")
		panic("Group index out of bounds.")
	}
	return func(matcher *base.Matcher) *base.Matcher {
		match := func(s string) *base.Result {
			matches := re.FindAllStringSubmatchIndex(s, -1)
			if matches == nil {
				return base.NewResultf(false,
					"No occurrences of pattern \"%v\"", pattern)
			}

			for index, loc := range matches {
				substart, subend := loc[2*group], loc[2*group+1]
				substring := s[substart:subend]
				result := matcher.Match(substring)
				if result.Matched() {
					start, end := loc[0], loc[1]
					prefix, suffix := s[start:substart], s[subend:end]
					return base.NewResultf(true,
						"matched substring[%v:%v], [%v:%v]=\"%v[%v]%v\", occurrence #%v (of %v) of pattern \"%v\"",
						substart, subend, start, end,
						prefix, substring, suffix, index+1, len(matches), pattern)
				}
			}
			return base.NewResultf(false,
				"Did not match any occurrence (of %v) of pattern \"%v\"",
				len(matches), pattern)
		}
		return base.NewMatcherf(match,
			"AnyPatternGroup[\"%v\", %v][%v]", pattern, group, matcher)
	}
}
Example #4
0
// Second part of a builder for an either/xor matcher:
//     matcher := Either(matcher1).Xor(matcher2)
// This matcher matches when exactly one of the two matchers matches
// a given value;  if both or neither of the matchers is successful,
// xor fails to match.  Note that this is *never* a short-circuiting
// operation.
func (self *EitherClause) Xor(matcher2 *base.Matcher) *base.Matcher {
	matcher1 := self.matcher
	match := func(actual interface{}) *base.Result {
		result1 := matcher1.Match(actual)
		result2 := matcher2.Match(actual)
		if result1.Matched() {
			if result2.Matched() {
				return base.NewResultf(false,
					"both parts of 'Either/Xor' matched [%v]", actual).
					WithCauses(result1, result2)
			}
			return base.NewResultf(true,
				"only the first part of 'Either/Xor' matched [%v]", actual).
				WithCauses(result1, result2)
		}
		if result2.Matched() {
			return base.NewResultf(true,
				"only the second part of 'Either/Xor' matched [%v]", actual).
				WithCauses(result1, result2)
		}
		return base.NewResultf(false,
			"neither part of 'Either/Xor' matched [%v]", actual).
			WithCauses(result1, result2)
	}
	return base.NewMatcherf(match, "either [%v] xor [%v]", matcher1, matcher2)
}
Example #5
0
// Constructs an if-and-only-if/then matcher:
//     matcher := IfAndOnlyIf(AntecedentMatcher).Then(ConsequentMatcher)
// that matches when both or neither of the Antecedent and the
// Consequent match.  Note that this is logically equivalent to:
//     Either(Not(AntecedentMatcher)).Xor(ConsequentMatcher)
// But may be more readable in practice.
func (self *IfAndOnlyIfClause) Then(consequent *base.Matcher) *base.Matcher {
	antecedent := self.antecedent
	match := func(actual interface{}) *base.Result {
		result1 := antecedent.Match(actual)
		result2 := consequent.Match(actual)
		if result1.Matched() {
			if result2.Matched() {
				return base.NewResultf(true,
					"Matched because both parts of 'Iff/Then' matched on [%v]", actual).
					WithCauses(result1, result2)
			}
			return base.NewResultf(false,
				"Failed because only the first part of 'Iff/Then' matched on [%v]", actual).
				WithCauses(result1, result2)
		}
		if result2.Matched() {
			return base.NewResultf(false,
				"Failed because only the second part of 'IFf/Then' matched on [%v]", actual).
				WithCauses(result1, result2)
		}
		return base.NewResultf(true,
			"Matched because neither part of 'Iff/Then' matched on [%v]", actual).
			WithCauses(result1, result2)
	}
	return base.NewMatcherf(match, "if and only if [%v] then [%v]", antecedent, consequent)
}
Example #6
0
// Returns a matcher that matches on any array or slice input value
// if the given matcher matches every element of that array or slice.
//
// The returned matcher does not match any non-array-or-slice value.
func EachElem(matcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		v := reflect.NewValue(actual)
		var value _ElemAndLen
		var ok bool
		value, ok = v.(*reflect.ArrayValue)
		if !ok {
			value, ok = v.(*reflect.SliceValue)
		}
		if !ok {
			return base.NewResultf(false,
				"Was not array or slice: was type %T", actual)
		}
		n := value.Len()
		for i := 0; i < n; i++ {
			elem := value.Elem(i).Interface()
			result := matcher.Match(elem)
			if !result.Matched() {
				return base.NewResultf(false,
					"Failed to match element %v of %v: %v",
					i+1, n, elem).
					WithCauses(result)
			}
		}
		return base.NewResultf(true,
			"Matched all of the %v elements", n)
	}
	return base.NewMatcherf(match, "EveryElement[%v]", matcher)
}
Example #7
0
// Returns a short-circuiting function that applies the matcher to each
// occurrence of the pattern in an input string, until a matching pattern
// is found (in which case the matcher successfully matches) or all
// matching instances are exhausted (in which case the output matcher
// fails to match).
//
// For example:
//    AnyPattern("x.")(EqualTo("xy"))
// would match:
//    "six sax are sexy" (three matches of "x.", third is "xy")
// but not:
//    "pox pix are pixelated" (three matches of "x.", none is "xy")
func AnyPattern(pattern string) func(matcher *base.Matcher) *base.Matcher {
	re := regexp.MustCompile(pattern)
	return func(matcher *base.Matcher) *base.Matcher {
		match := func(s string) *base.Result {
			matches := re.FindAllStringIndex(s, -1)
			if matches == nil {
				return base.NewResultf(false,
					"No occurrences of pattern \"%v\"", pattern)
			}

			for index, loc := range matches {
				start, end := loc[0], loc[1]
				substring := s[start:end]
				result := matcher.Match(substring)
				if result.Matched() {
					return base.NewResultf(true,
						"matched substring[%v:%v]=\"%v\", occurrence #%v (of %v) of pattern \"%v\"",
						start, end, substring, index+1, len(matches), pattern)
				}
			}
			return base.NewResultf(false,
				"Did not match any occurrence (of %v) of pattern \"%v\"",
				len(matches), pattern)
		}
		return base.NewMatcherf(match,
			"AnyPattern[\"%v\"][%v]", pattern, matcher)
	}
}
Example #8
0
// Matches any input element that is an empty array, slice, or map.
func Empty() *base.Matcher {
	match := func(actual interface{}) *base.Result {
		value := reflect.NewValue(actual)
		if hasLen, ok := value.(_HasLen); ok {
			length := hasLen.Len()
			return base.NewResultf(length == 0,
				"Len() returned %v", length)
		}
		return base.NewResultf(false, "Can't determine length of type %T", actual)
	}
	return base.NewMatcherf(match, "Empty")
}
Example #9
0
// Applies the given matcher to the length of the input element.
func ToLen(matcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		value := reflect.NewValue(actual)
		if hasLen, ok := value.(_HasLen); ok {
			length := hasLen.Len()
			result := matcher.Match(length)
			return base.NewResultf(result.Matched(), "Len() returned %v", length)
		}
		return base.NewResultf(false,
			"Can't determine Len() for %T", actual)
	}
	return base.NewMatcherf(match, "ToLen[%v]", matcher)
}
Example #10
0
// Returns a new matcher that, on any input that is a *reflect.SliceType,
// extracts the type of element and matches it against the given matcher.
//
// If the given input is not an *reflect.SliceType, this fails to match.
// Note:  this matches slice *types*, not slices.  (See SliceOf.)
func SliceTypeOf(elementTypeMatcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		if sliceType, ok := actual.(*reflect.SliceType); ok {
			elementType := sliceType.Elem()
			result := elementTypeMatcher.Match(elementType)
			return base.NewResultf(
				result.Matched(),
				"was SliceType with elements of type %v", elementType.Name()).
				WithCauses(result)
		}
		return base.NewResultf(false, "was of type %T, not a slice", actual)
	}
	return base.NewMatcherf(match, "SliceTypeOf(%v)", elementTypeMatcher)
}
Example #11
0
func _TypeMatcher(name string, expectedType reflect.Type) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		if actual == nil {
			return base.NewResultf(false, "was nil")
		}
		actualType := reflect.Typeof(actual)
		if reflect.DeepEqual(actualType, expectedType) {
			return base.NewResultf(true, "was of type %v", expectedType)
		}
		return base.NewResultf(false,
			"was a %v, not a %v", actualType, expectedType)
	}
	return base.NewMatcherf(match, "Typeof[%v]", expectedType)
}
Example #12
0
// Matches strings that contain the given regexp pattern, using
// the same syntax as the standard regexp package.
func HasPattern(pattern string) *base.Matcher {
	re := regexp.MustCompile(pattern)
	match := func(s string) *base.Result {
		if found := re.FindStringIndex(s); found != nil {
			start, end := found[0], found[1]
			return base.NewResultf(true,
				"pattern \"%v\" matched substring[%v:%v]=\"%v\"",
				pattern, start, end, s[start:end])
		}
		return base.NewResultf(false,
			"pattern \"%v\" not found in \"%v\"", pattern, s)
	}
	return base.NewMatcherf(match, "HasPattern[\"%v\"]", pattern)
}
Example #13
0
func EqualToIgnoringCase(expected string) *base.Matcher {
	expectedToLower := strings.ToLower(expected)
	match := func(actual string) *base.Result {
		actualToLower := strings.ToLower(actual)
		if actualToLower == expectedToLower {
			return base.NewResultf(true,
				"\"%v\" matches \"%v\" (ignoring case)",
				actual, expected)
		}
		return base.NewResultf(false,
			"\"%v\" differs from \"%v\" (ignoring case)",
			actual, expected)
	}
	return base.NewMatcherf(match, "EqualToIgnoringCase(\"%v\")", expected)
}
Example #14
0
// Returns a new matcher that, on any input that is an array, extracts
// its type and matches it against the given matcher.
//
// If the given input is not an array, this fails to match.
// Note: this matches *arrays*, not array *types*. (See ArrayTypeOf.)
func ArrayOf(elementTypeMatcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		actualType := reflect.Typeof(actual)
		if arrayType, ok := actualType.(*reflect.ArrayType); ok {
			elementType := arrayType.Elem()
			result := elementTypeMatcher.Match(elementType)
			return base.NewResultf(
				result.Matched(),
				"was array with elements of type %v", elementType).
				WithCauses(result)
		}
		return base.NewResultf(false, "was of type %T, not an array", actual)
	}
	return base.NewMatcherf(match, "ArrayOf(%v)", elementTypeMatcher)
}
Example #15
0
// Returns a new matcher that, on any input that is a channel, extracts
// its type and matches it against the given matcher.
//
// If the given input is not a channel, this fails to match.
// Note: this matches *channels*, not channel *types*. (See ChannelTypeOf.)
func ChannelOf(elementTypeMatcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		actualType := reflect.Typeof(actual)
		if channelType, ok := actualType.(*reflect.ChanType); ok {
			elementType := channelType.Elem()
			result := elementTypeMatcher.Match(elementType)
			return base.NewResultf(result.Matched(),
				"was channel with elements of type %v",
				elementType).
				WithCauses(result)
		}
		return base.NewResultf(false, "was of type %T, not a channel", actual)
	}
	return base.NewMatcherf(match, "ChannelOf(%v)", elementTypeMatcher)
}
Example #16
0
// Check Matchers
func Test_BothAnd(t *testing.T) {
	yes, no := Anything(), Not(Anything())
	calledSnoop := false
	snoop := base.NewMatcherf(func(v interface{}) *base.Result {
		calledSnoop = true
		return base.NewResultf(false, "snooped!")
	}, "Snoop")

	if result := Both(yes).And(yes).Match(0); !result.Matched() {
		t.Errorf("yes and yes should match, was [%v]", result)
	}
	if result := Both(yes).And(no).Match(0); result.Matched() {
		t.Errorf("yes and no should not match, was [%v]", result)
	}
	result := Both(no).And(snoop).Match(0)
	if calledSnoop {
		t.Errorf("no and snoop should short-circuit before calling snoop")
	}
	if result.Matched() {
		t.Errorf("no and snoop should not match, was [%v]", result)
	}
	logSamples(t, Both(yes).And(yes))
	logSamples(t, Both(yes).And(no))
	logSamples(t, Both(no).And(yes))
	logSamples(t, Both(no).And(no))
}
Example #17
0
func Test_IfThen(t *testing.T) {
	yes, no := Anything(), Not(Anything())
	calledSnoop := false
	snoop := base.NewMatcherf(func(v interface{}) *base.Result {
		calledSnoop = true
		return base.NewResultf(false, "snooped!")
	}, "Snoop")

	if result := If(yes).Then(yes).Match(0); !result.Matched() {
		t.Errorf("if yes then yes should match, was [%v]", result)
	}
	if result := If(yes).Then(no).Match(0); result.Matched() {
		t.Errorf("if yes then no should not match, was [%v]", result)
	}
	result := If(no).Then(snoop).Match(0)
	if calledSnoop {
		t.Errorf("If-no-then-snoop should short-circuit before calling snoop")
	}
	if !result.Matched() {
		t.Errorf("if-no-then-snoop should match on failing antecedent, was [%v]",
			result)
	}
	logSamples(t, If(yes).Then(yes))
	logSamples(t, If(yes).Then(no))
	logSamples(t, If(no).Then(yes))
	logSamples(t, If(no).Then(no))
}
Example #18
0
// Matches strings that begin with the given prefix.
func HasPrefix(prefix string) *base.Matcher {
	maxLength := len(prefix) + 8 // arbitrary extra amount
	match := func(s string) *base.Result {
		continued := ""
		if len(s) > maxLength {
			s, continued = s[:maxLength], "..."
		}
		if strings.HasPrefix(s, prefix) {
			return base.NewResultf(true,
				"\"%v%v\" starts with \"%v\"", s, continued, prefix)
		}
		return base.NewResultf(false,
			"\"%v%v\" does not start with \"%v\"", s, continued, prefix)
	}
	return base.NewMatcherf(match, "HasPrefix(\"%v\")", prefix)
}
Example #19
0
// Matches strings that end with the given prefix.
func HasSuffix(suffix string) *base.Matcher {
	maxLength := len(suffix) + 8 // arbitrary extra amount
	match := func(s string) *base.Result {
		continued := ""
		if len(s) > maxLength {
			continued, s = "...", s[len(s)-maxLength:]
		}
		if strings.HasSuffix(s, suffix) {
			return base.NewResultf(true,
				"\"%v%v\" ends with \"%v\"", s, continued, suffix)
		}
		return base.NewResultf(false,
			"\"%v%v\" does not end with \"%v\"", s, continued, suffix)
	}
	return base.NewMatcherf(match, "HasSuffix(\"%v\")", suffix)
}
Example #20
0
// Returns a new matcher that, on any input that is a pointer, extracts the
// type of object that it thinks it's pointing to (the "pointee") and
// matches it against the given matcher.
//
// If the given input is not an pointer, this fails to match.
// Note:  this matches *pointers*, not pointer *types*. (See PtrTypeTo.)
func PtrTo(pointeeTypeMatcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		actualType := reflect.Typeof(actual)
		if ptrType, ok := actualType.(*reflect.PtrType); ok {
			elementType := ptrType.Elem()
			result := pointeeTypeMatcher.Match(elementType)
			return base.NewResultf(
				result.Matched(), "was PtrType to type %v", elementType).
				WithCauses(result)
		}
		return base.NewResultf(false,
			"was type %T, not a pointer", actual)
	}
	return base.NewMatcherf(match,
		"PtrTo(%v)", pointeeTypeMatcher)
}
Example #21
0
// Applies the given matcher to the result of writing the input object's
// to a string by using fmt.Sprintf("%#v", object).
func ToGoString(matcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		if gostringer, ok := actual.(fmt.GoStringer); ok {
			s := gostringer.GoString()
			result := matcher.Match(s)
			return base.NewResultf(result.Matched(),
				"GoString() returned %v", s).
				WithCauses(result)
		}
		s := fmt.Sprintf("%#v", actual)
		result := matcher.Match(s)
		return base.NewResultf(result.Matched(),
			"Not a fmt.GoStringer, but prints as %v", s).
			WithCauses(result)
	}
	return base.NewMatcherf(match, "ToGoString(%v)", matcher)
}
Example #22
0
// Creates a new matcher that applies the given matcher to the result of
// converting an input string its length. (using the `len()` builtin).
// If the input value is not a string, the matcher fails to match.
func ToLen(matcher *base.Matcher) *base.Matcher {
	match := func(s string) *base.Result {
		length := len(s)
		result := matcher.Match(length)
		return base.NewResultf(result.Matched(),
			"length is %v", length).
			WithCauses(result)
	}
	return base.NewMatcherf(match, "ToLen(%v)", matcher)
}
Example #23
0
// Creates a new matcher that applies the given matcher to the result of
// converting an input string to uppercase (using strings.ToUpper).
// If the input value is not a string, the matcher fails to match.
func ToUpper(matcher *base.Matcher) *base.Matcher {
	match := func(s string) *base.Result {
		upper := strings.ToUpper(s)
		result := matcher.Match(upper)
		return base.NewResultf(result.Matched(),
			"ToUpper is %v", upper).
			WithCauses(result)
	}
	return base.NewMatcherf(match, "ToUpper(%v)", matcher)
}
Example #24
0
// Returns a new matcher that applies the type of its input
// element to the given matcher.
func ToType(matcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		actualType := reflect.Typeof(actual)
		result := matcher.Match(actualType)
		return base.NewResultf(result.Matched(),
			"reflect.Typeof() returned %v", actualType).
			WithCauses(result)
	}
	return base.NewMatcherf(match, "ToType(%v)", matcher)
}
Example #25
0
func safeMatch(value interface{}, matcher *base.Matcher) (result *base.Result) {
	defer func() {
		if x := recover(); x != nil {
			result = base.NewResultf(false, "Panic: %v", x).
				WithMatcherAndValue(matcher, value)
		}
	}()
	result = matcher.Match(value)
	return
}
Example #26
0
// Returns a function that applies the matcher to the first occurrence of
// the pattern in an input string.
//
// For example:
//    OnPattern("h.s")(EqualTo("his"))
// would match:
//    "hers and his" (because the first instance of "h.s" is equal to "his")
// but none of:
//    "just hers" (no instances of "h.s")
//    "has chisel" (the first instance of "h.s" is not "his")
func OnPattern(pattern string) func(matcher *base.Matcher) *base.Matcher {
	re := regexp.MustCompile(pattern)
	return func(matcher *base.Matcher) *base.Matcher {
		match := func(s string) *base.Result {
			matches := re.FindStringIndex(s)
			if matches == nil {
				return base.NewResultf(false,
					"No occurrences of pattern \"%v\"", pattern)
			}
			start, end := matches[0], matches[1]
			substring := s[start:end]
			result := matcher.Match(substring)
			return base.NewResultf(result.Matched(),
				"Found substring[%v:%v]=\"%v\" for pattern \"%v\"",
				start, end, substring, pattern).WithCauses(result)
		}
		return base.NewMatcherf(match,
			"OnPattern[\"%v\"][%v]", pattern, matcher)
	}
}
Example #27
0
// Creates a matcher that passes when neither this matcher nor the
// other matcher pass.  This operation is short-circuiting, so that
// if the first matcher matches, the second is not attempted.
//  Note that this is logically equivalent to:
//     Both(Not(matcher1)).And(Not(matcher2))
// But may be more readable in practice.
func (self *NeitherClause) Nor(matcher2 *base.Matcher) *base.Matcher {
	matcher1 := self.matcher
	match := func(actual interface{}) *base.Result {
		result1 := matcher1.Match(actual)
		if result1.Matched() {
			return base.NewResultf(false,
				"first part of 'Nor' matched [%v]", actual).
				WithCauses(result1)
		}
		result2 := matcher2.Match(actual)
		if result2.Matched() {
			return base.NewResultf(false,
				"second part of 'Nor' matched [%v]", actual).
				WithCauses(result2)
		}
		return base.NewResultf(true,
			"neither part of 'Nor' matched [%v]", actual).
			WithCauses(result1, result2)
	}
	return base.NewMatcherf(match, "neither [%v] nor [%v]", matcher1, matcher2)
}
Example #28
0
// Second part of a builder for a short-circuiting both/and matcher.
func (self *BothClause) And(matcher2 *base.Matcher) *base.Matcher {
	matcher1 := self.matcher
	match := func(actual interface{}) *base.Result {
		result1 := matcher1.Match(actual)
		if !result1.Matched() {
			return base.NewResultf(false,
				"first part of 'Both/And' did not match [%v]", actual).
				WithCauses(result1)
		}
		result2 := matcher2.Match(actual)
		if !result2.Matched() {
			return base.NewResultf(false,
				"second part of 'Both/And' did not match [%v]", actual).
				WithCauses(result2)
		}
		return base.NewResultf(true,
			"both parts of 'Both/And' matched [%v]", actual).
			WithCauses(result1, result2)
	}
	return base.NewMatcherf(match, "both [%v] and [%v]", matcher1, matcher2)
}
Example #29
0
// Returns a matcher that matches on any array or slice input value
// if the given matcher matches at least one element of that array
// or slice.
//
// The returned matcher does not match any non-array-or-slice value.
func AnyElem(matcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		v := reflect.NewValue(actual)
		if value, ok := v.(_ElemAndLen); ok {
			n := value.Len()
			for i := 0; i < n; i++ {
				elem := value.Elem(i).Interface()
				result := matcher.Match(elem)
				if result.Matched() {
					return base.NewResultf(true,
						"Matched element %v of %v: %v", i+1, n, elem).
						WithCauses(result)
				}
			}
			return base.NewResultf(false,
				"Matched none of the %v elements", n)
		}
		return matcher.Match(v)
	}
	return base.NewMatcherf(match, "AnyElement[%v]", matcher)
}
Example #30
0
// Returns a new matcher that, on any input that is a *reflect.MapType,
// extracts the type of keys and element and matches them against two
// given matchers.
//
// If the given input is not an *reflect.MapType, this fails to match.
// Note:  this matches map *types*, not maps.  (See MapOf.)
func MapTypeOf(keyTypeMatcher, elementTypeMatcher *base.Matcher) *base.Matcher {
	match := func(actual interface{}) *base.Result {
		if mapType, ok := actual.(*reflect.MapType); ok {
			keyType := mapType.Key()
			elementType := mapType.Elem()
			keyResult := keyTypeMatcher.Match(keyType)
			if !keyResult.Matched() {
				return base.NewResultf(false,
					"was MapType with keys of type %v", keyType).
					WithCauses(keyResult)
			}
			elementResult := elementTypeMatcher.Match(elementType)
			return base.NewResultf(elementResult.Matched(),
				"was MapType with keys/elements of type %v/%v",
				keyType, elementType).
				WithCauses(keyResult, elementResult)
		}
		return base.NewResultf(false, "was of type %T, not a MapType", actual)
	}
	return base.NewMatcherf(match,
		"MapTypeOf(%v, %v)", keyTypeMatcher, elementTypeMatcher)
}