10 "github.com/onsi/gomega/format"
11 errorsutil "github.com/onsi/gomega/gstruct/errors"
12 "github.com/onsi/gomega/types"
15 //MatchAllFields succeeds if every field of a struct matches the field matcher associated with
16 //it, and every element matcher is matched.
17 // Expect([]string{"a", "b"}).To(MatchAllFields(idFn, gstruct.Fields{
21 func MatchAllFields(fields Fields) types.GomegaMatcher {
22 return &FieldsMatcher{
27 //MatchFields succeeds if each element of a struct matches the field matcher associated with
28 //it. It can ignore extra fields and/or missing fields.
29 // Expect([]string{"a", "c"}).To(MatchFields(idFn, IgnoreMissing|IgnoreExtra, gstruct.Fields{
33 func MatchFields(options Options, fields Fields) types.GomegaMatcher {
34 return &FieldsMatcher{
36 IgnoreExtras: options&IgnoreExtras != 0,
37 IgnoreMissing: options&IgnoreMissing != 0,
41 type FieldsMatcher struct {
42 // Matchers for each field.
45 // Whether to ignore extra elements or consider it an error.
47 // Whether to ignore missing elements or consider it an error.
54 // Field name to matcher.
55 type Fields map[string]types.GomegaMatcher
57 func (m *FieldsMatcher) Match(actual interface{}) (success bool, err error) {
58 if reflect.TypeOf(actual).Kind() != reflect.Struct {
59 return false, fmt.Errorf("%v is type %T, expected struct", actual, actual)
62 m.failures = m.matchFields(actual)
63 if len(m.failures) > 0 {
69 func (m *FieldsMatcher) matchFields(actual interface{}) (errs []error) {
70 val := reflect.ValueOf(actual)
72 fields := map[string]bool{}
73 for i := 0; i < val.NumField(); i++ {
74 fieldName := typ.Field(i).Name
75 fields[fieldName] = true
77 err := func() (err error) {
78 // This test relies heavily on reflect, which tends to panic.
79 // Recover here to provide more useful error messages in that case.
81 if r := recover(); r != nil {
82 err = fmt.Errorf("panic checking %+v: %v\n%s", actual, r, debug.Stack())
86 matcher, expected := m.Fields[fieldName]
89 return fmt.Errorf("unexpected field %s: %+v", fieldName, actual)
95 if val.Field(i).IsValid() {
96 field = val.Field(i).Interface()
98 field = reflect.Zero(typ.Field(i).Type)
101 match, err := matcher.Match(field)
105 if nesting, ok := matcher.(errorsutil.NestingMatcher); ok {
106 return errorsutil.AggregateError(nesting.Failures())
108 return errors.New(matcher.FailureMessage(field))
113 errs = append(errs, errorsutil.Nest("."+fieldName, err))
117 for field := range m.Fields {
118 if !fields[field] && !m.IgnoreMissing {
119 errs = append(errs, fmt.Errorf("missing expected field %s", field))
126 func (m *FieldsMatcher) FailureMessage(actual interface{}) (message string) {
127 failures := make([]string, len(m.failures))
128 for i := range m.failures {
129 failures[i] = m.failures[i].Error()
131 return format.Message(reflect.TypeOf(actual).Name(),
132 fmt.Sprintf("to match fields: {\n%v\n}\n", strings.Join(failures, "\n")))
135 func (m *FieldsMatcher) NegatedFailureMessage(actual interface{}) (message string) {
136 return format.Message(actual, "not to match fields")
139 func (m *FieldsMatcher) Failures() []error {