审查视图

vendor/github.com/onsi/gomega/matchers/receive_matcher.go 3.4 KB
tangxvhui authored
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
// untested sections: 3

package matchers

import (
	"fmt"
	"reflect"

	"github.com/onsi/gomega/format"
)

type ReceiveMatcher struct {
	Arg           interface{}
	receivedValue reflect.Value
	channelClosed bool
}

func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err error) {
	if !isChan(actual) {
		return false, fmt.Errorf("ReceiveMatcher expects a channel.  Got:\n%s", format.Object(actual, 1))
	}

	channelType := reflect.TypeOf(actual)
	channelValue := reflect.ValueOf(actual)

	if channelType.ChanDir() == reflect.SendDir {
		return false, fmt.Errorf("ReceiveMatcher matcher cannot be passed a send-only channel.  Got:\n%s", format.Object(actual, 1))
	}

	var subMatcher omegaMatcher
	var hasSubMatcher bool

	if matcher.Arg != nil {
		subMatcher, hasSubMatcher = (matcher.Arg).(omegaMatcher)
		if !hasSubMatcher {
			argType := reflect.TypeOf(matcher.Arg)
			if argType.Kind() != reflect.Ptr {
				return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(matcher.Arg, 1))
			}
		}
	}

	winnerIndex, value, open := reflect.Select([]reflect.SelectCase{
		{Dir: reflect.SelectRecv, Chan: channelValue},
		{Dir: reflect.SelectDefault},
	})

	var closed bool
	var didReceive bool
	if winnerIndex == 0 {
		closed = !open
		didReceive = open
	}
	matcher.channelClosed = closed

	if closed {
		return false, nil
	}

	if hasSubMatcher {
		if didReceive {
			matcher.receivedValue = value
			return subMatcher.Match(matcher.receivedValue.Interface())
		}
		return false, nil
	}

	if didReceive {
		if matcher.Arg != nil {
			outValue := reflect.ValueOf(matcher.Arg)

			if value.Type().AssignableTo(outValue.Elem().Type()) {
				outValue.Elem().Set(value)
				return true, nil
			}
			if value.Type().Kind() == reflect.Interface && value.Elem().Type().AssignableTo(outValue.Elem().Type()) {
				outValue.Elem().Set(value.Elem())
				return true, nil
			} else {
				return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(matcher.Arg, 1))
			}

		}

		return true, nil
	}
	return false, nil
}

func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) {
	subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher)

	closedAddendum := ""
	if matcher.channelClosed {
		closedAddendum = " The channel is closed."
	}

	if hasSubMatcher {
		if matcher.receivedValue.IsValid() {
			return subMatcher.FailureMessage(matcher.receivedValue.Interface())
		}
		return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
	}
	return format.Message(actual, "to receive something."+closedAddendum)
}

func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) {
	subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher)

	closedAddendum := ""
	if matcher.channelClosed {
		closedAddendum = " The channel is closed."
	}

	if hasSubMatcher {
		if matcher.receivedValue.IsValid() {
			return subMatcher.NegatedFailureMessage(matcher.receivedValue.Interface())
		}
		return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
	}
	return format.Message(actual, "not to receive anything."+closedAddendum)
}

func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
	if !isChan(actual) {
		return false
	}

	return !matcher.channelClosed
}