-
Notifications
You must be signed in to change notification settings - Fork 0
/
expectation.go
145 lines (118 loc) · 3.25 KB
/
expectation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package hex
import (
"fmt"
"net/http"
"strings"
)
// Expectation captures details about an ExpectReq call and subsequent conditions
// chained to it.
type Expectation struct {
// Our parent expecter object
expecter *Expecter
parent *Expectation
children []*Expectation
method stringMatcher
path stringMatcher
quantifier *quantifier
matches []*http.Request
matchers []matcher
handler http.Handler
callThrough bool
}
type quantifier struct {
desc string
min, max, count uint
}
func (e *Expectation) String() string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "%s %s", e.method.String(), e.path.String())
if len(e.matchers) > 0 {
fmt.Fprintf(buf, " with ")
for _, m := range e.matchers {
fmt.Fprintf(buf, m.String())
}
}
if e.pass() {
fmt.Fprintf(buf, " - passed")
} else {
fmt.Fprintf(buf, " - failed, %s", e.failureReason())
}
return buf.String()
}
func (e *Expectation) failureReason() string {
if e.pass() {
panic("failureReason called for non-failing expectation")
}
if len(e.matches) == 0 {
return "no matching requests"
}
if e.quantifier != nil {
if e.quantifier.min == e.quantifier.max {
return fmt.Sprintf("expected %d matches, got %d", e.quantifier.min, e.quantifier.count)
}
return fmt.Sprintf("expected %d..%d matches, got %d", e.quantifier.min, e.quantifier.max, e.quantifier.count)
}
return ""
}
// Do opens a scope. Expectations in the current scope may be matched by requests in the current or nested scopes, but
// requests in higher scopes cannot fulfill expections in lower scopes.
//
// For example:
//
// expector.ExpectReq("POST", "/foo")
// expector.ExpectReq("GET", "/bar").Do(func() {
// // matches POST expectation in parent scope
// expector.LogReq(httptest.NewRequest("GET" "/foo", nil))
// })
//
// // Does NOT match GET expectation in previous scope
// expector.LogReq(httptest.NewRequest("GET" "/foo", nil)) // does not match
//
// The current expectation becomes the first expectation within the new scope
func (e *Expectation) Do(fn func()) {
e.expecter.do(fn)
}
func (e *Expectation) pass() bool {
if e.quantifier != nil {
return e.quantifier.count >= e.quantifier.min && e.quantifier.count <= e.quantifier.max
}
return len(e.matches) > 0
}
// Matches returns true if the expectation is fulfilled by the given http.Request
func (e *Expectation) matchAgainst(req *http.Request) bool {
// Baseline check against method and path
if !e.method.match(req.Method) || !e.path.match(req.URL.Path) {
return false
}
for _, c := range e.matchers {
if !c.matches(req) {
return false
}
}
e.matches = append(e.matches, req)
if e.quantifier != nil {
e.quantifier.count++
}
return true
}
// Quantification
func (e *Expectation) quantify(desc string, min, max uint) {
if e.quantifier != nil {
panic("A quantifier was added multiple times to the same expectations")
}
e.quantifier = &quantifier{
desc: desc,
min: min,
max: max,
}
}
// Never asserts that the expectation is matched zero times
func (e *Expectation) Never() *Expectation {
e.quantify("never", 0, 0)
return e
}
// Once adds a quantity condition that requires exactly one request to be matched
func (e *Expectation) Once() *Expectation {
e.quantify("once", 1, 1)
return e
}