package matchers import ( "errors" "reflect" "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" ) const maxIndirections = 31 type HaveValueMatcher struct { Matcher types.GomegaMatcher // the matcher to apply to the "resolved" actual value. resolvedActual interface{} // the ("resolved") value. } func (m *HaveValueMatcher) Match(actual interface{}) (bool, error) { val := reflect.ValueOf(actual) for allowedIndirs := maxIndirections; allowedIndirs > 0; allowedIndirs-- { // return an error if value isn't valid. Please note that we cannot // check for nil here, as we might not deal with a pointer or interface // at this point. if !val.IsValid() { return false, errors.New(format.Message( actual, "not to be ")) } switch val.Kind() { case reflect.Ptr, reflect.Interface: // resolve pointers and interfaces to their values, then rinse and // repeat. if val.IsNil() { return false, errors.New(format.Message( actual, "not to be ")) } val = val.Elem() continue default: // forward the final value to the specified matcher. m.resolvedActual = val.Interface() return m.Matcher.Match(m.resolvedActual) } } // too many indirections: extreme star gazing, indeed...? return false, errors.New(format.Message(actual, "too many indirections")) } func (m *HaveValueMatcher) FailureMessage(_ interface{}) (message string) { return m.Matcher.FailureMessage(m.resolvedActual) } func (m *HaveValueMatcher) NegatedFailureMessage(_ interface{}) (message string) { return m.Matcher.NegatedFailureMessage(m.resolvedActual) }