Update go dependencies
This commit is contained in:
parent
f9624cbe46
commit
307bf76454
280 changed files with 54728 additions and 2991 deletions
9
vendor/gopkg.in/gavv/httpexpect.v2/.golangci.yml
generated
vendored
Normal file
9
vendor/gopkg.in/gavv/httpexpect.v2/.golangci.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
linters-settings:
|
||||
lll:
|
||||
line-length: 90
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- golint
|
||||
- lll
|
||||
- misspell
|
||||
17
vendor/gopkg.in/gavv/httpexpect.v2/.travis.yml
generated
vendored
Normal file
17
vendor/gopkg.in/gavv/httpexpect.v2/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
language: go
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
|
||||
script:
|
||||
- go get -v -t . ./_examples
|
||||
- go test -coverprofile profile.cov .
|
||||
- go test ./_examples
|
||||
- ${GOPATH}/bin/golangci-lint run ./...
|
||||
- ${GOPATH}/bin/goveralls -coverprofile profile.cov -service=travis-ci
|
||||
21
vendor/gopkg.in/gavv/httpexpect.v2/LICENSE
generated
vendored
Normal file
21
vendor/gopkg.in/gavv/httpexpect.v2/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Victor Gaydov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
13
vendor/gopkg.in/gavv/httpexpect.v2/Makefile
generated
vendored
Normal file
13
vendor/gopkg.in/gavv/httpexpect.v2/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
all: update test check
|
||||
|
||||
update:
|
||||
go get -u -t . ./_examples
|
||||
|
||||
test:
|
||||
go test . ./_examples
|
||||
|
||||
check:
|
||||
golangci-lint run ./...
|
||||
|
||||
fmt:
|
||||
gofmt -s -w . ./_examples
|
||||
503
vendor/gopkg.in/gavv/httpexpect.v2/README.md
generated
vendored
Normal file
503
vendor/gopkg.in/gavv/httpexpect.v2/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
# httpexpect [](https://godoc.org/github.com/gavv/httpexpect) [](https://gitter.im/gavv/httpexpect?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/gavv/httpexpect) [](https://coveralls.io/github/gavv/httpexpect?branch=master)
|
||||
|
||||
Concise, declarative, and easy to use end-to-end HTTP and REST API testing for Go (golang).
|
||||
|
||||
Basically, httpexpect is a set of chainable *builders* for HTTP requests and *assertions* for HTTP responses and payload, on top of net/http and several utility packages.
|
||||
|
||||
Workflow:
|
||||
|
||||
* Incrementally build HTTP requests.
|
||||
* Inspect HTTP responses.
|
||||
* Inspect response payload recursively.
|
||||
|
||||
## Features
|
||||
|
||||
##### Request builder
|
||||
|
||||
* URL path construction, with simple string interpolation provided by [`go-interpol`](https://github.com/imkira/go-interpol) package.
|
||||
* URL query parameters (encoding using [`go-querystring`](https://github.com/google/go-querystring) package).
|
||||
* Headers, cookies, payload: JSON, urlencoded or multipart forms (encoding using [`form`](https://github.com/ajg/form) package), plain text.
|
||||
* Custom reusable [request builders](#reusable-builders).
|
||||
|
||||
##### Response assertions
|
||||
|
||||
* Response status, predefined status ranges.
|
||||
* Headers, cookies, payload: JSON, JSONP, forms, text.
|
||||
* Round-trip time.
|
||||
* Custom reusable [response matchers](#reusable-matchers).
|
||||
|
||||
##### Payload assertions
|
||||
|
||||
* Type-specific assertions, supported types: object, array, string, number, boolean, null, datetime.
|
||||
* Regular expressions.
|
||||
* Simple JSON queries (using subset of [JSONPath](http://goessner.net/articles/JsonPath/)), provided by [`jsonpath`](https://github.com/yalp/jsonpath) package.
|
||||
* [JSON Schema](http://json-schema.org/) validation, provided by [`gojsonschema`](https://github.com/xeipuuv/gojsonschema) package.
|
||||
|
||||
##### WebSocket support (thanks to [@tyranron](https://github.com/tyranron))
|
||||
|
||||
* Upgrade an HTTP connection to a WebSocket connection (we use [`gorilla/websocket`](https://github.com/gorilla/websocket) internally).
|
||||
* Interact with the WebSocket server.
|
||||
* Inspect WebSocket connection parameters and WebSocket messages.
|
||||
|
||||
##### Pretty printing
|
||||
|
||||
* Verbose error messages.
|
||||
* JSON diff is produced on failure using [`gojsondiff`](https://github.com/yudai/gojsondiff/) package.
|
||||
* Failures are reported using [`testify`](https://github.com/stretchr/testify/) (`assert` or `require` package) or standard `testing` package.
|
||||
* Dumping requests and responses in various formats, using [`httputil`](https://golang.org/pkg/net/http/httputil/), [`http2curl`](https://github.com/moul/http2curl), or simple compact logger.
|
||||
|
||||
##### Tuning
|
||||
|
||||
* Tests can communicate with server via real HTTP client or invoke `net/http` or [`fasthttp`](https://github.com/valyala/fasthttp/) handler directly.
|
||||
* Custom HTTP client, logger, printer, and failure reporter may be provided by user.
|
||||
* Custom HTTP request factory may be provided, e.g. from the Google App Engine testing.
|
||||
|
||||
## Status
|
||||
|
||||
Stable branches are available on [`gopkg.in`](http://labix.org/gopkg.in) and will not introduce backward-incompatible changes.
|
||||
|
||||
Current stable branch is [`v2`](http://gopkg.in/gavv/httpexpect.v2):
|
||||
|
||||
```go
|
||||
import "gopkg.in/gavv/httpexpect.v2"
|
||||
```
|
||||
|
||||
Development is done in `master` branch on github:
|
||||
|
||||
```go
|
||||
import "github.com/gavv/httpexpect"
|
||||
```
|
||||
|
||||
When the master is merged into a stable branch, a new version tag is assigned to the branch head. The versions are selected according to the [semantic versioning](https://semver.org/) scheme.
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation is available on [GoDoc](https://godoc.org/github.com/gavv/httpexpect). It contains an overview and reference.
|
||||
|
||||
## Examples
|
||||
|
||||
See [`_examples`](_examples) directory for complete standalone examples.
|
||||
|
||||
* [`fruits_test.go`](_examples/fruits_test.go)
|
||||
|
||||
Testing a simple CRUD server made with bare `net/http`.
|
||||
|
||||
* [`iris_test.go`](_examples/iris_test.go)
|
||||
|
||||
Testing a server made with [`iris`](https://github.com/kataras/iris/) framework. Example includes JSON queries and validation, URL and form parameters, basic auth, sessions, and streaming. Tests invoke the `http.Handler` directly.
|
||||
|
||||
* [`echo_test.go`](_examples/echo_test.go)
|
||||
|
||||
Testing a server with JWT authentication made with [`echo`](https://github.com/labstack/echo/) framework. Tests use either HTTP client or invoke the `http.Handler` directly.
|
||||
|
||||
* [`fasthttp_test.go`](_examples/fasthttp_test.go)
|
||||
|
||||
Testing a server made with [`fasthttp`](https://github.com/valyala/fasthttp) package. Tests invoke the `fasthttp.RequestHandler` directly.
|
||||
|
||||
* [`websocket_test.go`](_examples/websocket_test.go)
|
||||
|
||||
Testing a WebSocket server based on [`gorilla/websocket`](https://github.com/gorilla/websocket). Tests invoke the `http.Handler` or `fasthttp.RequestHandler` directly.
|
||||
|
||||
* [`gae_test.go`](_examples/gae_test.go)
|
||||
|
||||
Testing a server running under the [Google App Engine](https://en.wikipedia.org/wiki/Google_App_Engine).
|
||||
|
||||
## Quick start
|
||||
|
||||
##### Hello, world!
|
||||
|
||||
```go
|
||||
package example
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gavv/httpexpect"
|
||||
)
|
||||
|
||||
func TestFruits(t *testing.T) {
|
||||
// create http.Handler
|
||||
handler := FruitsHandler()
|
||||
|
||||
// run server using httptest
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
// create httpexpect instance
|
||||
e := httpexpect.New(t, server.URL)
|
||||
|
||||
// is it working?
|
||||
e.GET("/fruits").
|
||||
Expect().
|
||||
Status(http.StatusOK).JSON().Array().Empty()
|
||||
}
|
||||
```
|
||||
|
||||
##### JSON
|
||||
|
||||
```go
|
||||
orange := map[string]interface{}{
|
||||
"weight": 100,
|
||||
}
|
||||
|
||||
e.PUT("/fruits/orange").WithJSON(orange).
|
||||
Expect().
|
||||
Status(http.StatusNoContent).NoContent()
|
||||
|
||||
e.GET("/fruits/orange").
|
||||
Expect().
|
||||
Status(http.StatusOK).
|
||||
JSON().Object().ContainsKey("weight").ValueEqual("weight", 100)
|
||||
|
||||
apple := map[string]interface{}{
|
||||
"colors": []interface{}{"green", "red"},
|
||||
"weight": 200,
|
||||
}
|
||||
|
||||
e.PUT("/fruits/apple").WithJSON(apple).
|
||||
Expect().
|
||||
Status(http.StatusNoContent).NoContent()
|
||||
|
||||
obj := e.GET("/fruits/apple").
|
||||
Expect().
|
||||
Status(http.StatusOK).JSON().Object()
|
||||
|
||||
obj.Keys().ContainsOnly("colors", "weight")
|
||||
|
||||
obj.Value("colors").Array().Elements("green", "red")
|
||||
obj.Value("colors").Array().Element(0).String().Equal("green")
|
||||
obj.Value("colors").Array().Element(1).String().Equal("red")
|
||||
obj.Value("colors").Array().First().String().Equal("green")
|
||||
obj.Value("colors").Array().Last().String().Equal("red")
|
||||
```
|
||||
|
||||
##### JSON Schema and JSON Path
|
||||
|
||||
```go
|
||||
schema := `{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
...
|
||||
"private": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
repos := e.GET("/repos/octocat").
|
||||
Expect().
|
||||
Status(http.StatusOK).JSON()
|
||||
|
||||
// validate JSON schema
|
||||
repos.Schema(schema)
|
||||
|
||||
// run JSONPath query and iterate results
|
||||
for _, private := range repos.Path("$..private").Array().Iter() {
|
||||
private.Boolean().False()
|
||||
}
|
||||
```
|
||||
|
||||
##### Forms
|
||||
|
||||
```go
|
||||
// post form encoded from struct or map
|
||||
e.POST("/form").WithForm(structOrMap).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
// set individual fields
|
||||
e.POST("/form").WithFormField("foo", "hello").WithFormField("bar", 123).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
// multipart form
|
||||
e.POST("/form").WithMultipart().
|
||||
WithFile("avatar", "./john.png").WithFormField("username", "john").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
```
|
||||
|
||||
##### URL construction
|
||||
|
||||
```go
|
||||
// construct path using ordered parameters
|
||||
e.GET("/repos/{user}/{repo}", "octocat", "hello-world").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
// construct path using named parameters
|
||||
e.GET("/repos/{user}/{repo}").
|
||||
WithPath("user", "octocat").WithPath("repo", "hello-world").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
// set query parameters
|
||||
e.GET("/repos/{user}", "octocat").WithQuery("sort", "asc").
|
||||
Expect().
|
||||
Status(http.StatusOK) // "/repos/octocat?sort=asc"
|
||||
```
|
||||
|
||||
##### Headers
|
||||
|
||||
```go
|
||||
// set If-Match
|
||||
e.POST("/users/john").WithHeader("If-Match", etag).WithJSON(john).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
// check ETag
|
||||
e.GET("/users/john").
|
||||
Expect().
|
||||
Status(http.StatusOK).Header("ETag").NotEmpty()
|
||||
|
||||
// check Date
|
||||
t := time.Now()
|
||||
|
||||
e.GET("/users/john").
|
||||
Expect().
|
||||
Status(http.StatusOK).Header("Date").DateTime().InRange(t, time.Now())
|
||||
```
|
||||
|
||||
##### Cookies
|
||||
|
||||
```go
|
||||
// set cookie
|
||||
t := time.Now()
|
||||
|
||||
e.POST("/users/john").WithCookie("session", sessionID).WithJSON(john).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
// check cookies
|
||||
c := e.GET("/users/john").
|
||||
Expect().
|
||||
Status(http.StatusOK).Cookie("session")
|
||||
|
||||
c.Value().Equal(sessionID)
|
||||
c.Domain().Equal("example.com")
|
||||
c.Path().Equal("/")
|
||||
c.Expires().InRange(t, t.Add(time.Hour * 24))
|
||||
```
|
||||
|
||||
##### Regular expressions
|
||||
|
||||
```go
|
||||
// simple match
|
||||
e.GET("/users/john").
|
||||
Expect().
|
||||
Header("Location").
|
||||
Match("http://(.+)/users/(.+)").Values("example.com", "john")
|
||||
|
||||
// check capture groups by index or name
|
||||
m := e.GET("/users/john").
|
||||
Expect().
|
||||
Header("Location").Match("http://(?P<host>.+)/users/(?P<user>.+)")
|
||||
|
||||
m.Index(0).Equal("http://example.com/users/john")
|
||||
m.Index(1).Equal("example.com")
|
||||
m.Index(2).Equal("john")
|
||||
|
||||
m.Name("host").Equal("example.com")
|
||||
m.Name("user").Equal("john")
|
||||
```
|
||||
|
||||
##### Subdomains and per-request URL
|
||||
|
||||
```go
|
||||
e.GET("/path").WithURL("http://example.com").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
e.GET("/path").WithURL("http://subdomain.example.com").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
```
|
||||
|
||||
##### WebSocket support
|
||||
|
||||
```go
|
||||
ws := e.GET("/mysocket").WithWebsocketUpgrade().
|
||||
Expect().
|
||||
Status(http.StatusSwitchingProtocols).
|
||||
Websocket()
|
||||
defer ws.Disconnect()
|
||||
|
||||
ws.WriteText("some request").
|
||||
Expect().
|
||||
TextMessage().Body().Equal("some response")
|
||||
|
||||
ws.CloseWithText("bye").
|
||||
Expect().
|
||||
CloseMessage().NoContent()
|
||||
```
|
||||
|
||||
##### Reusable builders
|
||||
|
||||
```go
|
||||
e := httpexpect.New(t, "http://example.com")
|
||||
|
||||
r := e.POST("/login").WithForm(Login{"ford", "betelgeuse7"}).
|
||||
Expect().
|
||||
Status(http.StatusOK).JSON().Object()
|
||||
|
||||
token := r.Value("token").String().Raw()
|
||||
|
||||
auth := e.Builder(func (req *httpexpect.Request) {
|
||||
req.WithHeader("Authorization", "Bearer "+token)
|
||||
})
|
||||
|
||||
auth.GET("/restricted").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
e.GET("/restricted").
|
||||
Expect().
|
||||
Status(http.StatusUnauthorized)
|
||||
```
|
||||
|
||||
##### Reusable matchers
|
||||
|
||||
```go
|
||||
e := httpexpect.New(t, "http://example.com")
|
||||
|
||||
// every response should have this header
|
||||
m := e.Matcher(func (resp *httpexpect.Response) {
|
||||
resp.Header("API-Version").NotEmpty()
|
||||
})
|
||||
|
||||
m.GET("/some-path").
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
m.GET("/bad-path").
|
||||
Expect().
|
||||
Status(http.StatusNotFound)
|
||||
```
|
||||
|
||||
##### Custom config
|
||||
|
||||
```go
|
||||
e := httpexpect.WithConfig(httpexpect.Config{
|
||||
// prepend this url to all requests
|
||||
BaseURL: "http://example.com",
|
||||
|
||||
// use http.Client with a cookie jar and timeout
|
||||
Client: &http.Client{
|
||||
Jar: httpexpect.NewJar(),
|
||||
Timeout: time.Second * 30,
|
||||
},
|
||||
|
||||
// use fatal failures
|
||||
Reporter: httpexpect.NewRequireReporter(t),
|
||||
|
||||
// use verbose logging
|
||||
Printers: []httpexpect.Printer{
|
||||
httpexpect.NewCurlPrinter(t),
|
||||
httpexpect.NewDebugPrinter(t, true),
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
##### Session support
|
||||
|
||||
```go
|
||||
// cookie jar is used to store cookies from server
|
||||
e := httpexpect.WithConfig(httpexpect.Config{
|
||||
Reporter: httpexpect.NewAssertReporter(t),
|
||||
Client: &http.Client{
|
||||
Jar: httpexpect.NewJar(), // used by default if Client is nil
|
||||
},
|
||||
})
|
||||
|
||||
// cookies are disabled
|
||||
e := httpexpect.WithConfig(httpexpect.Config{
|
||||
Reporter: httpexpect.NewAssertReporter(t),
|
||||
Client: &http.Client{
|
||||
Jar: nil,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
##### Use HTTP handler directly
|
||||
|
||||
```go
|
||||
// invoke http.Handler directly using httpexpect.Binder
|
||||
var handler http.Handler = MyHandler()
|
||||
|
||||
e := httpexpect.WithConfig(httpexpect.Config{
|
||||
Reporter: httpexpect.NewAssertReporter(t),
|
||||
Client: &http.Client{
|
||||
Transport: httpexpect.NewBinder(handler),
|
||||
Jar: httpexpect.NewJar(),
|
||||
},
|
||||
})
|
||||
|
||||
// invoke fasthttp.RequestHandler directly using httpexpect.FastBinder
|
||||
var handler fasthttp.RequestHandler = myHandler()
|
||||
|
||||
e := httpexpect.WithConfig(httpexpect.Config{
|
||||
Reporter: httpexpect.NewAssertReporter(t),
|
||||
Client: &http.Client{
|
||||
Transport: httpexpect.NewFastBinder(handler),
|
||||
Jar: httpexpect.NewJar(),
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
##### Per-request client or handler
|
||||
|
||||
```go
|
||||
e := httpexpect.New(t, server.URL)
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
DisableCompression: true,
|
||||
},
|
||||
}
|
||||
|
||||
// overwrite client
|
||||
e.GET("/path").WithClient(client).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
// construct client that invokes a handler directly and overwrite client
|
||||
e.GET("/path").WithHandler(handler).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
```
|
||||
|
||||
## Similar packages
|
||||
|
||||
* [`gorequest`](https://github.com/parnurzeal/gorequest)
|
||||
* [`baloo`](https://github.com/h2non/baloo)
|
||||
* [`gofight`](https://github.com/appleboy/gofight)
|
||||
* [`frisby`](https://github.com/verdverm/frisby)
|
||||
* [`forest`](https://github.com/emicklei/forest)
|
||||
* [`restit`](https://github.com/go-restit/restit)
|
||||
* [`http-test`](https://github.com/vsco/http-test)
|
||||
* [`go-json-rest`](https://github.com/ant0ine/go-json-rest)
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to report bugs, suggest improvements, and send pull requests! Please add documentation and tests for new features.
|
||||
|
||||
Update dependencies, build code, and run tests and linters:
|
||||
|
||||
```
|
||||
$ make
|
||||
```
|
||||
|
||||
Format code:
|
||||
|
||||
```
|
||||
$ make fmt
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
299
vendor/gopkg.in/gavv/httpexpect.v2/array.go
generated
vendored
Normal file
299
vendor/gopkg.in/gavv/httpexpect.v2/array.go
generated
vendored
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Array provides methods to inspect attached []interface{} object
|
||||
// (Go representation of JSON array).
|
||||
type Array struct {
|
||||
chain chain
|
||||
value []interface{}
|
||||
}
|
||||
|
||||
// NewArray returns a new Array given a reporter used to report failures
|
||||
// and value to be inspected.
|
||||
//
|
||||
// Both reporter and value should not be nil. If value is nil, failure is
|
||||
// reported.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
func NewArray(reporter Reporter, value []interface{}) *Array {
|
||||
chain := makeChain(reporter)
|
||||
if value == nil {
|
||||
chain.fail("expected non-nil array value")
|
||||
} else {
|
||||
value, _ = canonArray(&chain, value)
|
||||
}
|
||||
return &Array{chain, value}
|
||||
}
|
||||
|
||||
// Raw returns underlying value attached to Array.
|
||||
// This is the value originally passed to NewArray, converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// assert.Equal(t, []interface{}{"foo", 123.0}, array.Raw())
|
||||
func (a *Array) Raw() []interface{} {
|
||||
return a.value
|
||||
}
|
||||
|
||||
// Path is similar to Value.Path.
|
||||
func (a *Array) Path(path string) *Value {
|
||||
return getPath(&a.chain, a.value, path)
|
||||
}
|
||||
|
||||
// Schema is similar to Value.Schema.
|
||||
func (a *Array) Schema(schema interface{}) *Array {
|
||||
checkSchema(&a.chain, a.value, schema)
|
||||
return a
|
||||
}
|
||||
|
||||
// Length returns a new Number object that may be used to inspect array length.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{1, 2, 3})
|
||||
// array.Length().Equal(3)
|
||||
func (a *Array) Length() *Number {
|
||||
return &Number{a.chain, float64(len(a.value))}
|
||||
}
|
||||
|
||||
// Element returns a new Value object that may be used to inspect array element
|
||||
// for given index.
|
||||
//
|
||||
// If index is out of array bounds, Element reports failure and returns empty
|
||||
// (but non-nil) value.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.Element(0).String().Equal("foo")
|
||||
// array.Element(1).Number().Equal(123)
|
||||
func (a *Array) Element(index int) *Value {
|
||||
if index < 0 || index >= len(a.value) {
|
||||
a.chain.fail(
|
||||
"\narray index out of bounds:\n index %d\n\n bounds [%d; %d)",
|
||||
index,
|
||||
0,
|
||||
len(a.value))
|
||||
return &Value{a.chain, nil}
|
||||
}
|
||||
return &Value{a.chain, a.value[index]}
|
||||
}
|
||||
|
||||
// First returns a new Value object that may be used to inspect first element
|
||||
// of given array.
|
||||
//
|
||||
// If given array is empty, First reports failure and returns empty
|
||||
// (but non-nil) value.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.First().String().Equal("foo")
|
||||
func (a *Array) First() *Value {
|
||||
if len(a.value) < 1 {
|
||||
a.chain.fail("\narray is empty")
|
||||
return &Value{a.chain, nil}
|
||||
}
|
||||
return &Value{a.chain, a.value[0]}
|
||||
}
|
||||
|
||||
// Last returns a new Value object that may be used to inspect last element
|
||||
// of given array.
|
||||
//
|
||||
// If given array is empty, Last reports failure and returns empty
|
||||
// (but non-nil) value.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.Last().Number().Equal(123)
|
||||
func (a *Array) Last() *Value {
|
||||
if len(a.value) < 1 {
|
||||
a.chain.fail("\narray is empty")
|
||||
return &Value{a.chain, nil}
|
||||
}
|
||||
return &Value{a.chain, a.value[len(a.value)-1]}
|
||||
}
|
||||
|
||||
// Iter returns a new slice of Values attached to array elements.
|
||||
//
|
||||
// Example:
|
||||
// strings := []interface{}{"foo", "bar"}
|
||||
// array := NewArray(t, strings)
|
||||
//
|
||||
// for n, val := range array.Iter() {
|
||||
// val.String().Equal(strings[n])
|
||||
// }
|
||||
func (a *Array) Iter() []Value {
|
||||
if a.chain.failed() {
|
||||
return []Value{}
|
||||
}
|
||||
ret := []Value{}
|
||||
for n := range a.value {
|
||||
ret = append(ret, Value{a.chain, a.value[n]})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Empty succeeds if array is empty.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{})
|
||||
// array.Empty()
|
||||
func (a *Array) Empty() *Array {
|
||||
return a.Equal([]interface{}{})
|
||||
}
|
||||
|
||||
// NotEmpty succeeds if array is non-empty.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.NotEmpty()
|
||||
func (a *Array) NotEmpty() *Array {
|
||||
return a.NotEqual([]interface{}{})
|
||||
}
|
||||
|
||||
// Equal succeeds if array is equal to given Go slice.
|
||||
// Before comparison, both array and value are converted to canonical form.
|
||||
//
|
||||
// value should be a slice of any type.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.Equal([]interface{}{"foo", 123})
|
||||
//
|
||||
// array := NewArray(t, []interface{}{"foo", "bar"})
|
||||
// array.Equal([]string{}{"foo", "bar"})
|
||||
//
|
||||
// array := NewArray(t, []interface{}{123, 456})
|
||||
// array.Equal([]int{}{123, 456})
|
||||
func (a *Array) Equal(value interface{}) *Array {
|
||||
expected, ok := canonArray(&a.chain, value)
|
||||
if !ok {
|
||||
return a
|
||||
}
|
||||
if !reflect.DeepEqual(expected, a.value) {
|
||||
a.chain.fail("\nexpected array equal to:\n%s\n\nbut got:\n%s\n\ndiff:\n%s",
|
||||
dumpValue(expected),
|
||||
dumpValue(a.value),
|
||||
diffValues(expected, a.value))
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// NotEqual succeeds if array is not equal to given Go slice.
|
||||
// Before comparison, both array and value are converted to canonical form.
|
||||
//
|
||||
// value should be a slice of any type.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.NotEqual([]interface{}{123, "foo"})
|
||||
func (a *Array) NotEqual(value interface{}) *Array {
|
||||
expected, ok := canonArray(&a.chain, value)
|
||||
if !ok {
|
||||
return a
|
||||
}
|
||||
if reflect.DeepEqual(expected, a.value) {
|
||||
a.chain.fail("\nexpected array not equal to:\n%s",
|
||||
dumpValue(expected))
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Elements succeeds if array contains all given elements, in given order, and only
|
||||
// them. Before comparison, array and all elements are converted to canonical form.
|
||||
//
|
||||
// For partial or unordered comparison, see Contains and ContainsOnly.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.Elements("foo", 123)
|
||||
//
|
||||
// This calls are equivalent:
|
||||
// array.Elelems("a", "b")
|
||||
// array.Equal([]interface{}{"a", "b"})
|
||||
func (a *Array) Elements(values ...interface{}) *Array {
|
||||
return a.Equal(values)
|
||||
}
|
||||
|
||||
// Contains succeeds if array contains all given elements (in any order).
|
||||
// Before comparison, array and all elements are converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.Contains(123, "foo")
|
||||
func (a *Array) Contains(values ...interface{}) *Array {
|
||||
elements, ok := canonArray(&a.chain, values)
|
||||
if !ok {
|
||||
return a
|
||||
}
|
||||
for _, e := range elements {
|
||||
if !a.containsElement(e) {
|
||||
a.chain.fail("\nexpected array containing element:\n%s\n\nbut got:\n%s",
|
||||
dumpValue(e), dumpValue(a.value))
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// NotContains succeeds if array contains none of given elements.
|
||||
// Before comparison, array and all elements are converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.NotContains("bar") // success
|
||||
// array.NotContains("bar", "foo") // failure (array contains "foo")
|
||||
func (a *Array) NotContains(values ...interface{}) *Array {
|
||||
elements, ok := canonArray(&a.chain, values)
|
||||
if !ok {
|
||||
return a
|
||||
}
|
||||
for _, e := range elements {
|
||||
if a.containsElement(e) {
|
||||
a.chain.fail("\nexpected array not containing element:\n%s\n\nbut got:\n%s",
|
||||
dumpValue(e), dumpValue(a.value))
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ContainsOnly succeeds if array contains all given elements, in any order, and only
|
||||
// them. Before comparison, array and all elements are converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(t, []interface{}{"foo", 123})
|
||||
// array.ContainsOnly(123, "foo")
|
||||
//
|
||||
// This calls are equivalent:
|
||||
// array.ContainsOnly("a", "b")
|
||||
// array.ContainsOnly("b", "a")
|
||||
func (a *Array) ContainsOnly(values ...interface{}) *Array {
|
||||
elements, ok := canonArray(&a.chain, values)
|
||||
if !ok {
|
||||
return a
|
||||
}
|
||||
if len(elements) != len(a.value) {
|
||||
a.chain.fail("\nexpected array of length == %d:\n%s\n\n"+
|
||||
"but got array of length %d:\n%s",
|
||||
len(elements), dumpValue(elements),
|
||||
len(a.value), dumpValue(a.value))
|
||||
return a
|
||||
}
|
||||
for _, e := range elements {
|
||||
if !a.containsElement(e) {
|
||||
a.chain.fail("\nexpected array containing element:\n%s\n\nbut got:\n%s",
|
||||
dumpValue(e), dumpValue(a.value))
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Array) containsElement(expected interface{}) bool {
|
||||
for _, e := range a.value {
|
||||
if reflect.DeepEqual(expected, e) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
218
vendor/gopkg.in/gavv/httpexpect.v2/binder.go
generated
vendored
Normal file
218
vendor/gopkg.in/gavv/httpexpect.v2/binder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// Binder implements networkless http.RoundTripper attached directly to
|
||||
// http.Handler.
|
||||
//
|
||||
// Binder emulates network communication by invoking given http.Handler
|
||||
// directly. It passes httptest.ResponseRecorder as http.ResponseWriter
|
||||
// to the handler, and then constructs http.Response from recorded data.
|
||||
type Binder struct {
|
||||
// HTTP handler invoked for every request.
|
||||
Handler http.Handler
|
||||
// TLS connection state used for https:// requests.
|
||||
TLS *tls.ConnectionState
|
||||
}
|
||||
|
||||
// NewBinder returns a new Binder given a http.Handler.
|
||||
//
|
||||
// Example:
|
||||
// client := &http.Client{
|
||||
// Transport: NewBinder(handler),
|
||||
// }
|
||||
func NewBinder(handler http.Handler) Binder {
|
||||
return Binder{Handler: handler}
|
||||
}
|
||||
|
||||
// RoundTrip implements http.RoundTripper.RoundTrip.
|
||||
func (binder Binder) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if req.Proto == "" {
|
||||
req.Proto = fmt.Sprintf("HTTP/%d.%d", req.ProtoMajor, req.ProtoMinor)
|
||||
}
|
||||
|
||||
if req.Body != nil {
|
||||
if req.ContentLength == -1 {
|
||||
req.TransferEncoding = []string{"chunked"}
|
||||
}
|
||||
} else {
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(nil))
|
||||
}
|
||||
|
||||
if req.URL != nil && req.URL.Scheme == "https" && binder.TLS != nil {
|
||||
req.TLS = binder.TLS
|
||||
}
|
||||
|
||||
if req.RequestURI == "" {
|
||||
req.RequestURI = req.URL.RequestURI()
|
||||
}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
binder.Handler.ServeHTTP(recorder, req)
|
||||
|
||||
resp := http.Response{
|
||||
Request: req,
|
||||
StatusCode: recorder.Code,
|
||||
Status: http.StatusText(recorder.Code),
|
||||
Header: recorder.Result().Header,
|
||||
}
|
||||
|
||||
if recorder.Flushed {
|
||||
resp.TransferEncoding = []string{"chunked"}
|
||||
}
|
||||
|
||||
if recorder.Body != nil {
|
||||
resp.Body = ioutil.NopCloser(recorder.Body)
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// FastBinder implements networkless http.RoundTripper attached directly
|
||||
// to fasthttp.RequestHandler.
|
||||
//
|
||||
// FastBinder emulates network communication by invoking given fasthttp.RequestHandler
|
||||
// directly. It converts http.Request to fasthttp.Request, invokes handler, and then
|
||||
// converts fasthttp.Response to http.Response.
|
||||
type FastBinder struct {
|
||||
// FastHTTP handler invoked for every request.
|
||||
Handler fasthttp.RequestHandler
|
||||
// TLS connection state used for https:// requests.
|
||||
TLS *tls.ConnectionState
|
||||
}
|
||||
|
||||
// NewFastBinder returns a new FastBinder given a fasthttp.RequestHandler.
|
||||
//
|
||||
// Example:
|
||||
// client := &http.Client{
|
||||
// Transport: NewFastBinder(fasthandler),
|
||||
// }
|
||||
func NewFastBinder(handler fasthttp.RequestHandler) FastBinder {
|
||||
return FastBinder{Handler: handler}
|
||||
}
|
||||
|
||||
// RoundTrip implements http.RoundTripper.RoundTrip.
|
||||
func (binder FastBinder) RoundTrip(stdreq *http.Request) (*http.Response, error) {
|
||||
fastreq := std2fast(stdreq)
|
||||
|
||||
var conn net.Conn
|
||||
if stdreq.URL != nil && stdreq.URL.Scheme == "https" && binder.TLS != nil {
|
||||
conn = connTLS{state: binder.TLS}
|
||||
} else {
|
||||
conn = connNonTLS{}
|
||||
}
|
||||
|
||||
ctx := fasthttp.RequestCtx{}
|
||||
ctx.Init2(conn, fastLogger{}, true)
|
||||
fastreq.CopyTo(&ctx.Request)
|
||||
|
||||
if stdreq.ContentLength >= 0 {
|
||||
ctx.Request.Header.SetContentLength(int(stdreq.ContentLength))
|
||||
} else {
|
||||
ctx.Request.Header.Add("Transfer-Encoding", "chunked")
|
||||
}
|
||||
|
||||
if stdreq.Body != nil {
|
||||
b, err := ioutil.ReadAll(stdreq.Body)
|
||||
if err == nil {
|
||||
ctx.Request.SetBody(b)
|
||||
}
|
||||
}
|
||||
|
||||
binder.Handler(&ctx)
|
||||
|
||||
return fast2std(stdreq, &ctx.Response), nil
|
||||
}
|
||||
|
||||
func std2fast(stdreq *http.Request) *fasthttp.Request {
|
||||
fastreq := &fasthttp.Request{}
|
||||
fastreq.SetRequestURI(stdreq.URL.String())
|
||||
|
||||
fastreq.Header.SetMethod(stdreq.Method)
|
||||
|
||||
for k, a := range stdreq.Header {
|
||||
for n, v := range a {
|
||||
if n == 0 {
|
||||
fastreq.Header.Set(k, v)
|
||||
} else {
|
||||
fastreq.Header.Add(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fastreq
|
||||
}
|
||||
|
||||
func fast2std(stdreq *http.Request, fastresp *fasthttp.Response) *http.Response {
|
||||
status := fastresp.Header.StatusCode()
|
||||
body := fastresp.Body()
|
||||
|
||||
stdresp := &http.Response{
|
||||
Request: stdreq,
|
||||
StatusCode: status,
|
||||
Status: http.StatusText(status),
|
||||
}
|
||||
|
||||
fastresp.Header.VisitAll(func(k, v []byte) {
|
||||
sk := string(k)
|
||||
sv := string(v)
|
||||
if stdresp.Header == nil {
|
||||
stdresp.Header = make(http.Header)
|
||||
}
|
||||
stdresp.Header.Add(sk, sv)
|
||||
})
|
||||
|
||||
if fastresp.Header.ContentLength() == -1 {
|
||||
stdresp.TransferEncoding = []string{"chunked"}
|
||||
}
|
||||
|
||||
if body != nil {
|
||||
stdresp.Body = ioutil.NopCloser(bytes.NewReader(body))
|
||||
} else {
|
||||
stdresp.Body = ioutil.NopCloser(bytes.NewReader(nil))
|
||||
}
|
||||
|
||||
return stdresp
|
||||
}
|
||||
|
||||
type fastLogger struct{}
|
||||
|
||||
func (fastLogger) Printf(format string, args ...interface{}) {
|
||||
_, _ = format, args
|
||||
}
|
||||
|
||||
type connNonTLS struct {
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (connNonTLS) RemoteAddr() net.Addr {
|
||||
return &net.TCPAddr{IP: net.IPv4zero}
|
||||
}
|
||||
|
||||
func (connNonTLS) LocalAddr() net.Addr {
|
||||
return &net.TCPAddr{IP: net.IPv4zero}
|
||||
}
|
||||
|
||||
type connTLS struct {
|
||||
connNonTLS
|
||||
state *tls.ConnectionState
|
||||
}
|
||||
|
||||
func (c connTLS) Handshake() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c connTLS) ConnectionState() tls.ConnectionState {
|
||||
return *c.state
|
||||
}
|
||||
82
vendor/gopkg.in/gavv/httpexpect.v2/boolean.go
generated
vendored
Normal file
82
vendor/gopkg.in/gavv/httpexpect.v2/boolean.go
generated
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package httpexpect
|
||||
|
||||
// Boolean provides methods to inspect attached bool value
|
||||
// (Go representation of JSON boolean).
|
||||
type Boolean struct {
|
||||
chain chain
|
||||
value bool
|
||||
}
|
||||
|
||||
// NewBoolean returns a new Boolean given a reporter used to report
|
||||
// failures and value to be inspected.
|
||||
//
|
||||
// reporter should not be nil.
|
||||
//
|
||||
// Example:
|
||||
// boolean := NewBoolean(t, true)
|
||||
func NewBoolean(reporter Reporter, value bool) *Boolean {
|
||||
return &Boolean{makeChain(reporter), value}
|
||||
}
|
||||
|
||||
// Raw returns underlying value attached to Boolean.
|
||||
// This is the value originally passed to NewBoolean.
|
||||
//
|
||||
// Example:
|
||||
// boolean := NewBoolean(t, true)
|
||||
// assert.Equal(t, true, boolean.Raw())
|
||||
func (b *Boolean) Raw() bool {
|
||||
return b.value
|
||||
}
|
||||
|
||||
// Path is similar to Value.Path.
|
||||
func (b *Boolean) Path(path string) *Value {
|
||||
return getPath(&b.chain, b.value, path)
|
||||
}
|
||||
|
||||
// Schema is similar to Value.Schema.
|
||||
func (b *Boolean) Schema(schema interface{}) *Boolean {
|
||||
checkSchema(&b.chain, b.value, schema)
|
||||
return b
|
||||
}
|
||||
|
||||
// Equal succeeds if boolean is equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// boolean := NewBoolean(t, true)
|
||||
// boolean.Equal(true)
|
||||
func (b *Boolean) Equal(value bool) *Boolean {
|
||||
if !(b.value == value) {
|
||||
b.chain.fail("expected boolean == %v, but got %v", value, b.value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// NotEqual succeeds if boolean is not equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// boolean := NewBoolean(t, true)
|
||||
// boolean.NotEqual(false)
|
||||
func (b *Boolean) NotEqual(value bool) *Boolean {
|
||||
if !(b.value != value) {
|
||||
b.chain.fail("expected boolean != %v, but got %v", value, b.value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// True succeeds if boolean is true.
|
||||
//
|
||||
// Example:
|
||||
// boolean := NewBoolean(t, true)
|
||||
// boolean.True()
|
||||
func (b *Boolean) True() *Boolean {
|
||||
return b.Equal(true)
|
||||
}
|
||||
|
||||
// False succeeds if boolean is false.
|
||||
//
|
||||
// Example:
|
||||
// boolean := NewBoolean(t, false)
|
||||
// boolean.False()
|
||||
func (b *Boolean) False() *Boolean {
|
||||
return b.Equal(false)
|
||||
}
|
||||
38
vendor/gopkg.in/gavv/httpexpect.v2/chain.go
generated
vendored
Normal file
38
vendor/gopkg.in/gavv/httpexpect.v2/chain.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package httpexpect
|
||||
|
||||
type chain struct {
|
||||
reporter Reporter
|
||||
failbit bool
|
||||
}
|
||||
|
||||
func makeChain(reporter Reporter) chain {
|
||||
return chain{reporter, false}
|
||||
}
|
||||
|
||||
func (c *chain) failed() bool {
|
||||
return c.failbit
|
||||
}
|
||||
|
||||
func (c *chain) fail(message string, args ...interface{}) {
|
||||
if c.failbit {
|
||||
return
|
||||
}
|
||||
c.failbit = true
|
||||
c.reporter.Errorf(message, args...)
|
||||
}
|
||||
|
||||
func (c *chain) reset() {
|
||||
c.failbit = false
|
||||
}
|
||||
|
||||
func (c *chain) assertFailed(r Reporter) {
|
||||
if !c.failbit {
|
||||
r.Errorf("expected chain is failed, but it's ok")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *chain) assertOK(r Reporter) {
|
||||
if c.failbit {
|
||||
r.Errorf("expected chain is ok, but it's failed")
|
||||
}
|
||||
}
|
||||
133
vendor/gopkg.in/gavv/httpexpect.v2/cookie.go
generated
vendored
Normal file
133
vendor/gopkg.in/gavv/httpexpect.v2/cookie.go
generated
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Cookie provides methods to inspect attached http.Cookie value.
|
||||
type Cookie struct {
|
||||
chain chain
|
||||
value *http.Cookie
|
||||
}
|
||||
|
||||
// NewCookie returns a new Cookie object given a reporter used to report
|
||||
// failures and cookie value to be inspected.
|
||||
//
|
||||
// reporter and value should not be nil.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(reporter, &http.Cookie{...})
|
||||
// cookie.Domain().Equal("example.com")
|
||||
// cookie.Path().Equal("/")
|
||||
// cookie.Expires().InRange(time.Now(), time.Now().Add(time.Hour * 24))
|
||||
func NewCookie(reporter Reporter, value *http.Cookie) *Cookie {
|
||||
chain := makeChain(reporter)
|
||||
if value == nil {
|
||||
chain.fail("expected non-nil cookie")
|
||||
}
|
||||
return &Cookie{chain, value}
|
||||
}
|
||||
|
||||
// Raw returns underlying http.Cookie value attached to Cookie.
|
||||
// This is the value originally passed to NewCookie.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(t, c)
|
||||
// assert.Equal(t, c, cookie.Raw())
|
||||
func (c *Cookie) Raw() *http.Cookie {
|
||||
return c.value
|
||||
}
|
||||
|
||||
// Name returns a new String object that may be used to inspect
|
||||
// cookie name.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(t, &http.Cookie{...})
|
||||
// cookie.Name().Equal("session")
|
||||
func (c *Cookie) Name() *String {
|
||||
if c.chain.failed() {
|
||||
return &String{c.chain, ""}
|
||||
}
|
||||
return &String{c.chain, c.value.Name}
|
||||
}
|
||||
|
||||
// Value returns a new String object that may be used to inspect
|
||||
// cookie value.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(t, &http.Cookie{...})
|
||||
// cookie.Value().Equal("gH6z7Y")
|
||||
func (c *Cookie) Value() *String {
|
||||
if c.chain.failed() {
|
||||
return &String{c.chain, ""}
|
||||
}
|
||||
return &String{c.chain, c.value.Value}
|
||||
}
|
||||
|
||||
// Domain returns a new String object that may be used to inspect
|
||||
// cookie domain.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(t, &http.Cookie{...})
|
||||
// cookie.Domain().Equal("example.com")
|
||||
func (c *Cookie) Domain() *String {
|
||||
if c.chain.failed() {
|
||||
return &String{c.chain, ""}
|
||||
}
|
||||
return &String{c.chain, c.value.Domain}
|
||||
}
|
||||
|
||||
// Path returns a new String object that may be used to inspect
|
||||
// cookie path.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(t, &http.Cookie{...})
|
||||
// cookie.Path().Equal("/foo")
|
||||
func (c *Cookie) Path() *String {
|
||||
if c.chain.failed() {
|
||||
return &String{c.chain, ""}
|
||||
}
|
||||
return &String{c.chain, c.value.Path}
|
||||
}
|
||||
|
||||
// Expires returns a new DateTime object that may be used to inspect
|
||||
// cookie expiration date.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(t, &http.Cookie{...})
|
||||
// cookie.Expires().InRange(time.Now(), time.Now().Add(time.Hour * 24))
|
||||
func (c *Cookie) Expires() *DateTime {
|
||||
if c.chain.failed() {
|
||||
return &DateTime{c.chain, time.Unix(0, 0)}
|
||||
}
|
||||
return &DateTime{c.chain, c.value.Expires}
|
||||
}
|
||||
|
||||
// MaxAge returns a new Duration object that may be used to inspect
|
||||
// cookie Max-age field.
|
||||
//
|
||||
// If MaxAge is not set, the returned Duration is unset. Whether a Duration
|
||||
// is set or not can be chacked using its IsSet and NotSet methods.
|
||||
//
|
||||
// If MaxAge is zero (which means delete cookie now), the returned Duration
|
||||
// is set and equals to zero.
|
||||
//
|
||||
// Example:
|
||||
// cookie := NewCookie(t, &http.Cookie{...})
|
||||
// cookie.MaxAge().IsSet()
|
||||
// cookie.MaxAge().InRange(time.Minute, time.Minute*10)
|
||||
func (c *Cookie) MaxAge() *Duration {
|
||||
if c.chain.failed() {
|
||||
return &Duration{c.chain, nil}
|
||||
}
|
||||
if c.value.MaxAge == 0 {
|
||||
return &Duration{c.chain, nil}
|
||||
}
|
||||
if c.value.MaxAge < 0 {
|
||||
var zero time.Duration
|
||||
return &Duration{c.chain, &zero}
|
||||
}
|
||||
d := time.Duration(c.value.MaxAge) * time.Second
|
||||
return &Duration{c.chain, &d}
|
||||
}
|
||||
129
vendor/gopkg.in/gavv/httpexpect.v2/datetime.go
generated
vendored
Normal file
129
vendor/gopkg.in/gavv/httpexpect.v2/datetime.go
generated
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// DateTime provides methods to inspect attached time.Time value.
|
||||
type DateTime struct {
|
||||
chain chain
|
||||
value time.Time
|
||||
}
|
||||
|
||||
// NewDateTime returns a new DateTime object given a reporter used to report
|
||||
// failures and time.Time value to be inspected.
|
||||
//
|
||||
// reporter should not be nil.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(reporter, time.Now())
|
||||
// dt.Le(time.Now())
|
||||
//
|
||||
// time.Sleep(time.Second)
|
||||
// dt.Lt(time.Now())
|
||||
func NewDateTime(reporter Reporter, value time.Time) *DateTime {
|
||||
return &DateTime{makeChain(reporter), value}
|
||||
}
|
||||
|
||||
// Raw returns underlying time.Time value attached to DateTime.
|
||||
// This is the value originally passed to NewDateTime.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, timestamp)
|
||||
// assert.Equal(t, timestamp, dt.Raw())
|
||||
func (dt *DateTime) Raw() time.Time {
|
||||
return dt.value
|
||||
}
|
||||
|
||||
// Equal succeeds if DateTime is equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, time.Unix(0, 1))
|
||||
// dt.Equal(time.Unix(0, 1))
|
||||
func (dt *DateTime) Equal(value time.Time) *DateTime {
|
||||
if !dt.value.Equal(value) {
|
||||
dt.chain.fail("\nexpected datetime equal to:\n %s\n\nbut got:\n %s",
|
||||
value, dt.value)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
// NotEqual succeeds if DateTime is not equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, time.Unix(0, 1))
|
||||
// dt.NotEqual(time.Unix(0, 2))
|
||||
func (dt *DateTime) NotEqual(value time.Time) *DateTime {
|
||||
if dt.value.Equal(value) {
|
||||
dt.chain.fail("\nexpected datetime not equal to:\n %s", value)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
// Gt succeeds if DateTime is greater than given value.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, time.Unix(0, 2))
|
||||
// dt.Gt(time.Unix(0, 1))
|
||||
func (dt *DateTime) Gt(value time.Time) *DateTime {
|
||||
if !dt.value.After(value) {
|
||||
dt.chain.fail("\nexpected datetime > then:\n %s\n\nbut got:\n %s",
|
||||
value, dt.value)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
// Ge succeeds if DateTime is greater than or equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, time.Unix(0, 2))
|
||||
// dt.Ge(time.Unix(0, 1))
|
||||
func (dt *DateTime) Ge(value time.Time) *DateTime {
|
||||
if !(dt.value.After(value) || dt.value.Equal(value)) {
|
||||
dt.chain.fail("\nexpected datetime >= then:\n %s\n\nbut got:\n %s",
|
||||
value, dt.value)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
// Lt succeeds if DateTime is lesser than given value.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, time.Unix(0, 1))
|
||||
// dt.Lt(time.Unix(0, 2))
|
||||
func (dt *DateTime) Lt(value time.Time) *DateTime {
|
||||
if !dt.value.Before(value) {
|
||||
dt.chain.fail("\nexpected datetime < then:\n %s\n\nbut got:\n %s",
|
||||
value, dt.value)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
// Le succeeds if DateTime is lesser than or equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, time.Unix(0, 1))
|
||||
// dt.Le(time.Unix(0, 2))
|
||||
func (dt *DateTime) Le(value time.Time) *DateTime {
|
||||
if !(dt.value.Before(value) || dt.value.Equal(value)) {
|
||||
dt.chain.fail("\nexpected datetime <= then:\n %s\n\nbut got:\n %s",
|
||||
value, dt.value)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
// InRange succeeds if DateTime is in given range [min; max].
|
||||
//
|
||||
// Example:
|
||||
// dt := NewDateTime(t, time.Unix(0, 2))
|
||||
// dt.InRange(time.Unix(0, 1), time.Unix(0, 3))
|
||||
// dt.InRange(time.Unix(0, 2), time.Unix(0, 2))
|
||||
func (dt *DateTime) InRange(min, max time.Time) *DateTime {
|
||||
if !((dt.value.After(min) || dt.value.Equal(min)) &&
|
||||
(dt.value.Before(max) || dt.value.Equal(max))) {
|
||||
dt.chain.fail(
|
||||
"\nexpected datetime in range:\n min: %s\n max: %s\n\nbut got: %s",
|
||||
min, max, dt.value)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
176
vendor/gopkg.in/gavv/httpexpect.v2/duration.go
generated
vendored
Normal file
176
vendor/gopkg.in/gavv/httpexpect.v2/duration.go
generated
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration provides methods to inspect attached time.Duration value.
|
||||
type Duration struct {
|
||||
chain chain
|
||||
value *time.Duration
|
||||
}
|
||||
|
||||
// NewDuration returns a new Duration object given a reporter used to report
|
||||
// failures and time.Duration value to be inspected.
|
||||
//
|
||||
// reporter should not be nil.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(reporter, time.Second)
|
||||
// d.Le(time.Minute)
|
||||
func NewDuration(reporter Reporter, value time.Duration) *Duration {
|
||||
return &Duration{makeChain(reporter), &value}
|
||||
}
|
||||
|
||||
// Raw returns underlying time.Duration value attached to Duration.
|
||||
// This is the value originally passed to NewDuration.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, duration)
|
||||
// assert.Equal(t, timestamp, d.Raw())
|
||||
func (d *Duration) Raw() time.Duration {
|
||||
if d.value == nil {
|
||||
return 0
|
||||
}
|
||||
return *d.value
|
||||
}
|
||||
|
||||
// IsSet succeeds if Duration is set.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Second)
|
||||
// d.IsSet()
|
||||
func (d *Duration) IsSet() *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// NotSet succeeds if Duration is not set.
|
||||
func (d *Duration) NotSet() *Duration {
|
||||
if d.value != nil {
|
||||
d.chain.fail("expected duration is not set, but it is")
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Equal succeeds if Duration is equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Second)
|
||||
// d.Equal(time.Second)
|
||||
func (d *Duration) Equal(value time.Duration) *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
return d
|
||||
}
|
||||
if !(*d.value == value) {
|
||||
d.chain.fail("\nexpected duration equal to:\n %s\n\nbut got:\n %s",
|
||||
value, *d.value)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// NotEqual succeeds if Duration is not equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Second)
|
||||
// d.NotEqual(time.Minute)
|
||||
func (d *Duration) NotEqual(value time.Duration) *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
return d
|
||||
}
|
||||
if !(*d.value != value) {
|
||||
d.chain.fail("\nexpected duration not equal to:\n %s", value)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Gt succeeds if Duration is greater than given value.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Minute)
|
||||
// d.Gt(time.Second)
|
||||
func (d *Duration) Gt(value time.Duration) *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
return d
|
||||
}
|
||||
if !(*d.value > value) {
|
||||
d.chain.fail("\nexpected duration > then:\n %s\n\nbut got:\n %s",
|
||||
value, *d.value)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Ge succeeds if Duration is greater than or equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Minute)
|
||||
// d.Ge(time.Second)
|
||||
func (d *Duration) Ge(value time.Duration) *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
return d
|
||||
}
|
||||
if !(*d.value >= value) {
|
||||
d.chain.fail("\nexpected duration >= then:\n %s\n\nbut got:\n %s",
|
||||
value, *d.value)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Lt succeeds if Duration is lesser than given value.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Second)
|
||||
// d.Lt(time.Minute)
|
||||
func (d *Duration) Lt(value time.Duration) *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
return d
|
||||
}
|
||||
if !(*d.value < value) {
|
||||
d.chain.fail("\nexpected duration < then:\n %s\n\nbut got:\n %s",
|
||||
value, *d.value)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Le succeeds if Duration is lesser than or equal to given value.
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Second)
|
||||
// d.Le(time.Minute)
|
||||
func (d *Duration) Le(value time.Duration) *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
return d
|
||||
}
|
||||
if !(*d.value <= value) {
|
||||
d.chain.fail("\nexpected duration <= then:\n %s\n\nbut got:\n %s",
|
||||
value, *d.value)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// InRange succeeds if Duration is in given range [min; max].
|
||||
//
|
||||
// Example:
|
||||
// d := NewDuration(t, time.Minute)
|
||||
// d.InRange(time.Second, time.Hour)
|
||||
// d.InRange(time.Minute, time.Minute)
|
||||
func (d *Duration) InRange(min, max time.Duration) *Duration {
|
||||
if d.value == nil {
|
||||
d.chain.fail("expected duration is set, but it is not")
|
||||
return d
|
||||
}
|
||||
if !(*d.value >= min && *d.value <= max) {
|
||||
d.chain.fail(
|
||||
"\nexpected duration in range:\n min: %s\n max: %s\n\nbut got: %s",
|
||||
min, max, *d.value)
|
||||
}
|
||||
return d
|
||||
}
|
||||
463
vendor/gopkg.in/gavv/httpexpect.v2/expect.go
generated
vendored
Normal file
463
vendor/gopkg.in/gavv/httpexpect.v2/expect.go
generated
vendored
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
// Package httpexpect helps with end-to-end HTTP and REST API testing.
|
||||
//
|
||||
// Usage examples
|
||||
//
|
||||
// See example directory:
|
||||
// - https://godoc.org/github.com/gavv/httpexpect/_examples
|
||||
// - https://github.com/gavv/httpexpect/tree/master/_examples
|
||||
//
|
||||
// Communication mode
|
||||
//
|
||||
// There are two common ways to test API with httpexpect:
|
||||
// - start HTTP server and instruct httpexpect to use HTTP client for communication
|
||||
// - don't start server and instruct httpexpect to invoke http handler directly
|
||||
//
|
||||
// The second approach works only if the server is a Go module and its handler can
|
||||
// be imported in tests.
|
||||
//
|
||||
// Concrete behaviour is determined by Client implementation passed to Config struct.
|
||||
// If you're using http.Client, set its Transport field (http.RoundTriper) to one of
|
||||
// the following:
|
||||
// 1. default (nil) - use HTTP transport from net/http (you should start server)
|
||||
// 2. httpexpect.Binder - invoke given http.Handler directly
|
||||
// 3. httpexpect.FastBinder - invoke given fasthttp.RequestHandler directly
|
||||
//
|
||||
// Note that http handler can be usually obtained from http framework you're using.
|
||||
// E.g., echo framework provides either http.Handler or fasthttp.RequestHandler.
|
||||
//
|
||||
// You can also provide your own implementation of RequestFactory (creates http.Request),
|
||||
// or Client (gets http.Request and returns http.Response).
|
||||
//
|
||||
// If you're starting server from tests, it's very handy to use net/http/httptest.
|
||||
//
|
||||
// Value equality
|
||||
//
|
||||
// Whenever values are checked for equality in httpexpect, they are converted
|
||||
// to "canonical form":
|
||||
// - structs are converted to map[string]interface{}
|
||||
// - type aliases are removed
|
||||
// - numeric types are converted to float64
|
||||
// - non-nil interfaces pointing to nil slices and maps are replaced with
|
||||
// nil interfaces
|
||||
//
|
||||
// This is equivalent to subsequently json.Marshal() and json.Unmarshal() the value
|
||||
// and currently is implemented so.
|
||||
//
|
||||
// Failure handling
|
||||
//
|
||||
// When some check fails, failure is reported. If non-fatal failures are used
|
||||
// (see Reporter interface), execution is continued and instance that was checked
|
||||
// is marked as failed.
|
||||
//
|
||||
// If specific instance is marked as failed, all subsequent checks are ignored
|
||||
// for this instance and for any child instances retrieved after failure.
|
||||
//
|
||||
// Example:
|
||||
// array := NewArray(NewAssertReporter(t), []interface{}{"foo", 123})
|
||||
//
|
||||
// e0 := array.Element(0) // success
|
||||
// e1 := array.Element(1) // success
|
||||
//
|
||||
// s0 := e0.String() // success
|
||||
// s1 := e1.String() // failure; e1 and s1 are marked as failed, e0 and s0 are not
|
||||
//
|
||||
// s0.Equal("foo") // success
|
||||
// s1.Equal("bar") // this check is ignored because s1 is marked as failed
|
||||
package httpexpect
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
// Expect is a toplevel object that contains user Config and allows
|
||||
// to construct Request objects.
|
||||
type Expect struct {
|
||||
config Config
|
||||
builders []func(*Request)
|
||||
matchers []func(*Response)
|
||||
}
|
||||
|
||||
// Config contains various settings.
|
||||
type Config struct {
|
||||
// BaseURL is a URL to prepended to all request. My be empty. If
|
||||
// non-empty, trailing slash is allowed but not required and is
|
||||
// appended automatically.
|
||||
BaseURL string
|
||||
|
||||
// RequestFactory is used to pass in a custom *http.Request generation func.
|
||||
// May be nil.
|
||||
//
|
||||
// You can use DefaultRequestFactory, or provide custom implementation.
|
||||
// Useful for Google App Engine testing for example.
|
||||
RequestFactory RequestFactory
|
||||
|
||||
// Client is used to send http.Request and receive http.Response.
|
||||
// Should not be nil.
|
||||
//
|
||||
// You can use http.DefaultClient or http.Client, or provide
|
||||
// custom implementation.
|
||||
Client Client
|
||||
|
||||
// WebsocketDialer is used to establish websocket.Conn and receive
|
||||
// http.Response of handshake result.
|
||||
// Should not be nil.
|
||||
//
|
||||
// You can use websocket.DefaultDialer or websocket.Dialer, or provide
|
||||
// custom implementation.
|
||||
WebsocketDialer WebsocketDialer
|
||||
|
||||
// Reporter is used to report failures.
|
||||
// Should not be nil.
|
||||
//
|
||||
// You can use AssertReporter, RequireReporter (they use testify),
|
||||
// or testing.TB, or provide custom implementation.
|
||||
Reporter Reporter
|
||||
|
||||
// Printers are used to print requests and responses.
|
||||
// May be nil.
|
||||
//
|
||||
// You can use CompactPrinter, DebugPrinter, CurlPrinter, or provide
|
||||
// custom implementation.
|
||||
//
|
||||
// You can also use builtin printers with alternative Logger if
|
||||
// you're happy with their format, but want to send logs somewhere
|
||||
// else instead of testing.TB.
|
||||
Printers []Printer
|
||||
}
|
||||
|
||||
// RequestFactory is used to create all http.Request objects.
|
||||
// aetest.Instance from the Google App Engine implements this interface.
|
||||
type RequestFactory interface {
|
||||
NewRequest(method, urlStr string, body io.Reader) (*http.Request, error)
|
||||
}
|
||||
|
||||
// Client is used to send http.Request and receive http.Response.
|
||||
// http.Client implements this interface.
|
||||
//
|
||||
// Binder and FastBinder may be used to obtain this interface implementation.
|
||||
//
|
||||
// Example:
|
||||
// httpBinderClient := &http.Client{
|
||||
// Transport: httpexpect.NewBinder(HTTPHandler),
|
||||
// }
|
||||
// fastBinderClient := &http.Client{
|
||||
// Transport: httpexpect.NewFastBinder(FastHTTPHandler),
|
||||
// }
|
||||
type Client interface {
|
||||
// Do sends request and returns response.
|
||||
Do(*http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// WebsocketDialer is used to establish websocket.Conn and receive http.Response
|
||||
// of handshake result.
|
||||
// websocket.Dialer implements this interface.
|
||||
//
|
||||
// NewWebsocketDialer and NewFastWebsocketDialer may be used to obtain this
|
||||
// interface implementation.
|
||||
//
|
||||
// Example:
|
||||
// e := httpexpect.WithConfig(httpexpect.Config{
|
||||
// BaseURL: "http://example.com",
|
||||
// WebsocketDialer: httpexpect.NewWebsocketDialer(myHandler),
|
||||
// })
|
||||
type WebsocketDialer interface {
|
||||
// Dial establishes new WebSocket connection and returns response
|
||||
// of handshake result.
|
||||
Dial(url string, reqH http.Header) (*websocket.Conn, *http.Response, error)
|
||||
}
|
||||
|
||||
// Printer is used to print requests and responses.
|
||||
// CompactPrinter, DebugPrinter, and CurlPrinter implement this interface.
|
||||
type Printer interface {
|
||||
// Request is called before request is sent.
|
||||
Request(*http.Request)
|
||||
|
||||
// Response is called after response is received.
|
||||
Response(*http.Response, time.Duration)
|
||||
}
|
||||
|
||||
// WebsocketPrinter is used to print writes and reads of WebSocket connection.
|
||||
//
|
||||
// If WebSocket connection is used, all Printers that also implement WebsocketPrinter
|
||||
// are invoked on every WebSocket message read or written.
|
||||
//
|
||||
// DebugPrinter implements this interface.
|
||||
type WebsocketPrinter interface {
|
||||
Printer
|
||||
|
||||
// WebsocketWrite is called before writes to WebSocket connection.
|
||||
WebsocketWrite(typ int, content []byte, closeCode int)
|
||||
|
||||
// WebsocketRead is called after reads from WebSocket connection.
|
||||
WebsocketRead(typ int, content []byte, closeCode int)
|
||||
}
|
||||
|
||||
// Logger is used as output backend for Printer.
|
||||
// testing.TB implements this interface.
|
||||
type Logger interface {
|
||||
// Logf writes message to log.
|
||||
Logf(fmt string, args ...interface{})
|
||||
}
|
||||
|
||||
// Reporter is used to report failures.
|
||||
// testing.TB, AssertReporter, and RequireReporter implement this interface.
|
||||
type Reporter interface {
|
||||
// Errorf reports failure.
|
||||
// Allowed to return normally or terminate test using t.FailNow().
|
||||
Errorf(message string, args ...interface{})
|
||||
}
|
||||
|
||||
// LoggerReporter combines Logger and Reporter interfaces.
|
||||
type LoggerReporter interface {
|
||||
Logger
|
||||
Reporter
|
||||
}
|
||||
|
||||
// DefaultRequestFactory is the default RequestFactory implementation which just
|
||||
// calls http.NewRequest.
|
||||
type DefaultRequestFactory struct{}
|
||||
|
||||
// NewRequest implements RequestFactory.NewRequest.
|
||||
func (DefaultRequestFactory) NewRequest(
|
||||
method, urlStr string, body io.Reader) (*http.Request, error) {
|
||||
return http.NewRequest(method, urlStr, body)
|
||||
}
|
||||
|
||||
// New returns a new Expect object.
|
||||
//
|
||||
// baseURL specifies URL to prepended to all request. My be empty. If non-empty,
|
||||
// trailing slash is allowed but not required and is appended automatically.
|
||||
//
|
||||
// New is a shorthand for WithConfig. It uses:
|
||||
// - CompactPrinter as Printer, with testing.TB as Logger
|
||||
// - AssertReporter as Reporter
|
||||
// - DefaultRequestFactory as RequestFactory
|
||||
//
|
||||
// Client is set to a default client with a non-nil Jar:
|
||||
// &http.Client{
|
||||
// Jar: httpexpect.NewJar(),
|
||||
// }
|
||||
//
|
||||
// Example:
|
||||
// func TestSomething(t *testing.T) {
|
||||
// e := httpexpect.New(t, "http://example.com/")
|
||||
//
|
||||
// e.GET("/path").
|
||||
// Expect().
|
||||
// Status(http.StatusOK)
|
||||
// }
|
||||
func New(t LoggerReporter, baseURL string) *Expect {
|
||||
return WithConfig(Config{
|
||||
BaseURL: baseURL,
|
||||
Reporter: NewAssertReporter(t),
|
||||
Printers: []Printer{
|
||||
NewCompactPrinter(t),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// WithConfig returns a new Expect object with given config.
|
||||
//
|
||||
// Reporter should not be nil.
|
||||
//
|
||||
// If RequestFactory is nil, it's set to a DefaultRequestFactory instance.
|
||||
//
|
||||
// If Client is nil, it's set to a default client with a non-nil Jar:
|
||||
// &http.Client{
|
||||
// Jar: httpexpect.NewJar(),
|
||||
// }
|
||||
//
|
||||
// If WebsocketDialer is nil, it's set to a default dialer:
|
||||
// &websocket.Dialer{}
|
||||
//
|
||||
// Example:
|
||||
// func TestSomething(t *testing.T) {
|
||||
// e := httpexpect.WithConfig(httpexpect.Config{
|
||||
// BaseURL: "http://example.com/",
|
||||
// Client: &http.Client{
|
||||
// Transport: httpexpect.NewBinder(myHandler()),
|
||||
// Jar: httpexpect.NewJar(),
|
||||
// },
|
||||
// Reporter: httpexpect.NewAssertReporter(t),
|
||||
// Printers: []httpexpect.Printer{
|
||||
// httpexpect.NewCurlPrinter(t),
|
||||
// httpexpect.NewDebugPrinter(t, true)
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// e.GET("/path").
|
||||
// Expect().
|
||||
// Status(http.StatusOK)
|
||||
// }
|
||||
func WithConfig(config Config) *Expect {
|
||||
if config.Reporter == nil {
|
||||
panic("config.Reporter is nil")
|
||||
}
|
||||
if config.RequestFactory == nil {
|
||||
config.RequestFactory = DefaultRequestFactory{}
|
||||
}
|
||||
if config.Client == nil {
|
||||
config.Client = &http.Client{
|
||||
Jar: NewJar(),
|
||||
}
|
||||
}
|
||||
if config.WebsocketDialer == nil {
|
||||
config.WebsocketDialer = &websocket.Dialer{}
|
||||
}
|
||||
return &Expect{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// NewJar returns a new http.CookieJar.
|
||||
//
|
||||
// Returned jar is implemented in net/http/cookiejar. PublicSuffixList is
|
||||
// implemented in golang.org/x/net/publicsuffix.
|
||||
//
|
||||
// Note that this jar ignores cookies when request url is empty.
|
||||
func NewJar() http.CookieJar {
|
||||
jar, err := cookiejar.New(&cookiejar.Options{
|
||||
PublicSuffixList: publicsuffix.List,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return jar
|
||||
}
|
||||
|
||||
// Builder returns a copy of Expect instance with given builder attached to it.
|
||||
// Returned copy contains all previously attached builders plus a new one.
|
||||
// Builders are invoked from Request method, after constructing every new request.
|
||||
//
|
||||
// Example:
|
||||
// e := httpexpect.New(t, "http://example.com")
|
||||
//
|
||||
// token := e.POST("/login").WithForm(Login{"ford", "betelgeuse7"}).
|
||||
// Expect().
|
||||
// Status(http.StatusOK).JSON().Object().Value("token").String().Raw()
|
||||
//
|
||||
// auth := e.Builder(func (req *httpexpect.Request) {
|
||||
// req.WithHeader("Authorization", "Bearer "+token)
|
||||
// })
|
||||
//
|
||||
// auth.GET("/restricted").
|
||||
// Expect().
|
||||
// Status(http.StatusOK)
|
||||
func (e *Expect) Builder(builder func(*Request)) *Expect {
|
||||
ret := *e
|
||||
ret.builders = append(e.builders, builder)
|
||||
return &ret
|
||||
}
|
||||
|
||||
// Matcher returns a copy of Expect instance with given matcher attached to it.
|
||||
// Returned copy contains all previously attached matchers plus a new one.
|
||||
// Matchers are invoked from Request.Expect method, after retrieving a new response.
|
||||
//
|
||||
// Example:
|
||||
// e := httpexpect.New(t, "http://example.com")
|
||||
//
|
||||
// m := e.Matcher(func (resp *httpexpect.Response) {
|
||||
// resp.Header("API-Version").NotEmpty()
|
||||
// })
|
||||
//
|
||||
// m.GET("/some-path").
|
||||
// Expect().
|
||||
// Status(http.StatusOK)
|
||||
//
|
||||
// m.GET("/bad-path").
|
||||
// Expect().
|
||||
// Status(http.StatusNotFound)
|
||||
func (e *Expect) Matcher(matcher func(*Response)) *Expect {
|
||||
ret := *e
|
||||
ret.matchers = append(e.matchers, matcher)
|
||||
return &ret
|
||||
}
|
||||
|
||||
// Request returns a new Request object.
|
||||
// Arguments a similar to NewRequest.
|
||||
// After creating request, all builders attached to Expect object are invoked.
|
||||
// See Builder.
|
||||
func (e *Expect) Request(method, path string, pathargs ...interface{}) *Request {
|
||||
req := NewRequest(e.config, method, path, pathargs...)
|
||||
|
||||
for _, builder := range e.builders {
|
||||
builder(req)
|
||||
}
|
||||
|
||||
for _, matcher := range e.matchers {
|
||||
req.WithMatcher(matcher)
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
// OPTIONS is a shorthand for e.Request("OPTIONS", path, pathargs...).
|
||||
func (e *Expect) OPTIONS(path string, pathargs ...interface{}) *Request {
|
||||
return e.Request("OPTIONS", path, pathargs...)
|
||||
}
|
||||
|
||||
// HEAD is a shorthand for e.Request("HEAD", path, pathargs...).
|
||||
func (e *Expect) HEAD(path string, pathargs ...interface{}) *Request {
|
||||
return e.Request("HEAD", path, pathargs...)
|
||||
}
|
||||
|
||||
// GET is a shorthand for e.Request("GET", path, pathargs...).
|
||||
func (e *Expect) GET(path string, pathargs ...interface{}) *Request {
|
||||
return e.Request("GET", path, pathargs...)
|
||||
}
|
||||
|
||||
// POST is a shorthand for e.Request("POST", path, pathargs...).
|
||||
func (e *Expect) POST(path string, pathargs ...interface{}) *Request {
|
||||
return e.Request("POST", path, pathargs...)
|
||||
}
|
||||
|
||||
// PUT is a shorthand for e.Request("PUT", path, pathargs...).
|
||||
func (e *Expect) PUT(path string, pathargs ...interface{}) *Request {
|
||||
return e.Request("PUT", path, pathargs...)
|
||||
}
|
||||
|
||||
// PATCH is a shorthand for e.Request("PATCH", path, pathargs...).
|
||||
func (e *Expect) PATCH(path string, pathargs ...interface{}) *Request {
|
||||
return e.Request("PATCH", path, pathargs...)
|
||||
}
|
||||
|
||||
// DELETE is a shorthand for e.Request("DELETE", path, pathargs...).
|
||||
func (e *Expect) DELETE(path string, pathargs ...interface{}) *Request {
|
||||
return e.Request("DELETE", path, pathargs...)
|
||||
}
|
||||
|
||||
// Value is a shorthand for NewValue(e.config.Reporter, value).
|
||||
func (e *Expect) Value(value interface{}) *Value {
|
||||
return NewValue(e.config.Reporter, value)
|
||||
}
|
||||
|
||||
// Object is a shorthand for NewObject(e.config.Reporter, value).
|
||||
func (e *Expect) Object(value map[string]interface{}) *Object {
|
||||
return NewObject(e.config.Reporter, value)
|
||||
}
|
||||
|
||||
// Array is a shorthand for NewArray(e.config.Reporter, value).
|
||||
func (e *Expect) Array(value []interface{}) *Array {
|
||||
return NewArray(e.config.Reporter, value)
|
||||
}
|
||||
|
||||
// String is a shorthand for NewString(e.config.Reporter, value).
|
||||
func (e *Expect) String(value string) *String {
|
||||
return NewString(e.config.Reporter, value)
|
||||
}
|
||||
|
||||
// Number is a shorthand for NewNumber(e.config.Reporter, value).
|
||||
func (e *Expect) Number(value float64) *Number {
|
||||
return NewNumber(e.config.Reporter, value)
|
||||
}
|
||||
|
||||
// Boolean is a shorthand for NewBoolean(e.config.Reporter, value).
|
||||
func (e *Expect) Boolean(value bool) *Boolean {
|
||||
return NewBoolean(e.config.Reporter, value)
|
||||
}
|
||||
184
vendor/gopkg.in/gavv/httpexpect.v2/helpers.go
generated
vendored
Normal file
184
vendor/gopkg.in/gavv/httpexpect.v2/helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"github.com/yalp/jsonpath"
|
||||
"github.com/yudai/gojsondiff"
|
||||
"github.com/yudai/gojsondiff/formatter"
|
||||
)
|
||||
|
||||
func toString(str interface{}) (s string, ok bool) {
|
||||
ok = true
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
s = reflect.ValueOf(str).Convert(reflect.TypeOf("")).String()
|
||||
return
|
||||
}
|
||||
|
||||
func getPath(chain *chain, value interface{}, path string) *Value {
|
||||
if chain.failed() {
|
||||
return &Value{*chain, nil}
|
||||
}
|
||||
|
||||
result, err := jsonpath.Read(value, path)
|
||||
if err != nil {
|
||||
chain.fail(err.Error())
|
||||
return &Value{*chain, nil}
|
||||
}
|
||||
|
||||
return &Value{*chain, result}
|
||||
}
|
||||
|
||||
func checkSchema(chain *chain, value, schema interface{}) {
|
||||
if chain.failed() {
|
||||
return
|
||||
}
|
||||
|
||||
valueLoader := gojsonschema.NewGoLoader(value)
|
||||
|
||||
var schemaLoader gojsonschema.JSONLoader
|
||||
|
||||
if str, ok := toString(schema); ok {
|
||||
if ok, _ := regexp.MatchString(`^\w+://`, str); ok {
|
||||
schemaLoader = gojsonschema.NewReferenceLoader(str)
|
||||
} else {
|
||||
schemaLoader = gojsonschema.NewStringLoader(str)
|
||||
}
|
||||
} else {
|
||||
schemaLoader = gojsonschema.NewGoLoader(schema)
|
||||
}
|
||||
|
||||
result, err := gojsonschema.Validate(schemaLoader, valueLoader)
|
||||
if err != nil {
|
||||
chain.fail("\n%s\n\nschema:\n%s\n\nvalue:\n%s",
|
||||
err.Error(),
|
||||
dumpSchema(schema),
|
||||
dumpValue(value))
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
errors := ""
|
||||
for _, err := range result.Errors() {
|
||||
errors += fmt.Sprintf(" %s\n", err)
|
||||
}
|
||||
|
||||
chain.fail(
|
||||
"\njson schema validation failed, schema:\n%s\n\nvalue:%s\n\nerrors:\n%s",
|
||||
dumpSchema(schema),
|
||||
dumpValue(value),
|
||||
errors)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func dumpSchema(schema interface{}) string {
|
||||
if s, ok := toString(schema); ok {
|
||||
schema = s
|
||||
}
|
||||
return regexp.MustCompile(`(?m:^)`).
|
||||
ReplaceAllString(fmt.Sprintf("%v", schema), " ")
|
||||
}
|
||||
|
||||
func canonNumber(chain *chain, number interface{}) (f float64, ok bool) {
|
||||
ok = true
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
chain.fail("%v", err)
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
f = reflect.ValueOf(number).Convert(reflect.TypeOf(float64(0))).Float()
|
||||
return
|
||||
}
|
||||
|
||||
func canonArray(chain *chain, in interface{}) ([]interface{}, bool) {
|
||||
var out []interface{}
|
||||
data, ok := canonValue(chain, in)
|
||||
if ok {
|
||||
out, ok = data.([]interface{})
|
||||
if !ok {
|
||||
chain.fail("expected array, got %v", out)
|
||||
}
|
||||
}
|
||||
return out, ok
|
||||
}
|
||||
|
||||
func canonMap(chain *chain, in interface{}) (map[string]interface{}, bool) {
|
||||
var out map[string]interface{}
|
||||
data, ok := canonValue(chain, in)
|
||||
if ok {
|
||||
out, ok = data.(map[string]interface{})
|
||||
if !ok {
|
||||
chain.fail("expected map, got %v", out)
|
||||
}
|
||||
}
|
||||
return out, ok
|
||||
}
|
||||
|
||||
func canonValue(chain *chain, in interface{}) (interface{}, bool) {
|
||||
b, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
chain.fail(err.Error())
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var out interface{}
|
||||
if err := json.Unmarshal(b, &out); err != nil {
|
||||
chain.fail(err.Error())
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return out, true
|
||||
}
|
||||
|
||||
func dumpValue(value interface{}) string {
|
||||
b, err := json.MarshalIndent(value, " ", " ")
|
||||
if err != nil {
|
||||
return " " + fmt.Sprintf("%#v", value)
|
||||
}
|
||||
return " " + string(b)
|
||||
}
|
||||
|
||||
func diffValues(expected, actual interface{}) string {
|
||||
differ := gojsondiff.New()
|
||||
|
||||
var diff gojsondiff.Diff
|
||||
|
||||
if ve, ok := expected.(map[string]interface{}); ok {
|
||||
if va, ok := actual.(map[string]interface{}); ok {
|
||||
diff = differ.CompareObjects(ve, va)
|
||||
} else {
|
||||
return " (unavailable)"
|
||||
}
|
||||
} else if ve, ok := expected.([]interface{}); ok {
|
||||
if va, ok := actual.([]interface{}); ok {
|
||||
diff = differ.CompareArrays(ve, va)
|
||||
} else {
|
||||
return " (unavailable)"
|
||||
}
|
||||
} else {
|
||||
return " (unavailable)"
|
||||
}
|
||||
|
||||
config := formatter.AsciiFormatterConfig{
|
||||
ShowArrayIndex: true,
|
||||
}
|
||||
f := formatter.NewAsciiFormatter(expected, config)
|
||||
|
||||
str, err := f.Format(diff)
|
||||
if err != nil {
|
||||
return " (unavailable)"
|
||||
}
|
||||
|
||||
return "--- expected\n+++ actual\n" + str
|
||||
}
|
||||
198
vendor/gopkg.in/gavv/httpexpect.v2/match.go
generated
vendored
Normal file
198
vendor/gopkg.in/gavv/httpexpect.v2/match.go
generated
vendored
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Match provides methods to inspect attached regexp match results.
|
||||
type Match struct {
|
||||
chain chain
|
||||
submatches []string
|
||||
names map[string]int
|
||||
}
|
||||
|
||||
// NewMatch returns a new Match object given a reporter used to report
|
||||
// failures and submatches to be inspected.
|
||||
//
|
||||
// reporter should not be nil. submatches and names may be nil.
|
||||
//
|
||||
// Example:
|
||||
// s := "http://example.com/users/john"
|
||||
// r := regexp.MustCompile(`http://(?P<host>.+)/users/(?P<user>.+)`)
|
||||
// m := NewMatch(reporter, r.FindStringSubmatch(s), r.SubexpNames())
|
||||
//
|
||||
// m.NotEmpty()
|
||||
// m.Length().Equal(3)
|
||||
//
|
||||
// m.Index(0).Equal("http://example.com/users/john")
|
||||
// m.Index(1).Equal("example.com")
|
||||
// m.Index(2).Equal("john")
|
||||
//
|
||||
// m.Name("host").Equal("example.com")
|
||||
// m.Name("user").Equal("john")
|
||||
func NewMatch(reporter Reporter, submatches []string, names []string) *Match {
|
||||
return makeMatch(makeChain(reporter), submatches, names)
|
||||
}
|
||||
|
||||
func makeMatch(chain chain, submatches []string, names []string) *Match {
|
||||
if submatches == nil {
|
||||
submatches = []string{}
|
||||
}
|
||||
namemap := map[string]int{}
|
||||
for n, name := range names {
|
||||
if name != "" {
|
||||
namemap[name] = n
|
||||
}
|
||||
}
|
||||
return &Match{chain, submatches, namemap}
|
||||
}
|
||||
|
||||
// Raw returns underlying submatches attached to Match.
|
||||
// This is the value originally passed to NewMatch.
|
||||
//
|
||||
// Example:
|
||||
// m := NewMatch(t, submatches, names)
|
||||
// assert.Equal(t, submatches, m.Raw())
|
||||
func (m *Match) Raw() []string {
|
||||
return m.submatches
|
||||
}
|
||||
|
||||
// Length returns a new Number object that may be used to inspect
|
||||
// number of submatches.
|
||||
//
|
||||
// Example:
|
||||
// m := NewMatch(t, submatches, names)
|
||||
// m.Length().Equal(len(submatches))
|
||||
func (m *Match) Length() *Number {
|
||||
return &Number{m.chain, float64(len(m.submatches))}
|
||||
}
|
||||
|
||||
// Index returns a new String object that may be used to inspect submatch
|
||||
// with given index.
|
||||
//
|
||||
// Note that submatch with index 0 contains the whole match. If index is out
|
||||
// of bounds, Index reports failure and returns empty (but non-nil) value.
|
||||
//
|
||||
// Example:
|
||||
// s := "http://example.com/users/john"
|
||||
//
|
||||
// r := regexp.MustCompile(`http://(.+)/users/(.+)`)
|
||||
// m := NewMatch(t, r.FindStringSubmatch(s), nil)
|
||||
//
|
||||
// m.Index(0).Equal("http://example.com/users/john")
|
||||
// m.Index(1).Equal("example.com")
|
||||
// m.Index(2).Equal("john")
|
||||
func (m *Match) Index(index int) *String {
|
||||
if index < 0 || index >= len(m.submatches) {
|
||||
m.chain.fail(
|
||||
"\nsubmatch index out of bounds:\n index %d\n\n bounds [%d; %d)",
|
||||
index,
|
||||
0,
|
||||
len(m.submatches))
|
||||
return &String{m.chain, ""}
|
||||
}
|
||||
return &String{m.chain, m.submatches[index]}
|
||||
}
|
||||
|
||||
// Name returns a new String object that may be used to inspect submatch
|
||||
// with given name.
|
||||
//
|
||||
// If there is no submatch with given name, Name reports failure and returns
|
||||
// empty (but non-nil) value.
|
||||
//
|
||||
// Example:
|
||||
// s := "http://example.com/users/john"
|
||||
//
|
||||
// r := regexp.MustCompile(`http://(?P<host>.+)/users/(?P<user>.+)`)
|
||||
// m := NewMatch(t, r.FindStringSubmatch(s), r.SubexpNames())
|
||||
//
|
||||
// m.Name("host").Equal("example.com")
|
||||
// m.Name("user").Equal("john")
|
||||
func (m *Match) Name(name string) *String {
|
||||
index, ok := m.names[name]
|
||||
if !ok {
|
||||
m.chain.fail(
|
||||
"\nsubmatch name not found:\n %q\n\navailable names:\n%s",
|
||||
name,
|
||||
dumpValue(m.names))
|
||||
return &String{m.chain, ""}
|
||||
}
|
||||
return m.Index(index)
|
||||
}
|
||||
|
||||
// Empty succeeds if submatches array is empty.
|
||||
//
|
||||
// Example:
|
||||
// m := NewMatch(t, submatches, names)
|
||||
// m.Empty()
|
||||
func (m *Match) Empty() *Match {
|
||||
if len(m.submatches) != 0 {
|
||||
m.chain.fail("\nexpected zero submatches, but got:\n %s",
|
||||
dumpValue(m.submatches))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// NotEmpty succeeds if submatches array is non-empty.
|
||||
//
|
||||
// Example:
|
||||
// m := NewMatch(t, submatches, names)
|
||||
// m.NotEmpty()
|
||||
func (m *Match) NotEmpty() *Match {
|
||||
if len(m.submatches) == 0 {
|
||||
m.chain.fail("expected non-zero submatches")
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Values succeeds if submatches array, starting from index 1, is equal to
|
||||
// given array.
|
||||
//
|
||||
// Note that submatch with index 0 contains the whole match and is not
|
||||
// included into this check.
|
||||
//
|
||||
// Example:
|
||||
// s := "http://example.com/users/john"
|
||||
// r := regexp.MustCompile(`http://(.+)/users/(.+)`)
|
||||
// m := NewMatch(t, r.FindStringSubmatch(s), nil)
|
||||
// m.Values("example.com", "john")
|
||||
func (m *Match) Values(values ...string) *Match {
|
||||
if values == nil {
|
||||
values = []string{}
|
||||
}
|
||||
if !reflect.DeepEqual(values, m.getValues()) {
|
||||
m.chain.fail("\nexpected submatches equal to:\n%s\n\nbut got:\n%s",
|
||||
dumpValue(values),
|
||||
dumpValue(m.getValues()))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// NotValues succeeds if submatches array, starting from index 1, is not
|
||||
// equal to given array.
|
||||
//
|
||||
// Note that submatch with index 0 contains the whole match and is not
|
||||
// included into this check.
|
||||
//
|
||||
// Example:
|
||||
// s := "http://example.com/users/john"
|
||||
// r := regexp.MustCompile(`http://(.+)/users/(.+)`)
|
||||
// m := NewMatch(t, r.FindStringSubmatch(s), nil)
|
||||
// m.NotValues("example.com", "bob")
|
||||
func (m *Match) NotValues(values ...string) *Match {
|
||||
if values == nil {
|
||||
values = []string{}
|
||||
}
|
||||
if reflect.DeepEqual(values, m.getValues()) {
|
||||
m.chain.fail("\nexpected submatches not equal to:\n%s",
|
||||
dumpValue(values))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Match) getValues() []string {
|
||||
if len(m.submatches) > 1 {
|
||||
return m.submatches[1:]
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
244
vendor/gopkg.in/gavv/httpexpect.v2/number.go
generated
vendored
Normal file
244
vendor/gopkg.in/gavv/httpexpect.v2/number.go
generated
vendored
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Number provides methods to inspect attached float64 value
|
||||
// (Go representation of JSON number).
|
||||
type Number struct {
|
||||
chain chain
|
||||
value float64
|
||||
}
|
||||
|
||||
// NewNumber returns a new Number given a reporter used to report
|
||||
// failures and value to be inspected.
|
||||
//
|
||||
// reporter should not be nil.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123.4)
|
||||
func NewNumber(reporter Reporter, value float64) *Number {
|
||||
return &Number{makeChain(reporter), value}
|
||||
}
|
||||
|
||||
// Raw returns underlying value attached to Number.
|
||||
// This is the value originally passed to NewNumber.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123.4)
|
||||
// assert.Equal(t, 123.4, number.Raw())
|
||||
func (n *Number) Raw() float64 {
|
||||
return n.value
|
||||
}
|
||||
|
||||
// Path is similar to Value.Path.
|
||||
func (n *Number) Path(path string) *Value {
|
||||
return getPath(&n.chain, n.value, path)
|
||||
}
|
||||
|
||||
// Schema is similar to Value.Schema.
|
||||
func (n *Number) Schema(schema interface{}) *Number {
|
||||
checkSchema(&n.chain, n.value, schema)
|
||||
return n
|
||||
}
|
||||
|
||||
// Equal succeeds if number is equal to given value.
|
||||
//
|
||||
// value should have numeric type convertible to float64. Before comparison,
|
||||
// it is converted to float64.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123)
|
||||
// number.Equal(float64(123))
|
||||
// number.Equal(int32(123))
|
||||
func (n *Number) Equal(value interface{}) *Number {
|
||||
v, ok := canonNumber(&n.chain, value)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
if !(n.value == v) {
|
||||
n.chain.fail("\nexpected number equal to:\n %v\n\nbut got:\n %v",
|
||||
v, n.value)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// NotEqual succeeds if number is not equal to given value.
|
||||
//
|
||||
// value should have numeric type convertible to float64. Before comparison,
|
||||
// it is converted to float64.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123)
|
||||
// number.NotEqual(float64(321))
|
||||
// number.NotEqual(int32(321))
|
||||
func (n *Number) NotEqual(value interface{}) *Number {
|
||||
v, ok := canonNumber(&n.chain, value)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
if !(n.value != v) {
|
||||
n.chain.fail("\nexpected number not equal to:\n %v\n\nbut got:\n %v",
|
||||
v, n.value)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// EqualDelta succeeds if two numerals are within delta of each other.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123.0)
|
||||
// number.EqualDelta(123.2, 0.3)
|
||||
func (n *Number) EqualDelta(value, delta float64) *Number {
|
||||
if math.IsNaN(n.value) || math.IsNaN(value) || math.IsNaN(delta) {
|
||||
n.chain.fail("\nexpected number equal to:\n %v\n\nbut got:\n %v\n\ndelta:\n %v",
|
||||
value, n.value, delta)
|
||||
return n
|
||||
}
|
||||
|
||||
diff := (n.value - value)
|
||||
|
||||
if diff < -delta || diff > delta {
|
||||
n.chain.fail("\nexpected number equal to:\n %v\n\nbut got:\n %v\n\ndelta:\n %v",
|
||||
value, n.value, delta)
|
||||
return n
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// NotEqualDelta succeeds if two numerals are not within delta of each other.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123.0)
|
||||
// number.NotEqualDelta(123.2, 0.1)
|
||||
func (n *Number) NotEqualDelta(value, delta float64) *Number {
|
||||
if math.IsNaN(n.value) || math.IsNaN(value) || math.IsNaN(delta) {
|
||||
n.chain.fail(
|
||||
"\nexpected number not equal to:\n %v\n\nbut got:\n %v\n\ndelta:\n %v",
|
||||
value, n.value, delta)
|
||||
return n
|
||||
}
|
||||
|
||||
diff := (n.value - value)
|
||||
|
||||
if !(diff < -delta || diff > delta) {
|
||||
n.chain.fail(
|
||||
"\nexpected number not equal to:\n %v\n\nbut got:\n %v\n\ndelta:\n %v",
|
||||
value, n.value, delta)
|
||||
return n
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// Gt succeeds if number is greater than given value.
|
||||
//
|
||||
// value should have numeric type convertible to float64. Before comparison,
|
||||
// it is converted to float64.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123)
|
||||
// number.Gt(float64(122))
|
||||
// number.Gt(int32(122))
|
||||
func (n *Number) Gt(value interface{}) *Number {
|
||||
v, ok := canonNumber(&n.chain, value)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
if !(n.value > v) {
|
||||
n.chain.fail("\nexpected number > then:\n %v\n\nbut got:\n %v",
|
||||
v, n.value)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Ge succeeds if number is greater than or equal to given value.
|
||||
//
|
||||
// value should have numeric type convertible to float64. Before comparison,
|
||||
// it is converted to float64.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123)
|
||||
// number.Ge(float64(122))
|
||||
// number.Ge(int32(122))
|
||||
func (n *Number) Ge(value interface{}) *Number {
|
||||
v, ok := canonNumber(&n.chain, value)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
if !(n.value >= v) {
|
||||
n.chain.fail("\nexpected number >= then:\n %v\n\nbut got:\n %v",
|
||||
v, n.value)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Lt succeeds if number is lesser than given value.
|
||||
//
|
||||
// value should have numeric type convertible to float64. Before comparison,
|
||||
// it is converted to float64.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123)
|
||||
// number.Lt(float64(124))
|
||||
// number.Lt(int32(124))
|
||||
func (n *Number) Lt(value interface{}) *Number {
|
||||
v, ok := canonNumber(&n.chain, value)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
if !(n.value < v) {
|
||||
n.chain.fail("\nexpected number < then:\n %v\n\nbut got:\n %v",
|
||||
v, n.value)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Le succeeds if number is lesser than or equal to given value.
|
||||
//
|
||||
// value should have numeric type convertible to float64. Before comparison,
|
||||
// it is converted to float64.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123)
|
||||
// number.Le(float64(124))
|
||||
// number.Le(int32(124))
|
||||
func (n *Number) Le(value interface{}) *Number {
|
||||
v, ok := canonNumber(&n.chain, value)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
if !(n.value <= v) {
|
||||
n.chain.fail("\nexpected number <= then:\n %v\n\nbut got:\n %v",
|
||||
v, n.value)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// InRange succeeds if number is in given range [min; max].
|
||||
//
|
||||
// min and max should have numeric type convertible to float64. Before comparison,
|
||||
// they are converted to float64.
|
||||
//
|
||||
// Example:
|
||||
// number := NewNumber(t, 123)
|
||||
// number.InRange(float32(100), int32(200)) // success
|
||||
// number.InRange(100, 200) // success
|
||||
// number.InRange(123, 123) // success
|
||||
func (n *Number) InRange(min, max interface{}) *Number {
|
||||
a, ok := canonNumber(&n.chain, min)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
b, ok := canonNumber(&n.chain, max)
|
||||
if !ok {
|
||||
return n
|
||||
}
|
||||
if !(n.value >= a && n.value <= b) {
|
||||
n.chain.fail("\nexpected number in range:\n [%v; %v]\n\nbut got:\n %v",
|
||||
a, b, n.value)
|
||||
}
|
||||
return n
|
||||
}
|
||||
329
vendor/gopkg.in/gavv/httpexpect.v2/object.go
generated
vendored
Normal file
329
vendor/gopkg.in/gavv/httpexpect.v2/object.go
generated
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Object provides methods to inspect attached map[string]interface{} object
|
||||
// (Go representation of JSON object).
|
||||
type Object struct {
|
||||
chain chain
|
||||
value map[string]interface{}
|
||||
}
|
||||
|
||||
// NewObject returns a new Object given a reporter used to report failures
|
||||
// and value to be inspected.
|
||||
//
|
||||
// Both reporter and value should not be nil. If value is nil, failure is
|
||||
// reported.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
func NewObject(reporter Reporter, value map[string]interface{}) *Object {
|
||||
chain := makeChain(reporter)
|
||||
if value == nil {
|
||||
chain.fail("expected non-nil map value")
|
||||
} else {
|
||||
value, _ = canonMap(&chain, value)
|
||||
}
|
||||
return &Object{chain, value}
|
||||
}
|
||||
|
||||
// Raw returns underlying value attached to Object.
|
||||
// This is the value originally passed to NewObject, converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// assert.Equal(t, map[string]interface{}{"foo": 123.0}, object.Raw())
|
||||
func (o *Object) Raw() map[string]interface{} {
|
||||
return o.value
|
||||
}
|
||||
|
||||
// Path is similar to Value.Path.
|
||||
func (o *Object) Path(path string) *Value {
|
||||
return getPath(&o.chain, o.value, path)
|
||||
}
|
||||
|
||||
// Schema is similar to Value.Schema.
|
||||
func (o *Object) Schema(schema interface{}) *Object {
|
||||
checkSchema(&o.chain, o.value, schema)
|
||||
return o
|
||||
}
|
||||
|
||||
// Keys returns a new Array object that may be used to inspect objects keys.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123, "bar": 456})
|
||||
// object.Keys().ContainsOnly("foo", "bar")
|
||||
func (o *Object) Keys() *Array {
|
||||
keys := []interface{}{}
|
||||
for k := range o.value {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return &Array{o.chain, keys}
|
||||
}
|
||||
|
||||
// Values returns a new Array object that may be used to inspect objects values.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123, "bar": 456})
|
||||
// object.Values().ContainsOnly(123, 456)
|
||||
func (o *Object) Values() *Array {
|
||||
values := []interface{}{}
|
||||
for _, v := range o.value {
|
||||
values = append(values, v)
|
||||
}
|
||||
return &Array{o.chain, values}
|
||||
}
|
||||
|
||||
// Value returns a new Value object that may be used to inspect single value
|
||||
// for given key.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.Value("foo").Number().Equal(123)
|
||||
func (o *Object) Value(key string) *Value {
|
||||
value, ok := o.value[key]
|
||||
if !ok {
|
||||
o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
|
||||
key, dumpValue(o.value))
|
||||
return &Value{o.chain, nil}
|
||||
}
|
||||
return &Value{o.chain, value}
|
||||
}
|
||||
|
||||
// Empty succeeds if object is empty.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{})
|
||||
// object.Empty()
|
||||
func (o *Object) Empty() *Object {
|
||||
return o.Equal(map[string]interface{}{})
|
||||
}
|
||||
|
||||
// NotEmpty succeeds if object is non-empty.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.NotEmpty()
|
||||
func (o *Object) NotEmpty() *Object {
|
||||
return o.NotEqual(map[string]interface{}{})
|
||||
}
|
||||
|
||||
// Equal succeeds if object is equal to given Go map or struct.
|
||||
// Before comparison, both object and value are converted to canonical form.
|
||||
//
|
||||
// value should be map[string]interface{} or struct.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.Equal(map[string]interface{}{"foo": 123})
|
||||
func (o *Object) Equal(value interface{}) *Object {
|
||||
expected, ok := canonMap(&o.chain, value)
|
||||
if !ok {
|
||||
return o
|
||||
}
|
||||
if !reflect.DeepEqual(expected, o.value) {
|
||||
o.chain.fail("\nexpected object equal to:\n%s\n\nbut got:\n%s\n\ndiff:\n%s",
|
||||
dumpValue(expected),
|
||||
dumpValue(o.value),
|
||||
diffValues(expected, o.value))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// NotEqual succeeds if object is not equal to given Go map or struct.
|
||||
// Before comparison, both object and value are converted to canonical form.
|
||||
//
|
||||
// value should be map[string]interface{} or struct.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.Equal(map[string]interface{}{"bar": 123})
|
||||
func (o *Object) NotEqual(v interface{}) *Object {
|
||||
expected, ok := canonMap(&o.chain, v)
|
||||
if !ok {
|
||||
return o
|
||||
}
|
||||
if reflect.DeepEqual(expected, o.value) {
|
||||
o.chain.fail("\nexpected object not equal to:\n%s",
|
||||
dumpValue(expected))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// ContainsKey succeeds if object contains given key.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.ContainsKey("foo")
|
||||
func (o *Object) ContainsKey(key string) *Object {
|
||||
if !o.containsKey(key) {
|
||||
o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
|
||||
key, dumpValue(o.value))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// NotContainsKey succeeds if object doesn't contain given key.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.NotContainsKey("bar")
|
||||
func (o *Object) NotContainsKey(key string) *Object {
|
||||
if o.containsKey(key) {
|
||||
o.chain.fail(
|
||||
"\nexpected object not containing key '%s', but got:\n%s", key,
|
||||
dumpValue(o.value))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// ContainsMap succeeds if object contains given Go value.
|
||||
// Before comparison, both object and value are converted to canonical form.
|
||||
//
|
||||
// value should be map[string]interface{} or struct.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{
|
||||
// "foo": 123,
|
||||
// "bar": []interface{}{"x", "y"},
|
||||
// "bar": map[string]interface{}{
|
||||
// "a": true,
|
||||
// "b": false,
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// object.ContainsMap(map[string]interface{}{ // success
|
||||
// "foo": 123,
|
||||
// "bar": map[string]interface{}{
|
||||
// "a": true,
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// object.ContainsMap(map[string]interface{}{ // failure
|
||||
// "foo": 123,
|
||||
// "qux": 456,
|
||||
// })
|
||||
//
|
||||
// object.ContainsMap(map[string]interface{}{ // failure, slices should match exactly
|
||||
// "bar": []interface{}{"x"},
|
||||
// })
|
||||
func (o *Object) ContainsMap(value interface{}) *Object {
|
||||
if !o.containsMap(value) {
|
||||
o.chain.fail("\nexpected object containing sub-object:\n%s\n\nbut got:\n%s",
|
||||
dumpValue(value), dumpValue(o.value))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// NotContainsMap succeeds if object doesn't contain given Go value.
|
||||
// Before comparison, both object and value are converted to canonical form.
|
||||
//
|
||||
// value should be map[string]interface{} or struct.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123, "bar": 456})
|
||||
// object.NotContainsMap(map[string]interface{}{"foo": 123, "bar": "no-no-no"})
|
||||
func (o *Object) NotContainsMap(value interface{}) *Object {
|
||||
if o.containsMap(value) {
|
||||
o.chain.fail("\nexpected object not containing sub-object:\n%s\n\nbut got:\n%s",
|
||||
dumpValue(value), dumpValue(o.value))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// ValueEqual succeeds if object's value for given key is equal to given Go value.
|
||||
// Before comparison, both values are converted to canonical form.
|
||||
//
|
||||
// value should be map[string]interface{} or struct.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.ValueEqual("foo", 123)
|
||||
func (o *Object) ValueEqual(key string, value interface{}) *Object {
|
||||
if !o.containsKey(key) {
|
||||
o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
|
||||
key, dumpValue(o.value))
|
||||
return o
|
||||
}
|
||||
expected, ok := canonValue(&o.chain, value)
|
||||
if !ok {
|
||||
return o
|
||||
}
|
||||
if !reflect.DeepEqual(expected, o.value[key]) {
|
||||
o.chain.fail(
|
||||
"\nexpected value for key '%s' equal to:\n%s\n\nbut got:\n%s\n\ndiff:\n%s",
|
||||
key,
|
||||
dumpValue(expected),
|
||||
dumpValue(o.value[key]),
|
||||
diffValues(expected, o.value[key]))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// ValueNotEqual succeeds if object's value for given key is not equal to given
|
||||
// Go value. Before comparison, both values are converted to canonical form.
|
||||
//
|
||||
// value should be map[string]interface{} or struct.
|
||||
//
|
||||
// If object doesn't contain any value for given key, failure is reported.
|
||||
//
|
||||
// Example:
|
||||
// object := NewObject(t, map[string]interface{}{"foo": 123})
|
||||
// object.ValueNotEqual("foo", "bad value") // success
|
||||
// object.ValueNotEqual("bar", "bad value") // failure! (key is missing)
|
||||
func (o *Object) ValueNotEqual(key string, value interface{}) *Object {
|
||||
if !o.containsKey(key) {
|
||||
o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
|
||||
key, dumpValue(o.value))
|
||||
return o
|
||||
}
|
||||
expected, ok := canonValue(&o.chain, value)
|
||||
if !ok {
|
||||
return o
|
||||
}
|
||||
if reflect.DeepEqual(expected, o.value[key]) {
|
||||
o.chain.fail("\nexpected value for key '%s' not equal to:\n%s",
|
||||
key, dumpValue(expected))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Object) containsKey(key string) bool {
|
||||
for k := range o.value {
|
||||
if k == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *Object) containsMap(sm interface{}) bool {
|
||||
submap, ok := canonMap(&o.chain, sm)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return checkContainsMap(o.value, submap)
|
||||
}
|
||||
|
||||
func checkContainsMap(outer, inner map[string]interface{}) bool {
|
||||
for k, iv := range inner {
|
||||
ov, ok := outer[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if ovm, ok := ov.(map[string]interface{}); ok {
|
||||
if ivm, ok := iv.(map[string]interface{}); ok {
|
||||
if !checkContainsMap(ovm, ivm) {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(ov, iv) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
141
vendor/gopkg.in/gavv/httpexpect.v2/printer.go
generated
vendored
Normal file
141
vendor/gopkg.in/gavv/httpexpect.v2/printer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/moul/http2curl"
|
||||
)
|
||||
|
||||
// CurlPrinter implements Printer. Uses http2curl to dump requests as
|
||||
// curl commands.
|
||||
type CurlPrinter struct {
|
||||
logger Logger
|
||||
}
|
||||
|
||||
// NewCurlPrinter returns a new CurlPrinter given a logger.
|
||||
func NewCurlPrinter(logger Logger) CurlPrinter {
|
||||
return CurlPrinter{logger}
|
||||
}
|
||||
|
||||
// Request implements Printer.Request.
|
||||
func (p CurlPrinter) Request(req *http.Request) {
|
||||
if req != nil {
|
||||
cmd, err := http2curl.GetCurlCommand(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p.logger.Logf("%s", cmd.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Response implements Printer.Response.
|
||||
func (CurlPrinter) Response(*http.Response, time.Duration) {
|
||||
}
|
||||
|
||||
// CompactPrinter implements Printer. It prints requests in compact form.
|
||||
type CompactPrinter struct {
|
||||
logger Logger
|
||||
}
|
||||
|
||||
// NewCompactPrinter returns a new CompactPrinter given a logger.
|
||||
func NewCompactPrinter(logger Logger) CompactPrinter {
|
||||
return CompactPrinter{logger}
|
||||
}
|
||||
|
||||
// Request implements Printer.Request.
|
||||
func (p CompactPrinter) Request(req *http.Request) {
|
||||
if req != nil {
|
||||
p.logger.Logf("%s %s", req.Method, req.URL)
|
||||
}
|
||||
}
|
||||
|
||||
// Response implements Printer.Response.
|
||||
func (CompactPrinter) Response(*http.Response, time.Duration) {
|
||||
}
|
||||
|
||||
// DebugPrinter implements Printer. Uses net/http/httputil to dump
|
||||
// both requests and responses.
|
||||
type DebugPrinter struct {
|
||||
logger Logger
|
||||
body bool
|
||||
}
|
||||
|
||||
// NewDebugPrinter returns a new DebugPrinter given a logger and body
|
||||
// flag. If body is true, request and response body is also printed.
|
||||
func NewDebugPrinter(logger Logger, body bool) DebugPrinter {
|
||||
return DebugPrinter{logger, body}
|
||||
}
|
||||
|
||||
// Request implements Printer.Request.
|
||||
func (p DebugPrinter) Request(req *http.Request) {
|
||||
if req == nil {
|
||||
return
|
||||
}
|
||||
|
||||
dump, err := httputil.DumpRequest(req, p.body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p.logger.Logf("%s", dump)
|
||||
}
|
||||
|
||||
// Response implements Printer.Response.
|
||||
func (p DebugPrinter) Response(resp *http.Response, duration time.Duration) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
dump, err := httputil.DumpResponse(resp, p.body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
text := strings.Replace(string(dump), "\r\n", "\n", -1)
|
||||
lines := strings.SplitN(text, "\n", 2)
|
||||
|
||||
p.logger.Logf("%s %s\n%s", lines[0], duration, lines[1])
|
||||
}
|
||||
|
||||
// WebsocketWrite implements WebsocketPrinter.WebsocketWrite.
|
||||
func (p DebugPrinter) WebsocketWrite(typ int, content []byte, closeCode int) {
|
||||
b := &bytes.Buffer{}
|
||||
fmt.Fprintf(b, "-> Sent: %s", wsMessageTypeName(typ))
|
||||
if typ == websocket.CloseMessage {
|
||||
fmt.Fprintf(b, " (%d)", closeCode)
|
||||
}
|
||||
fmt.Fprint(b, "\n")
|
||||
if len(content) > 0 {
|
||||
if typ == websocket.BinaryMessage {
|
||||
fmt.Fprintf(b, "%v\n", content)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%s\n", content)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "\n")
|
||||
p.logger.Logf(b.String())
|
||||
}
|
||||
|
||||
// WebsocketRead implements WebsocketPrinter.WebsocketRead.
|
||||
func (p DebugPrinter) WebsocketRead(typ int, content []byte, closeCode int) {
|
||||
b := &bytes.Buffer{}
|
||||
fmt.Fprintf(b, "<- Received: %s", wsMessageTypeName(typ))
|
||||
if typ == websocket.CloseMessage {
|
||||
fmt.Fprintf(b, " (%d)", closeCode)
|
||||
}
|
||||
fmt.Fprint(b, "\n")
|
||||
if len(content) > 0 {
|
||||
if typ == websocket.BinaryMessage {
|
||||
fmt.Fprintf(b, "%v\n", content)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%s\n", content)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "\n")
|
||||
p.logger.Logf(b.String())
|
||||
}
|
||||
40
vendor/gopkg.in/gavv/httpexpect.v2/reporter.go
generated
vendored
Normal file
40
vendor/gopkg.in/gavv/httpexpect.v2/reporter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// AssertReporter implements Reporter interface using `testify/assert'
|
||||
// package. Failures are non-fatal with this reporter.
|
||||
type AssertReporter struct {
|
||||
backend *assert.Assertions
|
||||
}
|
||||
|
||||
// NewAssertReporter returns a new AssertReporter object.
|
||||
func NewAssertReporter(t assert.TestingT) *AssertReporter {
|
||||
return &AssertReporter{assert.New(t)}
|
||||
}
|
||||
|
||||
// Errorf implements Reporter.Errorf.
|
||||
func (r *AssertReporter) Errorf(message string, args ...interface{}) {
|
||||
r.backend.Fail(fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// RequireReporter implements Reporter interface using `testify/require'
|
||||
// package. Failures fatal with this reporter.
|
||||
type RequireReporter struct {
|
||||
backend *require.Assertions
|
||||
}
|
||||
|
||||
// NewRequireReporter returns a new RequireReporter object.
|
||||
func NewRequireReporter(t require.TestingT) *RequireReporter {
|
||||
return &RequireReporter{require.New(t)}
|
||||
}
|
||||
|
||||
// Errorf implements Reporter.Errorf.
|
||||
func (r *RequireReporter) Errorf(message string, args ...interface{}) {
|
||||
r.backend.FailNow(fmt.Sprintf(message, args...))
|
||||
}
|
||||
1071
vendor/gopkg.in/gavv/httpexpect.v2/request.go
generated
vendored
Normal file
1071
vendor/gopkg.in/gavv/httpexpect.v2/request.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
588
vendor/gopkg.in/gavv/httpexpect.v2/response.go
generated
vendored
Normal file
588
vendor/gopkg.in/gavv/httpexpect.v2/response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,588 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ajg/form"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// StatusRange is enum for response status ranges.
|
||||
type StatusRange int
|
||||
|
||||
const (
|
||||
// Status1xx defines "Informational" status codes.
|
||||
Status1xx StatusRange = 100
|
||||
|
||||
// Status2xx defines "Success" status codes.
|
||||
Status2xx StatusRange = 200
|
||||
|
||||
// Status3xx defines "Redirection" status codes.
|
||||
Status3xx StatusRange = 300
|
||||
|
||||
// Status4xx defines "Client Error" status codes.
|
||||
Status4xx StatusRange = 400
|
||||
|
||||
// Status5xx defines "Server Error" status codes.
|
||||
Status5xx StatusRange = 500
|
||||
)
|
||||
|
||||
// Response provides methods to inspect attached http.Response object.
|
||||
type Response struct {
|
||||
config Config
|
||||
chain chain
|
||||
resp *http.Response
|
||||
content []byte
|
||||
cookies []*http.Cookie
|
||||
websocket *websocket.Conn
|
||||
rtt *time.Duration
|
||||
}
|
||||
|
||||
// NewResponse returns a new Response given a reporter used to report
|
||||
// failures and http.Response to be inspected.
|
||||
//
|
||||
// Both reporter and response should not be nil. If response is nil,
|
||||
// failure is reported.
|
||||
//
|
||||
// If rtt is given, it defines response round-trip time to be reported
|
||||
// by response.RoundTripTime().
|
||||
func NewResponse(
|
||||
reporter Reporter, response *http.Response, rtt ...time.Duration,
|
||||
) *Response {
|
||||
var rttPtr *time.Duration
|
||||
if len(rtt) > 0 {
|
||||
rttPtr = &rtt[0]
|
||||
}
|
||||
return makeResponse(responseOpts{
|
||||
chain: makeChain(reporter),
|
||||
response: response,
|
||||
rtt: rttPtr,
|
||||
})
|
||||
}
|
||||
|
||||
type responseOpts struct {
|
||||
config Config
|
||||
chain chain
|
||||
response *http.Response
|
||||
websocket *websocket.Conn
|
||||
rtt *time.Duration
|
||||
}
|
||||
|
||||
func makeResponse(opts responseOpts) *Response {
|
||||
var content []byte
|
||||
var cookies []*http.Cookie
|
||||
if opts.response != nil {
|
||||
content = getContent(&opts.chain, opts.response)
|
||||
cookies = opts.response.Cookies()
|
||||
} else {
|
||||
opts.chain.fail("expected non-nil response")
|
||||
}
|
||||
return &Response{
|
||||
config: opts.config,
|
||||
chain: opts.chain,
|
||||
resp: opts.response,
|
||||
content: content,
|
||||
cookies: cookies,
|
||||
websocket: opts.websocket,
|
||||
rtt: opts.rtt,
|
||||
}
|
||||
}
|
||||
|
||||
func getContent(chain *chain, resp *http.Response) []byte {
|
||||
if resp.Body == nil {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
chain.fail(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
// Raw returns underlying http.Response object.
|
||||
// This is the value originally passed to NewResponse.
|
||||
func (r *Response) Raw() *http.Response {
|
||||
return r.resp
|
||||
}
|
||||
|
||||
// RoundTripTime returns a new Duration object that may be used to inspect
|
||||
// the round-trip time.
|
||||
//
|
||||
// The returned duration is a time interval starting just before request is
|
||||
// sent and ending right after response is received (handshake finished for
|
||||
// WebSocket request), retrieved from a monotonic clock source.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response, time.Duration(10000000))
|
||||
// resp.RoundTripTime().Lt(10 * time.Millisecond)
|
||||
func (r *Response) RoundTripTime() *Duration {
|
||||
return &Duration{r.chain, r.rtt}
|
||||
}
|
||||
|
||||
// Deprecated: use RoundTripTime instead.
|
||||
func (r *Response) Duration() *Number {
|
||||
if r.rtt == nil {
|
||||
return &Number{r.chain, 0}
|
||||
}
|
||||
return &Number{r.chain, float64(*r.rtt)}
|
||||
}
|
||||
|
||||
// Status succeeds if response contains given status code.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Status(http.StatusOK)
|
||||
func (r *Response) Status(status int) *Response {
|
||||
if r.chain.failed() {
|
||||
return r
|
||||
}
|
||||
r.checkEqual("status", statusCodeText(status), statusCodeText(r.resp.StatusCode))
|
||||
return r
|
||||
}
|
||||
|
||||
// StatusRange succeeds if response status belongs to given range.
|
||||
//
|
||||
// Supported ranges:
|
||||
// - Status1xx - Informational
|
||||
// - Status2xx - Success
|
||||
// - Status3xx - Redirection
|
||||
// - Status4xx - Client Error
|
||||
// - Status5xx - Server Error
|
||||
//
|
||||
// See https://en.wikipedia.org/wiki/List_of_HTTP_status_codes.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.StatusRange(Status2xx)
|
||||
func (r *Response) StatusRange(rn StatusRange) *Response {
|
||||
if r.chain.failed() {
|
||||
return r
|
||||
}
|
||||
|
||||
status := statusCodeText(r.resp.StatusCode)
|
||||
|
||||
actual := statusRangeText(r.resp.StatusCode)
|
||||
expected := statusRangeText(int(rn))
|
||||
|
||||
if actual == "" || actual != expected {
|
||||
if actual == "" {
|
||||
r.chain.fail("\nexpected status from range:\n %q\n\nbut got:\n %q",
|
||||
expected, status)
|
||||
} else {
|
||||
r.chain.fail(
|
||||
"\nexpected status from range:\n %q\n\nbut got:\n %q (%q)",
|
||||
expected, actual, status)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func statusCodeText(code int) string {
|
||||
if s := http.StatusText(code); s != "" {
|
||||
return strconv.Itoa(code) + " " + s
|
||||
}
|
||||
return strconv.Itoa(code)
|
||||
}
|
||||
|
||||
func statusRangeText(code int) string {
|
||||
switch {
|
||||
case code >= 100 && code < 200:
|
||||
return "1xx Informational"
|
||||
case code >= 200 && code < 300:
|
||||
return "2xx Success"
|
||||
case code >= 300 && code < 400:
|
||||
return "3xx Redirection"
|
||||
case code >= 400 && code < 500:
|
||||
return "4xx Client Error"
|
||||
case code >= 500 && code < 600:
|
||||
return "5xx Server Error"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// Headers returns a new Object that may be used to inspect header map.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Headers().Value("Content-Type").String().Equal("application-json")
|
||||
func (r *Response) Headers() *Object {
|
||||
var value map[string]interface{}
|
||||
if !r.chain.failed() {
|
||||
value, _ = canonMap(&r.chain, r.resp.Header)
|
||||
}
|
||||
return &Object{r.chain, value}
|
||||
}
|
||||
|
||||
// Header returns a new String object that may be used to inspect given header.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Header("Content-Type").Equal("application-json")
|
||||
// resp.Header("Date").DateTime().Le(time.Now())
|
||||
func (r *Response) Header(header string) *String {
|
||||
value := ""
|
||||
if !r.chain.failed() {
|
||||
value = r.resp.Header.Get(header)
|
||||
}
|
||||
return &String{r.chain, value}
|
||||
}
|
||||
|
||||
// Cookies returns a new Array object with all cookie names set by this response.
|
||||
// Returned Array contains a String value for every cookie name.
|
||||
//
|
||||
// Note that this returns only cookies set by Set-Cookie headers of this response.
|
||||
// It doesn't return session cookies from previous responses, which may be stored
|
||||
// in a cookie jar.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Cookies().Contains("session")
|
||||
func (r *Response) Cookies() *Array {
|
||||
if r.chain.failed() {
|
||||
return &Array{r.chain, nil}
|
||||
}
|
||||
names := []interface{}{}
|
||||
for _, c := range r.cookies {
|
||||
names = append(names, c.Name)
|
||||
}
|
||||
return &Array{r.chain, names}
|
||||
}
|
||||
|
||||
// Cookie returns a new Cookie object that may be used to inspect given cookie
|
||||
// set by this response.
|
||||
//
|
||||
// Note that this returns only cookies set by Set-Cookie headers of this response.
|
||||
// It doesn't return session cookies from previous responses, which may be stored
|
||||
// in a cookie jar.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Cookie("session").Domain().Equal("example.com")
|
||||
func (r *Response) Cookie(name string) *Cookie {
|
||||
if r.chain.failed() {
|
||||
return &Cookie{r.chain, nil}
|
||||
}
|
||||
names := []string{}
|
||||
for _, c := range r.cookies {
|
||||
if c.Name == name {
|
||||
return &Cookie{r.chain, c}
|
||||
}
|
||||
names = append(names, c.Name)
|
||||
}
|
||||
r.chain.fail("\nexpected response with cookie:\n %q\n\nbut got only cookies:\n%s",
|
||||
name, dumpValue(names))
|
||||
return &Cookie{r.chain, nil}
|
||||
}
|
||||
|
||||
// Websocket returns Websocket object that can be used to interact with
|
||||
// WebSocket server.
|
||||
//
|
||||
// May be called only if the WithWebsocketUpgrade was called on the request.
|
||||
// That is responsibility of the caller to explicitly close the websocket after use.
|
||||
//
|
||||
// Example:
|
||||
// req := NewRequest(config, "GET", "/path")
|
||||
// req.WithWebsocketUpgrade()
|
||||
// ws := req.Expect().Websocket()
|
||||
// defer ws.Disconnect()
|
||||
func (r *Response) Websocket() *Websocket {
|
||||
if !r.chain.failed() && r.websocket == nil {
|
||||
r.chain.fail("\nunexpected Websocket call for non-WebSocket response")
|
||||
}
|
||||
return makeWebsocket(r.config, r.chain, r.websocket)
|
||||
}
|
||||
|
||||
// Body returns a new String object that may be used to inspect response body.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Body().NotEmpty()
|
||||
// resp.Body().Length().Equal(100)
|
||||
func (r *Response) Body() *String {
|
||||
return &String{r.chain, string(r.content)}
|
||||
}
|
||||
|
||||
// NoContent succeeds if response contains empty Content-Type header and
|
||||
// empty body.
|
||||
func (r *Response) NoContent() *Response {
|
||||
if r.chain.failed() {
|
||||
return r
|
||||
}
|
||||
|
||||
contentType := r.resp.Header.Get("Content-Type")
|
||||
|
||||
r.checkEqual("\"Content-Type\" header", "", contentType)
|
||||
r.checkEqual("body", "", string(r.content))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// ContentType succeeds if response contains Content-Type header with given
|
||||
// media type and charset.
|
||||
//
|
||||
// If charset is omitted, and mediaType is non-empty, Content-Type header
|
||||
// should contain empty or utf-8 charset.
|
||||
//
|
||||
// If charset is omitted, and mediaType is also empty, Content-Type header
|
||||
// should contain no charset.
|
||||
func (r *Response) ContentType(mediaType string, charset ...string) *Response {
|
||||
r.checkContentType(mediaType, charset...)
|
||||
return r
|
||||
}
|
||||
|
||||
// ContentEncoding succeeds if response has exactly given Content-Encoding list.
|
||||
// Common values are empty, "gzip", "compress", "deflate", "identity" and "br".
|
||||
func (r *Response) ContentEncoding(encoding ...string) *Response {
|
||||
if r.chain.failed() {
|
||||
return r
|
||||
}
|
||||
r.checkEqual("\"Content-Encoding\" header", encoding, r.resp.Header["Content-Encoding"])
|
||||
return r
|
||||
}
|
||||
|
||||
// TransferEncoding succeeds if response contains given Transfer-Encoding list.
|
||||
// Common values are empty, "chunked" and "identity".
|
||||
func (r *Response) TransferEncoding(encoding ...string) *Response {
|
||||
if r.chain.failed() {
|
||||
return r
|
||||
}
|
||||
r.checkEqual("\"Transfer-Encoding\" header", encoding, r.resp.TransferEncoding)
|
||||
return r
|
||||
}
|
||||
|
||||
// ContentOpts define parameters for matching the response content parameters.
|
||||
type ContentOpts struct {
|
||||
// The media type Content-Type part, e.g. "application/json"
|
||||
MediaType string
|
||||
// The character set Content-Type part, e.g. "utf-8"
|
||||
Charset string
|
||||
}
|
||||
|
||||
// Text returns a new String object that may be used to inspect response body.
|
||||
//
|
||||
// Text succeeds if response contains "text/plain" Content-Type header
|
||||
// with empty or "utf-8" charset.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Text().Equal("hello, world!")
|
||||
// resp.Text(ContentOpts{
|
||||
// MediaType: "text/plain",
|
||||
// }).Equal("hello, world!")
|
||||
func (r *Response) Text(opts ...ContentOpts) *String {
|
||||
var content string
|
||||
|
||||
if !r.chain.failed() && r.checkContentOpts(opts, "text/plain") {
|
||||
content = string(r.content)
|
||||
}
|
||||
|
||||
return &String{r.chain, content}
|
||||
}
|
||||
|
||||
// Form returns a new Object that may be used to inspect form contents
|
||||
// of response.
|
||||
//
|
||||
// Form succeeds if response contains "application/x-www-form-urlencoded"
|
||||
// Content-Type header and if form may be decoded from response body.
|
||||
// Decoding is performed using https://github.com/ajg/form.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.Form().Value("foo").Equal("bar")
|
||||
// resp.Form(ContentOpts{
|
||||
// MediaType: "application/x-www-form-urlencoded",
|
||||
// }).Value("foo").Equal("bar")
|
||||
func (r *Response) Form(opts ...ContentOpts) *Object {
|
||||
object := r.getForm(opts...)
|
||||
return &Object{r.chain, object}
|
||||
}
|
||||
|
||||
func (r *Response) getForm(opts ...ContentOpts) map[string]interface{} {
|
||||
if r.chain.failed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !r.checkContentOpts(opts, "application/x-www-form-urlencoded", "") {
|
||||
return nil
|
||||
}
|
||||
|
||||
decoder := form.NewDecoder(bytes.NewReader(r.content))
|
||||
|
||||
var object map[string]interface{}
|
||||
if err := decoder.Decode(&object); err != nil {
|
||||
r.chain.fail(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
// JSON returns a new Value object that may be used to inspect JSON contents
|
||||
// of response.
|
||||
//
|
||||
// JSON succeeds if response contains "application/json" Content-Type header
|
||||
// with empty or "utf-8" charset and if JSON may be decoded from response body.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.JSON().Array().Elements("foo", "bar")
|
||||
// resp.JSON(ContentOpts{
|
||||
// MediaType: "application/json",
|
||||
// }).Array.Elements("foo", "bar")
|
||||
func (r *Response) JSON(opts ...ContentOpts) *Value {
|
||||
value := r.getJSON(opts...)
|
||||
return &Value{r.chain, value}
|
||||
}
|
||||
|
||||
func (r *Response) getJSON(opts ...ContentOpts) interface{} {
|
||||
if r.chain.failed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !r.checkContentOpts(opts, "application/json") {
|
||||
return nil
|
||||
}
|
||||
|
||||
var value interface{}
|
||||
if err := json.Unmarshal(r.content, &value); err != nil {
|
||||
r.chain.fail(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// JSONP returns a new Value object that may be used to inspect JSONP contents
|
||||
// of response.
|
||||
//
|
||||
// JSONP succeeds if response contains "application/javascript" Content-Type
|
||||
// header with empty or "utf-8" charset and response body of the following form:
|
||||
// callback(<valid json>);
|
||||
// or:
|
||||
// callback(<valid json>)
|
||||
//
|
||||
// Whitespaces are allowed.
|
||||
//
|
||||
// Example:
|
||||
// resp := NewResponse(t, response)
|
||||
// resp.JSONP("myCallback").Array().Elements("foo", "bar")
|
||||
// resp.JSONP("myCallback", ContentOpts{
|
||||
// MediaType: "application/javascript",
|
||||
// }).Array.Elements("foo", "bar")
|
||||
func (r *Response) JSONP(callback string, opts ...ContentOpts) *Value {
|
||||
value := r.getJSONP(callback, opts...)
|
||||
return &Value{r.chain, value}
|
||||
}
|
||||
|
||||
var (
|
||||
jsonp = regexp.MustCompile(`^\s*([^\s(]+)\s*\((.*)\)\s*;*\s*$`)
|
||||
)
|
||||
|
||||
func (r *Response) getJSONP(callback string, opts ...ContentOpts) interface{} {
|
||||
if r.chain.failed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !r.checkContentOpts(opts, "application/javascript") {
|
||||
return nil
|
||||
}
|
||||
|
||||
m := jsonp.FindSubmatch(r.content)
|
||||
if len(m) != 3 || string(m[1]) != callback {
|
||||
r.chain.fail(
|
||||
"\nexpected JSONP body in form of:\n \"%s(<valid json>)\"\n\nbut got:\n %q\n",
|
||||
callback,
|
||||
string(r.content))
|
||||
return nil
|
||||
}
|
||||
|
||||
var value interface{}
|
||||
if err := json.Unmarshal(m[2], &value); err != nil {
|
||||
r.chain.fail(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func (r *Response) checkContentOpts(
|
||||
opts []ContentOpts, expectedType string, expectedCharset ...string,
|
||||
) bool {
|
||||
if len(opts) != 0 {
|
||||
if opts[0].MediaType != "" {
|
||||
expectedType = opts[0].MediaType
|
||||
}
|
||||
if opts[0].Charset != "" {
|
||||
expectedCharset = []string{opts[0].Charset}
|
||||
}
|
||||
}
|
||||
return r.checkContentType(expectedType, expectedCharset...)
|
||||
}
|
||||
|
||||
func (r *Response) checkContentType(expectedType string, expectedCharset ...string) bool {
|
||||
if r.chain.failed() {
|
||||
return false
|
||||
}
|
||||
|
||||
contentType := r.resp.Header.Get("Content-Type")
|
||||
|
||||
if expectedType == "" && len(expectedCharset) == 0 {
|
||||
if contentType == "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
mediaType, params, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
r.chain.fail("\ngot invalid \"Content-Type\" header %q", contentType)
|
||||
return false
|
||||
}
|
||||
|
||||
if mediaType != expectedType {
|
||||
r.chain.fail(
|
||||
"\nexpected \"Content-Type\" header with %q media type,"+
|
||||
"\nbut got %q", expectedType, mediaType)
|
||||
return false
|
||||
}
|
||||
|
||||
charset := params["charset"]
|
||||
|
||||
if len(expectedCharset) == 0 {
|
||||
if charset != "" && !strings.EqualFold(charset, "utf-8") {
|
||||
r.chain.fail(
|
||||
"\nexpected \"Content-Type\" header with \"utf-8\" or empty charset,"+
|
||||
"\nbut got %q", charset)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !strings.EqualFold(charset, expectedCharset[0]) {
|
||||
r.chain.fail(
|
||||
"\nexpected \"Content-Type\" header with %q charset,"+
|
||||
"\nbut got %q", expectedCharset[0], charset)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *Response) checkEqual(what string, expected, actual interface{}) {
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
r.chain.fail("\nexpected %s equal to:\n%s\n\nbut got:\n%s", what,
|
||||
dumpValue(expected), dumpValue(actual))
|
||||
}
|
||||
}
|
||||
320
vendor/gopkg.in/gavv/httpexpect.v2/string.go
generated
vendored
Normal file
320
vendor/gopkg.in/gavv/httpexpect.v2/string.go
generated
vendored
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// String provides methods to inspect attached string value
|
||||
// (Go representation of JSON string).
|
||||
type String struct {
|
||||
chain chain
|
||||
value string
|
||||
}
|
||||
|
||||
// NewString returns a new String given a reporter used to report failures
|
||||
// and value to be inspected.
|
||||
//
|
||||
// reporter should not be nil.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
func NewString(reporter Reporter, value string) *String {
|
||||
return &String{makeChain(reporter), value}
|
||||
}
|
||||
|
||||
// Raw returns underlying value attached to String.
|
||||
// This is the value originally passed to NewString.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// assert.Equal(t, "Hello", str.Raw())
|
||||
func (s *String) Raw() string {
|
||||
return s.value
|
||||
}
|
||||
|
||||
// Path is similar to Value.Path.
|
||||
func (s *String) Path(path string) *Value {
|
||||
return getPath(&s.chain, s.value, path)
|
||||
}
|
||||
|
||||
// Schema is similar to Value.Schema.
|
||||
func (s *String) Schema(schema interface{}) *String {
|
||||
checkSchema(&s.chain, s.value, schema)
|
||||
return s
|
||||
}
|
||||
|
||||
// Length returns a new Number object that may be used to inspect string length.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.Length().Equal(5)
|
||||
func (s *String) Length() *Number {
|
||||
return &Number{s.chain, float64(len(s.value))}
|
||||
}
|
||||
|
||||
// DateTime parses date/time from string an returns a new DateTime object.
|
||||
//
|
||||
// If layout is given, DateTime() uses time.Parse() with given layout.
|
||||
// Otherwise, it uses http.ParseTime(). If pasing error occurred,
|
||||
// DateTime reports failure and returns empty (but non-nil) object.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Tue, 15 Nov 1994 08:12:31 GMT")
|
||||
// str.DateTime().Lt(time.Now())
|
||||
//
|
||||
// str := NewString(t, "15 Nov 94 08:12 GMT")
|
||||
// str.DateTime(time.RFC822).Lt(time.Now())
|
||||
func (s *String) DateTime(layout ...string) *DateTime {
|
||||
if s.chain.failed() {
|
||||
return &DateTime{s.chain, time.Unix(0, 0)}
|
||||
}
|
||||
var (
|
||||
t time.Time
|
||||
err error
|
||||
)
|
||||
if len(layout) != 0 {
|
||||
t, err = time.Parse(layout[0], s.value)
|
||||
} else {
|
||||
t, err = http.ParseTime(s.value)
|
||||
}
|
||||
if err != nil {
|
||||
s.chain.fail(err.Error())
|
||||
return &DateTime{s.chain, time.Unix(0, 0)}
|
||||
}
|
||||
return &DateTime{s.chain, t}
|
||||
}
|
||||
|
||||
// Empty succeeds if string is empty.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "")
|
||||
// str.Empty()
|
||||
func (s *String) Empty() *String {
|
||||
return s.Equal("")
|
||||
}
|
||||
|
||||
// NotEmpty succeeds if string is non-empty.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.NotEmpty()
|
||||
func (s *String) NotEmpty() *String {
|
||||
return s.NotEqual("")
|
||||
}
|
||||
|
||||
// Equal succeeds if string is equal to given Go string.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.Equal("Hello")
|
||||
func (s *String) Equal(value string) *String {
|
||||
if !(s.value == value) {
|
||||
s.chain.fail("\nexpected string equal to:\n %q\n\nbut got:\n %q",
|
||||
value, s.value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// NotEqual succeeds if string is not equal to given Go string.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.NotEqual("Goodbye")
|
||||
func (s *String) NotEqual(value string) *String {
|
||||
if !(s.value != value) {
|
||||
s.chain.fail("\nexpected string not equal to:\n %q", value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// EqualFold succeeds if string is equal to given Go string after applying Unicode
|
||||
// case-folding (so it's a case-insensitive match).
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.EqualFold("hELLo")
|
||||
func (s *String) EqualFold(value string) *String {
|
||||
if !strings.EqualFold(s.value, value) {
|
||||
s.chain.fail(
|
||||
"\nexpected string equal to (case-insensitive):\n %q\n\nbut got:\n %q",
|
||||
value, s.value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// NotEqualFold succeeds if string is not equal to given Go string after applying
|
||||
// Unicode case-folding (so it's a case-insensitive match).
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.NotEqualFold("gOODBYe")
|
||||
func (s *String) NotEqualFold(value string) *String {
|
||||
if strings.EqualFold(s.value, value) {
|
||||
s.chain.fail(
|
||||
"\nexpected string not equal to (case-insensitive):\n %q\n\nbut got:\n %q",
|
||||
value, s.value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Contains succeeds if string contains given Go string as a substring.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.Contains("ell")
|
||||
func (s *String) Contains(value string) *String {
|
||||
if !strings.Contains(s.value, value) {
|
||||
s.chain.fail(
|
||||
"\nexpected string containing substring:\n %q\n\nbut got:\n %q",
|
||||
value, s.value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// NotContains succeeds if string doesn't contain Go string as a substring.
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.NotContains("bye")
|
||||
func (s *String) NotContains(value string) *String {
|
||||
if strings.Contains(s.value, value) {
|
||||
s.chain.fail(
|
||||
"\nexpected string not containing substring:\n %q\n\nbut got:\n %q",
|
||||
value, s.value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ContainsFold succeeds if string contains given Go string as a substring after
|
||||
// applying Unicode case-folding (so it's a case-insensitive match).
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.ContainsFold("ELL")
|
||||
func (s *String) ContainsFold(value string) *String {
|
||||
if !strings.Contains(strings.ToLower(s.value), strings.ToLower(value)) {
|
||||
s.chain.fail(
|
||||
"\nexpected string containing substring (case-insensitive):\n %q"+
|
||||
"\n\nbut got:\n %q", value, s.value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// NotContainsFold succeeds if string doesn't contain given Go string as a substring
|
||||
// after applying Unicode case-folding (so it's a case-insensitive match).
|
||||
//
|
||||
// Example:
|
||||
// str := NewString(t, "Hello")
|
||||
// str.NotContainsFold("BYE")
|
||||
func (s *String) NotContainsFold(value string) *String {
|
||||
if strings.Contains(strings.ToLower(s.value), strings.ToLower(value)) {
|
||||
s.chain.fail(
|
||||
"\nexpected string not containing substring (case-insensitive):\n %q"+
|
||||
"\n\nbut got:\n %q", value, s.value)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Match matches the string with given regexp and returns a new Match object
|
||||
// with found submatches.
|
||||
//
|
||||
// If regexp is invalid or string doesn't match regexp, Match fails and returns
|
||||
// empty (but non-nil) object. regexp.Compile is used to construct regexp, and
|
||||
// Regexp.FindStringSubmatch is used to construct matches.
|
||||
//
|
||||
// Example:
|
||||
// s := NewString(t, "http://example.com/users/john")
|
||||
// m := s.Match(`http://(?P<host>.+)/users/(?P<user>.+)`)
|
||||
//
|
||||
// m.NotEmpty()
|
||||
// m.Length().Equal(3)
|
||||
//
|
||||
// m.Index(0).Equal("http://example.com/users/john")
|
||||
// m.Index(1).Equal("example.com")
|
||||
// m.Index(2).Equal("john")
|
||||
//
|
||||
// m.Name("host").Equal("example.com")
|
||||
// m.Name("user").Equal("john")
|
||||
func (s *String) Match(re string) *Match {
|
||||
r, err := regexp.Compile(re)
|
||||
if err != nil {
|
||||
s.chain.fail(err.Error())
|
||||
return makeMatch(s.chain, nil, nil)
|
||||
}
|
||||
|
||||
m := r.FindStringSubmatch(s.value)
|
||||
if m == nil {
|
||||
s.chain.fail("\nexpected string matching regexp:\n `%s`\n\nbut got:\n %q",
|
||||
re, s.value)
|
||||
return makeMatch(s.chain, nil, nil)
|
||||
}
|
||||
|
||||
return makeMatch(s.chain, m, r.SubexpNames())
|
||||
}
|
||||
|
||||
// MatchAll find all matches in string for given regexp and returns a list
|
||||
// of found matches.
|
||||
//
|
||||
// If regexp is invalid or string doesn't match regexp, MatchAll fails and
|
||||
// returns empty (but non-nil) slice. regexp.Compile is used to construct
|
||||
// regexp, and Regexp.FindAllStringSubmatch is used to find matches.
|
||||
//
|
||||
// Example:
|
||||
// s := NewString(t,
|
||||
// "http://example.com/users/john http://example.com/users/bob")
|
||||
//
|
||||
// m := s.MatchAll(`http://(?P<host>\S+)/users/(?P<user>\S+)`)
|
||||
//
|
||||
// m[0].Name("user").Equal("john")
|
||||
// m[1].Name("user").Equal("bob")
|
||||
func (s *String) MatchAll(re string) []Match {
|
||||
r, err := regexp.Compile(re)
|
||||
if err != nil {
|
||||
s.chain.fail(err.Error())
|
||||
return []Match{}
|
||||
}
|
||||
|
||||
matches := r.FindAllStringSubmatch(s.value, -1)
|
||||
if matches == nil {
|
||||
s.chain.fail("\nexpected string matching regexp:\n `%s`\n\nbut got:\n %q",
|
||||
re, s.value)
|
||||
return []Match{}
|
||||
}
|
||||
|
||||
ret := []Match{}
|
||||
for _, m := range matches {
|
||||
ret = append(ret, *makeMatch(
|
||||
s.chain,
|
||||
m,
|
||||
r.SubexpNames()))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// NotMatch succeeds if the string doesn't match to given regexp.
|
||||
//
|
||||
// regexp.Compile is used to construct regexp, and Regexp.MatchString
|
||||
// is used to perform match.
|
||||
//
|
||||
// Example:
|
||||
// s := NewString(t, "a")
|
||||
// s.NotMatch(`[^a]`)
|
||||
func (s *String) NotMatch(re string) *String {
|
||||
r, err := regexp.Compile(re)
|
||||
if err != nil {
|
||||
s.chain.fail(err.Error())
|
||||
return s
|
||||
}
|
||||
|
||||
if r.MatchString(s.value) {
|
||||
s.chain.fail("\nexpected string not matching regexp:\n `%s`\n\nbut got:\n %q",
|
||||
re, s.value)
|
||||
return s
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
286
vendor/gopkg.in/gavv/httpexpect.v2/value.go
generated
vendored
Normal file
286
vendor/gopkg.in/gavv/httpexpect.v2/value.go
generated
vendored
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Value provides methods to inspect attached interface{} object
|
||||
// (Go representation of arbitrary JSON value) and cast it to
|
||||
// concrete type.
|
||||
type Value struct {
|
||||
chain chain
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// NewValue returns a new Value given a reporter used to report failures
|
||||
// and value to be inspected.
|
||||
//
|
||||
// reporter should not be nil, but value may be nil.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, map[string]interface{}{"foo": 123})
|
||||
// value.Object()
|
||||
//
|
||||
// value := NewValue(t, []interface{}{"foo", 123})
|
||||
// value.Array()
|
||||
//
|
||||
// value := NewValue(t, "foo")
|
||||
// value.String()
|
||||
//
|
||||
// value := NewValue(t, 123)
|
||||
// value.Number()
|
||||
//
|
||||
// value := NewValue(t, true)
|
||||
// value.Boolean()
|
||||
//
|
||||
// value := NewValue(t, nil)
|
||||
// value.Null()
|
||||
func NewValue(reporter Reporter, value interface{}) *Value {
|
||||
chain := makeChain(reporter)
|
||||
if value != nil {
|
||||
value, _ = canonValue(&chain, value)
|
||||
}
|
||||
return &Value{chain, value}
|
||||
}
|
||||
|
||||
// Raw returns underlying value attached to Value.
|
||||
// This is the value originally passed to NewValue, converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, "foo")
|
||||
// assert.Equal(t, "foo", number.Raw().(string))
|
||||
func (v *Value) Raw() interface{} {
|
||||
return v.value
|
||||
}
|
||||
|
||||
// Path returns a new Value object for child object(s) matching given
|
||||
// JSONPath expression.
|
||||
//
|
||||
// JSONPath is a simple XPath-like query language.
|
||||
// See http://goessner.net/articles/JsonPath/.
|
||||
//
|
||||
// We currently use https://github.com/yalp/jsonpath, which implements
|
||||
// only a subset of JSONPath, yet useful for simple queries. It doesn't
|
||||
// support filters and requires double quotes for strings.
|
||||
//
|
||||
// Example 1:
|
||||
// json := `{"users": [{"name": "john"}, {"name": "bob"}]}`
|
||||
// value := NewValue(t, json)
|
||||
//
|
||||
// value.Path("$.users[0].name").String().Equal("john")
|
||||
// value.Path("$.users[1].name").String().Equal("bob")
|
||||
//
|
||||
// Example 2:
|
||||
// json := `{"yfGH2a": {"user": "john"}, "f7GsDd": {"user": "john"}}`
|
||||
// value := NewValue(t, json)
|
||||
//
|
||||
// for _, user := range value.Path("$..user").Array().Iter() {
|
||||
// user.String().Equal("john")
|
||||
// }
|
||||
func (v *Value) Path(path string) *Value {
|
||||
return getPath(&v.chain, v.value, path)
|
||||
}
|
||||
|
||||
// Schema succeeds if value matches given JSON Schema.
|
||||
//
|
||||
// JSON Schema specifies a JSON-based format to define the structure of
|
||||
// JSON data. See http://json-schema.org/.
|
||||
// We use https://github.com/xeipuuv/gojsonschema implementation.
|
||||
//
|
||||
// schema should be one of the following:
|
||||
// - go value that can be json.Marshal-ed to a valid schema
|
||||
// - type convertible to string containing valid schema
|
||||
// - type convertible to string containing valid http:// or file:// URI,
|
||||
// pointing to reachable and valid schema
|
||||
//
|
||||
// Example 1:
|
||||
// schema := `{
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "foo": {
|
||||
// "type": "string"
|
||||
// },
|
||||
// "bar": {
|
||||
// "type": "integer"
|
||||
// }
|
||||
// },
|
||||
// "require": ["foo", "bar"]
|
||||
// }`
|
||||
//
|
||||
// value := NewValue(t, map[string]interface{}{
|
||||
// "foo": "a",
|
||||
// "bar": 1,
|
||||
// })
|
||||
//
|
||||
// value.Schema(schema)
|
||||
//
|
||||
// Example 2:
|
||||
// value := NewValue(t, data)
|
||||
// value.Schema("http://example.com/schema.json")
|
||||
func (v *Value) Schema(schema interface{}) *Value {
|
||||
checkSchema(&v.chain, v.value, schema)
|
||||
return v
|
||||
}
|
||||
|
||||
// Object returns a new Object attached to underlying value.
|
||||
//
|
||||
// If underlying value is not an object (map[string]interface{}), failure is reported
|
||||
// and empty (but non-nil) value is returned.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, map[string]interface{}{"foo": 123})
|
||||
// value.Object().ContainsKey("foo")
|
||||
func (v *Value) Object() *Object {
|
||||
data, ok := v.value.(map[string]interface{})
|
||||
if !ok {
|
||||
v.chain.fail("\nexpected object value (map or struct), but got:\n%s",
|
||||
dumpValue(v.value))
|
||||
}
|
||||
return &Object{v.chain, data}
|
||||
}
|
||||
|
||||
// Array returns a new Array attached to underlying value.
|
||||
//
|
||||
// If underlying value is not an array ([]interface{}), failure is reported and empty
|
||||
// (but non-nil) value is returned.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, []interface{}{"foo", 123})
|
||||
// value.Array().Elements("foo", 123)
|
||||
func (v *Value) Array() *Array {
|
||||
data, ok := v.value.([]interface{})
|
||||
if !ok {
|
||||
v.chain.fail("\nexpected array value, but got:\n%s",
|
||||
dumpValue(v.value))
|
||||
}
|
||||
return &Array{v.chain, data}
|
||||
}
|
||||
|
||||
// String returns a new String attached to underlying value.
|
||||
//
|
||||
// If underlying value is not a string, failure is reported and empty (but non-nil)
|
||||
// value is returned.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, "foo")
|
||||
// value.String().EqualFold("FOO")
|
||||
func (v *Value) String() *String {
|
||||
data, ok := v.value.(string)
|
||||
if !ok {
|
||||
v.chain.fail("\nexpected string value, but got:\n%s",
|
||||
dumpValue(v.value))
|
||||
}
|
||||
return &String{v.chain, data}
|
||||
}
|
||||
|
||||
// Number returns a new Number attached to underlying value.
|
||||
//
|
||||
// If underlying value is not a number (numeric type convertible to float64), failure
|
||||
// is reported and empty (but non-nil) value is returned.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, 123)
|
||||
// value.Number().InRange(100, 200)
|
||||
func (v *Value) Number() *Number {
|
||||
data, ok := v.value.(float64)
|
||||
if !ok {
|
||||
v.chain.fail("\nexpected numeric value, but got:\n%s",
|
||||
dumpValue(v.value))
|
||||
}
|
||||
return &Number{v.chain, data}
|
||||
}
|
||||
|
||||
// Boolean returns a new Boolean attached to underlying value.
|
||||
//
|
||||
// If underlying value is not a bool, failure is reported and empty (but non-nil)
|
||||
// value is returned.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, true)
|
||||
// value.Boolean().True()
|
||||
func (v *Value) Boolean() *Boolean {
|
||||
data, ok := v.value.(bool)
|
||||
if !ok {
|
||||
v.chain.fail("\nexpected boolean value, but got:\n%s",
|
||||
dumpValue(v.value))
|
||||
}
|
||||
return &Boolean{v.chain, data}
|
||||
}
|
||||
|
||||
// Null succeeds if value is nil.
|
||||
//
|
||||
// Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
|
||||
// is also treated as null value. Empty (non-nil) slice or map, empty string, and
|
||||
// zero number are not treated as null value.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, nil)
|
||||
// value.Null()
|
||||
//
|
||||
// value := NewValue(t, []interface{}(nil))
|
||||
// value.Null()
|
||||
func (v *Value) Null() *Value {
|
||||
if v.value != nil {
|
||||
v.chain.fail("\nexpected nil value, but got:\n%s",
|
||||
dumpValue(v.value))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// NotNull succeeds if value is not nil.
|
||||
//
|
||||
// Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
|
||||
// is also treated as null value. Empty (non-nil) slice or map, empty string, and
|
||||
// zero number are not treated as null value.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, "")
|
||||
// value.NotNull()
|
||||
//
|
||||
// value := NewValue(t, make([]interface{}, 0)
|
||||
// value.Null()
|
||||
func (v *Value) NotNull() *Value {
|
||||
if v.value == nil {
|
||||
v.chain.fail("\nexpected non-nil value, but got:\n%s",
|
||||
dumpValue(v.value))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Equal succeeds if value is equal to given Go value (e.g. map, slice, string, etc).
|
||||
// Before comparison, both values are converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, "foo")
|
||||
// value.Equal("foo")
|
||||
func (v *Value) Equal(value interface{}) *Value {
|
||||
expected, ok := canonValue(&v.chain, value)
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
if !reflect.DeepEqual(expected, v.value) {
|
||||
v.chain.fail("\nexpected value equal to:\n%s\n\nbut got:\n%s\n\ndiff:\n%s",
|
||||
dumpValue(expected),
|
||||
dumpValue(v.value),
|
||||
diffValues(expected, v.value))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// NotEqual succeeds if value is not equal to given Go value (e.g. map, slice,
|
||||
// string, etc). Before comparison, both values are converted to canonical form.
|
||||
//
|
||||
// Example:
|
||||
// value := NewValue(t, "foo")
|
||||
// value.NorEqual("bar")
|
||||
func (v *Value) NotEqual(value interface{}) *Value {
|
||||
expected, ok := canonValue(&v.chain, value)
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
if reflect.DeepEqual(expected, v.value) {
|
||||
v.chain.fail("\nexpected value not equal to:\n%s",
|
||||
dumpValue(expected))
|
||||
}
|
||||
return v
|
||||
}
|
||||
424
vendor/gopkg.in/gavv/httpexpect.v2/websocket.go
generated
vendored
Normal file
424
vendor/gopkg.in/gavv/httpexpect.v2/websocket.go
generated
vendored
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const noDuration = time.Duration(0)
|
||||
|
||||
var infiniteTime = time.Time{}
|
||||
|
||||
// Websocket provides methods to read from, write into and close WebSocket
|
||||
// connection.
|
||||
type Websocket struct {
|
||||
config Config
|
||||
chain chain
|
||||
conn *websocket.Conn
|
||||
readTimeout time.Duration
|
||||
writeTimeout time.Duration
|
||||
isClosed bool
|
||||
}
|
||||
|
||||
// NewWebsocket returns a new Websocket given a Config with Reporter and
|
||||
// Printers, and websocket.Conn to be inspected and handled.
|
||||
func NewWebsocket(config Config, conn *websocket.Conn) *Websocket {
|
||||
return makeWebsocket(config, makeChain(config.Reporter), conn)
|
||||
}
|
||||
|
||||
func makeWebsocket(config Config, chain chain, conn *websocket.Conn) *Websocket {
|
||||
return &Websocket{
|
||||
config: config,
|
||||
chain: chain,
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
// Raw returns underlying websocket.Conn object.
|
||||
// This is the value originally passed to NewConnection.
|
||||
func (c *Websocket) Raw() *websocket.Conn {
|
||||
return c.conn
|
||||
}
|
||||
|
||||
// WithReadTimeout sets timeout duration for WebSocket connection reads.
|
||||
//
|
||||
// By default no timeout is used.
|
||||
func (c *Websocket) WithReadTimeout(timeout time.Duration) *Websocket {
|
||||
c.readTimeout = timeout
|
||||
return c
|
||||
}
|
||||
|
||||
// WithoutReadTimeout removes timeout for WebSocket connection reads.
|
||||
func (c *Websocket) WithoutReadTimeout() *Websocket {
|
||||
c.readTimeout = noDuration
|
||||
return c
|
||||
}
|
||||
|
||||
// WithWriteTimeout sets timeout duration for WebSocket connection writes.
|
||||
//
|
||||
// By default no timeout is used.
|
||||
func (c *Websocket) WithWriteTimeout(timeout time.Duration) *Websocket {
|
||||
c.writeTimeout = timeout
|
||||
return c
|
||||
}
|
||||
|
||||
// WithoutWriteTimeout removes timeout for WebSocket connection writes.
|
||||
//
|
||||
// If not used then DefaultWebsocketTimeout will be used.
|
||||
func (c *Websocket) WithoutWriteTimeout() *Websocket {
|
||||
c.writeTimeout = noDuration
|
||||
return c
|
||||
}
|
||||
|
||||
// Subprotocol returns a new String object that may be used to inspect
|
||||
// negotiated protocol for the connection.
|
||||
func (c *Websocket) Subprotocol() *String {
|
||||
s := &String{chain: c.chain}
|
||||
if c.conn != nil {
|
||||
s.value = c.conn.Subprotocol()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Expect reads next message from WebSocket connection and
|
||||
// returns a new WebsocketMessage object to inspect received message.
|
||||
//
|
||||
// Example:
|
||||
// msg := conn.Expect()
|
||||
// msg.JSON().Object().ValueEqual("message", "hi")
|
||||
func (c *Websocket) Expect() *WebsocketMessage {
|
||||
switch {
|
||||
case c.chain.failed():
|
||||
return makeWebsocketMessage(c.chain)
|
||||
case c.conn == nil:
|
||||
c.chain.fail("\nunexpected read from failed WebSocket connection")
|
||||
return makeWebsocketMessage(c.chain)
|
||||
case c.isClosed:
|
||||
c.chain.fail("\nunexpected read from closed WebSocket connection")
|
||||
return makeWebsocketMessage(c.chain)
|
||||
case !c.setReadDeadline():
|
||||
return makeWebsocketMessage(c.chain)
|
||||
}
|
||||
var err error
|
||||
m := makeWebsocketMessage(c.chain)
|
||||
m.typ, m.content, err = c.conn.ReadMessage()
|
||||
if err != nil {
|
||||
if cls, ok := err.(*websocket.CloseError); ok {
|
||||
m.typ = websocket.CloseMessage
|
||||
m.closeCode = cls.Code
|
||||
m.content = []byte(cls.Text)
|
||||
c.printRead(m.typ, m.content, m.closeCode)
|
||||
} else {
|
||||
c.chain.fail(
|
||||
"\nexpected read WebSocket connection, "+
|
||||
"but got failure: %s", err.Error())
|
||||
return makeWebsocketMessage(c.chain)
|
||||
}
|
||||
} else {
|
||||
c.printRead(m.typ, m.content, m.closeCode)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (c *Websocket) setReadDeadline() bool {
|
||||
deadline := infiniteTime
|
||||
if c.readTimeout != noDuration {
|
||||
deadline = time.Now().Add(c.readTimeout)
|
||||
}
|
||||
if err := c.conn.SetReadDeadline(deadline); err != nil {
|
||||
c.chain.fail(
|
||||
"\nunexpected failure when setting "+
|
||||
"read WebSocket connection deadline: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Websocket) printRead(typ int, content []byte, closeCode int) {
|
||||
for _, printer := range c.config.Printers {
|
||||
if p, ok := printer.(WebsocketPrinter); ok {
|
||||
p.WebsocketRead(typ, content, closeCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect closes the underlying WebSocket connection without sending or
|
||||
// waiting for a close message.
|
||||
//
|
||||
// It's okay to call this function multiple times.
|
||||
//
|
||||
// It's recommended to always call this function after connection usage is over
|
||||
// to ensure that no resource leaks will happen.
|
||||
//
|
||||
// Example:
|
||||
// conn := resp.Connection()
|
||||
// defer conn.Disconnect()
|
||||
func (c *Websocket) Disconnect() *Websocket {
|
||||
if c.conn == nil || c.isClosed {
|
||||
return c
|
||||
}
|
||||
c.isClosed = true
|
||||
if err := c.conn.Close(); err != nil {
|
||||
c.chain.fail("close error when disconnecting webcoket: " + err.Error())
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Close cleanly closes the underlying WebSocket connection
|
||||
// by sending an empty close message and then waiting (with timeout)
|
||||
// for the server to close the connection.
|
||||
//
|
||||
// WebSocket close code may be optionally specified.
|
||||
// If not, then "1000 - Normal Closure" will be used.
|
||||
//
|
||||
// WebSocket close codes are defined in RFC 6455, section 11.7.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// It's okay to call this function multiple times.
|
||||
//
|
||||
// Example:
|
||||
// conn := resp.Connection()
|
||||
// conn.Close(websocket.CloseUnsupportedData)
|
||||
func (c *Websocket) Close(code ...int) *Websocket {
|
||||
switch {
|
||||
case c.checkUnusable("Close"):
|
||||
return c
|
||||
case len(code) > 1:
|
||||
c.chain.fail("\nunexpected multiple code arguments passed to Close")
|
||||
return c
|
||||
}
|
||||
return c.CloseWithBytes(nil, code...)
|
||||
}
|
||||
|
||||
// CloseWithBytes cleanly closes the underlying WebSocket connection
|
||||
// by sending given slice of bytes as a close message and then waiting
|
||||
// (with timeout) for the server to close the connection.
|
||||
//
|
||||
// WebSocket close code may be optionally specified.
|
||||
// If not, then "1000 - Normal Closure" will be used.
|
||||
//
|
||||
// WebSocket close codes are defined in RFC 6455, section 11.7.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// It's okay to call this function multiple times.
|
||||
//
|
||||
// Example:
|
||||
// conn := resp.Connection()
|
||||
// conn.CloseWithBytes([]byte("bye!"), websocket.CloseGoingAway)
|
||||
func (c *Websocket) CloseWithBytes(b []byte, code ...int) *Websocket {
|
||||
switch {
|
||||
case c.checkUnusable("CloseWithBytes"):
|
||||
return c
|
||||
case len(code) > 1:
|
||||
c.chain.fail(
|
||||
"\nunexpected multiple code arguments passed to CloseWithBytes")
|
||||
return c
|
||||
}
|
||||
|
||||
c.WriteMessage(websocket.CloseMessage, b, code...)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// CloseWithJSON cleanly closes the underlying WebSocket connection
|
||||
// by sending given object (marshaled using json.Marshal()) as a close message
|
||||
// and then waiting (with timeout) for the server to close the connection.
|
||||
//
|
||||
// WebSocket close code may be optionally specified.
|
||||
// If not, then "1000 - Normal Closure" will be used.
|
||||
//
|
||||
// WebSocket close codes are defined in RFC 6455, section 11.7.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// It's okay to call this function multiple times.
|
||||
//
|
||||
// Example:
|
||||
// type MyJSON struct {
|
||||
// Foo int `json:"foo"`
|
||||
// }
|
||||
//
|
||||
// conn := resp.Connection()
|
||||
// conn.CloseWithJSON(MyJSON{Foo: 123}, websocket.CloseUnsupportedData)
|
||||
func (c *Websocket) CloseWithJSON(
|
||||
object interface{}, code ...int,
|
||||
) *Websocket {
|
||||
switch {
|
||||
case c.checkUnusable("CloseWithJSON"):
|
||||
return c
|
||||
case len(code) > 1:
|
||||
c.chain.fail(
|
||||
"\nunexpected multiple code arguments passed to CloseWithJSON")
|
||||
return c
|
||||
}
|
||||
|
||||
b, err := json.Marshal(object)
|
||||
if err != nil {
|
||||
c.chain.fail(err.Error())
|
||||
return c
|
||||
}
|
||||
return c.CloseWithBytes(b, code...)
|
||||
}
|
||||
|
||||
// CloseWithText cleanly closes the underlying WebSocket connection
|
||||
// by sending given text as a close message and then waiting (with timeout)
|
||||
// for the server to close the connection.
|
||||
//
|
||||
// WebSocket close code may be optionally specified.
|
||||
// If not, then "1000 - Normal Closure" will be used.
|
||||
//
|
||||
// WebSocket close codes are defined in RFC 6455, section 11.7.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// It's okay to call this function multiple times.
|
||||
//
|
||||
// Example:
|
||||
// conn := resp.Connection()
|
||||
// conn.CloseWithText("bye!")
|
||||
func (c *Websocket) CloseWithText(s string, code ...int) *Websocket {
|
||||
switch {
|
||||
case c.checkUnusable("CloseWithText"):
|
||||
return c
|
||||
case len(code) > 1:
|
||||
c.chain.fail(
|
||||
"\nunexpected multiple code arguments passed to CloseWithText")
|
||||
return c
|
||||
}
|
||||
return c.CloseWithBytes([]byte(s), code...)
|
||||
}
|
||||
|
||||
// WriteMessage writes to the underlying WebSocket connection a message
|
||||
// of given type with given content.
|
||||
// Additionally, WebSocket close code may be specified for close messages.
|
||||
//
|
||||
// WebSocket message types are defined in RFC 6455, section 11.8.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// WebSocket close codes are defined in RFC 6455, section 11.7.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// Example:
|
||||
// conn := resp.Connection()
|
||||
// conn.WriteMessage(websocket.CloseMessage, []byte("Namárië..."))
|
||||
func (c *Websocket) WriteMessage(
|
||||
typ int, content []byte, closeCode ...int,
|
||||
) *Websocket {
|
||||
if c.checkUnusable("WriteMessage") {
|
||||
return c
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case websocket.TextMessage, websocket.BinaryMessage:
|
||||
c.printWrite(typ, content, 0)
|
||||
case websocket.CloseMessage:
|
||||
if len(closeCode) > 1 {
|
||||
c.chain.fail("\nunexpected multiple closeCode arguments " +
|
||||
"passed to WriteMessage")
|
||||
return c
|
||||
}
|
||||
|
||||
code := websocket.CloseNormalClosure
|
||||
if len(closeCode) > 0 {
|
||||
code = closeCode[0]
|
||||
}
|
||||
|
||||
c.printWrite(typ, content, code)
|
||||
|
||||
content = websocket.FormatCloseMessage(code, string(content))
|
||||
default:
|
||||
c.chain.fail("\nunexpected WebSocket message type '%s' "+
|
||||
"passed to WriteMessage", wsMessageTypeName(typ))
|
||||
return c
|
||||
}
|
||||
|
||||
if !c.setWriteDeadline() {
|
||||
return c
|
||||
}
|
||||
if err := c.conn.WriteMessage(typ, content); err != nil {
|
||||
c.chain.fail(
|
||||
"\nexpected write into WebSocket connection, "+
|
||||
"but got failure: %s", err.Error())
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// WriteBytesBinary is a shorthand for c.WriteMessage(websocket.BinaryMessage, b).
|
||||
func (c *Websocket) WriteBytesBinary(b []byte) *Websocket {
|
||||
if c.checkUnusable("WriteBytesBinary") {
|
||||
return c
|
||||
}
|
||||
return c.WriteMessage(websocket.BinaryMessage, b)
|
||||
}
|
||||
|
||||
// WriteBytesText is a shorthand for c.WriteMessage(websocket.TextMessage, b).
|
||||
func (c *Websocket) WriteBytesText(b []byte) *Websocket {
|
||||
if c.checkUnusable("WriteBytesText") {
|
||||
return c
|
||||
}
|
||||
return c.WriteMessage(websocket.TextMessage, b)
|
||||
}
|
||||
|
||||
// WriteText is a shorthand for
|
||||
// c.WriteMessage(websocket.TextMessage, []byte(s)).
|
||||
func (c *Websocket) WriteText(s string) *Websocket {
|
||||
if c.checkUnusable("WriteText") {
|
||||
return c
|
||||
}
|
||||
return c.WriteMessage(websocket.TextMessage, []byte(s))
|
||||
}
|
||||
|
||||
// WriteJSON writes to the underlying WebSocket connection given object,
|
||||
// marshaled using json.Marshal().
|
||||
func (c *Websocket) WriteJSON(object interface{}) *Websocket {
|
||||
if c.checkUnusable("WriteJSON") {
|
||||
return c
|
||||
}
|
||||
|
||||
b, err := json.Marshal(object)
|
||||
if err != nil {
|
||||
c.chain.fail(err.Error())
|
||||
return c
|
||||
}
|
||||
|
||||
return c.WriteMessage(websocket.TextMessage, b)
|
||||
}
|
||||
|
||||
func (c *Websocket) checkUnusable(where string) bool {
|
||||
switch {
|
||||
case c.chain.failed():
|
||||
return true
|
||||
case c.conn == nil:
|
||||
c.chain.fail("\nunexpected %s call for failed WebSocket connection",
|
||||
where)
|
||||
return true
|
||||
case c.isClosed:
|
||||
c.chain.fail("\nunexpected %s call for closed WebSocket connection",
|
||||
where)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Websocket) setWriteDeadline() bool {
|
||||
deadline := infiniteTime
|
||||
if c.writeTimeout != noDuration {
|
||||
deadline = time.Now().Add(c.writeTimeout)
|
||||
}
|
||||
if err := c.conn.SetWriteDeadline(deadline); err != nil {
|
||||
c.chain.fail(
|
||||
"\nunexpected failure when setting "+
|
||||
"write WebSocket connection deadline: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Websocket) printWrite(typ int, content []byte, closeCode int) {
|
||||
for _, printer := range c.config.Printers {
|
||||
if p, ok := printer.(WebsocketPrinter); ok {
|
||||
p.WebsocketWrite(typ, content, closeCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
111
vendor/gopkg.in/gavv/httpexpect.v2/websocket_dialer.go
generated
vendored
Normal file
111
vendor/gopkg.in/gavv/httpexpect.v2/websocket_dialer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// NewWebsocketDialer produces new websocket.Dialer which dials to bound
|
||||
// http.Handler without creating a real net.Conn.
|
||||
func NewWebsocketDialer(handler http.Handler) *websocket.Dialer {
|
||||
return &websocket.Dialer{
|
||||
NetDial: func(network, addr string) (net.Conn, error) {
|
||||
hc := newHandlerConn()
|
||||
hc.runHandler(handler)
|
||||
return hc, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewFastWebsocketDialer produces new websocket.Dialer which dials to bound
|
||||
// fasthttp.RequestHandler without creating a real net.Conn.
|
||||
func NewFastWebsocketDialer(handler fasthttp.RequestHandler) *websocket.Dialer {
|
||||
return &websocket.Dialer{
|
||||
NetDial: func(network, addr string) (net.Conn, error) {
|
||||
hc := newHandlerConn()
|
||||
hc.runFastHandler(handler)
|
||||
return hc, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type handlerConn struct {
|
||||
net.Conn // returned from dialer
|
||||
backConn net.Conn // passed to the background goroutine
|
||||
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func newHandlerConn() *handlerConn {
|
||||
dialConn, backConn := net.Pipe()
|
||||
|
||||
return &handlerConn{
|
||||
Conn: dialConn,
|
||||
backConn: backConn,
|
||||
}
|
||||
}
|
||||
|
||||
func (hc *handlerConn) Close() error {
|
||||
err := hc.Conn.Close()
|
||||
hc.wg.Wait() // wait the background goroutine
|
||||
return err
|
||||
}
|
||||
|
||||
func (hc *handlerConn) runHandler(handler http.Handler) {
|
||||
hc.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer hc.wg.Done()
|
||||
|
||||
recorder := &hijackRecorder{conn: hc.backConn}
|
||||
|
||||
for {
|
||||
req, err := http.ReadRequest(bufio.NewReader(hc.backConn))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
handler.ServeHTTP(recorder, req)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (hc *handlerConn) runFastHandler(handler fasthttp.RequestHandler) {
|
||||
hc.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer hc.wg.Done()
|
||||
|
||||
_ = fasthttp.ServeConn(hc.backConn, handler)
|
||||
}()
|
||||
}
|
||||
|
||||
// hijackRecorder it similar to httptest.ResponseRecorder,
|
||||
// but with Hijack capabilities.
|
||||
//
|
||||
// Original idea is stolen from https://github.com/posener/wstest
|
||||
type hijackRecorder struct {
|
||||
httptest.ResponseRecorder
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
// Hijack the connection for caller.
|
||||
//
|
||||
// Implements http.Hijacker interface.
|
||||
func (r *hijackRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
rw := bufio.NewReadWriter(bufio.NewReader(r.conn), bufio.NewWriter(r.conn))
|
||||
return r.conn, rw, nil
|
||||
}
|
||||
|
||||
// WriteHeader write HTTP header to the client and closes the connection
|
||||
//
|
||||
// Implements http.ResponseWriter interface.
|
||||
func (r *hijackRecorder) WriteHeader(code int) {
|
||||
resp := http.Response{StatusCode: code, Header: r.Header()}
|
||||
_ = resp.Write(r.conn)
|
||||
}
|
||||
314
vendor/gopkg.in/gavv/httpexpect.v2/websocket_message.go
generated
vendored
Normal file
314
vendor/gopkg.in/gavv/httpexpect.v2/websocket_message.go
generated
vendored
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
package httpexpect
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// WebsocketMessage provides methods to inspect message read from WebSocket connection.
|
||||
type WebsocketMessage struct {
|
||||
chain chain
|
||||
typ int
|
||||
content []byte
|
||||
closeCode int
|
||||
}
|
||||
|
||||
// NewWebsocketMessage returns a new WebsocketMessage object given a reporter used to
|
||||
// report failures and the message parameters to be inspected.
|
||||
//
|
||||
// reporter should not be nil.
|
||||
//
|
||||
// Example:
|
||||
// m := NewWebsocketMessage(reporter, websocket.TextMessage, []byte("content"), 0)
|
||||
// m.TextMessage()
|
||||
func NewWebsocketMessage(
|
||||
reporter Reporter, typ int, content []byte, closeCode ...int,
|
||||
) *WebsocketMessage {
|
||||
m := &WebsocketMessage{
|
||||
chain: makeChain(reporter),
|
||||
typ: typ,
|
||||
content: content,
|
||||
}
|
||||
if len(closeCode) != 0 {
|
||||
m.closeCode = closeCode[0]
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func makeWebsocketMessage(chain chain) *WebsocketMessage {
|
||||
return &WebsocketMessage{
|
||||
chain: chain,
|
||||
}
|
||||
}
|
||||
|
||||
// Raw returns underlying type, content and close code of WebSocket message.
|
||||
// Theses values are originally read from WebSocket connection.
|
||||
func (m *WebsocketMessage) Raw() (typ int, content []byte, closeCode int) {
|
||||
return m.typ, m.content, m.closeCode
|
||||
}
|
||||
|
||||
// CloseMessage is a shorthand for m.Type(websocket.CloseMessage).
|
||||
func (m *WebsocketMessage) CloseMessage() *WebsocketMessage {
|
||||
return m.Type(websocket.CloseMessage)
|
||||
}
|
||||
|
||||
// NotCloseMessage is a shorthand for m.NotType(websocket.CloseMessage).
|
||||
func (m *WebsocketMessage) NotCloseMessage() *WebsocketMessage {
|
||||
return m.NotType(websocket.CloseMessage)
|
||||
}
|
||||
|
||||
// BinaryMessage is a shorthand for m.Type(websocket.BinaryMessage).
|
||||
func (m *WebsocketMessage) BinaryMessage() *WebsocketMessage {
|
||||
return m.Type(websocket.BinaryMessage)
|
||||
}
|
||||
|
||||
// NotBinaryMessage is a shorthand for m.NotType(websocket.BinaryMessage).
|
||||
func (m *WebsocketMessage) NotBinaryMessage() *WebsocketMessage {
|
||||
return m.NotType(websocket.BinaryMessage)
|
||||
}
|
||||
|
||||
// TextMessage is a shorthand for m.Type(websocket.TextMessage).
|
||||
func (m *WebsocketMessage) TextMessage() *WebsocketMessage {
|
||||
return m.Type(websocket.TextMessage)
|
||||
}
|
||||
|
||||
// NotTextMessage is a shorthand for m.NotType(websocket.TextMessage).
|
||||
func (m *WebsocketMessage) NotTextMessage() *WebsocketMessage {
|
||||
return m.NotType(websocket.TextMessage)
|
||||
}
|
||||
|
||||
// Type succeeds if WebSocket message type is one of the given.
|
||||
//
|
||||
// WebSocket message types are defined in RFC 6455, section 11.8.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// Example:
|
||||
// msg := conn.Expect()
|
||||
// msg.Type(websocket.TextMessage, websocket.BinaryMessage)
|
||||
func (m *WebsocketMessage) Type(typ ...int) *WebsocketMessage {
|
||||
switch {
|
||||
case m.chain.failed():
|
||||
return m
|
||||
case len(typ) == 0:
|
||||
m.chain.fail("\nunexpected nil argument passed to Type")
|
||||
return m
|
||||
}
|
||||
yes := false
|
||||
for _, t := range typ {
|
||||
if t == m.typ {
|
||||
yes = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !yes {
|
||||
if len(typ) > 1 {
|
||||
m.chain.fail(
|
||||
"\nexpected message type equal to one of:\n %v\n\nbut got:\n %d",
|
||||
typ, m.typ)
|
||||
} else {
|
||||
m.chain.fail(
|
||||
"\nexpected message type:\n %d\n\nbut got:\n %d",
|
||||
typ[0], m.typ)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// NotType succeeds if WebSocket message type is none of the given.
|
||||
//
|
||||
// WebSocket message types are defined in RFC 6455, section 11.8.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// Example:
|
||||
// msg := conn.Expect()
|
||||
// msg.NotType(websocket.CloseMessage, websocket.BinaryMessage)
|
||||
func (m *WebsocketMessage) NotType(typ ...int) *WebsocketMessage {
|
||||
switch {
|
||||
case m.chain.failed():
|
||||
return m
|
||||
case len(typ) == 0:
|
||||
m.chain.fail("\nunexpected nil argument passed to NotType")
|
||||
return m
|
||||
}
|
||||
for _, t := range typ {
|
||||
if t == m.typ {
|
||||
if len(typ) > 1 {
|
||||
m.chain.fail(
|
||||
"\nexpected message type not equal:\n %v\n\nbut got:\n %d",
|
||||
typ, m.typ)
|
||||
} else {
|
||||
m.chain.fail(
|
||||
"\nexpected message type not equal:\n %d\n\nbut it did",
|
||||
typ[0], m.typ)
|
||||
}
|
||||
return m
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Code succeeds if WebSocket close code is one of the given.
|
||||
//
|
||||
// Code fails if WebSocket message type is not "8 - Connection Close Frame".
|
||||
//
|
||||
// WebSocket close codes are defined in RFC 6455, section 11.7.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// Example:
|
||||
// msg := conn.Expect().Closed()
|
||||
// msg.Code(websocket.CloseNormalClosure, websocket.CloseGoingAway)
|
||||
func (m *WebsocketMessage) Code(code ...int) *WebsocketMessage {
|
||||
switch {
|
||||
case m.chain.failed():
|
||||
return m
|
||||
case len(code) == 0:
|
||||
m.chain.fail("\nunexpected nil argument passed to Code")
|
||||
return m
|
||||
case m.checkClosed("Code"):
|
||||
return m
|
||||
}
|
||||
yes := false
|
||||
for _, c := range code {
|
||||
if c == m.closeCode {
|
||||
yes = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !yes {
|
||||
if len(code) > 1 {
|
||||
m.chain.fail(
|
||||
"\nexpected close code equal to one of:\n %v\n\nbut got:\n %d",
|
||||
code, m.closeCode)
|
||||
} else {
|
||||
m.chain.fail(
|
||||
"\nexpected close code:\n %d\n\nbut got:\n %d",
|
||||
code[0], m.closeCode)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// NotCode succeeds if WebSocket close code is none of the given.
|
||||
//
|
||||
// NotCode fails if WebSocket message type is not "8 - Connection Close Frame".
|
||||
//
|
||||
// WebSocket close codes are defined in RFC 6455, section 11.7.
|
||||
// See also https://godoc.org/github.com/gorilla/websocket#pkg-constants
|
||||
//
|
||||
// Example:
|
||||
// msg := conn.Expect().Closed()
|
||||
// msg.NotCode(websocket.CloseAbnormalClosure, websocket.CloseNoStatusReceived)
|
||||
func (m *WebsocketMessage) NotCode(code ...int) *WebsocketMessage {
|
||||
switch {
|
||||
case m.chain.failed():
|
||||
return m
|
||||
case len(code) == 0:
|
||||
m.chain.fail("\nunexpected nil argument passed to CodeNotEqual")
|
||||
return m
|
||||
case m.checkClosed("NotCode"):
|
||||
return m
|
||||
}
|
||||
for _, c := range code {
|
||||
if c == m.closeCode {
|
||||
if len(code) > 1 {
|
||||
m.chain.fail(
|
||||
"\nexpected close code not equal:\n %v\n\nbut got:\n %d",
|
||||
code, m.closeCode)
|
||||
} else {
|
||||
m.chain.fail(
|
||||
"\nexpected close code not equal:\n %d\n\nbut it did",
|
||||
code[0], m.closeCode)
|
||||
}
|
||||
return m
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *WebsocketMessage) checkClosed(where string) bool {
|
||||
if m.typ != websocket.CloseMessage {
|
||||
m.chain.fail(
|
||||
"\nunexpected %s usage for not '%' WebSocket message type\n\n"+
|
||||
"got type:\n %s",
|
||||
where,
|
||||
wsMessageTypeName(websocket.CloseMessage),
|
||||
wsMessageTypeName(m.typ))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Body returns a new String object that may be used to inspect
|
||||
// WebSocket message content.
|
||||
//
|
||||
// Example:
|
||||
// msg := conn.Expect()
|
||||
// msg.Body().NotEmpty()
|
||||
// msg.Body().Length().Equal(100)
|
||||
func (m *WebsocketMessage) Body() *String {
|
||||
return &String{m.chain, string(m.content)}
|
||||
}
|
||||
|
||||
// NoContent succeeds if WebSocket message has no content (is empty).
|
||||
func (m *WebsocketMessage) NoContent() *WebsocketMessage {
|
||||
switch {
|
||||
case m.chain.failed():
|
||||
return m
|
||||
case len(m.content) == 0:
|
||||
return m
|
||||
}
|
||||
switch m.typ {
|
||||
case websocket.BinaryMessage:
|
||||
m.chain.fail(
|
||||
"\nexpected message body being empty, but got:\n %d bytes",
|
||||
len(m.content))
|
||||
default:
|
||||
m.chain.fail(
|
||||
"\nexpected message body being empty, but got:\n %s",
|
||||
string(m.content))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// JSON returns a new Value object that may be used to inspect JSON contents
|
||||
// of WebSocket message.
|
||||
//
|
||||
// JSON succeeds if JSON may be decoded from message content.
|
||||
//
|
||||
// Example:
|
||||
// msg := conn.Expect()
|
||||
// msg.JSON().Array().Elements("foo", "bar")
|
||||
func (m *WebsocketMessage) JSON() *Value {
|
||||
return &Value{m.chain, m.getJSON()}
|
||||
}
|
||||
|
||||
func (m *WebsocketMessage) getJSON() interface{} {
|
||||
if m.chain.failed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var value interface{}
|
||||
if err := json.Unmarshal(m.content, &value); err != nil {
|
||||
m.chain.fail(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func wsMessageTypeName(typ int) string {
|
||||
switch typ {
|
||||
case websocket.TextMessage:
|
||||
return "text"
|
||||
case websocket.BinaryMessage:
|
||||
return "binary"
|
||||
case websocket.CloseMessage:
|
||||
return "close"
|
||||
case websocket.PingMessage:
|
||||
return "ping"
|
||||
case websocket.PongMessage:
|
||||
return "pong"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue