Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/onsi/gomega/matchers/have_field.go
2880 views
1
package matchers
2
3
import (
4
"fmt"
5
"reflect"
6
"strings"
7
8
"github.com/onsi/gomega/format"
9
)
10
11
// missingFieldError represents a missing field extraction error that
12
// HaveExistingFieldMatcher can ignore, as opposed to other, sever field
13
// extraction errors, such as nil pointers, et cetera.
14
type missingFieldError string
15
16
func (e missingFieldError) Error() string {
17
return string(e)
18
}
19
20
func extractField(actual any, field string, matchername string) (any, error) {
21
fields := strings.SplitN(field, ".", 2)
22
actualValue := reflect.ValueOf(actual)
23
24
if actualValue.Kind() == reflect.Ptr {
25
actualValue = actualValue.Elem()
26
}
27
if actualValue == (reflect.Value{}) {
28
return nil, fmt.Errorf("%s encountered nil while dereferencing a pointer of type %T.", matchername, actual)
29
}
30
31
if actualValue.Kind() != reflect.Struct {
32
return nil, fmt.Errorf("%s encountered:\n%s\nWhich is not a struct.", matchername, format.Object(actual, 1))
33
}
34
35
var extractedValue reflect.Value
36
37
if strings.HasSuffix(fields[0], "()") {
38
extractedValue = actualValue.MethodByName(strings.TrimSuffix(fields[0], "()"))
39
if extractedValue == (reflect.Value{}) && actualValue.CanAddr() {
40
extractedValue = actualValue.Addr().MethodByName(strings.TrimSuffix(fields[0], "()"))
41
}
42
if extractedValue == (reflect.Value{}) {
43
ptr := reflect.New(actualValue.Type())
44
ptr.Elem().Set(actualValue)
45
extractedValue = ptr.MethodByName(strings.TrimSuffix(fields[0], "()"))
46
if extractedValue == (reflect.Value{}) {
47
return nil, missingFieldError(fmt.Sprintf("%s could not find method named '%s' in struct of type %T.", matchername, fields[0], actual))
48
}
49
}
50
t := extractedValue.Type()
51
if t.NumIn() != 0 || t.NumOut() != 1 {
52
return nil, fmt.Errorf("%s found an invalid method named '%s' in struct of type %T.\nMethods must take no arguments and return exactly one value.", matchername, fields[0], actual)
53
}
54
extractedValue = extractedValue.Call([]reflect.Value{})[0]
55
} else {
56
extractedValue = actualValue.FieldByName(fields[0])
57
if extractedValue == (reflect.Value{}) {
58
return nil, missingFieldError(fmt.Sprintf("%s could not find field named '%s' in struct:\n%s", matchername, fields[0], format.Object(actual, 1)))
59
}
60
}
61
62
if len(fields) == 1 {
63
return extractedValue.Interface(), nil
64
} else {
65
return extractField(extractedValue.Interface(), fields[1], matchername)
66
}
67
}
68
69
type HaveFieldMatcher struct {
70
Field string
71
Expected any
72
}
73
74
func (matcher *HaveFieldMatcher) expectedMatcher() omegaMatcher {
75
var isMatcher bool
76
expectedMatcher, isMatcher := matcher.Expected.(omegaMatcher)
77
if !isMatcher {
78
expectedMatcher = &EqualMatcher{Expected: matcher.Expected}
79
}
80
return expectedMatcher
81
}
82
83
func (matcher *HaveFieldMatcher) Match(actual any) (success bool, err error) {
84
extractedField, err := extractField(actual, matcher.Field, "HaveField")
85
if err != nil {
86
return false, err
87
}
88
89
return matcher.expectedMatcher().Match(extractedField)
90
}
91
92
func (matcher *HaveFieldMatcher) FailureMessage(actual any) (message string) {
93
extractedField, err := extractField(actual, matcher.Field, "HaveField")
94
if err != nil {
95
// this really shouldn't happen
96
return fmt.Sprintf("Failed to extract field '%s': %s", matcher.Field, err)
97
}
98
message = fmt.Sprintf("Value for field '%s' failed to satisfy matcher.\n", matcher.Field)
99
message += matcher.expectedMatcher().FailureMessage(extractedField)
100
101
return message
102
}
103
104
func (matcher *HaveFieldMatcher) NegatedFailureMessage(actual any) (message string) {
105
extractedField, err := extractField(actual, matcher.Field, "HaveField")
106
if err != nil {
107
// this really shouldn't happen
108
return fmt.Sprintf("Failed to extract field '%s': %s", matcher.Field, err)
109
}
110
message = fmt.Sprintf("Value for field '%s' satisfied matcher, but should not have.\n", matcher.Field)
111
message += matcher.expectedMatcher().NegatedFailureMessage(extractedField)
112
113
return message
114
}
115
116