podman

Форк
0
126 строк · 2.9 Кб
1
// untested sections: 6
2

3
package gstruct
4

5
import (
6
	"errors"
7
	"fmt"
8
	"reflect"
9
	"runtime/debug"
10
	"strings"
11

12
	"github.com/onsi/gomega/format"
13
	errorsutil "github.com/onsi/gomega/gstruct/errors"
14
	"github.com/onsi/gomega/types"
15
)
16

17
func MatchAllKeys(keys Keys) types.GomegaMatcher {
18
	return &KeysMatcher{
19
		Keys: keys,
20
	}
21
}
22

23
func MatchKeys(options Options, keys Keys) types.GomegaMatcher {
24
	return &KeysMatcher{
25
		Keys:          keys,
26
		IgnoreExtras:  options&IgnoreExtras != 0,
27
		IgnoreMissing: options&IgnoreMissing != 0,
28
	}
29
}
30

31
type KeysMatcher struct {
32
	// Matchers for each key.
33
	Keys Keys
34

35
	// Whether to ignore extra keys or consider it an error.
36
	IgnoreExtras bool
37
	// Whether to ignore missing keys or consider it an error.
38
	IgnoreMissing bool
39

40
	// State.
41
	failures []error
42
}
43

44
type Keys map[interface{}]types.GomegaMatcher
45

46
func (m *KeysMatcher) Match(actual interface{}) (success bool, err error) {
47
	if reflect.TypeOf(actual).Kind() != reflect.Map {
48
		return false, fmt.Errorf("%v is type %T, expected map", actual, actual)
49
	}
50

51
	m.failures = m.matchKeys(actual)
52
	if len(m.failures) > 0 {
53
		return false, nil
54
	}
55
	return true, nil
56
}
57

58
func (m *KeysMatcher) matchKeys(actual interface{}) (errs []error) {
59
	actualValue := reflect.ValueOf(actual)
60
	keys := map[interface{}]bool{}
61
	for _, keyValue := range actualValue.MapKeys() {
62
		key := keyValue.Interface()
63
		keys[key] = true
64

65
		err := func() (err error) {
66
			// This test relies heavily on reflect, which tends to panic.
67
			// Recover here to provide more useful error messages in that case.
68
			defer func() {
69
				if r := recover(); r != nil {
70
					err = fmt.Errorf("panic checking %+v: %v\n%s", actual, r, debug.Stack())
71
				}
72
			}()
73

74
			matcher, ok := m.Keys[key]
75
			if !ok {
76
				if !m.IgnoreExtras {
77
					return fmt.Errorf("unexpected key %s: %+v", key, actual)
78
				}
79
				return nil
80
			}
81

82
			valInterface := actualValue.MapIndex(keyValue).Interface()
83

84
			match, err := matcher.Match(valInterface)
85
			if err != nil {
86
				return err
87
			}
88

89
			if !match {
90
				if nesting, ok := matcher.(errorsutil.NestingMatcher); ok {
91
					return errorsutil.AggregateError(nesting.Failures())
92
				}
93
				return errors.New(matcher.FailureMessage(valInterface))
94
			}
95
			return nil
96
		}()
97
		if err != nil {
98
			errs = append(errs, errorsutil.Nest(fmt.Sprintf(".%#v", key), err))
99
		}
100
	}
101

102
	for key := range m.Keys {
103
		if !keys[key] && !m.IgnoreMissing {
104
			errs = append(errs, fmt.Errorf("missing expected key %s", key))
105
		}
106
	}
107

108
	return errs
109
}
110

111
func (m *KeysMatcher) FailureMessage(actual interface{}) (message string) {
112
	failures := make([]string, len(m.failures))
113
	for i := range m.failures {
114
		failures[i] = m.failures[i].Error()
115
	}
116
	return format.Message(reflect.TypeOf(actual).Name(),
117
		fmt.Sprintf("to match keys: {\n%v\n}\n", strings.Join(failures, "\n")))
118
}
119

120
func (m *KeysMatcher) NegatedFailureMessage(actual interface{}) (message string) {
121
	return format.Message(actual, "not to match keys")
122
}
123

124
func (m *KeysMatcher) Failures() []error {
125
	return m.failures
126
}
127

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.