1 package internal
2
3 import (
4 "fmt"
5 "reflect"
6
7 "github.com/onsi/gomega/format"
8 "github.com/onsi/gomega/types"
9 )
10
11 type Assertion struct {
12 actuals []interface{}
13 actualIndex int
14 vet vetinari
15 offset int
16 g *Gomega
17 }
18
19
20 type vetinari func(assertion *Assertion, optionalDescription ...interface{}) bool
21
22 func NewAssertion(actualInput interface{}, g *Gomega, offset int, extra ...interface{}) *Assertion {
23 return &Assertion{
24 actuals: append([]interface{}{actualInput}, extra...),
25 actualIndex: 0,
26 vet: (*Assertion).vetActuals,
27 offset: offset,
28 g: g,
29 }
30 }
31
32 func (assertion *Assertion) WithOffset(offset int) types.Assertion {
33 assertion.offset = offset
34 return assertion
35 }
36
37 func (assertion *Assertion) Error() types.Assertion {
38 return &Assertion{
39 actuals: assertion.actuals,
40 actualIndex: len(assertion.actuals) - 1,
41 vet: (*Assertion).vetError,
42 offset: assertion.offset,
43 g: assertion.g,
44 }
45 }
46
47 func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
48 assertion.g.THelper()
49 vetOptionalDescription("Assertion", optionalDescription...)
50 return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
51 }
52
53 func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
54 assertion.g.THelper()
55 vetOptionalDescription("Assertion", optionalDescription...)
56 return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
57 }
58
59 func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
60 assertion.g.THelper()
61 vetOptionalDescription("Assertion", optionalDescription...)
62 return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
63 }
64
65 func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
66 assertion.g.THelper()
67 vetOptionalDescription("Assertion", optionalDescription...)
68 return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
69 }
70
71 func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
72 assertion.g.THelper()
73 vetOptionalDescription("Assertion", optionalDescription...)
74 return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
75 }
76
77 func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string {
78 switch len(optionalDescription) {
79 case 0:
80 return ""
81 case 1:
82 if describe, ok := optionalDescription[0].(func() string); ok {
83 return describe() + "\n"
84 }
85 }
86 return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
87 }
88
89 func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
90 actualInput := assertion.actuals[assertion.actualIndex]
91 matches, err := matcher.Match(actualInput)
92 assertion.g.THelper()
93 if err != nil {
94 description := assertion.buildDescription(optionalDescription...)
95 assertion.g.Fail(description+err.Error(), 2+assertion.offset)
96 return false
97 }
98 if matches != desiredMatch {
99 var message string
100 if desiredMatch {
101 message = matcher.FailureMessage(actualInput)
102 } else {
103 message = matcher.NegatedFailureMessage(actualInput)
104 }
105 description := assertion.buildDescription(optionalDescription...)
106 assertion.g.Fail(description+message, 2+assertion.offset)
107 return false
108 }
109
110 return true
111 }
112
113
114
115
116 func (assertion *Assertion) vetActuals(optionalDescription ...interface{}) bool {
117 success, message := vetActuals(assertion.actuals, assertion.actualIndex)
118 if success {
119 return true
120 }
121
122 description := assertion.buildDescription(optionalDescription...)
123 assertion.g.THelper()
124 assertion.g.Fail(description+message, 2+assertion.offset)
125 return false
126 }
127
128
129
130
131
132 func (assertion *Assertion) vetError(optionalDescription ...interface{}) bool {
133 if err := assertion.actuals[assertion.actualIndex]; err != nil {
134
135 return assertion.vetActuals(optionalDescription...)
136 }
137 return true
138 }
139
140
141
142 func vetActuals(actuals []interface{}, skipIndex int) (bool, string) {
143 for i, actual := range actuals {
144 if i == skipIndex {
145 continue
146 }
147 if actual != nil {
148 zeroValue := reflect.Zero(reflect.TypeOf(actual)).Interface()
149 if !reflect.DeepEqual(zeroValue, actual) {
150 var message string
151 if err, ok := actual.(error); ok {
152 message = fmt.Sprintf("Unexpected error: %s\n%s", err, format.Object(err, 1))
153 } else {
154 message = fmt.Sprintf("Unexpected non-nil/non-zero argument at index %d:\n\t<%T>: %#v", i, actual, actual)
155 }
156 return false, message
157 }
158 }
159 }
160 return true, ""
161 }
162
View as plain text