Skip to content
This repository was archived by the owner on Mar 12, 2024. It is now read-only.

Commit 68a35f2

Browse files
committed
x
1 parent 2b2a6b8 commit 68a35f2

17 files changed

+1950
-0
lines changed

assert.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package httptest
2+
3+
import (
4+
"reflect"
5+
6+
"github.com/qiniu/x/jsonutil"
7+
)
8+
9+
// ---------------------------------------------------------------------------
10+
11+
func castFloat(v interface{}) (float64, bool) {
12+
13+
t := reflect.ValueOf(v)
14+
15+
kind := t.Kind()
16+
if kind < reflect.Int || kind > reflect.Float64 {
17+
return 0, false
18+
}
19+
20+
if kind <= reflect.Int64 {
21+
return float64(t.Int()), true
22+
}
23+
if kind <= reflect.Uintptr {
24+
return float64(t.Uint()), true
25+
}
26+
return t.Float(), true
27+
}
28+
29+
func Equal(v1, v2 interface{}) bool {
30+
31+
f1, ok1 := castFloat(v1)
32+
f2, ok2 := castFloat(v2)
33+
if ok1 != ok2 {
34+
return false
35+
}
36+
if ok1 && f1 == f2 {
37+
return true
38+
}
39+
return reflect.DeepEqual(v1, v2)
40+
}
41+
42+
func EqualSet(obj1, obj2 interface{}) bool {
43+
44+
var v interface{}
45+
if text, ok := obj1.(string); ok {
46+
err := jsonutil.Unmarshal(text, &v)
47+
if err != nil {
48+
return false
49+
}
50+
obj1 = v
51+
}
52+
53+
v1 := reflect.ValueOf(obj1)
54+
if v1.Kind() != reflect.Slice {
55+
return false
56+
}
57+
58+
if text, ok := obj2.(string); ok {
59+
err := jsonutil.Unmarshal(text, &v)
60+
if err != nil {
61+
return false
62+
}
63+
obj2 = v
64+
}
65+
66+
v2 := reflect.ValueOf(obj2)
67+
if v2.Kind() != reflect.Slice {
68+
return false
69+
}
70+
71+
if v1.Len() != v2.Len() {
72+
return false
73+
}
74+
for i := 0; i < v1.Len(); i++ {
75+
item1 := v1.Index(i)
76+
if !hasElem(item1.Interface(), v2) {
77+
return false
78+
}
79+
}
80+
return true
81+
}
82+
83+
func hasElem(item1 interface{}, v2 reflect.Value) bool {
84+
85+
for j := 0; j < v2.Len(); j++ {
86+
item2 := v2.Index(j)
87+
if Equal(item1, item2.Interface()) {
88+
return true
89+
}
90+
}
91+
return false
92+
}
93+
94+
// ---------------------------------------------------------------------------
95+
96+
type Var struct {
97+
Data interface{}
98+
Ok bool
99+
}
100+
101+
func (p Var) Equal(v interface{}) bool {
102+
103+
return p.Ok && Equal(p.Data, v)
104+
}
105+
106+
func (p Var) EqualObject(obj string) bool {
107+
108+
if !p.Ok {
109+
return false
110+
}
111+
112+
var v interface{}
113+
err := jsonutil.Unmarshal(obj, &v)
114+
if err != nil {
115+
return false
116+
}
117+
118+
return Equal(p.Data, v)
119+
}
120+
121+
func (p Var) EqualSet(obj interface{}) bool {
122+
123+
if !p.Ok {
124+
return false
125+
}
126+
return EqualSet(p.Data, obj)
127+
}
128+
129+
// ---------------------------------------------------------------------------

assert_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package httptest
2+
3+
import (
4+
"testing"
5+
)
6+
7+
// ---------------------------------------------------------------------------
8+
9+
func TestVar(t *testing.T) {
10+
11+
if !(Var{1, true}.EqualObject("1")) {
12+
t.Fatal("EqualObject failed")
13+
}
14+
15+
if !(Var{[]float64{1, 2}, true}.EqualSet("[2, 1]")) {
16+
t.Fatal("EqualSet failed")
17+
}
18+
19+
if (Var{[]float64{1, 2, 3}, true}.EqualSet("[2, 1]")) {
20+
t.Fatal("EqualSet failed")
21+
}
22+
}
23+
24+
// ---------------------------------------------------------------------------
25+

context.go

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
package httptest
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"strings"
8+
)
9+
10+
// ---------------------------------------------------------------------------
11+
12+
type TransportComposer interface {
13+
Compose(base http.RoundTripper) http.RoundTripper
14+
}
15+
16+
type Executor interface {
17+
Exec(ctx *Context, code string)
18+
}
19+
20+
// ---------------------------------------------------------------------------
21+
22+
func mimeType(ct string) string {
23+
24+
if ct == "form" {
25+
return "application/x-www-form-urlencoded"
26+
}
27+
if ct == "binary" {
28+
return "application/octet-stream"
29+
}
30+
if strings.Index(ct, "/") < 0 {
31+
return "application/" + ct
32+
}
33+
return ct
34+
}
35+
36+
// ---------------------------------------------------------------------------
37+
38+
type Request struct {
39+
method string
40+
url string
41+
auth TransportComposer
42+
ctx *Context
43+
header http.Header
44+
bodyType string
45+
body string
46+
}
47+
48+
func NewRequest(ctx *Context, method, url string) *Request {
49+
50+
ctx.DeleteVar("resp")
51+
52+
p := &Request{
53+
ctx: ctx,
54+
method: method,
55+
url: url,
56+
header: make(http.Header),
57+
}
58+
ctx.Log(" ====>", method, url)
59+
return p
60+
}
61+
62+
func (p *Request) WithAuth(v interface{}) *Request {
63+
64+
if v == nil {
65+
p.auth = nil
66+
return p
67+
}
68+
if name, ok := v.(string); ok {
69+
auth, ok := p.ctx.auths[name]
70+
if !ok {
71+
p.ctx.Fatal("WithAuth failed: auth not found -", name)
72+
}
73+
p.auth = auth
74+
return p
75+
}
76+
if auth, ok := v.(TransportComposer); ok {
77+
p.auth = auth
78+
return p
79+
}
80+
p.ctx.Fatal("WithAuth failed: invalid auth -", v)
81+
return p
82+
}
83+
84+
func (p *Request) WithHeader(key string, values ...string) *Request {
85+
86+
p.header[key] = values
87+
return p
88+
}
89+
90+
func (p *Request) WithBody(bodyType, body string) *Request {
91+
92+
p.bodyType = mimeType(bodyType)
93+
p.body = body
94+
return p
95+
}
96+
97+
func (p *Request) WithBodyf(bodyType, format string, v ...interface{}) *Request {
98+
99+
p.bodyType = mimeType(bodyType)
100+
p.body = fmt.Sprintf(format, v...)
101+
return p
102+
}
103+
104+
func mergeHeader(to, from http.Header) {
105+
106+
for k, v := range from {
107+
to[k] = v
108+
}
109+
}
110+
111+
func (p *Request) send() (resp *http.Response, err error) {
112+
113+
var body io.Reader
114+
if len(p.body) > 0 {
115+
body = strings.NewReader(p.body)
116+
}
117+
req, err := p.ctx.newRequest(p.method, p.url, body)
118+
if err != nil {
119+
p.ctx.Fatal("http.NewRequest failed:", p.method, p.url, p.body, err)
120+
return
121+
}
122+
123+
mergeHeader(req.Header, p.ctx.DefaultHeader)
124+
125+
if body != nil {
126+
if p.bodyType != "" {
127+
req.Header.Set("Content-Type", p.bodyType)
128+
}
129+
req.ContentLength = int64(len(p.body))
130+
}
131+
132+
mergeHeader(req.Header, p.header)
133+
134+
t := p.ctx.transport
135+
if p.auth != nil {
136+
t = p.auth.Compose(t)
137+
}
138+
139+
c := &http.Client{Transport: t}
140+
return c.Do(req)
141+
}
142+
143+
func (p *Request) Ret(code int) (resp *Response) {
144+
145+
resp1, err := p.send()
146+
resp = newResponse(p, resp1, err)
147+
p.ctx.MatchVar("resp", map[string]interface{}{
148+
"body": resp.BodyObj,
149+
"header": resp.Header,
150+
"code": float64(resp.StatusCode),
151+
})
152+
return resp.matchCode(code)
153+
}
154+
155+
// ---------------------------------------------------------------------------
156+
157+
type TestingT interface {
158+
Fatal(args ...interface{})
159+
Log(args ...interface{})
160+
}
161+
162+
type NilTestingT struct {}
163+
164+
func (p NilTestingT) Fatal(args ...interface{}) {}
165+
func (p NilTestingT) Log(args ...interface{}) {}
166+
167+
// ---------------------------------------------------------------------------
168+
169+
type Context struct {
170+
TestingT
171+
varsMgr
172+
hostsMgr
173+
transport http.RoundTripper
174+
auths map[string]TransportComposer
175+
DefaultHeader http.Header
176+
MatchResponseError func(message string, req *Request, resp *Response)
177+
}
178+
179+
func New(t TestingT) *Context {
180+
181+
auths := make(map[string]TransportComposer)
182+
p := &Context{
183+
TestingT: t,
184+
auths: auths,
185+
transport: http.DefaultTransport,
186+
DefaultHeader: make(http.Header),
187+
MatchResponseError: matchRespError,
188+
}
189+
p.initHostsMgr()
190+
p.initVarsMgr()
191+
return p
192+
}
193+
194+
func (p *Context) SetTransport(transport http.RoundTripper) {
195+
196+
p.transport = transport
197+
}
198+
199+
func (p *Context) SetAuth(name string, auth TransportComposer) {
200+
201+
p.auths[name] = auth
202+
}
203+
204+
func (p *Context) Exec(executor Executor, code string) *Context {
205+
206+
executor.Exec(p, code)
207+
return p
208+
}
209+
210+
func (p *Context) Request(method, url string) *Request {
211+
212+
return NewRequest(p, method, url)
213+
}
214+
215+
func (p *Context) Requestf(method, format string, v ...interface{}) *Request {
216+
217+
url := fmt.Sprintf(format, v...)
218+
return NewRequest(p, method, url)
219+
}
220+
221+
// ---------------------------------------------------------------------------
222+

0 commit comments

Comments
 (0)