-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathcontext.go
More file actions
183 lines (159 loc) · 5.34 KB
/
context.go
File metadata and controls
183 lines (159 loc) · 5.34 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
package echotest
import (
"bytes"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/labstack/echo/v5"
)
// ContextConfig is configuration for creating echo.Context for testing purposes.
type ContextConfig struct {
// Request will be used instead of default `httptest.NewRequest(http.MethodGet, "/", nil)`
Request *http.Request
// Response will be used instead of default `httptest.NewRecorder()`
Response *httptest.ResponseRecorder
// QueryValues wil be set as Request.URL.RawQuery value
QueryValues url.Values
// Headers wil be set as Request.Header value
Headers http.Header
// PathValues initializes context.PathValues with given value.
PathValues echo.PathValues
// RouteInfo initializes context.RouteInfo() with given value
RouteInfo *echo.RouteInfo
// FormValues creates form-urlencoded form out of given values. If there is no
// `content-type` header it will be set to `application/x-www-form-urlencoded`
// In case Request was not set the Request.Method is set to `POST`
//
// FormValues, MultipartForm and JSONBody are mutually exclusive.
FormValues url.Values
// MultipartForm creates multipart form out of given value. If there is no
// `content-type` header it will be set to `multipart/form-data`
// In case Request was not set the Request.Method is set to `POST`
//
// FormValues, MultipartForm and JSONBody are mutually exclusive.
MultipartForm *MultipartForm
// JSONBody creates JSON body out of given bytes. If there is no
// `content-type` header it will be set to `application/json`
// In case Request was not set the Request.Method is set to `POST`
//
// FormValues, MultipartForm and JSONBody are mutually exclusive.
JSONBody []byte
}
// MultipartForm is used to create multipart form out of given value
type MultipartForm struct {
Fields map[string]string
Files []MultipartFormFile
}
// MultipartFormFile is used to create file in multipart form out of given value
type MultipartFormFile struct {
Fieldname string
Filename string
Content []byte
}
// ToContext converts ContextConfig to echo.Context
func (conf ContextConfig) ToContext(t *testing.T) *echo.Context {
c, _ := conf.ToContextRecorder(t)
return c
}
// ToContextRecorder converts ContextConfig to echo.Context and httptest.ResponseRecorder
func (conf ContextConfig) ToContextRecorder(t *testing.T) (*echo.Context, *httptest.ResponseRecorder) {
if conf.Response == nil {
conf.Response = httptest.NewRecorder()
}
isDefaultRequest := false
if conf.Request == nil {
isDefaultRequest = true
conf.Request = httptest.NewRequest(http.MethodGet, "/", nil)
}
if len(conf.QueryValues) > 0 {
conf.Request.URL.RawQuery = conf.QueryValues.Encode()
}
if len(conf.Headers) > 0 {
conf.Request.Header = conf.Headers
}
if len(conf.FormValues) > 0 {
body := strings.NewReader(conf.FormValues.Encode())
conf.Request.Body = io.NopCloser(body)
conf.Request.ContentLength = int64(body.Len())
if conf.Request.Header.Get(echo.HeaderContentType) == "" {
conf.Request.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm)
}
if isDefaultRequest {
conf.Request.Method = http.MethodPost
}
} else if conf.MultipartForm != nil {
var body bytes.Buffer
mw := multipart.NewWriter(&body)
for field, value := range conf.MultipartForm.Fields {
if err := mw.WriteField(field, value); err != nil {
t.Fatal(err)
}
}
for _, file := range conf.MultipartForm.Files {
fw, err := mw.CreateFormFile(file.Fieldname, file.Filename)
if err != nil {
t.Fatal(err)
}
if _, err = fw.Write(file.Content); err != nil {
t.Fatal(err)
}
}
if err := mw.Close(); err != nil {
t.Fatal(err)
}
conf.Request.Body = io.NopCloser(&body)
conf.Request.ContentLength = int64(body.Len())
if conf.Request.Header.Get(echo.HeaderContentType) == "" {
conf.Request.Header.Set(echo.HeaderContentType, mw.FormDataContentType())
}
if isDefaultRequest {
conf.Request.Method = http.MethodPost
}
} else if conf.JSONBody != nil {
body := bytes.NewReader(conf.JSONBody)
conf.Request.Body = io.NopCloser(body)
conf.Request.ContentLength = int64(body.Len())
if conf.Request.Header.Get(echo.HeaderContentType) == "" {
conf.Request.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
}
if isDefaultRequest {
conf.Request.Method = http.MethodPost
}
}
ec := echo.NewContext(conf.Request, conf.Response, echo.New())
if conf.RouteInfo == nil {
conf.RouteInfo = &echo.RouteInfo{
Name: "",
Method: conf.Request.Method,
Path: "/test",
Parameters: []string{},
}
for _, p := range conf.PathValues {
conf.RouteInfo.Parameters = append(conf.RouteInfo.Parameters, p.Name)
}
}
ec.InitializeRoute(conf.RouteInfo, &conf.PathValues)
return ec, conf.Response
}
// ServeWithHandler serves ContextConfig with given handler and returns httptest.ResponseRecorder for response checking
func (conf ContextConfig) ServeWithHandler(t *testing.T, handler echo.HandlerFunc, opts ...any) *httptest.ResponseRecorder {
c, rec := conf.ToContextRecorder(t)
errHandler := echo.DefaultHTTPErrorHandler(false)
for _, opt := range opts {
switch o := opt.(type) {
case echo.HTTPErrorHandler:
errHandler = o
}
}
err := handler(c)
if err != nil {
errHandler(c, err)
}
return rec
}