Update dependencies (#32)

This commit is contained in:
Joona Hoikkala 2018-01-22 11:19:33 +02:00 committed by GitHub
parent 733245fb3d
commit c5337fc841
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1727 changed files with 697927 additions and 12717 deletions

176
Gopkg.lock generated
View File

@ -7,35 +7,107 @@
revision = "b26d9c308763d68093482582cea63d69be07a0f0"
version = "v0.3.0"
[[projects]]
name = "github.com/ajg/form"
packages = ["."]
revision = "cc2954064ec9ea8d93917f0f87456e11d7b881ad"
version = "v1.5"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/erikstmartin/go-testdb"
packages = ["."]
revision = "8d10e4a1bae52cd8b81ffdec3445890d6dccab3d"
[[projects]]
name = "github.com/fatih/structs"
packages = ["."]
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
version = "v1.0"
[[projects]]
branch = "master"
name = "github.com/gavv/httpexpect"
packages = ["."]
revision = "c44a6d7bb636b17e880a53998a7f7061a56ffacb"
[[projects]]
branch = "master"
name = "github.com/gavv/monotime"
packages = ["."]
revision = "6f8212e8d10df7383609d3c377ca08884d8f3ec0"
[[projects]]
branch = "master"
name = "github.com/google/go-querystring"
packages = ["query"]
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
[[projects]]
name = "github.com/imkira/go-interpol"
packages = ["."]
revision = "5accad8134979a6ac504d456a6c7f1c53da237ca"
version = "v1.1.0"
[[projects]]
name = "github.com/julienschmidt/httprouter"
packages = ["."]
revision = "8c199fb6259ffc1af525cc3ad52ee60ba8359669"
version = "v1.1"
[[projects]]
name = "github.com/klauspost/compress"
packages = ["flate","gzip","zlib"]
revision = "6c8db69c4b49dd4df1fff66996cf556176d0b9bf"
version = "v1.2.1"
[[projects]]
name = "github.com/klauspost/cpuid"
packages = ["."]
revision = "ae7887de9fa5d2db4eaa8174a7eff2c1ac00f2da"
version = "v1.1"
[[projects]]
name = "github.com/klauspost/crc32"
packages = ["."]
revision = "cb6bfca970f6908083f26f39a79009d608efd5cd"
version = "v1.1"
[[projects]]
branch = "master"
name = "github.com/lib/pq"
packages = [".","oid"]
revision = "8c6ee72f3e6bcb1542298dd5f76cb74af9742cec"
revision = "27ea5d92de30060e7121ddd543fe14e9a327e0cc"
[[projects]]
name = "github.com/mattn/go-sqlite3"
packages = ["."]
revision = "ed69081a91fd053f17672236b0dd52ba7485e1a3"
version = "v1.4.0"
revision = "6c771bb9887719704b210e87e934f08be014bdb1"
version = "v1.6.0"
[[projects]]
name = "github.com/miekg/dns"
packages = ["."]
revision = "5ec25f2a5044291b6c8abf43ed8a201da241e69e"
version = "v1.0.3"
[[projects]]
branch = "master"
name = "github.com/miekg/dns"
packages = [".","internal/socket"]
revision = "9fc4eb252eedf0ef8adc05169ce35da5e31beaba"
name = "github.com/moul/http2curl"
packages = ["."]
revision = "9ac6cf4d929b2fa8fd2d2e6dec5bb0feb4f4911d"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/rs/cors"
@ -46,36 +118,108 @@
[[projects]]
name = "github.com/satori/go.uuid"
packages = ["."]
revision = "879c5887cd475cd7864858769793b2ceb0d44feb"
version = "v1.1.0"
revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/sergi/go-diff"
packages = ["diffmatchpatch"]
revision = "1744e2970ca51c86172c8190fadad617561ed6e7"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = [".","hooks/test"]
revision = "f006c2ac4710855cf0f916dd6b77acf6b048dc6e"
version = "v1.0.3"
revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba"
version = "v1.0.4"
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert","require"]
revision = "b91bfb9ebec76498946beb6af7c0230c7cc7ba6c"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/valyala/bytebufferpool"
packages = ["."]
revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7"
[[projects]]
branch = "master"
name = "github.com/valyala/fasthttp"
packages = [".","fasthttputil","stackless"]
revision = "e5f51c11919d4f66400334047b897ef0a94c6f3c"
[[projects]]
branch = "master"
name = "github.com/xeipuuv/gojsonpointer"
packages = ["."]
revision = "6fe8760cad3569743d51ddbb243b26f8456742dc"
[[projects]]
branch = "master"
name = "github.com/xeipuuv/gojsonreference"
packages = ["."]
revision = "e02fc20de94c78484cd5ffb007f8af96be030a45"
[[projects]]
branch = "master"
name = "github.com/xeipuuv/gojsonschema"
packages = ["."]
revision = "511d08a359d14c0dd9c4302af52ee9abb6f93c2a"
[[projects]]
branch = "master"
name = "github.com/yalp/jsonpath"
packages = ["."]
revision = "31a79c7593bb93eb10b163650d4a3e6ca190e4dc"
[[projects]]
name = "github.com/yudai/gojsondiff"
packages = [".","formatter"]
revision = "7b1b7adf999dab73a6eb02669c3d82dbb27a3dd6"
version = "1.0.0"
[[projects]]
branch = "master"
name = "github.com/yudai/golcs"
packages = ["."]
revision = "ecda9a501e8220fae3b4b600c3db4b0ba22cfc68"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["acme","acme/autocert","bcrypt","blowfish","ssh/terminal"]
revision = "9f005a07e0d31d45e6656d241bb5c0f2efd4bc94"
packages = ["acme","acme/autocert","bcrypt","blowfish","ed25519","ed25519/internal/edwards25519","ssh/terminal"]
revision = "a6600008915114d9c087fad9f03d75087b1a74df"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["context"]
revision = "a337091b0525af65de94df2eb7e98bd9962dcbe2"
packages = ["bpf","idna","internal/iana","internal/socket","ipv4","ipv6","publicsuffix"]
revision = "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix","windows"]
revision = "bf42f188b9bc6f2cf5b8ee5a912ef1aedd0eba4c"
revision = "af50095a40f9041b3b38960738837185c26e9419"
[[projects]]
branch = "master"
name = "golang.org/x/text"
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3"
[[projects]]
name = "gopkg.in/DATA-DOG/go-sqlmock.v1"
packages = ["."]
revision = "d76b18b42f285b792bf985118980ce9eacea9d10"
version = "v1.3.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "be83e227a7669195a51167f325db2e40653f4562e483247f914f862f6eea6b2f"
inputs-digest = "991ecc43a6e9bcfe3c39169d7509ee821076b0b75bbf7cb38ec06db3041cd009"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -20,6 +20,12 @@
# name = "github.com/x/y"
# version = "2.4.0"
# Need to pin fasthttp so it doesn't get the old version from branch names
required = ["github.com/valyala/fasthttp"]
[[constraint]]
name = "github.com/valyala/fasthttp"
branch = "master"
[[constraint]]
name = "github.com/BurntSushi/toml"
@ -29,6 +35,10 @@
branch = "master"
name = "github.com/erikstmartin/go-testdb"
[[constraint]]
branch = "master"
name = "github.com/gavv/httpexpect"
[[constraint]]
name = "github.com/julienschmidt/httprouter"
version = "1.1.0"
@ -39,11 +49,11 @@
[[constraint]]
name = "github.com/mattn/go-sqlite3"
version = "1.4.0"
version = "1.6.0"
[[constraint]]
branch = "master"
name = "github.com/miekg/dns"
version = "1.0.3"
[[constraint]]
name = "github.com/rs/cors"
@ -51,12 +61,16 @@
[[constraint]]
name = "github.com/satori/go.uuid"
version = "1.1.0"
version = "1.2.0"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.3"
version = "1.0.4"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
name = "gopkg.in/DATA-DOG/go-sqlmock.v1"
version = "1.3.0"

25
vendor/github.com/ajg/form/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,25 @@
## Copyright 2014 Alvaro J. Genial. All rights reserved.
## Use of this source code is governed by a BSD-style
## license that can be found in the LICENSE file.
language: go
go:
- tip
- 1.6
- 1.5
- 1.4
- 1.3
- 1.2
before_install:
# - go get -v golang.org/x/tools/cmd/cover
# - go get -v golang.org/x/tools/cmd/vet
# - go get -v github.com/golang/lint/golint
- export PATH=$PATH:/home/travis/gopath/bin
script:
- go build -v ./...
- go test -v -cover ./...
- go vet ./...
# - golint .

27
vendor/github.com/ajg/form/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2014 Alvaro J. Genial. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

246
vendor/github.com/ajg/form/README.md generated vendored Normal file
View File

@ -0,0 +1,246 @@
form
====
A Form Encoding & Decoding Package for Go, written by [Alvaro J. Genial](http://alva.ro).
[![Build Status](https://travis-ci.org/ajg/form.png?branch=master)](https://travis-ci.org/ajg/form)
[![GoDoc](https://godoc.org/github.com/ajg/form?status.png)](https://godoc.org/github.com/ajg/form)
Synopsis
--------
This library is designed to allow seamless, high-fidelity encoding and decoding of arbitrary data in `application/x-www-form-urlencoded` format and as [`url.Values`](http://golang.org/pkg/net/url/#Values). It is intended to be useful primarily in dealing with web forms and URI query strings, both of which natively employ said format.
Unsurprisingly, `form` is modeled after other Go [`encoding`](http://golang.org/pkg/encoding/) packages, in particular [`encoding/json`](http://golang.org/pkg/encoding/json/), and follows the same conventions (see below for more.) It aims to automatically handle any kind of concrete Go [data value](#values) (i.e., not functions, channels, etc.) while providing mechanisms for custom behavior.
Status
------
The implementation is in usable shape and is fairly well tested with its accompanying test suite. The API is unlikely to change much, but still may. Lastly, the code has not yet undergone a security review to ensure it is free of vulnerabilities. Please file an issue or send a pull request for fixes & improvements.
Dependencies
------------
The only requirement is [Go 1.2](http://golang.org/doc/go1.2) or later.
Usage
-----
```go
import "github.com/ajg/form"
```
Given a type like the following...
```go
type User struct {
Name string `form:"name"`
Email string `form:"email"`
Joined time.Time `form:"joined,omitempty"`
Posts []int `form:"posts"`
Preferences map[string]string `form:"prefs"`
Avatar []byte `form:"avatar"`
PasswordHash int64 `form:"-"`
}
```
...it is easy to encode data of that type...
```go
func PostUser(url string, u User) error {
var c http.Client
_, err := c.PostForm(url, form.EncodeToValues(u))
return err
}
```
...as well as decode it...
```go
func Handler(w http.ResponseWriter, r *http.Request) {
var u User
d := form.NewDecoder(r.Body)
if err := d.Decode(&u); err != nil {
http.Error(w, "Form could not be decoded", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "Decoded: %#v", u)
}
```
...without having to do any grunt work.
Field Tags
----------
Like other encoding packages, `form` supports the following options for fields:
- `` `form:"-"` ``: Causes the field to be ignored during encoding and decoding.
- `` `form:"<name>"` ``: Overrides the field's name; useful especially when dealing with external identifiers in camelCase, as are commonly found on the web.
- `` `form:",omitempty"` ``: Elides the field during encoding if it is empty (typically meaning equal to the type's zero value.)
- `` `form:"<name>,omitempty"` ``: The way to combine the two options above.
Values
------
### Simple Values
Values of the following types are all considered simple:
- `bool`
- `int`, `int8`, `int16`, `int32`, `int64`, `rune`
- `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `byte`
- `float32`, `float64`
- `complex64`, `complex128`
- `string`
- `[]byte` (see note)
- [`time.Time`](http://golang.org/pkg/time/#Time)
- [`url.URL`](http://golang.org/pkg/net/url/#URL)
- An alias of any of the above
- A pointer to any of the above
### Composite Values
A composite value is one that can contain other values. Values of the following kinds...
- Maps
- Slices; except `[]byte` (see note)
- Structs; except [`time.Time`](http://golang.org/pkg/time/#Time) and [`url.URL`](http://golang.org/pkg/net/url/#URL)
- Arrays
- An alias of any of the above
- A pointer to any of the above
...are considered composites in general, unless they implement custom marshaling/unmarshaling. Composite values are encoded as a flat mapping of paths to values, where the paths are constructed by joining the parent and child paths with a period (`.`).
(Note: a byte slice is treated as a `string` by default because it's more efficient, but can also be decoded as a slice—i.e., with indexes.)
### Untyped Values
While encouraged, it is not necessary to define a type (e.g. a `struct`) in order to use `form`, since it is able to encode and decode untyped data generically using the following rules:
- Simple values will be treated as a `string`.
- Composite values will be treated as a `map[string]interface{}`, itself able to contain nested values (both scalar and compound) ad infinitum.
- However, if there is a value (of any supported type) already present in a map for a given key, then it will be used when possible, rather than being replaced with a generic value as specified above; this makes it possible to handle partially typed, dynamic or schema-less values.
### Zero Values
By default, and without custom marshaling, zero values (also known as empty/default values) are encoded as the empty string. To disable this behavior, meaning to keep zero values in their literal form (e.g. `0` for integral types), `Encoder` offers a `KeepZeros` setter method, which will do just that when set to `true`.
### Unsupported Values
Values of the following kinds aren't supported and, if present, must be ignored.
- Channel
- Function
- Unsafe pointer
- An alias of any of the above
- A pointer to any of the above
Custom Marshaling
-----------------
There is a default (generally lossless) marshaling & unmarshaling scheme for any concrete data value in Go, which is good enough in most cases. However, it is possible to override it and use a custom scheme. For instance, a "binary" field could be marshaled more efficiently using [base64](http://golang.org/pkg/encoding/base64/) to prevent it from being percent-escaped during serialization to `application/x-www-form-urlencoded` format.
Because `form` provides support for [`encoding.TextMarshaler`](http://golang.org/pkg/encoding/#TextMarshaler) and [`encoding.TextUnmarshaler`](http://golang.org/pkg/encoding/#TextUnmarshaler) it is easy to do that; for instance, like this:
```go
import "encoding"
type Binary []byte
var (
_ encoding.TextMarshaler = &Binary{}
_ encoding.TextUnmarshaler = &Binary{}
)
func (b Binary) MarshalText() ([]byte, error) {
return []byte(base64.URLEncoding.EncodeToString([]byte(b))), nil
}
func (b *Binary) UnmarshalText(text []byte) error {
bs, err := base64.URLEncoding.DecodeString(string(text))
if err == nil {
*b = Binary(bs)
}
return err
}
```
Now any value with type `Binary` will automatically be encoded using the [URL](http://golang.org/pkg/encoding/base64/#URLEncoding) variant of base64. It is left as an exercise to the reader to improve upon this scheme by eliminating the need for padding (which, besides being superfluous, uses `=`, a character that will end up percent-escaped.)
Keys
----
In theory any value can be a key as long as it has a string representation. However, by default, periods have special meaning to `form`, and thus, under the hood (i.e. in encoded form) they are transparently escaped using a preceding backslash (`\`). Backslashes within keys, themselves, are also escaped in this manner (e.g. as `\\`) in order to permit representing `\.` itself (as `\\\.`).
(Note: it is normally unnecessary to deal with this issue unless keys are being constructed manually—e.g. literally embedded in HTML or in a URI.)
The default delimiter and escape characters used for encoding and decoding composite keys can be changed using the `DelimitWith` and `EscapeWith` setter methods of `Encoder` and `Decoder`, respectively. For example...
```go
package main
import (
"os"
"github.com/ajg/form"
)
func main() {
type B struct {
Qux string `form:"qux"`
}
type A struct {
FooBar B `form:"foo.bar"`
}
a := A{FooBar: B{"XYZ"}}
os.Stdout.WriteString("Default: ")
form.NewEncoder(os.Stdout).Encode(a)
os.Stdout.WriteString("\nCustom: ")
form.NewEncoder(os.Stdout).DelimitWith('/').Encode(a)
os.Stdout.WriteString("\n")
}
```
...will produce...
```
Default: foo%5C.bar.qux=XYZ
Custom: foo.bar%2Fqux=XYZ
```
(`%5C` and `%2F` represent `\` and `/`, respectively.)
Limitations
-----------
- Circular (self-referential) values are untested.
Future Work
-----------
The following items would be nice to have in the future—though they are not being worked on yet:
- An option to treat all values as if they had been tagged with `omitempty`.
- An option to automatically treat all field names in `camelCase` or `underscore_case`.
- Built-in support for the types in [`math/big`](http://golang.org/pkg/math/big/).
- Built-in support for the types in [`image/color`](http://golang.org/pkg/image/color/).
- Improve encoding/decoding by reading/writing directly from/to the `io.Reader`/`io.Writer` when possible, rather than going through an intermediate representation (i.e. `node`) which requires more memory.
(Feel free to implement any of these and then send a pull request.)
Related Work
------------
- Package [gorilla/schema](https://github.com/gorilla/schema), which only implements decoding.
- Package [google/go-querystring](https://github.com/google/go-querystring), which only implements encoding.
License
-------
This library is distributed under a BSD-style [LICENSE](./LICENSE).

4
vendor/github.com/ajg/form/TODO.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
TODO
====
- Document IgnoreCase and IgnoreUnknownKeys in README.

370
vendor/github.com/ajg/form/decode.go generated vendored Normal file
View File

@ -0,0 +1,370 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"fmt"
"io"
"io/ioutil"
"net/url"
"reflect"
"strconv"
"time"
)
// NewDecoder returns a new form Decoder.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r, defaultDelimiter, defaultEscape, false, false}
}
// Decoder decodes data from a form (application/x-www-form-urlencoded).
type Decoder struct {
r io.Reader
d rune
e rune
ignoreUnknown bool
ignoreCase bool
}
// DelimitWith sets r as the delimiter used for composite keys by Decoder d and returns the latter; it is '.' by default.
func (d *Decoder) DelimitWith(r rune) *Decoder {
d.d = r
return d
}
// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Decoder d and returns the latter; it is '\\' by default.
func (d *Decoder) EscapeWith(r rune) *Decoder {
d.e = r
return d
}
// Decode reads in and decodes form-encoded data into dst.
func (d Decoder) Decode(dst interface{}) error {
bs, err := ioutil.ReadAll(d.r)
if err != nil {
return err
}
vs, err := url.ParseQuery(string(bs))
if err != nil {
return err
}
v := reflect.ValueOf(dst)
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
}
// IgnoreUnknownKeys if set to true it will make the Decoder ignore values
// that are not found in the destination object instead of returning an error.
func (d *Decoder) IgnoreUnknownKeys(ignoreUnknown bool) {
d.ignoreUnknown = ignoreUnknown
}
// IgnoreCase if set to true it will make the Decoder try to set values in the
// destination object even if the case does not match.
func (d *Decoder) IgnoreCase(ignoreCase bool) {
d.ignoreCase = ignoreCase
}
// DecodeString decodes src into dst.
func (d Decoder) DecodeString(dst interface{}, src string) error {
vs, err := url.ParseQuery(src)
if err != nil {
return err
}
v := reflect.ValueOf(dst)
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
}
// DecodeValues decodes vs into dst.
func (d Decoder) DecodeValues(dst interface{}, vs url.Values) error {
v := reflect.ValueOf(dst)
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
}
// DecodeString decodes src into dst.
func DecodeString(dst interface{}, src string) error {
return NewDecoder(nil).DecodeString(dst, src)
}
// DecodeValues decodes vs into dst.
func DecodeValues(dst interface{}, vs url.Values) error {
return NewDecoder(nil).DecodeValues(dst, vs)
}
func (d Decoder) decodeNode(v reflect.Value, n node) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
if v.Kind() == reflect.Slice {
return fmt.Errorf("could not decode directly into slice; use pointer to slice")
}
d.decodeValue(v, n)
return nil
}
func (d Decoder) decodeValue(v reflect.Value, x interface{}) {
t := v.Type()
k := v.Kind()
if k == reflect.Ptr && v.IsNil() {
v.Set(reflect.New(t.Elem()))
}
if unmarshalValue(v, x) {
return
}
empty := isEmpty(x)
switch k {
case reflect.Ptr:
d.decodeValue(v.Elem(), x)
return
case reflect.Interface:
if !v.IsNil() {
d.decodeValue(v.Elem(), x)
return
} else if empty {
return // Allow nil interfaces only if empty.
} else {
panic("form: cannot decode non-empty value into into nil interface")
}
}
if empty {
v.Set(reflect.Zero(t)) // Treat the empty string as the zero value.
return
}
switch k {
case reflect.Struct:
if t.ConvertibleTo(timeType) {
d.decodeTime(v, x)
} else if t.ConvertibleTo(urlType) {
d.decodeURL(v, x)
} else {
d.decodeStruct(v, x)
}
case reflect.Slice:
d.decodeSlice(v, x)
case reflect.Array:
d.decodeArray(v, x)
case reflect.Map:
d.decodeMap(v, x)
case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
panic(t.String() + " has unsupported kind " + k.String())
default:
d.decodeBasic(v, x)
}
}
func (d Decoder) decodeStruct(v reflect.Value, x interface{}) {
t := v.Type()
for k, c := range getNode(x) {
if f, ok := findField(v, k, d.ignoreCase); !ok && k == "" {
panic(getString(x) + " cannot be decoded as " + t.String())
} else if !ok {
if !d.ignoreUnknown {
panic(k + " doesn't exist in " + t.String())
}
} else if !f.CanSet() {
panic(k + " cannot be set in " + t.String())
} else {
d.decodeValue(f, c)
}
}
}
func (d Decoder) decodeMap(v reflect.Value, x interface{}) {
t := v.Type()
if v.IsNil() {
v.Set(reflect.MakeMap(t))
}
for k, c := range getNode(x) {
i := reflect.New(t.Key()).Elem()
d.decodeValue(i, k)
w := v.MapIndex(i)
if w.IsValid() { // We have an actual element value to decode into.
if w.Kind() == reflect.Interface {
w = w.Elem()
}
w = reflect.New(w.Type()).Elem()
} else if t.Elem().Kind() != reflect.Interface { // The map's element type is concrete.
w = reflect.New(t.Elem()).Elem()
} else {
// The best we can do here is to decode as either a string (for scalars) or a map[string]interface {} (for the rest).
// We could try to guess the type based on the string (e.g. true/false => bool) but that'll get ugly fast,
// especially if we have to guess the kind (slice vs. array vs. map) and index type (e.g. string, int, etc.)
switch c.(type) {
case node:
w = reflect.MakeMap(stringMapType)
case string:
w = reflect.New(stringType).Elem()
default:
panic("value is neither node nor string")
}
}
d.decodeValue(w, c)
v.SetMapIndex(i, w)
}
}
func (d Decoder) decodeArray(v reflect.Value, x interface{}) {
t := v.Type()
for k, c := range getNode(x) {
i, err := strconv.Atoi(k)
if err != nil {
panic(k + " is not a valid index for type " + t.String())
}
if l := v.Len(); i >= l {
panic("index is above array size")
}
d.decodeValue(v.Index(i), c)
}
}
func (d Decoder) decodeSlice(v reflect.Value, x interface{}) {
t := v.Type()
if t.Elem().Kind() == reflect.Uint8 {
// Allow, but don't require, byte slices to be encoded as a single string.
if s, ok := x.(string); ok {
v.SetBytes([]byte(s))
return
}
}
// NOTE: Implicit indexing is currently done at the parseValues level,
// so if if an implicitKey reaches here it will always replace the last.
implicit := 0
for k, c := range getNode(x) {
var i int
if k == implicitKey {
i = implicit
implicit++
} else {
explicit, err := strconv.Atoi(k)
if err != nil {
panic(k + " is not a valid index for type " + t.String())
}
i = explicit
implicit = explicit + 1
}
// "Extend" the slice if it's too short.
if l := v.Len(); i >= l {
delta := i - l + 1
v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta)))
}
d.decodeValue(v.Index(i), c)
}
}
func (d Decoder) decodeBasic(v reflect.Value, x interface{}) {
t := v.Type()
switch k, s := t.Kind(), getString(x); k {
case reflect.Bool:
if b, e := strconv.ParseBool(s); e == nil {
v.SetBool(b)
} else {
panic("could not parse bool from " + strconv.Quote(s))
}
case reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
if i, e := strconv.ParseInt(s, 10, 64); e == nil {
v.SetInt(i)
} else {
panic("could not parse int from " + strconv.Quote(s))
}
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
if u, e := strconv.ParseUint(s, 10, 64); e == nil {
v.SetUint(u)
} else {
panic("could not parse uint from " + strconv.Quote(s))
}
case reflect.Float32,
reflect.Float64:
if f, e := strconv.ParseFloat(s, 64); e == nil {
v.SetFloat(f)
} else {
panic("could not parse float from " + strconv.Quote(s))
}
case reflect.Complex64,
reflect.Complex128:
var c complex128
if n, err := fmt.Sscanf(s, "%g", &c); n == 1 && err == nil {
v.SetComplex(c)
} else {
panic("could not parse complex from " + strconv.Quote(s))
}
case reflect.String:
v.SetString(s)
default:
panic(t.String() + " has unsupported kind " + k.String())
}
}
func (d Decoder) decodeTime(v reflect.Value, x interface{}) {
t := v.Type()
s := getString(x)
// TODO: Find a more efficient way to do this.
for _, f := range allowedTimeFormats {
if p, err := time.Parse(f, s); err == nil {
v.Set(reflect.ValueOf(p).Convert(v.Type()))
return
}
}
panic("cannot decode string `" + s + "` as " + t.String())
}
func (d Decoder) decodeURL(v reflect.Value, x interface{}) {
t := v.Type()
s := getString(x)
if u, err := url.Parse(s); err == nil {
v.Set(reflect.ValueOf(*u).Convert(v.Type()))
return
}
panic("cannot decode string `" + s + "` as " + t.String())
}
var allowedTimeFormats = []string{
"2006-01-02T15:04:05.999999999Z07:00",
"2006-01-02T15:04:05.999999999Z07",
"2006-01-02T15:04:05.999999999Z",
"2006-01-02T15:04:05.999999999",
"2006-01-02T15:04:05Z07:00",
"2006-01-02T15:04:05Z07",
"2006-01-02T15:04:05Z",
"2006-01-02T15:04:05",
"2006-01-02T15:04Z",
"2006-01-02T15:04",
"2006-01-02T15Z",
"2006-01-02T15",
"2006-01-02",
"2006-01",
"2006",
"15:04:05.999999999Z07:00",
"15:04:05.999999999Z07",
"15:04:05.999999999Z",
"15:04:05.999999999",
"15:04:05Z07:00",
"15:04:05Z07",
"15:04:05Z",
"15:04:05",
"15:04Z",
"15:04",
"15Z",
"15",
}

114
vendor/github.com/ajg/form/decode_test.go generated vendored Normal file
View File

@ -0,0 +1,114 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"net/url"
"reflect"
"strings"
"testing"
)
func TestDecodeString(t *testing.T) {
for _, c := range testCases(decOnly) {
if err := DecodeString(c.a, c.s); err != nil {
t.Errorf("DecodeString(%#v): %s", c.s, err)
} else if !reflect.DeepEqual(c.a, c.b) {
t.Errorf("DecodeString(%#v)\n want (%#v)\n have (%#v)", c.s, c.b, c.a)
}
}
}
func TestDecodeValues(t *testing.T) {
for _, c := range testCases(decOnly) {
vs := mustParseQuery(c.s)
if err := DecodeValues(c.a, vs); err != nil {
t.Errorf("DecodeValues(%#v): %s", vs, err)
} else if !reflect.DeepEqual(c.a, c.b) {
t.Errorf("DecodeValues(%#v)\n want (%#v)\n have (%#v)", vs, c.b, c.a)
}
}
}
func TestDecode(t *testing.T) {
for _, c := range testCases(decOnly) {
r := strings.NewReader(c.s)
d := NewDecoder(r)
if err := d.Decode(c.a); err != nil {
t.Errorf("Decode(%#v): %s", r, err)
} else if !reflect.DeepEqual(c.a, c.b) {
t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", r, c.b, c.a)
}
}
}
func TestDecodeIgnoreUnknown(t *testing.T) {
type simpleStruct struct{ A string }
var dst simpleStruct
values := url.Values{
"b": []string{"2"},
"A": []string{"1"},
}
expected := simpleStruct{A: "1"}
d := NewDecoder(nil)
err := d.DecodeValues(&dst, values)
if err == nil || err.Error() != "b doesn't exist in form.simpleStruct" {
t.Errorf("Decode(%#v): expected error got nil", values)
}
d.IgnoreUnknownKeys(true)
err = d.DecodeValues(&dst, values)
if err != nil {
t.Errorf("Decode(%#v): %s", values, err)
}
if !reflect.DeepEqual(dst, expected) {
t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst)
}
}
func TestDecodeIgnoreCase(t *testing.T) {
type simpleStruct struct{ AaAA string }
var dst simpleStruct
values := url.Values{
"aAaA": []string{"1"},
}
expected := simpleStruct{AaAA: "1"}
d := NewDecoder(nil)
err := d.DecodeValues(&dst, values)
if err == nil || err.Error() != "aAaA doesn't exist in form.simpleStruct" {
t.Errorf("Decode(%#v): expected error got nil", values)
}
d.IgnoreCase(true)
err = d.DecodeValues(&dst, values)
if err != nil {
t.Errorf("Decode(%#v): %s", values, err)
}
if !reflect.DeepEqual(dst, expected) {
t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst)
}
}
func TestDecodeIgnoreCasePriority(t *testing.T) {
type simpleStruct struct {
Aaa string
AaA string
AAA string
}
var dst simpleStruct
values := url.Values{
"AaA": []string{"1"},
}
expected := simpleStruct{AaA: "1"}
d := NewDecoder(nil)
d.IgnoreCase(true)
err := d.DecodeValues(&dst, values)
if err != nil {
t.Errorf("Decode(%#v): %s", values, err)
}
if !reflect.DeepEqual(dst, expected) {
t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst)
}
}

388
vendor/github.com/ajg/form/encode.go generated vendored Normal file
View File

@ -0,0 +1,388 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"encoding"
"errors"
"fmt"
"io"
"net/url"
"reflect"
"strconv"
"strings"
"time"
)
// NewEncoder returns a new form Encoder.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w, defaultDelimiter, defaultEscape, false}
}
// Encoder provides a way to encode to a Writer.
type Encoder struct {
w io.Writer
d rune
e rune
z bool
}
// DelimitWith sets r as the delimiter used for composite keys by Encoder e and returns the latter; it is '.' by default.
func (e *Encoder) DelimitWith(r rune) *Encoder {
e.d = r
return e
}
// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Encoder e and returns the latter; it is '\\' by default.
func (e *Encoder) EscapeWith(r rune) *Encoder {
e.e = r
return e
}
// KeepZeros sets whether Encoder e should keep zero (default) values in their literal form when encoding, and returns the former; by default zero values are not kept, but are rather encoded as the empty string.
func (e *Encoder) KeepZeros(z bool) *Encoder {
e.z = z
return e
}
// Encode encodes dst as form and writes it out using the Encoder's Writer.
func (e Encoder) Encode(dst interface{}) error {
v := reflect.ValueOf(dst)
n, err := encodeToNode(v, e.z)
if err != nil {
return err
}
s := n.values(e.d, e.e).Encode()
l, err := io.WriteString(e.w, s)
switch {
case err != nil:
return err
case l != len(s):
return errors.New("could not write data completely")
}
return nil
}
// EncodeToString encodes dst as a form and returns it as a string.
func EncodeToString(dst interface{}) (string, error) {
v := reflect.ValueOf(dst)
n, err := encodeToNode(v, false)
if err != nil {
return "", err
}
vs := n.values(defaultDelimiter, defaultEscape)
return vs.Encode(), nil
}
// EncodeToValues encodes dst as a form and returns it as Values.
func EncodeToValues(dst interface{}) (url.Values, error) {
v := reflect.ValueOf(dst)
n, err := encodeToNode(v, false)
if err != nil {
return nil, err
}
vs := n.values(defaultDelimiter, defaultEscape)
return vs, nil
}
func encodeToNode(v reflect.Value, z bool) (n node, err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
return getNode(encodeValue(v, z)), nil
}
func encodeValue(v reflect.Value, z bool) interface{} {
t := v.Type()
k := v.Kind()
if s, ok := marshalValue(v); ok {
return s
} else if !z && isEmptyValue(v) {
return "" // Treat the zero value as the empty string.
}
switch k {
case reflect.Ptr, reflect.Interface:
return encodeValue(v.Elem(), z)
case reflect.Struct:
if t.ConvertibleTo(timeType) {
return encodeTime(v)
} else if t.ConvertibleTo(urlType) {
return encodeURL(v)
}
return encodeStruct(v, z)
case reflect.Slice:
return encodeSlice(v, z)
case reflect.Array:
return encodeArray(v, z)
case reflect.Map:
return encodeMap(v, z)
case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
panic(t.String() + " has unsupported kind " + t.Kind().String())
default:
return encodeBasic(v)
}
}
func encodeStruct(v reflect.Value, z bool) interface{} {
t := v.Type()
n := node{}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
k, oe := fieldInfo(f)
if k == "-" {
continue
} else if fv := v.Field(i); oe && isEmptyValue(fv) {
delete(n, k)
} else {
n[k] = encodeValue(fv, z)
}
}
return n
}
func encodeMap(v reflect.Value, z bool) interface{} {
n := node{}
for _, i := range v.MapKeys() {
k := getString(encodeValue(i, z))
n[k] = encodeValue(v.MapIndex(i), z)
}
return n
}
func encodeArray(v reflect.Value, z bool) interface{} {
n := node{}
for i := 0; i < v.Len(); i++ {
n[strconv.Itoa(i)] = encodeValue(v.Index(i), z)
}
return n
}
func encodeSlice(v reflect.Value, z bool) interface{} {
t := v.Type()
if t.Elem().Kind() == reflect.Uint8 {
return string(v.Bytes()) // Encode byte slices as a single string by default.
}
n := node{}
for i := 0; i < v.Len(); i++ {
n[strconv.Itoa(i)] = encodeValue(v.Index(i), z)
}
return n
}
func encodeTime(v reflect.Value) string {
t := v.Convert(timeType).Interface().(time.Time)
if t.Year() == 0 && (t.Month() == 0 || t.Month() == 1) && (t.Day() == 0 || t.Day() == 1) {
return t.Format("15:04:05.999999999Z07:00")
} else if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0 {
return t.Format("2006-01-02")
}
return t.Format("2006-01-02T15:04:05.999999999Z07:00")
}
func encodeURL(v reflect.Value) string {
u := v.Convert(urlType).Interface().(url.URL)
return u.String()
}
func encodeBasic(v reflect.Value) string {
t := v.Type()
switch k := t.Kind(); k {
case reflect.Bool:
return strconv.FormatBool(v.Bool())
case reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
return strconv.FormatInt(v.Int(), 10)
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
return strconv.FormatUint(v.Uint(), 10)
case reflect.Float32:
return strconv.FormatFloat(v.Float(), 'g', -1, 32)
case reflect.Float64:
return strconv.FormatFloat(v.Float(), 'g', -1, 64)
case reflect.Complex64, reflect.Complex128:
s := fmt.Sprintf("%g", v.Complex())
return strings.TrimSuffix(strings.TrimPrefix(s, "("), ")")
case reflect.String:
return v.String()
}
panic(t.String() + " has unsupported kind " + t.Kind().String())
}
func isEmptyValue(v reflect.Value) bool {
switch t := v.Type(); v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Complex64, reflect.Complex128:
return v.Complex() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
case reflect.Struct:
if t.ConvertibleTo(timeType) {
return v.Convert(timeType).Interface().(time.Time).IsZero()
}
return reflect.DeepEqual(v, reflect.Zero(t))
}
return false
}
// canIndexOrdinally returns whether a value contains an ordered sequence of elements.
func canIndexOrdinally(v reflect.Value) bool {
if !v.IsValid() {
return false
}
switch t := v.Type(); t.Kind() {
case reflect.Ptr, reflect.Interface:
return canIndexOrdinally(v.Elem())
case reflect.Slice, reflect.Array:
return true
}
return false
}
func fieldInfo(f reflect.StructField) (k string, oe bool) {
if f.PkgPath != "" { // Skip private fields.
return omittedKey, oe
}
k = f.Name
tag := f.Tag.Get("form")
if tag == "" {
return k, oe
}
ps := strings.SplitN(tag, ",", 2)
if ps[0] != "" {
k = ps[0]
}
if len(ps) == 2 {
oe = ps[1] == "omitempty"
}
return k, oe
}
func findField(v reflect.Value, n string, ignoreCase bool) (reflect.Value, bool) {
t := v.Type()
l := v.NumField()
var lowerN string
caseInsensitiveMatch := -1
if ignoreCase {
lowerN = strings.ToLower(n)
}
// First try named fields.
for i := 0; i < l; i++ {
f := t.Field(i)
k, _ := fieldInfo(f)
if k == omittedKey {
continue
} else if n == k {
return v.Field(i), true
} else if ignoreCase && lowerN == strings.ToLower(k) {
caseInsensitiveMatch = i
}
}
// If no exact match was found try case insensitive match.
if caseInsensitiveMatch != -1 {
return v.Field(caseInsensitiveMatch), true
}
// Then try anonymous (embedded) fields.
for i := 0; i < l; i++ {
f := t.Field(i)
k, _ := fieldInfo(f)
if k == omittedKey || !f.Anonymous { // || k != "" ?
continue
}
fv := v.Field(i)
fk := fv.Kind()
for fk == reflect.Ptr || fk == reflect.Interface {
fv = fv.Elem()
fk = fv.Kind()
}
if fk != reflect.Struct {
continue
}
if ev, ok := findField(fv, n, ignoreCase); ok {
return ev, true
}
}
return reflect.Value{}, false
}
var (
stringType = reflect.TypeOf(string(""))
stringMapType = reflect.TypeOf(map[string]interface{}{})
timeType = reflect.TypeOf(time.Time{})
timePtrType = reflect.TypeOf(&time.Time{})
urlType = reflect.TypeOf(url.URL{})
)
func skipTextMarshalling(t reflect.Type) bool {
/*// Skip time.Time because its text unmarshaling is overly rigid:
return t == timeType || t == timePtrType*/
// Skip time.Time & convertibles because its text unmarshaling is overly rigid:
return t.ConvertibleTo(timeType) || t.ConvertibleTo(timePtrType)
}
func unmarshalValue(v reflect.Value, x interface{}) bool {
if skipTextMarshalling(v.Type()) {
return false
}
tu, ok := v.Interface().(encoding.TextUnmarshaler)
if !ok && !v.CanAddr() {
return false
} else if !ok {
return unmarshalValue(v.Addr(), x)
}
s := getString(x)
if err := tu.UnmarshalText([]byte(s)); err != nil {
panic(err)
}
return true
}
func marshalValue(v reflect.Value) (string, bool) {
if skipTextMarshalling(v.Type()) {
return "", false
}
tm, ok := v.Interface().(encoding.TextMarshaler)
if !ok && !v.CanAddr() {
return "", false
} else if !ok {
return marshalValue(v.Addr())
}
bs, err := tm.MarshalText()
if err != nil {
panic(err)
}
return string(bs), true
}

101
vendor/github.com/ajg/form/encode_test.go generated vendored Normal file
View File

@ -0,0 +1,101 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"bytes"
"reflect"
"testing"
)
func TestEncodeToString(t *testing.T) {
for _, c := range testCases(encOnly) {
if s, err := EncodeToString(c.b); err != nil {
t.Errorf("EncodeToString(%#v): %s", c.b, err)
} else if !reflect.DeepEqual(c.s, s) {
t.Errorf("EncodeToString(%#v)\n want (%#v)\n have (%#v)", c.b, c.s, s)
}
}
}
func TestEncodeToValues(t *testing.T) {
for _, c := range testCases(encOnly) {
cvs := mustParseQuery(c.s)
if vs, err := EncodeToValues(c.b); err != nil {
t.Errorf("EncodeToValues(%#v): %s", c.b, err)
} else if !reflect.DeepEqual(cvs, vs) {
t.Errorf("EncodeToValues(%#v)\n want (%#v)\n have (%#v)", c.b, cvs, vs)
}
}
}
func TestEncode(t *testing.T) {
for _, c := range testCases(encOnly) {
var w bytes.Buffer
e := NewEncoder(&w)
if err := e.Encode(c.b); err != nil {
t.Errorf("Encode(%#v): %s", c.b, err)
} else if s := w.String(); !reflect.DeepEqual(c.s, s) {
t.Errorf("Encode(%#v)\n want (%#v)\n have (%#v)", c.b, c.s, s)
}
}
}
type Thing1 struct {
String string `form:"name,omitempty"`
Integer *uint `form:"num,omitempty"`
}
type Thing2 struct {
String string `form:"name,omitempty"`
Integer uint `form:"num,omitempty"`
}
type Thing3 struct {
String string `form:"name"`
Integer *uint `form:"num"`
}
type Thing4 struct {
String string `form:"name"`
Integer uint `form:"num"`
}
func TestEncode_KeepZero(t *testing.T) {
num := uint(0)
for _, c := range []struct {
b interface{}
s string
z bool
}{
{Thing1{"test", &num}, "name=test&num=", false},
{Thing1{"test", &num}, "name=test&num=0", true},
{Thing2{"test", num}, "name=test", false},
{Thing2{"test", num}, "name=test", true},
{Thing3{"test", &num}, "name=test&num=", false},
{Thing3{"test", &num}, "name=test&num=0", true},
{Thing4{"test", num}, "name=test&num=", false},
{Thing4{"test", num}, "name=test&num=0", true},
{Thing1{"", &num}, "num=", false},
{Thing1{"", &num}, "num=0", true},
{Thing2{"", num}, "", false},
{Thing2{"", num}, "", true},
{Thing3{"", &num}, "name=&num=", false},
{Thing3{"", &num}, "name=&num=0", true},
{Thing4{"", num}, "name=&num=", false},
{Thing4{"", num}, "name=&num=0", true},
} {
var w bytes.Buffer
e := NewEncoder(&w)
if err := e.KeepZeros(c.z).Encode(c.b); err != nil {
t.Errorf("KeepZeros(%#v).Encode(%#v): %s", c.z, c.b, err)
} else if s := w.String(); c.s != s {
t.Errorf("KeepZeros(%#v).Encode(%#v)\n want (%#v)\n have (%#v)", c.z, c.b, c.s, s)
}
}
}

14
vendor/github.com/ajg/form/form.go generated vendored Normal file
View File

@ -0,0 +1,14 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package form implements encoding and decoding of application/x-www-form-urlencoded data.
package form
const (
implicitKey = "_"
omittedKey = "-"
defaultDelimiter = '.'
defaultEscape = '\\'
)

342
vendor/github.com/ajg/form/form_test.go generated vendored Normal file
View File

@ -0,0 +1,342 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"encoding"
"fmt"
"net/url"
"time"
)
type Struct struct {
B bool
I int `form:"life"`
F float64
C complex128
R rune `form:",omitempty"` // For testing when non-empty.
Re rune `form:",omitempty"` // For testing when empty.
S string
T time.Time
U url.URL
A Array
M Map
Y interface{} `form:"-"` // For testing when non-empty.
Ye interface{} `form:"-"` // For testing when empty.
Zs Slice
E // Embedded.
P P `form:"P.D\\Q.B"`
}
type SXs map[string]interface{}
type E struct {
Bytes1 []byte // For testing explicit (qualified by embedder) name, e.g. "E.Bytes1".
Bytes2 []byte // For testing implicit (unqualified) name, e.g. just "Bytes2"
}
type Z time.Time // Defined as such to test conversions.
func (z Z) String() string { return time.Time(z).String() }
type Array [3]string
type Map map[string]int
type Slice []struct {
Z Z
Q Q
Qp *Q
Q2 Q `form:"-"`
E `form:"-"`
}
// Custom marshaling
type Q struct {
a, b uint16
}
var (
_ encoding.TextMarshaler = &Q{}
_ encoding.TextUnmarshaler = &Q{}
)
func (u Q) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%d_%d", u.a, u.b)), nil
}
func (u *Q) UnmarshalText(bs []byte) error {
_, err := fmt.Sscanf(string(bs), "%d_%d", &u.a, &u.b)
return err
}
func prepopulate(sxs SXs) SXs {
var B bool
var I int
var F float64
var C complex128
var R rune
var S string
var T time.Time
var U url.URL
var A Array
var M Map
// Y is ignored.
// Ye is ignored.
var Zs Slice
var E E
var P P
sxs["B"] = B
sxs["life"] = I
sxs["F"] = F
sxs["C"] = C
sxs["R"] = R
// Re is omitted.
sxs["S"] = S
sxs["T"] = T
sxs["U"] = U
sxs["A"] = A
sxs["M"] = M
// Y is ignored.
// Ye is ignored.
sxs["Zs"] = Zs
sxs["E"] = E
sxs["P.D\\Q.B"] = P
return sxs
}
type P struct {
A, B string
}
type direction int
const (
encOnly = 1
decOnly = 2
rndTrip = encOnly | decOnly
)
func testCases(dir direction) (cs []testCase) {
var B bool
var I int
var F float64
var C complex128
var R rune
var S string
var T time.Time
var U url.URL
const canonical = `A.0=x&A.1=y&A.2=z&B=true&C=42%2B6.6i&E.Bytes1=%00%01%02&E.Bytes2=%03%04%05&F=6.6&M.Bar=8&M.Foo=7&M.Qux=9&P%5C.D%5C%5CQ%5C.B.A=P%2FD&P%5C.D%5C%5CQ%5C.B.B=Q-B&R=8734&S=Hello%2C+there.&T=2013-10-01T07%3A05%3A34.000000088Z&U=http%3A%2F%2Fexample.org%2Ffoo%23bar&Zs.0.Q=11_22&Zs.0.Qp=33_44&Zs.0.Z=2006-12-01&life=42`
const variation = `;C=42%2B6.6i;A.0=x;M.Bar=8;F=6.6;A.1=y;R=8734;A.2=z;Zs.0.Qp=33_44;B=true;M.Foo=7;T=2013-10-01T07:05:34.000000088Z;E.Bytes1=%00%01%02;Bytes2=%03%04%05;Zs.0.Q=11_22;Zs.0.Z=2006-12-01;M.Qux=9;life=42;S=Hello,+there.;P\.D\\Q\.B.A=P/D;P\.D\\Q\.B.B=Q-B;U=http%3A%2F%2Fexample.org%2Ffoo%23bar;`
for _, c := range []testCase{
// Bools
{rndTrip, &B, "=", b(false)},
{rndTrip, &B, "=true", b(true)},
{decOnly, &B, "=false", b(false)},
// Ints
{rndTrip, &I, "=", i(0)},
{rndTrip, &I, "=42", i(42)},
{rndTrip, &I, "=-42", i(-42)},
{decOnly, &I, "=0", i(0)},
{decOnly, &I, "=-0", i(0)},
// Floats
{rndTrip, &F, "=", f(0)},
{rndTrip, &F, "=6.6", f(6.6)},
{rndTrip, &F, "=-6.6", f(-6.6)},
// Complexes
{rndTrip, &C, "=", c(complex(0, 0))},
{rndTrip, &C, "=42%2B6.6i", c(complex(42, 6.6))},
{rndTrip, &C, "=-42-6.6i", c(complex(-42, -6.6))},
// Runes
{rndTrip, &R, "=", r(0)},
{rndTrip, &R, "=97", r('a')},
{rndTrip, &R, "=8734", r('\u221E')},
// Strings
{rndTrip, &S, "=", s("")},
{rndTrip, &S, "=X+%26+Y+%26+Z", s("X & Y & Z")},
{rndTrip, &S, "=Hello%2C+there.", s("Hello, there.")},
{decOnly, &S, "=Hello, there.", s("Hello, there.")},
// Dates/Times
{rndTrip, &T, "=", t(time.Time{})},
{rndTrip, &T, "=2013-10-01T07%3A05%3A34.000000088Z", t(time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC))},
{decOnly, &T, "=2013-10-01T07:05:34.000000088Z", t(time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC))},
{rndTrip, &T, "=07%3A05%3A34.000000088Z", t(time.Date(0, 1, 1, 7, 5, 34, 88, time.UTC))},
{decOnly, &T, "=07:05:34.000000088Z", t(time.Date(0, 1, 1, 7, 5, 34, 88, time.UTC))},
{rndTrip, &T, "=2013-10-01", t(time.Date(2013, 10, 1, 0, 0, 0, 0, time.UTC))},
// URLs
{rndTrip, &U, "=", u(url.URL{})},
{rndTrip, &U, "=http%3A%2F%2Fexample.org%2Ffoo%23bar", u(url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"})},
{rndTrip, &U, "=git%3A%2F%2Fgithub.com%2Fajg%2Fform.git", u(url.URL{Scheme: "git", Host: "github.com", Path: "/ajg/form.git"})},
// Structs
{rndTrip, &Struct{Y: 786}, canonical,
&Struct{
true,
42,
6.6,
complex(42, 6.6),
'\u221E',
rune(0),
"Hello, there.",
time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC),
url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"},
Array{"x", "y", "z"},
Map{"Foo": 7, "Bar": 8, "Qux": 9},
786, // Y: This value should not change.
nil, // Ye: This value should not change.
Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}},
E{[]byte{0, 1, 2}, []byte{3, 4, 5}},
P{"P/D", "Q-B"},
},
},
{decOnly, &Struct{Y: 786}, variation,
&Struct{
true,
42,
6.6,
complex(42, 6.6),
'\u221E',
rune(0),
"Hello, there.",
time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC),
url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"},
Array{"x", "y", "z"},
Map{"Foo": 7, "Bar": 8, "Qux": 9},
786, // Y: This value should not change.
nil, // Ye: This value should not change.
Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}},
E{[]byte{0, 1, 2}, []byte{3, 4, 5}},
P{"P/D", "Q-B"},
},
},
// Maps
{rndTrip, prepopulate(SXs{}), canonical,
SXs{"B": true,
"life": 42,
"F": 6.6,
"C": complex(42, 6.6),
"R": '\u221E',
// Re is omitted.
"S": "Hello, there.",
"T": time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC),
"U": url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"},
"A": Array{"x", "y", "z"},
"M": Map{"Foo": 7, "Bar": 8, "Qux": 9},
// Y is ignored.
// Ye is ignored.
"Zs": Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}},
"E": E{[]byte{0, 1, 2}, []byte{3, 4, 5}},
"P.D\\Q.B": P{"P/D", "Q-B"},
},
},
{decOnly, prepopulate(SXs{}), variation,
SXs{"B": true,
"life": 42,
"F": 6.6,
"C": complex(42, 6.6),
"R": '\u221E',
// Re is omitted.
"S": "Hello, there.",
"T": time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC),
"U": url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"},
"A": Array{"x", "y", "z"},
"M": Map{"Foo": 7, "Bar": 8, "Qux": 9},
// Y is ignored.
// Ye is ignored.
"Zs": Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}},
"E": E{[]byte{0, 1, 2}, nil},
"Bytes2": string([]byte{3, 4, 5}),
"P.D\\Q.B": P{"P/D", "Q-B"},
},
},
{rndTrip, SXs{}, canonical,
SXs{"B": "true",
"life": "42",
"F": "6.6",
"C": "42+6.6i",
"R": "8734",
// Re is omitted.
"S": "Hello, there.",
"T": "2013-10-01T07:05:34.000000088Z",
"U": "http://example.org/foo#bar",
"A": map[string]interface{}{"0": "x", "1": "y", "2": "z"},
"M": map[string]interface{}{"Foo": "7", "Bar": "8", "Qux": "9"},
// Y is ignored.
// Ye is ignored.
"Zs": map[string]interface{}{
"0": map[string]interface{}{
"Z": "2006-12-01",
"Q": "11_22",
"Qp": "33_44",
},
},
"E": map[string]interface{}{"Bytes1": string([]byte{0, 1, 2}), "Bytes2": string([]byte{3, 4, 5})},
"P.D\\Q.B": map[string]interface{}{"A": "P/D", "B": "Q-B"},
},
},
{decOnly, SXs{}, variation,
SXs{"B": "true",
"life": "42",
"F": "6.6",
"C": "42+6.6i",
"R": "8734",
// Re is omitted.
"S": "Hello, there.",
"T": "2013-10-01T07:05:34.000000088Z",
"U": "http://example.org/foo#bar",
"A": map[string]interface{}{"0": "x", "1": "y", "2": "z"},
"M": map[string]interface{}{"Foo": "7", "Bar": "8", "Qux": "9"},
// Y is ignored.
// Ye is ignored.
"Zs": map[string]interface{}{
"0": map[string]interface{}{
"Z": "2006-12-01",
"Q": "11_22",
"Qp": "33_44",
},
},
"E": map[string]interface{}{"Bytes1": string([]byte{0, 1, 2})},
"Bytes2": string([]byte{3, 4, 5}),
"P.D\\Q.B": map[string]interface{}{"A": "P/D", "B": "Q-B"},
},
},
} {
if c.d&dir != 0 {
cs = append(cs, c)
}
}
return cs
}
type testCase struct {
d direction
a interface{}
s string
b interface{}
}
func b(b bool) *bool { return &b }
func i(i int) *int { return &i }
func f(f float64) *float64 { return &f }
func c(c complex128) *complex128 { return &c }
func r(r rune) *rune { return &r }
func s(s string) *string { return &s }
func t(t time.Time) *time.Time { return &t }
func u(u url.URL) *url.URL { return &u }
func mustParseQuery(s string) url.Values {
vs, err := url.ParseQuery(s)
if err != nil {
panic(err)
}
return vs
}

152
vendor/github.com/ajg/form/node.go generated vendored Normal file
View File

@ -0,0 +1,152 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"net/url"
"strconv"
"strings"
)
type node map[string]interface{}
func (n node) values(d, e rune) url.Values {
vs := url.Values{}
n.merge(d, e, "", &vs)
return vs
}
func (n node) merge(d, e rune, p string, vs *url.Values) {
for k, x := range n {
switch y := x.(type) {
case string:
vs.Add(p+escape(d, e, k), y)
case node:
y.merge(d, e, p+escape(d, e, k)+string(d), vs)
default:
panic("value is neither string nor node")
}
}
}
// TODO: Add tests for implicit indexing.
func parseValues(d, e rune, vs url.Values, canIndexFirstLevelOrdinally bool) node {
// NOTE: Because of the flattening of potentially multiple strings to one key, implicit indexing works:
// i. At the first level; e.g. Foo.Bar=A&Foo.Bar=B becomes 0.Foo.Bar=A&1.Foo.Bar=B
// ii. At the last level; e.g. Foo.Bar._=A&Foo.Bar._=B becomes Foo.Bar.0=A&Foo.Bar.1=B
// TODO: At in-between levels; e.g. Foo._.Bar=A&Foo._.Bar=B becomes Foo.0.Bar=A&Foo.1.Bar=B
// (This last one requires that there only be one placeholder in order for it to be unambiguous.)
m := map[string]string{}
for k, ss := range vs {
indexLastLevelOrdinally := strings.HasSuffix(k, string(d)+implicitKey)
for i, s := range ss {
if canIndexFirstLevelOrdinally {
k = strconv.Itoa(i) + string(d) + k
} else if indexLastLevelOrdinally {
k = strings.TrimSuffix(k, implicitKey) + strconv.Itoa(i)
}
m[k] = s
}
}
n := node{}
for k, s := range m {
n = n.split(d, e, k, s)
}
return n
}
func splitPath(d, e rune, path string) (k, rest string) {
esc := false
for i, r := range path {
switch {
case !esc && r == e:
esc = true
case !esc && r == d:
return unescape(d, e, path[:i]), path[i+1:]
default:
esc = false
}
}
return unescape(d, e, path), ""
}
func (n node) split(d, e rune, path, s string) node {
k, rest := splitPath(d, e, path)
if rest == "" {
return add(n, k, s)
}
if _, ok := n[k]; !ok {
n[k] = node{}
}
c := getNode(n[k])
n[k] = c.split(d, e, rest, s)
return n
}
func add(n node, k, s string) node {
if n == nil {
return node{k: s}
}
if _, ok := n[k]; ok {
panic("key " + k + " already set")
}
n[k] = s
return n
}
func isEmpty(x interface{}) bool {
switch y := x.(type) {
case string:
return y == ""
case node:
if s, ok := y[""].(string); ok {
return s == ""
}
return false
}
panic("value is neither string nor node")
}
func getNode(x interface{}) node {
switch y := x.(type) {
case string:
return node{"": y}
case node:
return y
}
panic("value is neither string nor node")
}
func getString(x interface{}) string {
switch y := x.(type) {
case string:
return y
case node:
if s, ok := y[""].(string); ok {
return s
}
return ""
}
panic("value is neither string nor node")
}
func escape(d, e rune, s string) string {
s = strings.Replace(s, string(e), string(e)+string(e), -1) // Escape the escape (\ => \\)
s = strings.Replace(s, string(d), string(e)+string(d), -1) // Escape the delimiter (. => \.)
return s
}
func unescape(d, e rune, s string) string {
s = strings.Replace(s, string(e)+string(d), string(d), -1) // Unescape the delimiter (\. => .)
s = strings.Replace(s, string(e)+string(e), string(e), -1) // Unescape the escape (\\ => \)
return s
}

87
vendor/github.com/ajg/form/node_test.go generated vendored Normal file
View File

@ -0,0 +1,87 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"reflect"
"testing"
)
type foo int
type bar interface {
void()
}
type qux struct{}
type zee []bar
func TestCanIndexOrdinally(t *testing.T) {
for _, c := range []struct {
x interface{}
b bool
}{
{int(0), false},
{foo(0), false},
{qux{}, false},
{(*int)(nil), false},
{(*foo)(nil), false},
{(*bar)(nil), false},
{(*qux)(nil), false},
{[]qux{}, true},
{[5]qux{}, true},
{&[]foo{}, true},
{&[5]foo{}, true},
{zee{}, true},
{&zee{}, true},
{map[int]foo{}, false},
{map[string]interface{}{}, false},
{map[interface{}]bar{}, false},
{(chan<- int)(nil), false},
{(chan bar)(nil), false},
{(<-chan foo)(nil), false},
} {
v := reflect.ValueOf(c.x)
if b := canIndexOrdinally(v); b != c.b {
t.Errorf("canIndexOrdinally(%#v)\n want (%#v)\n have (%#v)", v, c.b, b)
}
}
}
var escapingTestCases = []struct {
a, b string
d, e rune
}{
{"Foo", "Foo", defaultDelimiter, defaultEscape},
{"Foo", "Foo", '/', '^'},
{"Foo.Bar.Qux", "Foo\\.Bar\\.Qux", defaultDelimiter, defaultEscape},
{"Foo.Bar.Qux", "Foo.Bar.Qux", '/', '^'},
{"Foo/Bar/Qux", "Foo/Bar/Qux", defaultDelimiter, defaultEscape},
{"Foo/Bar/Qux", "Foo^/Bar^/Qux", '/', '^'},
{"0", "0", defaultDelimiter, defaultEscape},
{"0", "0", '/', '^'},
{"0.1.2", "0\\.1\\.2", defaultDelimiter, defaultEscape},
{"0.1.2", "0.1.2", '/', '^'},
{"0/1/2", "0/1/2", defaultDelimiter, defaultEscape},
{"0/1/2", "0^/1^/2", '/', '^'},
{"A\\B", "A\\\\B", defaultDelimiter, defaultEscape},
{"A\\B", "A\\B", '/', '^'},
{"A^B", "A^B", defaultDelimiter, defaultEscape},
{"A^B", "A^^B", '/', '^'},
}
func TestEscape(t *testing.T) {
for _, c := range escapingTestCases {
if b := escape(c.d, c.e, c.a); b != c.b {
t.Errorf("escape(%q, %q, %q)\n want (%#v)\n have (%#v)", c.d, c.e, c.a, c.b, b)
}
}
}
func TestUnescape(t *testing.T) {
for _, c := range escapingTestCases {
if a := unescape(c.d, c.e, c.b); a != c.a {
t.Errorf("unescape(%q, %q, %q)\n want (%#v)\n have (%#v)", c.d, c.e, c.b, c.a, a)
}
}
}

18
vendor/github.com/ajg/form/pre-commit.sh generated vendored Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash -eu
# TODO: Only colorize messages given a suitable terminal.
# FIXME: Handle case in which no stash entry is created due to no changes.
printf "\e[30m=== PRE-COMMIT STARTING ===\e[m\n"
git stash save --quiet --keep-index --include-untracked
if go build -v ./... && go test -v -cover ./... && go vet ./... && golint . && travis-lint; then
result=$?
printf "\e[32m=== PRE-COMMIT SUCCEEDED ===\e[m\n"
else
result=$?
printf "\e[31m=== PRE-COMMIT FAILED ===\e[m\n"
fi
git stash pop --quiet
exit $result

22
vendor/github.com/davecgh/go-spew/.gitignore generated vendored Normal file
View File

@ -0,0 +1,22 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe

14
vendor/github.com/davecgh/go-spew/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,14 @@
language: go
go:
- 1.5.4
- 1.6.3
- 1.7
install:
- go get -v golang.org/x/tools/cmd/cover
script:
- go test -v -tags=safe ./spew
- go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
after_success:
- go get -v github.com/mattn/goveralls
- export PATH=$PATH:$HOME/gopath/bin
- goveralls -coverprofile=profile.cov -service=travis-ci

15
vendor/github.com/davecgh/go-spew/LICENSE generated vendored Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

205
vendor/github.com/davecgh/go-spew/README.md generated vendored Normal file
View File

@ -0,0 +1,205 @@
go-spew
=======
[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)]
(https://travis-ci.org/davecgh/go-spew) [![ISC License]
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status]
(https://img.shields.io/coveralls/davecgh/go-spew.svg)]
(https://coveralls.io/r/davecgh/go-spew?branch=master)
Go-spew implements a deep pretty printer for Go data structures to aid in
debugging. A comprehensive suite of tests with 100% test coverage is provided
to ensure proper functionality. See `test_coverage.txt` for the gocov coverage
report. Go-spew is licensed under the liberal ISC license, so it may be used in
open source or commercial projects.
If you're interested in reading about how this package came to life and some
of the challenges involved in providing a deep pretty printer, there is a blog
post about it
[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
## Documentation
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
(http://godoc.org/github.com/davecgh/go-spew/spew)
Full `go doc` style documentation for the project can be viewed online without
installing this package by using the excellent GoDoc site here:
http://godoc.org/github.com/davecgh/go-spew/spew
You can also view the documentation locally once the package is installed with
the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
http://localhost:6060/pkg/github.com/davecgh/go-spew/spew
## Installation
```bash
$ go get -u github.com/davecgh/go-spew/spew
```
## Quick Start
Add this import line to the file you're working in:
```Go
import "github.com/davecgh/go-spew/spew"
```
To dump a variable with full newlines, indentation, type, and pointer
information use Dump, Fdump, or Sdump:
```Go
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
```
Alternatively, if you would prefer to use format strings with a compacted inline
printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most
compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types
and pointer addresses):
```Go
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
```
## Debugging a Web Application Example
Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production.
```Go
package main
import (
"fmt"
"html"
"net/http"
"github.com/davecgh/go-spew/spew"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
fmt.Fprintf(w, "<!--\n" + html.EscapeString(spew.Sdump(w)) + "\n-->")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
```
## Sample Dump Output
```
(main.Foo) {
unexportedField: (*main.Bar)(0xf84002e210)({
flag: (main.Flag) flagTwo,
data: (uintptr) <nil>
}),
ExportedField: (map[interface {}]interface {}) {
(string) "one": (bool) true
}
}
([]uint8) {
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000020 31 32 |12|
}
```
## Sample Formatter Output
Double pointer to a uint8:
```
%v: <**>5
%+v: <**>(0xf8400420d0->0xf8400420c8)5
%#v: (**uint8)5
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
```
Pointer to circular struct with a uint8 field and a pointer to itself:
```
%v: <*>{1 <*><shown>}
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
```
## Configuration Options
Configuration of spew is handled by fields in the ConfigState type. For
convenience, all of the top-level functions use a global state available via the
spew.Config global.
It is also possible to create a ConfigState instance that provides methods
equivalent to the top-level functions. This allows concurrent configuration
options. See the ConfigState documentation for more details.
```
* Indent
String to use for each indentation level for Dump functions.
It is a single space by default. A popular alternative is "\t".
* MaxDepth
Maximum number of levels to descend into nested data structures.
There is no limit by default.
* DisableMethods
Disables invocation of error and Stringer interface methods.
Method invocation is enabled by default.
* DisablePointerMethods
Disables invocation of error and Stringer interface methods on types
which only accept pointer receivers from non-pointer variables. This option
relies on access to the unsafe package, so it will not have any effect when
running in environments without access to the unsafe package such as Google
App Engine or with the "safe" build tag specified.
Pointer method invocation is enabled by default.
* DisablePointerAddresses
DisablePointerAddresses specifies whether to disable the printing of
pointer addresses. This is useful when diffing data structures in tests.
* DisableCapacities
DisableCapacities specifies whether to disable the printing of capacities
for arrays, slices, maps and channels. This is useful when diffing data
structures in tests.
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
* SortKeys
Specifies map keys should be sorted before being printed. Use
this to have a more deterministic, diffable output. Note that
only native types (bool, int, uint, floats, uintptr and string)
and types which implement error or Stringer interfaces are supported,
with other types sorted according to the reflect.Value.String() output
which guarantees display stability. Natural map order is used by
default.
* SpewKeys
SpewKeys specifies that, as a last resort attempt, map keys should be
spewed to strings and sorted by those strings. This is only considered
if SortKeys is true.
```
## Unsafe Package Dependency
This package relies on the unsafe package to perform some of the more advanced
features, however it also supports a "limited" mode which allows it to work in
environments where the unsafe package is not available. By default, it will
operate in this mode on Google App Engine and when compiled with GopherJS. The
"safe" build tag may also be specified to force the package to build without
using the unsafe package.
## License
Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.

22
vendor/github.com/davecgh/go-spew/cov_report.sh generated vendored Normal file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# This script uses gocov to generate a test coverage report.
# The gocov tool my be obtained with the following command:
# go get github.com/axw/gocov/gocov
#
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
# Check for gocov.
if ! type gocov >/dev/null 2>&1; then
echo >&2 "This script requires the gocov tool."
echo >&2 "You may obtain it with the following command:"
echo >&2 "go get github.com/axw/gocov/gocov"
exit 1
fi
# Only run the cgo tests if gcc is installed.
if type gcc >/dev/null 2>&1; then
(cd spew && gocov test -tags testcgo | gocov report)
else
(cd spew && gocov test | gocov report)
fi

152
vendor/github.com/davecgh/go-spew/spew/bypass.go generated vendored Normal file
View File

@ -0,0 +1,152 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
package spew
import (
"reflect"
"unsafe"
)
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = false
// ptrSize is the size of a pointer on the current arch.
ptrSize = unsafe.Sizeof((*byte)(nil))
)
var (
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
// flagKindWidth and flagKindShift indicate various bits that the
// reflect package uses internally to track kind information.
//
// flagRO indicates whether or not the value field of a reflect.Value is
// read-only.
//
// flagIndir indicates whether the value field of a reflect.Value is
// the actual data or a pointer to the data.
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
)
func init() {
// Older versions of reflect.Value stored small integers directly in the
// ptr field (which is named val in the older versions). Versions
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// Commit 90a7c3c86944 changed the flag positions such that the low
// order bits are the kind. This code extracts the kind from the flags
// field and ensures it's the correct type. When it's not, the flag
// order has been changed to the newer format, so the flags are updated
// accordingly.
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
upfv := *(*uintptr)(upf)
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
flagKindShift = 0
flagRO = 1 << 5
flagIndir = 1 << 6
// Commit adf9b30e5594 modified the flags to separate the
// flagRO flag into two bits which specifies whether or not the
// field is embedded. This causes flagIndir to move over a bit
// and means that flagRO is the combination of either of the
// original flagRO bit and the new bit.
//
// This code detects the change by extracting what used to be
// the indirect bit to ensure it's set. When it's not, the flag
// order has been changed to the newer format, so the flags are
// updated accordingly.
if upfv&flagIndir == 0 {
flagRO = 3 << 5
flagIndir = 1 << 7
}
}
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
// the typical safety restrictions preventing access to unaddressable and
// unexported data. It works by digging the raw pointer to the underlying
// value out of the protected value and generating a new unprotected (unsafe)
// reflect.Value to it.
//
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
indirects := 1
vt := v.Type()
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
if rvf&flagIndir != 0 {
vt = reflect.PtrTo(v.Type())
indirects++
} else if offsetScalar != 0 {
// The value is in the scalar field when it's not one of the
// reference types.
switch vt.Kind() {
case reflect.Uintptr:
case reflect.Chan:
case reflect.Func:
case reflect.Map:
case reflect.Ptr:
case reflect.UnsafePointer:
default:
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
offsetScalar)
}
}
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
}

38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe
package spew
import "reflect"
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = true
)
// unsafeReflectValue typically converts the passed reflect.Value into a one
// that bypasses the typical safety restrictions preventing access to
// unaddressable and unexported data. However, doing this relies on access to
// the unsafe package. This is a stub version which simply returns the passed
// reflect.Value when the unsafe package is not available.
func unsafeReflectValue(v reflect.Value) reflect.Value {
return v
}

341
vendor/github.com/davecgh/go-spew/spew/common.go generated vendored Normal file
View File

@ -0,0 +1,341 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"reflect"
"sort"
"strconv"
)
// Some constants in the form of bytes to avoid string overhead. This mirrors
// the technique used in the fmt package.
var (
panicBytes = []byte("(PANIC=")
plusBytes = []byte("+")
iBytes = []byte("i")
trueBytes = []byte("true")
falseBytes = []byte("false")
interfaceBytes = []byte("(interface {})")
commaNewlineBytes = []byte(",\n")
newlineBytes = []byte("\n")
openBraceBytes = []byte("{")
openBraceNewlineBytes = []byte("{\n")
closeBraceBytes = []byte("}")
asteriskBytes = []byte("*")
colonBytes = []byte(":")
colonSpaceBytes = []byte(": ")
openParenBytes = []byte("(")
closeParenBytes = []byte(")")
spaceBytes = []byte(" ")
pointerChainBytes = []byte("->")
nilAngleBytes = []byte("<nil>")
maxNewlineBytes = []byte("<max depth reached>\n")
maxShortBytes = []byte("<max>")
circularBytes = []byte("<already shown>")
circularShortBytes = []byte("<shown>")
invalidAngleBytes = []byte("<invalid>")
openBracketBytes = []byte("[")
closeBracketBytes = []byte("]")
percentBytes = []byte("%")
precisionBytes = []byte(".")
openAngleBytes = []byte("<")
closeAngleBytes = []byte(">")
openMapBytes = []byte("map[")
closeMapBytes = []byte("]")
lenEqualsBytes = []byte("len=")
capEqualsBytes = []byte("cap=")
)
// hexDigits is used to map a decimal value to a hex digit.
var hexDigits = "0123456789abcdef"
// catchPanic handles any panics that might occur during the handleMethods
// calls.
func catchPanic(w io.Writer, v reflect.Value) {
if err := recover(); err != nil {
w.Write(panicBytes)
fmt.Fprintf(w, "%v", err)
w.Write(closeParenBytes)
}
}
// handleMethods attempts to call the Error and String methods on the underlying
// type the passed reflect.Value represents and outputes the result to Writer w.
//
// It handles panics in any called methods by catching and displaying the error
// as the formatted value.
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
// We need an interface to check if the type implements the error or
// Stringer interface. However, the reflect package won't give us an
// interface on certain things like unexported struct fields in order
// to enforce visibility rules. We use unsafe, when it's available,
// to bypass these restrictions since this package does not mutate the
// values.
if !v.CanInterface() {
if UnsafeDisabled {
return false
}
v = unsafeReflectValue(v)
}
// Choose whether or not to do error and Stringer interface lookups against
// the base type or a pointer to the base type depending on settings.
// Technically calling one of these methods with a pointer receiver can
// mutate the value, however, types which choose to satisify an error or
// Stringer interface with a pointer receiver should not be mutating their
// state inside these interface methods.
if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
v = unsafeReflectValue(v)
}
if v.CanAddr() {
v = v.Addr()
}
// Is it an error or Stringer?
switch iface := v.Interface().(type) {
case error:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.Error()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.Error()))
return true
case fmt.Stringer:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.String()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.String()))
return true
}
return false
}
// printBool outputs a boolean value as true or false to Writer w.
func printBool(w io.Writer, val bool) {
if val {
w.Write(trueBytes)
} else {
w.Write(falseBytes)
}
}
// printInt outputs a signed integer value to Writer w.
func printInt(w io.Writer, val int64, base int) {
w.Write([]byte(strconv.FormatInt(val, base)))
}
// printUint outputs an unsigned integer value to Writer w.
func printUint(w io.Writer, val uint64, base int) {
w.Write([]byte(strconv.FormatUint(val, base)))
}
// printFloat outputs a floating point value using the specified precision,
// which is expected to be 32 or 64bit, to Writer w.
func printFloat(w io.Writer, val float64, precision int) {
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
}
// printComplex outputs a complex value using the specified float precision
// for the real and imaginary parts to Writer w.
func printComplex(w io.Writer, c complex128, floatPrecision int) {
r := real(c)
w.Write(openParenBytes)
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
i := imag(c)
if i >= 0 {
w.Write(plusBytes)
}
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
w.Write(iBytes)
w.Write(closeParenBytes)
}
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
// Null pointer.
num := uint64(p)
if num == 0 {
w.Write(nilAngleBytes)
return
}
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
buf := make([]byte, 18)
// It's simpler to construct the hex string right to left.
base := uint64(16)
i := len(buf) - 1
for num >= base {
buf[i] = hexDigits[num%base]
num /= base
i--
}
buf[i] = hexDigits[num]
// Add '0x' prefix.
i--
buf[i] = 'x'
i--
buf[i] = '0'
// Strip unused leading bytes.
buf = buf[i:]
w.Write(buf)
}
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
// elements to be sorted.
type valuesSorter struct {
values []reflect.Value
strings []string // either nil or same len and values
cs *ConfigState
}
// newValuesSorter initializes a valuesSorter instance, which holds a set of
// surrogate keys on which the data should be sorted. It uses flags in
// ConfigState to decide if and how to populate those surrogate keys.
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
vs := &valuesSorter{values: values, cs: cs}
if canSortSimply(vs.values[0].Kind()) {
return vs
}
if !cs.DisableMethods {
vs.strings = make([]string, len(values))
for i := range vs.values {
b := bytes.Buffer{}
if !handleMethods(cs, &b, vs.values[i]) {
vs.strings = nil
break
}
vs.strings[i] = b.String()
}
}
if vs.strings == nil && cs.SpewKeys {
vs.strings = make([]string, len(values))
for i := range vs.values {
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
}
}
return vs
}
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
// directly, or whether it should be considered for sorting by surrogate keys
// (if the ConfigState allows it).
func canSortSimply(kind reflect.Kind) bool {
// This switch parallels valueSortLess, except for the default case.
switch kind {
case reflect.Bool:
return true
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return true
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
case reflect.Uintptr:
return true
case reflect.Array:
return true
}
return false
}
// Len returns the number of values in the slice. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Len() int {
return len(s.values)
}
// Swap swaps the values at the passed indices. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Swap(i, j int) {
s.values[i], s.values[j] = s.values[j], s.values[i]
if s.strings != nil {
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
}
}
// valueSortLess returns whether the first value should sort before the second
// value. It is used by valueSorter.Less as part of the sort.Interface
// implementation.
func valueSortLess(a, b reflect.Value) bool {
switch a.Kind() {
case reflect.Bool:
return !a.Bool() && b.Bool()
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return a.Int() < b.Int()
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return a.Uint() < b.Uint()
case reflect.Float32, reflect.Float64:
return a.Float() < b.Float()
case reflect.String:
return a.String() < b.String()
case reflect.Uintptr:
return a.Uint() < b.Uint()
case reflect.Array:
// Compare the contents of both arrays.
l := a.Len()
for i := 0; i < l; i++ {
av := a.Index(i)
bv := b.Index(i)
if av.Interface() == bv.Interface() {
continue
}
return valueSortLess(av, bv)
}
}
return a.String() < b.String()
}
// Less returns whether the value at index i should sort before the
// value at index j. It is part of the sort.Interface implementation.
func (s *valuesSorter) Less(i, j int) bool {
if s.strings == nil {
return valueSortLess(s.values[i], s.values[j])
}
return s.strings[i] < s.strings[j]
}
// sortValues is a sort function that handles both native types and any type that
// can be converted to error or Stringer. Other inputs are sorted according to
// their Value.String() value to ensure display stability.
func sortValues(values []reflect.Value, cs *ConfigState) {
if len(values) == 0 {
return
}
sort.Sort(newValuesSorter(values, cs))
}

298
vendor/github.com/davecgh/go-spew/spew/common_test.go generated vendored Normal file
View File

@ -0,0 +1,298 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"fmt"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
)
// custom type to test Stinger interface on non-pointer receiver.
type stringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with non-pointer receivers.
func (s stringer) String() string {
return "stringer " + string(s)
}
// custom type to test Stinger interface on pointer receiver.
type pstringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with only pointer receivers.
func (s *pstringer) String() string {
return "stringer " + string(*s)
}
// xref1 and xref2 are cross referencing structs for testing circular reference
// detection.
type xref1 struct {
ps2 *xref2
}
type xref2 struct {
ps1 *xref1
}
// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
// reference for testing detection.
type indirCir1 struct {
ps2 *indirCir2
}
type indirCir2 struct {
ps3 *indirCir3
}
type indirCir3 struct {
ps1 *indirCir1
}
// embed is used to test embedded structures.
type embed struct {
a string
}
// embedwrap is used to test embedded structures.
type embedwrap struct {
*embed
e *embed
}
// panicer is used to intentionally cause a panic for testing spew properly
// handles them
type panicer int
func (p panicer) String() string {
panic("test panic")
}
// customError is used to test custom error interface invocation.
type customError int
func (e customError) Error() string {
return fmt.Sprintf("error: %d", int(e))
}
// stringizeWants converts a slice of wanted test output into a format suitable
// for a test error message.
func stringizeWants(wants []string) string {
s := ""
for i, want := range wants {
if i > 0 {
s += fmt.Sprintf("want%d: %s", i+1, want)
} else {
s += "want: " + want
}
}
return s
}
// testFailed returns whether or not a test failed by checking if the result
// of the test is in the slice of wanted strings.
func testFailed(result string, wants []string) bool {
for _, want := range wants {
if result == want {
return false
}
}
return true
}
type sortableStruct struct {
x int
}
func (ss sortableStruct) String() string {
return fmt.Sprintf("ss.%d", ss.x)
}
type unsortableStruct struct {
x int
}
type sortTestCase struct {
input []reflect.Value
expected []reflect.Value
}
func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
getInterfaces := func(values []reflect.Value) []interface{} {
interfaces := []interface{}{}
for _, v := range values {
interfaces = append(interfaces, v.Interface())
}
return interfaces
}
for _, test := range tests {
spew.SortValues(test.input, cs)
// reflect.DeepEqual cannot really make sense of reflect.Value,
// probably because of all the pointer tricks. For instance,
// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
// instead.
input := getInterfaces(test.input)
expected := getInterfaces(test.expected)
if !reflect.DeepEqual(input, expected) {
t.Errorf("Sort mismatch:\n %v != %v", input, expected)
}
}
}
// TestSortValues ensures the sort functionality for relect.Value based sorting
// works as intended.
func TestSortValues(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
embedA := v(embed{"a"})
embedB := v(embed{"b"})
embedC := v(embed{"c"})
tests := []sortTestCase{
// No values.
{
[]reflect.Value{},
[]reflect.Value{},
},
// Bools.
{
[]reflect.Value{v(false), v(true), v(false)},
[]reflect.Value{v(false), v(false), v(true)},
},
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Uints.
{
[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
},
// Floats.
{
[]reflect.Value{v(2.0), v(1.0), v(3.0)},
[]reflect.Value{v(1.0), v(2.0), v(3.0)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// Array
{
[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
},
// Uintptrs.
{
[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
},
// SortableStructs.
{
// Note: not sorted - DisableMethods is set.
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
// Invalid.
{
[]reflect.Value{embedB, embedA, embedC},
[]reflect.Value{embedB, embedA, embedC},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithMethods ensures the sort functionality for relect.Value
// based sorting works as intended when using string methods.
func TestSortValuesWithMethods(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithSpew ensures the sort functionality for relect.Value
// based sorting works as intended when using spew to stringify keys.
func TestSortValuesWithSpew(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
helpTestSortValues(tests, &cs, t)
}

306
vendor/github.com/davecgh/go-spew/spew/config.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"os"
)
// ConfigState houses the configuration options used by spew to format and
// display values. There is a global instance, Config, that is used to control
// all top-level Formatter and Dump functionality. Each ConfigState instance
// provides methods equivalent to the top-level functions.
//
// The zero value for ConfigState provides no indentation. You would typically
// want to set it to a space or a tab.
//
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
// with default settings. See the documentation of NewDefaultConfig for default
// values.
type ConfigState struct {
// Indent specifies the string to use for each indentation level. The
// global config instance that all top-level functions use set this to a
// single space by default. If you would like more indentation, you might
// set this to a tab with "\t" or perhaps two spaces with " ".
Indent string
// MaxDepth controls the maximum number of levels to descend into nested
// data structures. The default, 0, means there is no limit.
//
// NOTE: Circular data structures are properly detected, so it is not
// necessary to set this value unless you specifically want to limit deeply
// nested data structures.
MaxDepth int
// DisableMethods specifies whether or not error and Stringer interfaces are
// invoked for types that implement them.
DisableMethods bool
// DisablePointerMethods specifies whether or not to check for and invoke
// error and Stringer interfaces on types which only accept a pointer
// receiver when the current type is not a pointer.
//
// NOTE: This might be an unsafe action since calling one of these methods
// with a pointer receiver could technically mutate the value, however,
// in practice, types which choose to satisify an error or Stringer
// interface with a pointer receiver should not be mutating their state
// inside these interface methods. As a result, this option relies on
// access to the unsafe package, so it will not have any effect when
// running in environments without access to the unsafe package such as
// Google App Engine or with the "safe" build tag specified.
DisablePointerMethods bool
// DisablePointerAddresses specifies whether to disable the printing of
// pointer addresses. This is useful when diffing data structures in tests.
DisablePointerAddresses bool
// DisableCapacities specifies whether to disable the printing of capacities
// for arrays, slices, maps and channels. This is useful when diffing
// data structures in tests.
DisableCapacities bool
// ContinueOnMethod specifies whether or not recursion should continue once
// a custom error or Stringer interface is invoked. The default, false,
// means it will print the results of invoking the custom error or Stringer
// interface and return immediately instead of continuing to recurse into
// the internals of the data type.
//
// NOTE: This flag does not have any effect if method invocation is disabled
// via the DisableMethods or DisablePointerMethods options.
ContinueOnMethod bool
// SortKeys specifies map keys should be sorted before being printed. Use
// this to have a more deterministic, diffable output. Note that only
// native types (bool, int, uint, floats, uintptr and string) and types
// that support the error or Stringer interfaces (if methods are
// enabled) are supported, with other types sorted according to the
// reflect.Value.String() output which guarantees display stability.
SortKeys bool
// SpewKeys specifies that, as a last resort attempt, map keys should
// be spewed to strings and sorted by those strings. This is only
// considered if SortKeys is true.
SpewKeys bool
}
// Config is the active configuration of the top-level functions.
// The configuration can be changed by modifying the contents of spew.Config.
var Config = ConfigState{Indent: " "}
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the formatted string as a value that satisfies error. See NewFormatter
// for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, c.convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, c.convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, c.convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a Formatter interface returned by c.NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, c.convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
return fmt.Print(c.convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, c.convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
return fmt.Println(c.convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprint(a ...interface{}) string {
return fmt.Sprint(c.convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, c.convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a Formatter interface returned by c.NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintln(a ...interface{}) string {
return fmt.Sprintln(c.convertArgs(a)...)
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
c.Printf, c.Println, or c.Printf.
*/
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(c, v)
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
fdump(c, w, a...)
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by modifying the public members
of c. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func (c *ConfigState) Dump(a ...interface{}) {
fdump(c, os.Stdout, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func (c *ConfigState) Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(c, &buf, a...)
return buf.String()
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a spew Formatter interface using
// the ConfigState associated with s.
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = newFormatter(c, arg)
}
return formatters
}
// NewDefaultConfig returns a ConfigState with the following default settings.
//
// Indent: " "
// MaxDepth: 0
// DisableMethods: false
// DisablePointerMethods: false
// ContinueOnMethod: false
// SortKeys: false
func NewDefaultConfig() *ConfigState {
return &ConfigState{Indent: " "}
}

211
vendor/github.com/davecgh/go-spew/spew/doc.go generated vendored Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Package spew implements a deep pretty printer for Go data structures to aid in
debugging.
A quick overview of the additional features spew provides over the built-in
printing facilities for Go data types are as follows:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output (only when using
Dump style)
There are two different approaches spew allows for dumping Go data structures:
* Dump style which prints with newlines, customizable indentation,
and additional debug information such as types and all pointer addresses
used to indirect to the final value
* A custom Formatter interface that integrates cleanly with the standard fmt
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
similar to the default %v while providing the additional functionality
outlined above and passing unsupported format verbs such as %x and %q
along to fmt
Quick Start
This section demonstrates how to quickly get started with spew. See the
sections below for further details on formatting and configuration options.
To dump a variable with full newlines, indentation, type, and pointer
information use Dump, Fdump, or Sdump:
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
Alternatively, if you would prefer to use format strings with a compacted inline
printing style, use the convenience wrappers Printf, Fprintf, etc with
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
%#+v (adds types and pointer addresses):
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
Configuration Options
Configuration of spew is handled by fields in the ConfigState type. For
convenience, all of the top-level functions use a global state available
via the spew.Config global.
It is also possible to create a ConfigState instance that provides methods
equivalent to the top-level functions. This allows concurrent configuration
options. See the ConfigState documentation for more details.
The following configuration options are available:
* Indent
String to use for each indentation level for Dump functions.
It is a single space by default. A popular alternative is "\t".
* MaxDepth
Maximum number of levels to descend into nested data structures.
There is no limit by default.
* DisableMethods
Disables invocation of error and Stringer interface methods.
Method invocation is enabled by default.
* DisablePointerMethods
Disables invocation of error and Stringer interface methods on types
which only accept pointer receivers from non-pointer variables.
Pointer method invocation is enabled by default.
* DisablePointerAddresses
DisablePointerAddresses specifies whether to disable the printing of
pointer addresses. This is useful when diffing data structures in tests.
* DisableCapacities
DisableCapacities specifies whether to disable the printing of
capacities for arrays, slices, maps and channels. This is useful when
diffing data structures in tests.
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
* SortKeys
Specifies map keys should be sorted before being printed. Use
this to have a more deterministic, diffable output. Note that
only native types (bool, int, uint, floats, uintptr and string)
and types which implement error or Stringer interfaces are
supported with other types sorted according to the
reflect.Value.String() output which guarantees display
stability. Natural map order is used by default.
* SpewKeys
Specifies that, as a last resort attempt, map keys should be
spewed to strings and sorted by those strings. This is only
considered if SortKeys is true.
Dump Usage
Simply call spew.Dump with a list of variables you want to dump:
spew.Dump(myVar1, myVar2, ...)
You may also call spew.Fdump if you would prefer to output to an arbitrary
io.Writer. For example, to dump to standard error:
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
A third option is to call spew.Sdump to get the formatted output as a string:
str := spew.Sdump(myVar1, myVar2, ...)
Sample Dump Output
See the Dump example for details on the setup of the types and variables being
shown here.
(main.Foo) {
unexportedField: (*main.Bar)(0xf84002e210)({
flag: (main.Flag) flagTwo,
data: (uintptr) <nil>
}),
ExportedField: (map[interface {}]interface {}) (len=1) {
(string) (len=3) "one": (bool) true
}
}
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
command as shown.
([]uint8) (len=32 cap=32) {
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000020 31 32 |12|
}
Custom Formatter
Spew provides a custom formatter that implements the fmt.Formatter interface
so that it integrates cleanly with standard fmt package printing functions. The
formatter is useful for inline printing of smaller data types similar to the
standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Custom Formatter Usage
The simplest way to make use of the spew custom formatter is to call one of the
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
functions have syntax you are most likely already familiar with:
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Println(myVar, myVar2)
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
See the Index for the full list convenience functions.
Sample Formatter Output
Double pointer to a uint8:
%v: <**>5
%+v: <**>(0xf8400420d0->0xf8400420c8)5
%#v: (**uint8)5
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
Pointer to circular struct with a uint8 field and a pointer to itself:
%v: <*>{1 <*><shown>}
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
See the Printf example for details on the setup of variables being shown
here.
Errors
Since it is possible for custom Stringer/error interfaces to panic, spew
detects them and handles them internally by printing the panic information
inline with the output. Since spew is intended to provide deep pretty printing
capabilities on structures, it intentionally does not return any errors.
*/
package spew

509
vendor/github.com/davecgh/go-spew/spew/dump.go generated vendored Normal file
View File

@ -0,0 +1,509 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"os"
"reflect"
"regexp"
"strconv"
"strings"
)
var (
// uint8Type is a reflect.Type representing a uint8. It is used to
// convert cgo types to uint8 slices for hexdumping.
uint8Type = reflect.TypeOf(uint8(0))
// cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump
// them.
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
)
// dumpState contains information about the state of a dump operation.
type dumpState struct {
w io.Writer
depth int
pointers map[uintptr]int
ignoreNextType bool
ignoreNextIndent bool
cs *ConfigState
}
// indent performs indentation according to the depth level and cs.Indent
// option.
func (d *dumpState) indent() {
if d.ignoreNextIndent {
d.ignoreNextIndent = false
return
}
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
}
// unpackValue returns values inside of non-nil interfaces when possible.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface && !v.IsNil() {
v = v.Elem()
}
return v
}
// dumpPtr handles formatting of pointers by indirecting them as necessary.
func (d *dumpState) dumpPtr(v reflect.Value) {
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range d.pointers {
if depth >= d.depth {
delete(d.pointers, k)
}
}
// Keep list of all dereferenced pointers to show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by dereferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
cycleFound = true
indirects--
break
}
d.pointers[addr] = d.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type information.
d.w.Write(openParenBytes)
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
d.w.Write([]byte(ve.Type().String()))
d.w.Write(closeParenBytes)
// Display pointer information.
if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
d.w.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
d.w.Write(pointerChainBytes)
}
printHexPtr(d.w, addr)
}
d.w.Write(closeParenBytes)
}
// Display dereferenced value.
d.w.Write(openParenBytes)
switch {
case nilFound == true:
d.w.Write(nilAngleBytes)
case cycleFound == true:
d.w.Write(circularBytes)
default:
d.ignoreNextType = true
d.dump(ve)
}
d.w.Write(closeParenBytes)
}
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
// reflection) arrays and slices are dumped in hexdump -C fashion.
func (d *dumpState) dumpSlice(v reflect.Value) {
// Determine whether this type should be hex dumped or not. Also,
// for types which should be hexdumped, try to use the underlying data
// first, then fall back to trying to convert them to a uint8 slice.
var buf []uint8
doConvert := false
doHexDump := false
numEntries := v.Len()
if numEntries > 0 {
vt := v.Index(0).Type()
vts := vt.String()
switch {
// C types that need to be converted.
case cCharRE.MatchString(vts):
fallthrough
case cUnsignedCharRE.MatchString(vts):
fallthrough
case cUint8tCharRE.MatchString(vts):
doConvert = true
// Try to use existing uint8 slices and fall back to converting
// and copying if that fails.
case vt.Kind() == reflect.Uint8:
// We need an addressable interface to convert the type
// to a byte slice. However, the reflect package won't
// give us an interface on certain things like
// unexported struct fields in order to enforce
// visibility rules. We use unsafe, when available, to
// bypass these restrictions since this package does not
// mutate the values.
vs := v
if !vs.CanInterface() || !vs.CanAddr() {
vs = unsafeReflectValue(vs)
}
if !UnsafeDisabled {
vs = vs.Slice(0, numEntries)
// Use the existing uint8 slice if it can be
// type asserted.
iface := vs.Interface()
if slice, ok := iface.([]uint8); ok {
buf = slice
doHexDump = true
break
}
}
// The underlying data needs to be converted if it can't
// be type asserted to a uint8 slice.
doConvert = true
}
// Copy and convert the underlying type if needed.
if doConvert && vt.ConvertibleTo(uint8Type) {
// Convert and copy each element into a uint8 byte
// slice.
buf = make([]uint8, numEntries)
for i := 0; i < numEntries; i++ {
vv := v.Index(i)
buf[i] = uint8(vv.Convert(uint8Type).Uint())
}
doHexDump = true
}
}
// Hexdump the entire slice as needed.
if doHexDump {
indent := strings.Repeat(d.cs.Indent, d.depth)
str := indent + hex.Dump(buf)
str = strings.Replace(str, "\n", "\n"+indent, -1)
str = strings.TrimRight(str, d.cs.Indent)
d.w.Write([]byte(str))
return
}
// Recursively call dump for each item.
for i := 0; i < numEntries; i++ {
d.dump(d.unpackValue(v.Index(i)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
// dump is the main workhorse for dumping a value. It uses the passed reflect
// value to figure out what kind of object we are dealing with and formats it
// appropriately. It is a recursive function, however circular data structures
// are detected and handled properly.
func (d *dumpState) dump(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
d.w.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
d.indent()
d.dumpPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !d.ignoreNextType {
d.indent()
d.w.Write(openParenBytes)
d.w.Write([]byte(v.Type().String()))
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
d.ignoreNextType = false
// Display length and capacity if the built-in len and cap functions
// work with the value's kind and the len/cap itself is non-zero.
valueLen, valueCap := 0, 0
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Chan:
valueLen, valueCap = v.Len(), v.Cap()
case reflect.Map, reflect.String:
valueLen = v.Len()
}
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
d.w.Write(openParenBytes)
if valueLen != 0 {
d.w.Write(lenEqualsBytes)
printInt(d.w, int64(valueLen), 10)
}
if !d.cs.DisableCapacities && valueCap != 0 {
if valueLen != 0 {
d.w.Write(spaceBytes)
}
d.w.Write(capEqualsBytes)
printInt(d.w, int64(valueCap), 10)
}
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
// Call Stringer/error interfaces if they exist and the handle methods flag
// is enabled
if !d.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(d.cs, d.w, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(d.w, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(d.w, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(d.w, v.Uint(), 10)
case reflect.Float32:
printFloat(d.w, v.Float(), 32)
case reflect.Float64:
printFloat(d.w, v.Float(), 64)
case reflect.Complex64:
printComplex(d.w, v.Complex(), 32)
case reflect.Complex128:
printComplex(d.w, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
d.dumpSlice(v)
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.String:
d.w.Write([]byte(strconv.Quote(v.String())))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
d.w.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
numEntries := v.Len()
keys := v.MapKeys()
if d.cs.SortKeys {
sortValues(keys, d.cs)
}
for i, key := range keys {
d.dump(d.unpackValue(key))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.MapIndex(key)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Struct:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
vt := v.Type()
numFields := v.NumField()
for i := 0; i < numFields; i++ {
d.indent()
vtf := vt.Field(i)
d.w.Write([]byte(vtf.Name))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.Field(i)))
if i < (numFields - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(d.w, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(d.w, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it in case any new
// types are added.
default:
if v.CanInterface() {
fmt.Fprintf(d.w, "%v", v.Interface())
} else {
fmt.Fprintf(d.w, "%v", v.String())
}
}
}
// fdump is a helper function to consolidate the logic from the various public
// methods which take varying writers and config states.
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
for _, arg := range a {
if arg == nil {
w.Write(interfaceBytes)
w.Write(spaceBytes)
w.Write(nilAngleBytes)
w.Write(newlineBytes)
continue
}
d := dumpState{w: w, cs: cs}
d.pointers = make(map[uintptr]int)
d.dump(reflect.ValueOf(arg))
d.w.Write(newlineBytes)
}
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func Fdump(w io.Writer, a ...interface{}) {
fdump(&Config, w, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(&Config, &buf, a...)
return buf.String()
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by an exported package global,
spew.Config. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func Dump(a ...interface{}) {
fdump(&Config, os.Stdout, a...)
}

1042
vendor/github.com/davecgh/go-spew/spew/dump_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

99
vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when both cgo is supported and "-tags testcgo" is added to the go test
// command line. This means the cgo tests are only added (and hence run) when
// specifially requested. This configuration is used because spew itself
// does not require cgo to run even though it does handle certain cgo types
// specially. Rather than forcing all clients to require cgo and an external
// C compiler just to run the tests, this scheme makes them optional.
// +build cgo,testcgo
package spew_test
import (
"fmt"
"github.com/davecgh/go-spew/spew/testdata"
)
func addCgoDumpTests() {
// C char pointer.
v := testdata.GetCgoCharPointer()
nv := testdata.GetCgoNullCharPointer()
pv := &v
vcAddr := fmt.Sprintf("%p", v)
vAddr := fmt.Sprintf("%p", pv)
pvAddr := fmt.Sprintf("%p", &pv)
vt := "*testdata._Ctype_char"
vs := "116"
addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(nv, "("+vt+")(<nil>)\n")
// C char array.
v2, v2l, v2c := testdata.GetCgoCharArray()
v2Len := fmt.Sprintf("%d", v2l)
v2Cap := fmt.Sprintf("%d", v2c)
v2t := "[6]testdata._Ctype_char"
v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
"{\n 00000000 74 65 73 74 32 00 " +
" |test2.|\n}"
addDumpTest(v2, "("+v2t+") "+v2s+"\n")
// C unsigned char array.
v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
v3Len := fmt.Sprintf("%d", v3l)
v3Cap := fmt.Sprintf("%d", v3c)
v3t := "[6]testdata._Ctype_unsignedchar"
v3t2 := "[6]testdata._Ctype_uchar"
v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
"{\n 00000000 74 65 73 74 33 00 " +
" |test3.|\n}"
addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
// C signed char array.
v4, v4l, v4c := testdata.GetCgoSignedCharArray()
v4Len := fmt.Sprintf("%d", v4l)
v4Cap := fmt.Sprintf("%d", v4c)
v4t := "[6]testdata._Ctype_schar"
v4t2 := "testdata._Ctype_schar"
v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
") 0\n}"
addDumpTest(v4, "("+v4t+") "+v4s+"\n")
// C uint8_t array.
v5, v5l, v5c := testdata.GetCgoUint8tArray()
v5Len := fmt.Sprintf("%d", v5l)
v5Cap := fmt.Sprintf("%d", v5c)
v5t := "[6]testdata._Ctype_uint8_t"
v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
"{\n 00000000 74 65 73 74 35 00 " +
" |test5.|\n}"
addDumpTest(v5, "("+v5t+") "+v5s+"\n")
// C typedefed unsigned char array.
v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
v6Len := fmt.Sprintf("%d", v6l)
v6Cap := fmt.Sprintf("%d", v6c)
v6t := "[6]testdata._Ctype_custom_uchar_t"
v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
"{\n 00000000 74 65 73 74 36 00 " +
" |test6.|\n}"
addDumpTest(v6, "("+v6t+") "+v6s+"\n")
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when either cgo is not supported or "-tags testcgo" is not added to the go
// test command line. This file intentionally does not setup any cgo tests in
// this scenario.
// +build !cgo !testcgo
package spew_test
func addCgoDumpTests() {
// Don't add any tests for cgo since this file is only compiled when
// there should not be any cgo tests.
}

226
vendor/github.com/davecgh/go-spew/spew/example_test.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"fmt"
"github.com/davecgh/go-spew/spew"
)
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
// This example demonstrates how to use Dump to dump variables to stdout.
func ExampleDump() {
// The following package level declarations are assumed for this example:
/*
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
*/
// Setup some sample data structures for the example.
bar := Bar{uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
f := Flag(5)
b := []byte{
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32,
}
// Dump!
spew.Dump(s1, f, b)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Flag) Unknown flag (5)
// ([]uint8) (len=34 cap=34) {
// 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
// 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
// 00000020 31 32 |12|
// }
//
}
// This example demonstrates how to use Printf to display a variable with a
// format string and inline formatting.
func ExamplePrintf() {
// Create a double pointer to a uint 8.
ui8 := uint8(5)
pui8 := &ui8
ppui8 := &pui8
// Create a circular data type.
type circular struct {
ui8 uint8
c *circular
}
c := circular{ui8: 1}
c.c = &c
// Print!
spew.Printf("ppui8: %v\n", ppui8)
spew.Printf("circular: %v\n", c)
// Output:
// ppui8: <**>5
// circular: {1 <*>{1 <*><shown>}}
}
// This example demonstrates how to use a ConfigState.
func ExampleConfigState() {
// Modify the indent level of the ConfigState only. The global
// configuration is not modified.
scs := spew.ConfigState{Indent: "\t"}
// Output using the ConfigState instance.
v := map[string]int{"one": 1}
scs.Printf("v: %v\n", v)
scs.Dump(v)
// Output:
// v: map[one:1]
// (map[string]int) (len=1) {
// (string) (len=3) "one": (int) 1
// }
}
// This example demonstrates how to use ConfigState.Dump to dump variables to
// stdout
func ExampleConfigState_Dump() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances with different indentation.
scs := spew.ConfigState{Indent: "\t"}
scs2 := spew.ConfigState{Indent: " "}
// Setup some sample data structures for the example.
bar := Bar{uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
// Dump using the ConfigState instances.
scs.Dump(s1)
scs2.Dump(s1)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
//
}
// This example demonstrates how to use ConfigState.Printf to display a variable
// with a format string and inline formatting.
func ExampleConfigState_Printf() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances and modify the method handling of the
// first ConfigState only.
scs := spew.NewDefaultConfig()
scs2 := spew.NewDefaultConfig()
scs.DisableMethods = true
// Alternatively
// scs := spew.ConfigState{Indent: " ", DisableMethods: true}
// scs2 := spew.ConfigState{Indent: " "}
// This is of type Flag which implements a Stringer and has raw value 1.
f := flagTwo
// Dump using the ConfigState instances.
scs.Printf("f: %v\n", f)
scs2.Printf("f: %v\n", f)
// Output:
// f: 1
// f: flagTwo
}

419
vendor/github.com/davecgh/go-spew/spew/format.go generated vendored Normal file
View File

@ -0,0 +1,419 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"reflect"
"strconv"
"strings"
)
// supportedFlags is a list of all the character flags supported by fmt package.
const supportedFlags = "0-+# "
// formatState implements the fmt.Formatter interface and contains information
// about the state of a formatting operation. The NewFormatter function can
// be used to get a new Formatter which can be used directly as arguments
// in standard fmt package printing calls.
type formatState struct {
value interface{}
fs fmt.State
depth int
pointers map[uintptr]int
ignoreNextType bool
cs *ConfigState
}
// buildDefaultFormat recreates the original format string without precision
// and width information to pass in to fmt.Sprintf in the case of an
// unrecognized type. Unless new types are added to the language, this
// function won't ever be called.
func (f *formatState) buildDefaultFormat() (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
buf.WriteRune('v')
format = buf.String()
return format
}
// constructOrigFormat recreates the original format string including precision
// and width information to pass along to the standard fmt package. This allows
// automatic deferral of all format strings this package doesn't support.
func (f *formatState) constructOrigFormat(verb rune) (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
if width, ok := f.fs.Width(); ok {
buf.WriteString(strconv.Itoa(width))
}
if precision, ok := f.fs.Precision(); ok {
buf.Write(precisionBytes)
buf.WriteString(strconv.Itoa(precision))
}
buf.WriteRune(verb)
format = buf.String()
return format
}
// unpackValue returns values inside of non-nil interfaces when possible and
// ensures that types for values which have been unpacked from an interface
// are displayed when the show types flag is also set.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface {
f.ignoreNextType = false
if !v.IsNil() {
v = v.Elem()
}
}
return v
}
// formatPtr handles formatting of pointers by indirecting them as necessary.
func (f *formatState) formatPtr(v reflect.Value) {
// Display nil if top level pointer is nil.
showTypes := f.fs.Flag('#')
if v.IsNil() && (!showTypes || f.ignoreNextType) {
f.fs.Write(nilAngleBytes)
return
}
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range f.pointers {
if depth >= f.depth {
delete(f.pointers, k)
}
}
// Keep list of all dereferenced pointers to possibly show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by derferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
cycleFound = true
indirects--
break
}
f.pointers[addr] = f.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type or indirection level depending on flags.
if showTypes && !f.ignoreNextType {
f.fs.Write(openParenBytes)
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
f.fs.Write([]byte(ve.Type().String()))
f.fs.Write(closeParenBytes)
} else {
if nilFound || cycleFound {
indirects += strings.Count(ve.Type().String(), "*")
}
f.fs.Write(openAngleBytes)
f.fs.Write([]byte(strings.Repeat("*", indirects)))
f.fs.Write(closeAngleBytes)
}
// Display pointer information depending on flags.
if f.fs.Flag('+') && (len(pointerChain) > 0) {
f.fs.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
f.fs.Write(pointerChainBytes)
}
printHexPtr(f.fs, addr)
}
f.fs.Write(closeParenBytes)
}
// Display dereferenced value.
switch {
case nilFound == true:
f.fs.Write(nilAngleBytes)
case cycleFound == true:
f.fs.Write(circularShortBytes)
default:
f.ignoreNextType = true
f.format(ve)
}
}
// format is the main workhorse for providing the Formatter interface. It
// uses the passed reflect value to figure out what kind of object we are
// dealing with and formats it appropriately. It is a recursive function,
// however circular data structures are detected and handled properly.
func (f *formatState) format(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
f.fs.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
f.formatPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !f.ignoreNextType && f.fs.Flag('#') {
f.fs.Write(openParenBytes)
f.fs.Write([]byte(v.Type().String()))
f.fs.Write(closeParenBytes)
}
f.ignoreNextType = false
// Call Stringer/error interfaces if they exist and the handle methods
// flag is enabled.
if !f.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(f.cs, f.fs, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(f.fs, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(f.fs, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(f.fs, v.Uint(), 10)
case reflect.Float32:
printFloat(f.fs, v.Float(), 32)
case reflect.Float64:
printFloat(f.fs, v.Float(), 64)
case reflect.Complex64:
printComplex(f.fs, v.Complex(), 32)
case reflect.Complex128:
printComplex(f.fs, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
f.fs.Write(openBracketBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
numEntries := v.Len()
for i := 0; i < numEntries; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(v.Index(i)))
}
}
f.depth--
f.fs.Write(closeBracketBytes)
case reflect.String:
f.fs.Write([]byte(v.String()))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
f.fs.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
f.fs.Write(openMapBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
keys := v.MapKeys()
if f.cs.SortKeys {
sortValues(keys, f.cs)
}
for i, key := range keys {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(key))
f.fs.Write(colonBytes)
f.ignoreNextType = true
f.format(f.unpackValue(v.MapIndex(key)))
}
}
f.depth--
f.fs.Write(closeMapBytes)
case reflect.Struct:
numFields := v.NumField()
f.fs.Write(openBraceBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
vt := v.Type()
for i := 0; i < numFields; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
vtf := vt.Field(i)
if f.fs.Flag('+') || f.fs.Flag('#') {
f.fs.Write([]byte(vtf.Name))
f.fs.Write(colonBytes)
}
f.format(f.unpackValue(v.Field(i)))
}
}
f.depth--
f.fs.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(f.fs, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(f.fs, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it if any get added.
default:
format := f.buildDefaultFormat()
if v.CanInterface() {
fmt.Fprintf(f.fs, format, v.Interface())
} else {
fmt.Fprintf(f.fs, format, v.String())
}
}
}
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
// details.
func (f *formatState) Format(fs fmt.State, verb rune) {
f.fs = fs
// Use standard formatting for verbs that are not v.
if verb != 'v' {
format := f.constructOrigFormat(verb)
fmt.Fprintf(fs, format, f.value)
return
}
if f.value == nil {
if fs.Flag('#') {
fs.Write(interfaceBytes)
}
fs.Write(nilAngleBytes)
return
}
f.format(reflect.ValueOf(f.value))
}
// newFormatter is a helper function to consolidate the logic from the various
// public methods which take varying config states.
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
fs := &formatState{value: v, cs: cs}
fs.pointers = make(map[uintptr]int)
return fs
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
Printf, Println, or Fprintf.
*/
func NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(&Config, v)
}

1558
vendor/github.com/davecgh/go-spew/spew/format_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
This test file is part of the spew package rather than than the spew_test
package because it needs access to internals to properly test certain cases
which are not possible via the public interface since they should never happen.
*/
package spew
import (
"bytes"
"reflect"
"testing"
)
// dummyFmtState implements a fake fmt.State to use for testing invalid
// reflect.Value handling. This is necessary because the fmt package catches
// invalid values before invoking the formatter on them.
type dummyFmtState struct {
bytes.Buffer
}
func (dfs *dummyFmtState) Flag(f int) bool {
if f == int('+') {
return true
}
return false
}
func (dfs *dummyFmtState) Precision() (int, bool) {
return 0, false
}
func (dfs *dummyFmtState) Width() (int, bool) {
return 0, false
}
// TestInvalidReflectValue ensures the dump and formatter code handles an
// invalid reflect value properly. This needs access to internal state since it
// should never happen in real code and therefore can't be tested via the public
// API.
func TestInvalidReflectValue(t *testing.T) {
i := 1
// Dump invalid reflect value.
v := new(reflect.Value)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(*v)
s := buf.String()
want := "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter invalid reflect value.
buf2 := new(dummyFmtState)
f := formatState{value: *v, cs: &Config, fs: buf2}
f.format(*v)
s = buf2.String()
want = "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
}
}
// SortValues makes the internal sortValues function available to the test
// package.
func SortValues(values []reflect.Value, cs *ConfigState) {
sortValues(values, cs)
}

View File

@ -0,0 +1,102 @@
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
/*
This test file is part of the spew package rather than than the spew_test
package because it needs access to internals to properly test certain cases
which are not possible via the public interface since they should never happen.
*/
package spew
import (
"bytes"
"reflect"
"testing"
"unsafe"
)
// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
// the maximum kind value which does not exist. This is needed to test the
// fallback code which punts to the standard fmt library for new types that
// might get added to the language.
func changeKind(v *reflect.Value, readOnly bool) {
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
if readOnly {
*rvf |= flagRO
} else {
*rvf &= ^uintptr(flagRO)
}
}
// TestAddedReflectValue tests functionaly of the dump and formatter code which
// falls back to the standard fmt library for new types that might get added to
// the language.
func TestAddedReflectValue(t *testing.T) {
i := 1
// Dump using a reflect.Value that is exported.
v := reflect.ValueOf(int8(5))
changeKind(&v, false)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(v)
s := buf.String()
want := "(int8) 5"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Dump using a reflect.Value that is not exported.
changeKind(&v, true)
buf.Reset()
d.dump(v)
s = buf.String()
want = "(int8) <int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is exported.
changeKind(&v, false)
buf2 := new(dummyFmtState)
f := formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "5"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is not exported.
changeKind(&v, true)
buf2.Reset()
f = formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "<int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
}

148
vendor/github.com/davecgh/go-spew/spew/spew.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"fmt"
"io"
)
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the formatted string as a value that satisfies error. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a default Formatter interface returned by NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
func Print(a ...interface{}) (n int, err error) {
return fmt.Print(convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
func Println(a ...interface{}) (n int, err error) {
return fmt.Println(convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprint(a ...interface{}) string {
return fmt.Sprint(convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintln(a ...interface{}) string {
return fmt.Sprintln(convertArgs(a)...)
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a default spew Formatter interface.
func convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = NewFormatter(arg)
}
return formatters
}

320
vendor/github.com/davecgh/go-spew/spew/spew_test.go generated vendored Normal file
View File

@ -0,0 +1,320 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/davecgh/go-spew/spew"
)
// spewFunc is used to identify which public function of the spew package or
// ConfigState a test applies to.
type spewFunc int
const (
fCSFdump spewFunc = iota
fCSFprint
fCSFprintf
fCSFprintln
fCSPrint
fCSPrintln
fCSSdump
fCSSprint
fCSSprintf
fCSSprintln
fCSErrorf
fCSNewFormatter
fErrorf
fFprint
fFprintln
fPrint
fPrintln
fSdump
fSprint
fSprintf
fSprintln
)
// Map of spewFunc values to names for pretty printing.
var spewFuncStrings = map[spewFunc]string{
fCSFdump: "ConfigState.Fdump",
fCSFprint: "ConfigState.Fprint",
fCSFprintf: "ConfigState.Fprintf",
fCSFprintln: "ConfigState.Fprintln",
fCSSdump: "ConfigState.Sdump",
fCSPrint: "ConfigState.Print",
fCSPrintln: "ConfigState.Println",
fCSSprint: "ConfigState.Sprint",
fCSSprintf: "ConfigState.Sprintf",
fCSSprintln: "ConfigState.Sprintln",
fCSErrorf: "ConfigState.Errorf",
fCSNewFormatter: "ConfigState.NewFormatter",
fErrorf: "spew.Errorf",
fFprint: "spew.Fprint",
fFprintln: "spew.Fprintln",
fPrint: "spew.Print",
fPrintln: "spew.Println",
fSdump: "spew.Sdump",
fSprint: "spew.Sprint",
fSprintf: "spew.Sprintf",
fSprintln: "spew.Sprintln",
}
func (f spewFunc) String() string {
if s, ok := spewFuncStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
}
// spewTest is used to describe a test to be performed against the public
// functions of the spew package or ConfigState.
type spewTest struct {
cs *spew.ConfigState
f spewFunc
format string
in interface{}
want string
}
// spewTests houses the tests to be performed against the public functions of
// the spew package and ConfigState.
//
// These tests are only intended to ensure the public functions are exercised
// and are intentionally not exhaustive of types. The exhaustive type
// tests are handled in the dump and format tests.
var spewTests []spewTest
// redirStdout is a helper function to return the standard output from f as a
// byte slice.
func redirStdout(f func()) ([]byte, error) {
tempFile, err := ioutil.TempFile("", "ss-test")
if err != nil {
return nil, err
}
fileName := tempFile.Name()
defer os.Remove(fileName) // Ignore error
origStdout := os.Stdout
os.Stdout = tempFile
f()
os.Stdout = origStdout
tempFile.Close()
return ioutil.ReadFile(fileName)
}
func initSpewTests() {
// Config states with various settings.
scsDefault := spew.NewDefaultConfig()
scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true}
scsNoCap := &spew.ConfigState{DisableCapacities: true}
// Variables for tests on types which implement Stringer interface with and
// without a pointer receiver.
ts := stringer("test")
tps := pstringer("test")
type ptrTester struct {
s *struct{}
}
tptr := &ptrTester{s: &struct{}{}}
// depthTester is used to test max depth handling for structs, array, slices
// and maps.
type depthTester struct {
ic indirCir1
arr [1]string
slice []string
m map[string]int
}
dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
map[string]int{"one": 1}}
// Variable for tests on types which implement error interface.
te := customError(10)
spewTests = []spewTest{
{scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
{scsDefault, fCSFprint, "", int16(32767), "32767"},
{scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
{scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
{scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
{scsDefault, fCSPrintln, "", uint8(255), "255\n"},
{scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
{scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
{scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
{scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
{scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
{scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
{scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
{scsDefault, fFprint, "", float32(3.14), "3.14"},
{scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
{scsDefault, fPrint, "", true, "true"},
{scsDefault, fPrintln, "", false, "false\n"},
{scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
{scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
{scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
{scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
{scsNoMethods, fCSFprint, "", ts, "test"},
{scsNoMethods, fCSFprint, "", &ts, "<*>test"},
{scsNoMethods, fCSFprint, "", tps, "test"},
{scsNoMethods, fCSFprint, "", &tps, "<*>test"},
{scsNoPmethods, fCSFprint, "", ts, "stringer test"},
{scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
{scsNoPmethods, fCSFprint, "", tps, "test"},
{scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
"(len=4) (stringer test) \"test\"\n"},
{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
"(error: 10) 10\n"},
{scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"},
{scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"},
{scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"},
{scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"},
}
}
// TestSpew executes all of the tests described by spewTests.
func TestSpew(t *testing.T) {
initSpewTests()
t.Logf("Running %d tests", len(spewTests))
for i, test := range spewTests {
buf := new(bytes.Buffer)
switch test.f {
case fCSFdump:
test.cs.Fdump(buf, test.in)
case fCSFprint:
test.cs.Fprint(buf, test.in)
case fCSFprintf:
test.cs.Fprintf(buf, test.format, test.in)
case fCSFprintln:
test.cs.Fprintln(buf, test.in)
case fCSPrint:
b, err := redirStdout(func() { test.cs.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSPrintln:
b, err := redirStdout(func() { test.cs.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSSdump:
str := test.cs.Sdump(test.in)
buf.WriteString(str)
case fCSSprint:
str := test.cs.Sprint(test.in)
buf.WriteString(str)
case fCSSprintf:
str := test.cs.Sprintf(test.format, test.in)
buf.WriteString(str)
case fCSSprintln:
str := test.cs.Sprintln(test.in)
buf.WriteString(str)
case fCSErrorf:
err := test.cs.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fCSNewFormatter:
fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
case fErrorf:
err := spew.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fFprint:
spew.Fprint(buf, test.in)
case fFprintln:
spew.Fprintln(buf, test.in)
case fPrint:
b, err := redirStdout(func() { spew.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fPrintln:
b, err := redirStdout(func() { spew.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fSdump:
str := spew.Sdump(test.in)
buf.WriteString(str)
case fSprint:
str := spew.Sprint(test.in)
buf.WriteString(str)
case fSprintf:
str := spew.Sprintf(test.format, test.in)
buf.WriteString(str)
case fSprintln:
str := spew.Sprintln(test.in)
buf.WriteString(str)
default:
t.Errorf("%v #%d unrecognized function", test.f, i)
continue
}
s := buf.String()
if test.want != s {
t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
continue
}
}
}

View File

@ -0,0 +1,82 @@
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when both cgo is supported and "-tags testcgo" is added to the go test
// command line. This code should really only be in the dumpcgo_test.go file,
// but unfortunately Go will not allow cgo in test files, so this is a
// workaround to allow cgo types to be tested. This configuration is used
// because spew itself does not require cgo to run even though it does handle
// certain cgo types specially. Rather than forcing all clients to require cgo
// and an external C compiler just to run the tests, this scheme makes them
// optional.
// +build cgo,testcgo
package testdata
/*
#include <stdint.h>
typedef unsigned char custom_uchar_t;
char *ncp = 0;
char *cp = "test";
char ca[6] = {'t', 'e', 's', 't', '2', '\0'};
unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'};
signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'};
uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
*/
import "C"
// GetCgoNullCharPointer returns a null char pointer via cgo. This is only
// used for tests.
func GetCgoNullCharPointer() interface{} {
return C.ncp
}
// GetCgoCharPointer returns a char pointer via cgo. This is only used for
// tests.
func GetCgoCharPointer() interface{} {
return C.cp
}
// GetCgoCharArray returns a char array via cgo and the array's len and cap.
// This is only used for tests.
func GetCgoCharArray() (interface{}, int, int) {
return C.ca, len(C.ca), cap(C.ca)
}
// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
// array's len and cap. This is only used for tests.
func GetCgoUnsignedCharArray() (interface{}, int, int) {
return C.uca, len(C.uca), cap(C.uca)
}
// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
// and cap. This is only used for tests.
func GetCgoSignedCharArray() (interface{}, int, int) {
return C.sca, len(C.sca), cap(C.sca)
}
// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
// cap. This is only used for tests.
func GetCgoUint8tArray() (interface{}, int, int) {
return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
}
// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
// cgo and the array's len and cap. This is only used for tests.
func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
return C.tuca, len(C.tuca), cap(C.tuca)
}

61
vendor/github.com/davecgh/go-spew/test_coverage.txt generated vendored Normal file
View File

@ -0,0 +1,61 @@
github.com/davecgh/go-spew/spew/dump.go dumpState.dump 100.00% (88/88)
github.com/davecgh/go-spew/spew/format.go formatState.format 100.00% (82/82)
github.com/davecgh/go-spew/spew/format.go formatState.formatPtr 100.00% (52/52)
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44)
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39)
github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30)
github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18)
github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13)
github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12)
github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11)
github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11)
github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10)
github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9)
github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8)
github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7)
github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5)
github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4)
github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4)
github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4)
github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4)
github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3)
github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3)
github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3)
github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3)
github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3)
github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1)
github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1)
github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1)
github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505)

23
vendor/github.com/fatih/structs/.gitignore generated vendored Normal file
View File

@ -0,0 +1,23 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test

11
vendor/github.com/fatih/structs/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,11 @@
language: go
go:
- 1.7.x
- tip
sudo: false
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

21
vendor/github.com/fatih/structs/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Fatih Arslan
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.

163
vendor/github.com/fatih/structs/README.md generated vendored Normal file
View File

@ -0,0 +1,163 @@
# Structs [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/structs) [![Build Status](http://img.shields.io/travis/fatih/structs.svg?style=flat-square)](https://travis-ci.org/fatih/structs) [![Coverage Status](http://img.shields.io/coveralls/fatih/structs.svg?style=flat-square)](https://coveralls.io/r/fatih/structs)
Structs contains various utilities to work with Go (Golang) structs. It was
initially used by me to convert a struct into a `map[string]interface{}`. With
time I've added other utilities for structs. It's basically a high level
package based on primitives from the reflect package. Feel free to add new
functions or improve the existing code.
## Install
```bash
go get github.com/fatih/structs
```
## Usage and Examples
Just like the standard lib `strings`, `bytes` and co packages, `structs` has
many global functions to manipulate or organize your struct data. Lets define
and declare a struct:
```go
type Server struct {
Name string `json:"name,omitempty"`
ID int
Enabled bool
users []string // not exported
http.Server // embedded
}
server := &Server{
Name: "gopher",
ID: 123456,
Enabled: true,
}
```
```go
// Convert a struct to a map[string]interface{}
// => {"Name":"gopher", "ID":123456, "Enabled":true}
m := structs.Map(server)
// Convert the values of a struct to a []interface{}
// => ["gopher", 123456, true]
v := structs.Values(server)
// Convert the names of a struct to a []string
// (see "Names methods" for more info about fields)
n := structs.Names(server)
// Convert the values of a struct to a []*Field
// (see "Field methods" for more info about fields)
f := structs.Fields(server)
// Return the struct name => "Server"
n := structs.Name(server)
// Check if any field of a struct is initialized or not.
h := structs.HasZero(server)
// Check if all fields of a struct is initialized or not.
z := structs.IsZero(server)
// Check if server is a struct or a pointer to struct
i := structs.IsStruct(server)
```
### Struct methods
The structs functions can be also used as independent methods by creating a new
`*structs.Struct`. This is handy if you want to have more control over the
structs (such as retrieving a single Field).
```go
// Create a new struct type:
s := structs.New(server)
m := s.Map() // Get a map[string]interface{}
v := s.Values() // Get a []interface{}
f := s.Fields() // Get a []*Field
n := s.Names() // Get a []string
f := s.Field(name) // Get a *Field based on the given field name
f, ok := s.FieldOk(name) // Get a *Field based on the given field name
n := s.Name() // Get the struct name
h := s.HasZero() // Check if any field is initialized
z := s.IsZero() // Check if all fields are initialized
```
### Field methods
We can easily examine a single Field for more detail. Below you can see how we
get and interact with various field methods:
```go
s := structs.New(server)
// Get the Field struct for the "Name" field
name := s.Field("Name")
// Get the underlying value, value => "gopher"
value := name.Value().(string)
// Set the field's value
name.Set("another gopher")
// Get the field's kind, kind => "string"
name.Kind()
// Check if the field is exported or not
if name.IsExported() {
fmt.Println("Name field is exported")
}
// Check if the value is a zero value, such as "" for string, 0 for int
if !name.IsZero() {
fmt.Println("Name is initialized")
}
// Check if the field is an anonymous (embedded) field
if !name.IsEmbedded() {
fmt.Println("Name is not an embedded field")
}
// Get the Field's tag value for tag name "json", tag value => "name,omitempty"
tagValue := name.Tag("json")
```
Nested structs are supported too:
```go
addrField := s.Field("Server").Field("Addr")
// Get the value for addr
a := addrField.Value().(string)
// Or get all fields
httpServer := s.Field("Server").Fields()
```
We can also get a slice of Fields from the Struct type to iterate over all
fields. This is handy if you wish to examine all fields:
```go
s := structs.New(server)
for _, f := range s.Fields() {
fmt.Printf("field name: %+v\n", f.Name())
if f.IsExported() {
fmt.Printf("value : %+v\n", f.Value())
fmt.Printf("is zero : %+v\n", f.IsZero())
}
}
```
## Credits
* [Fatih Arslan](https://github.com/fatih)
* [Cihangir Savas](https://github.com/cihangir)
## License
The MIT License (MIT) - see LICENSE.md for more details

141
vendor/github.com/fatih/structs/field.go generated vendored Normal file
View File

@ -0,0 +1,141 @@
package structs
import (
"errors"
"fmt"
"reflect"
)
var (
errNotExported = errors.New("field is not exported")
errNotSettable = errors.New("field is not settable")
)
// Field represents a single struct field that encapsulates high level
// functions around the field.
type Field struct {
value reflect.Value
field reflect.StructField
defaultTag string
}
// Tag returns the value associated with key in the tag string. If there is no
// such key in the tag, Tag returns the empty string.
func (f *Field) Tag(key string) string {
return f.field.Tag.Get(key)
}
// Value returns the underlying value of the field. It panics if the field
// is not exported.
func (f *Field) Value() interface{} {
return f.value.Interface()
}
// IsEmbedded returns true if the given field is an anonymous field (embedded)
func (f *Field) IsEmbedded() bool {
return f.field.Anonymous
}
// IsExported returns true if the given field is exported.
func (f *Field) IsExported() bool {
return f.field.PkgPath == ""
}
// IsZero returns true if the given field is not initialized (has a zero value).
// It panics if the field is not exported.
func (f *Field) IsZero() bool {
zero := reflect.Zero(f.value.Type()).Interface()
current := f.Value()
return reflect.DeepEqual(current, zero)
}
// Name returns the name of the given field
func (f *Field) Name() string {
return f.field.Name
}
// Kind returns the fields kind, such as "string", "map", "bool", etc ..
func (f *Field) Kind() reflect.Kind {
return f.value.Kind()
}
// Set sets the field to given value v. It returns an error if the field is not
// settable (not addressable or not exported) or if the given value's type
// doesn't match the fields type.
func (f *Field) Set(val interface{}) error {
// we can't set unexported fields, so be sure this field is exported
if !f.IsExported() {
return errNotExported
}
// do we get here? not sure...
if !f.value.CanSet() {
return errNotSettable
}
given := reflect.ValueOf(val)
if f.value.Kind() != given.Kind() {
return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind())
}
f.value.Set(given)
return nil
}
// Zero sets the field to its zero value. It returns an error if the field is not
// settable (not addressable or not exported).
func (f *Field) Zero() error {
zero := reflect.Zero(f.value.Type()).Interface()
return f.Set(zero)
}
// Fields returns a slice of Fields. This is particular handy to get the fields
// of a nested struct . A struct tag with the content of "-" ignores the
// checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field *http.Request `structs:"-"`
//
// It panics if field is not exported or if field's kind is not struct
func (f *Field) Fields() []*Field {
return getFields(f.value, f.defaultTag)
}
// Field returns the field from a nested struct. It panics if the nested struct
// is not exported or if the field was not found.
func (f *Field) Field(name string) *Field {
field, ok := f.FieldOk(name)
if !ok {
panic("field not found")
}
return field
}
// FieldOk returns the field from a nested struct. The boolean returns whether
// the field was found (true) or not (false).
func (f *Field) FieldOk(name string) (*Field, bool) {
value := &f.value
// value must be settable so we need to make sure it holds the address of the
// variable and not a copy, so we can pass the pointer to strctVal instead of a
// copy (which is not assigned to any variable, hence not settable).
// see "https://blog.golang.org/laws-of-reflection#TOC_8."
if f.value.Kind() != reflect.Ptr {
a := f.value.Addr()
value = &a
}
v := strctVal(value.Interface())
t := v.Type()
field, ok := t.FieldByName(name)
if !ok {
return nil, false
}
return &Field{
field: field,
value: v.FieldByName(name),
}, true
}

397
vendor/github.com/fatih/structs/field_test.go generated vendored Normal file
View File

@ -0,0 +1,397 @@
package structs
import (
"reflect"
"testing"
)
// A test struct that defines all cases
type Foo struct {
A string
B int `structs:"y"`
C bool `json:"c"`
d string // not exported
E *Baz
x string `xml:"x"` // not exported, with tag
Y []string
Z map[string]interface{}
*Bar // embedded
}
type Baz struct {
A string
B int
}
type Bar struct {
E string
F int
g []string
}
func newStruct() *Struct {
b := &Bar{
E: "example",
F: 2,
g: []string{"zeynep", "fatih"},
}
// B and x is not initialized for testing
f := &Foo{
A: "gopher",
C: true,
d: "small",
E: nil,
Y: []string{"example"},
Z: nil,
}
f.Bar = b
return New(f)
}
func TestField_Set(t *testing.T) {
s := newStruct()
f := s.Field("A")
err := f.Set("fatih")
if err != nil {
t.Error(err)
}
if f.Value().(string) != "fatih" {
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
}
f = s.Field("Y")
err = f.Set([]string{"override", "with", "this"})
if err != nil {
t.Error(err)
}
sliceLen := len(f.Value().([]string))
if sliceLen != 3 {
t.Errorf("Setted values slice length is wrong: %d, want: %d", sliceLen, 3)
}
f = s.Field("C")
err = f.Set(false)
if err != nil {
t.Error(err)
}
if f.Value().(bool) {
t.Errorf("Setted value is wrong: %t want: %t", f.Value().(bool), false)
}
// let's pass a different type
f = s.Field("A")
err = f.Set(123) // Field A is of type string, but we are going to pass an integer
if err == nil {
t.Error("Setting a field's value with a different type than the field's type should return an error")
}
// old value should be still there :)
if f.Value().(string) != "fatih" {
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
}
// let's access an unexported field, which should give an error
f = s.Field("d")
err = f.Set("large")
if err != errNotExported {
t.Error(err)
}
// let's set a pointer to struct
b := &Bar{
E: "gopher",
F: 2,
}
f = s.Field("Bar")
err = f.Set(b)
if err != nil {
t.Error(err)
}
baz := &Baz{
A: "helloWorld",
B: 42,
}
f = s.Field("E")
err = f.Set(baz)
if err != nil {
t.Error(err)
}
ba := s.Field("E").Value().(*Baz)
if ba.A != "helloWorld" {
t.Errorf("could not set baz. Got: %s Want: helloWorld", ba.A)
}
}
func TestField_NotSettable(t *testing.T) {
a := map[int]Baz{
4: Baz{
A: "value",
},
}
s := New(a[4])
if err := s.Field("A").Set("newValue"); err != errNotSettable {
t.Errorf("Trying to set non-settable field should error with %q. Got %q instead.", errNotSettable, err)
}
}
func TestField_Zero(t *testing.T) {
s := newStruct()
f := s.Field("A")
err := f.Zero()
if err != nil {
t.Error(err)
}
if f.Value().(string) != "" {
t.Errorf("Zeroed value is wrong: %s want: %s", f.Value().(string), "")
}
f = s.Field("Y")
err = f.Zero()
if err != nil {
t.Error(err)
}
sliceLen := len(f.Value().([]string))
if sliceLen != 0 {
t.Errorf("Zeroed values slice length is wrong: %d, want: %d", sliceLen, 0)
}
f = s.Field("C")
err = f.Zero()
if err != nil {
t.Error(err)
}
if f.Value().(bool) {
t.Errorf("Zeroed value is wrong: %t want: %t", f.Value().(bool), false)
}
// let's access an unexported field, which should give an error
f = s.Field("d")
err = f.Zero()
if err != errNotExported {
t.Error(err)
}
f = s.Field("Bar")
err = f.Zero()
if err != nil {
t.Error(err)
}
f = s.Field("E")
err = f.Zero()
if err != nil {
t.Error(err)
}
v := s.Field("E").value
if !v.IsNil() {
t.Errorf("could not set baz. Got: %s Want: <nil>", v.Interface())
}
}
func TestField(t *testing.T) {
s := newStruct()
defer func() {
err := recover()
if err == nil {
t.Error("Retrieveing a non existing field from the struct should panic")
}
}()
_ = s.Field("no-field")
}
func TestField_Kind(t *testing.T) {
s := newStruct()
f := s.Field("A")
if f.Kind() != reflect.String {
t.Errorf("Field A has wrong kind: %s want: %s", f.Kind(), reflect.String)
}
f = s.Field("B")
if f.Kind() != reflect.Int {
t.Errorf("Field B has wrong kind: %s want: %s", f.Kind(), reflect.Int)
}
// unexported
f = s.Field("d")
if f.Kind() != reflect.String {
t.Errorf("Field d has wrong kind: %s want: %s", f.Kind(), reflect.String)
}
}
func TestField_Tag(t *testing.T) {
s := newStruct()
v := s.Field("B").Tag("json")
if v != "" {
t.Errorf("Field's tag value of a non existing tag should return empty, got: %s", v)
}
v = s.Field("C").Tag("json")
if v != "c" {
t.Errorf("Field's tag value of the existing field C should return 'c', got: %s", v)
}
v = s.Field("d").Tag("json")
if v != "" {
t.Errorf("Field's tag value of a non exported field should return empty, got: %s", v)
}
v = s.Field("x").Tag("xml")
if v != "x" {
t.Errorf("Field's tag value of a non exported field with a tag should return 'x', got: %s", v)
}
v = s.Field("A").Tag("json")
if v != "" {
t.Errorf("Field's tag value of a existing field without a tag should return empty, got: %s", v)
}
}
func TestField_Value(t *testing.T) {
s := newStruct()
v := s.Field("A").Value()
val, ok := v.(string)
if !ok {
t.Errorf("Field's value of a A should be string")
}
if val != "gopher" {
t.Errorf("Field's value of a existing tag should return 'gopher', got: %s", val)
}
defer func() {
err := recover()
if err == nil {
t.Error("Value of a non exported field from the field should panic")
}
}()
// should panic
_ = s.Field("d").Value()
}
func TestField_IsEmbedded(t *testing.T) {
s := newStruct()
if !s.Field("Bar").IsEmbedded() {
t.Errorf("Fields 'Bar' field is an embedded field")
}
if s.Field("d").IsEmbedded() {
t.Errorf("Fields 'd' field is not an embedded field")
}
}
func TestField_IsExported(t *testing.T) {
s := newStruct()
if !s.Field("Bar").IsExported() {
t.Errorf("Fields 'Bar' field is an exported field")
}
if !s.Field("A").IsExported() {
t.Errorf("Fields 'A' field is an exported field")
}
if s.Field("d").IsExported() {
t.Errorf("Fields 'd' field is not an exported field")
}
}
func TestField_IsZero(t *testing.T) {
s := newStruct()
if s.Field("A").IsZero() {
t.Errorf("Fields 'A' field is an initialized field")
}
if !s.Field("B").IsZero() {
t.Errorf("Fields 'B' field is not an initialized field")
}
}
func TestField_Name(t *testing.T) {
s := newStruct()
if s.Field("A").Name() != "A" {
t.Errorf("Fields 'A' field should have the name 'A'")
}
}
func TestField_Field(t *testing.T) {
s := newStruct()
e := s.Field("Bar").Field("E")
val, ok := e.Value().(string)
if !ok {
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
}
if val != "example" {
t.Errorf("The value of 'e' should be 'example, got: %s", val)
}
defer func() {
err := recover()
if err == nil {
t.Error("Field of a non existing nested struct should panic")
}
}()
_ = s.Field("Bar").Field("e")
}
func TestField_Fields(t *testing.T) {
s := newStruct()
fields := s.Field("Bar").Fields()
if len(fields) != 3 {
t.Errorf("We expect 3 fields in embedded struct, was: %d", len(fields))
}
}
func TestField_FieldOk(t *testing.T) {
s := newStruct()
b, ok := s.FieldOk("Bar")
if !ok {
t.Error("The field 'Bar' should exists.")
}
e, ok := b.FieldOk("E")
if !ok {
t.Error("The field 'E' should exists.")
}
val, ok := e.Value().(string)
if !ok {
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
}
if val != "example" {
t.Errorf("The value of 'e' should be 'example, got: %s", val)
}
}

586
vendor/github.com/fatih/structs/structs.go generated vendored Normal file
View File

@ -0,0 +1,586 @@
// Package structs contains various utilities functions to work with structs.
package structs
import (
"fmt"
"reflect"
)
var (
// DefaultTagName is the default tag name for struct fields which provides
// a more granular to tweak certain structs. Lookup the necessary functions
// for more info.
DefaultTagName = "structs" // struct's field default tag name
)
// Struct encapsulates a struct type to provide several high level functions
// around the struct.
type Struct struct {
raw interface{}
value reflect.Value
TagName string
}
// New returns a new *Struct with the struct s. It panics if the s's kind is
// not struct.
func New(s interface{}) *Struct {
return &Struct{
raw: s,
value: strctVal(s),
TagName: DefaultTagName,
}
}
// Map converts the given struct to a map[string]interface{}, where the keys
// of the map are the field names and the values of the map the associated
// values of the fields. The default key string is the struct field name but
// can be changed in the struct field's tag value. The "structs" key in the
// struct's field tag value is the key name. Example:
//
// // Field appears in map as key "myName".
// Name string `structs:"myName"`
//
// A tag value with the content of "-" ignores that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A tag value with the content of "string" uses the stringer to get the value. Example:
//
// // The value will be output of Animal's String() func.
// // Map will panic if Animal does not implement String().
// Field *Animal `structs:"field,string"`
//
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
// in the output map. Example:
//
// // The FieldStruct's fields will be flattened into the output map.
// FieldStruct time.Time `structs:",flatten"`
//
// A tag value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// A tag value with the option of "omitempty" ignores that particular field if
// the field value is empty. Example:
//
// // Field appears in map as key "myName", but the field is
// // skipped if empty.
// Field string `structs:"myName,omitempty"`
//
// // Field appears in map as key "Field" (the default), but
// // the field is skipped if empty.
// Field string `structs:",omitempty"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected.
func (s *Struct) Map() map[string]interface{} {
out := make(map[string]interface{})
s.FillMap(out)
return out
}
// FillMap is the same as Map. Instead of returning the output, it fills the
// given map.
func (s *Struct) FillMap(out map[string]interface{}) {
if out == nil {
return
}
fields := s.structFields()
for _, field := range fields {
name := field.Name
val := s.value.FieldByName(name)
isSubStruct := false
var finalVal interface{}
tagName, tagOpts := parseTag(field.Tag.Get(s.TagName))
if tagName != "" {
name = tagName
}
// if the value is a zero value and the field is marked as omitempty do
// not include
if tagOpts.Has("omitempty") {
zero := reflect.Zero(val.Type()).Interface()
current := val.Interface()
if reflect.DeepEqual(current, zero) {
continue
}
}
if !tagOpts.Has("omitnested") {
finalVal = s.nested(val)
v := reflect.ValueOf(val.Interface())
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Map, reflect.Struct:
isSubStruct = true
}
} else {
finalVal = val.Interface()
}
if tagOpts.Has("string") {
s, ok := val.Interface().(fmt.Stringer)
if ok {
out[name] = s.String()
}
continue
}
if isSubStruct && (tagOpts.Has("flatten")) {
for k := range finalVal.(map[string]interface{}) {
out[k] = finalVal.(map[string]interface{})[k]
}
} else {
out[name] = finalVal
}
}
}
// Values converts the given s struct's field values to a []interface{}. A
// struct tag with the content of "-" ignores the that particular field.
// Example:
//
// // Field is ignored by this package.
// Field int `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Fields is not processed further by this package.
// Field time.Time `structs:",omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// A tag value with the option of "omitempty" ignores that particular field and
// is not added to the values if the field value is empty. Example:
//
// // Field is skipped if empty
// Field string `structs:",omitempty"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected.
func (s *Struct) Values() []interface{} {
fields := s.structFields()
var t []interface{}
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
// if the value is a zero value and the field is marked as omitempty do
// not include
if tagOpts.Has("omitempty") {
zero := reflect.Zero(val.Type()).Interface()
current := val.Interface()
if reflect.DeepEqual(current, zero) {
continue
}
}
if tagOpts.Has("string") {
s, ok := val.Interface().(fmt.Stringer)
if ok {
t = append(t, s.String())
}
continue
}
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
// look out for embedded structs, and convert them to a
// []interface{} to be added to the final values slice
for _, embeddedVal := range Values(val.Interface()) {
t = append(t, embeddedVal)
}
} else {
t = append(t, val.Interface())
}
}
return t
}
// Fields returns a slice of Fields. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// It panics if s's kind is not struct.
func (s *Struct) Fields() []*Field {
return getFields(s.value, s.TagName)
}
// Names returns a slice of field names. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// It panics if s's kind is not struct.
func (s *Struct) Names() []string {
fields := getFields(s.value, s.TagName)
names := make([]string, len(fields))
for i, field := range fields {
names[i] = field.Name()
}
return names
}
func getFields(v reflect.Value, tagName string) []*Field {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
var fields []*Field
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if tag := field.Tag.Get(tagName); tag == "-" {
continue
}
f := &Field{
field: field,
value: v.FieldByName(field.Name),
}
fields = append(fields, f)
}
return fields
}
// Field returns a new Field struct that provides several high level functions
// around a single struct field entity. It panics if the field is not found.
func (s *Struct) Field(name string) *Field {
f, ok := s.FieldOk(name)
if !ok {
panic("field not found")
}
return f
}
// FieldOk returns a new Field struct that provides several high level functions
// around a single struct field entity. The boolean returns true if the field
// was found.
func (s *Struct) FieldOk(name string) (*Field, bool) {
t := s.value.Type()
field, ok := t.FieldByName(name)
if !ok {
return nil, false
}
return &Field{
field: field,
value: s.value.FieldByName(name),
defaultTag: s.TagName,
}, true
}
// IsZero returns true if all fields in a struct is a zero value (not
// initialized) A struct tag with the content of "-" ignores the checking of
// that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func (s *Struct) IsZero() bool {
fields := s.structFields()
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
ok := IsZero(val.Interface())
if !ok {
return false
}
continue
}
// zero value of the given field, such as "" for string, 0 for int
zero := reflect.Zero(val.Type()).Interface()
// current value of the given field
current := val.Interface()
if !reflect.DeepEqual(current, zero) {
return false
}
}
return true
}
// HasZero returns true if a field in a struct is not initialized (zero value).
// A struct tag with the content of "-" ignores the checking of that particular
// field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func (s *Struct) HasZero() bool {
fields := s.structFields()
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
ok := HasZero(val.Interface())
if ok {
return true
}
continue
}
// zero value of the given field, such as "" for string, 0 for int
zero := reflect.Zero(val.Type()).Interface()
// current value of the given field
current := val.Interface()
if reflect.DeepEqual(current, zero) {
return true
}
}
return false
}
// Name returns the structs's type name within its package. For more info refer
// to Name() function.
func (s *Struct) Name() string {
return s.value.Type().Name()
}
// structFields returns the exported struct fields for a given s struct. This
// is a convenient helper method to avoid duplicate code in some of the
// functions.
func (s *Struct) structFields() []reflect.StructField {
t := s.value.Type()
var f []reflect.StructField
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// we can't access the value of unexported fields
if field.PkgPath != "" {
continue
}
// don't check if it's omitted
if tag := field.Tag.Get(s.TagName); tag == "-" {
continue
}
f = append(f, field)
}
return f
}
func strctVal(s interface{}) reflect.Value {
v := reflect.ValueOf(s)
// if pointer get the underlying element≤
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
panic("not struct")
}
return v
}
// Map converts the given struct to a map[string]interface{}. For more info
// refer to Struct types Map() method. It panics if s's kind is not struct.
func Map(s interface{}) map[string]interface{} {
return New(s).Map()
}
// FillMap is the same as Map. Instead of returning the output, it fills the
// given map.
func FillMap(s interface{}, out map[string]interface{}) {
New(s).FillMap(out)
}
// Values converts the given struct to a []interface{}. For more info refer to
// Struct types Values() method. It panics if s's kind is not struct.
func Values(s interface{}) []interface{} {
return New(s).Values()
}
// Fields returns a slice of *Field. For more info refer to Struct types
// Fields() method. It panics if s's kind is not struct.
func Fields(s interface{}) []*Field {
return New(s).Fields()
}
// Names returns a slice of field names. For more info refer to Struct types
// Names() method. It panics if s's kind is not struct.
func Names(s interface{}) []string {
return New(s).Names()
}
// IsZero returns true if all fields is equal to a zero value. For more info
// refer to Struct types IsZero() method. It panics if s's kind is not struct.
func IsZero(s interface{}) bool {
return New(s).IsZero()
}
// HasZero returns true if any field is equal to a zero value. For more info
// refer to Struct types HasZero() method. It panics if s's kind is not struct.
func HasZero(s interface{}) bool {
return New(s).HasZero()
}
// IsStruct returns true if the given variable is a struct or a pointer to
// struct.
func IsStruct(s interface{}) bool {
v := reflect.ValueOf(s)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// uninitialized zero value of a struct
if v.Kind() == reflect.Invalid {
return false
}
return v.Kind() == reflect.Struct
}
// Name returns the structs's type name within its package. It returns an
// empty string for unnamed types. It panics if s's kind is not struct.
func Name(s interface{}) string {
return New(s).Name()
}
// nested retrieves recursively all types for the given value and returns the
// nested value.
func (s *Struct) nested(val reflect.Value) interface{} {
var finalVal interface{}
v := reflect.ValueOf(val.Interface())
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Struct:
n := New(val.Interface())
n.TagName = s.TagName
m := n.Map()
// do not add the converted value if there are no exported fields, ie:
// time.Time
if len(m) == 0 {
finalVal = val.Interface()
} else {
finalVal = m
}
case reflect.Map:
// get the element type of the map
mapElem := val.Type()
switch val.Type().Kind() {
case reflect.Ptr, reflect.Array, reflect.Map,
reflect.Slice, reflect.Chan:
mapElem = val.Type().Elem()
if mapElem.Kind() == reflect.Ptr {
mapElem = mapElem.Elem()
}
}
// only iterate over struct types, ie: map[string]StructType,
// map[string][]StructType,
if mapElem.Kind() == reflect.Struct ||
(mapElem.Kind() == reflect.Slice &&
mapElem.Elem().Kind() == reflect.Struct) {
m := make(map[string]interface{}, val.Len())
for _, k := range val.MapKeys() {
m[k.String()] = s.nested(val.MapIndex(k))
}
finalVal = m
break
}
// TODO(arslan): should this be optional?
finalVal = val.Interface()
case reflect.Slice, reflect.Array:
if val.Type().Kind() == reflect.Interface {
finalVal = val.Interface()
break
}
// TODO(arslan): should this be optional?
// do not iterate of non struct types, just pass the value. Ie: []int,
// []string, co... We only iterate further if it's a struct.
// i.e []foo or []*foo
if val.Type().Elem().Kind() != reflect.Struct &&
!(val.Type().Elem().Kind() == reflect.Ptr &&
val.Type().Elem().Elem().Kind() == reflect.Struct) {
finalVal = val.Interface()
break
}
slices := make([]interface{}, val.Len(), val.Len())
for x := 0; x < val.Len(); x++ {
slices[x] = s.nested(val.Index(x))
}
finalVal = slices
default:
finalVal = val.Interface()
}
return finalVal
}

351
vendor/github.com/fatih/structs/structs_example_test.go generated vendored Normal file
View File

@ -0,0 +1,351 @@
package structs
import (
"fmt"
"time"
)
func ExampleNew() {
type Server struct {
Name string
ID int32
Enabled bool
}
server := &Server{
Name: "Arslan",
ID: 123456,
Enabled: true,
}
s := New(server)
fmt.Printf("Name : %v\n", s.Name())
fmt.Printf("Values : %v\n", s.Values())
fmt.Printf("Value of ID : %v\n", s.Field("ID").Value())
// Output:
// Name : Server
// Values : [Arslan 123456 true]
// Value of ID : 123456
}
func ExampleMap() {
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "Arslan",
ID: 123456,
Enabled: true,
}
m := Map(s)
fmt.Printf("%#v\n", m["Name"])
fmt.Printf("%#v\n", m["ID"])
fmt.Printf("%#v\n", m["Enabled"])
// Output:
// "Arslan"
// 123456
// true
}
func ExampleMap_tags() {
// Custom tags can change the map keys instead of using the fields name
type Server struct {
Name string `structs:"server_name"`
ID int32 `structs:"server_id"`
Enabled bool `structs:"enabled"`
}
s := &Server{
Name: "Zeynep",
ID: 789012,
}
m := Map(s)
// access them by the custom tags defined above
fmt.Printf("%#v\n", m["server_name"])
fmt.Printf("%#v\n", m["server_id"])
fmt.Printf("%#v\n", m["enabled"])
// Output:
// "Zeynep"
// 789012
// false
}
func ExampleMap_omitNested() {
// By default field with struct types are processed too. We can stop
// processing them via "omitnested" tag option.
type Server struct {
Name string `structs:"server_name"`
ID int32 `structs:"server_id"`
Time time.Time `structs:"time,omitnested"` // do not convert to map[string]interface{}
}
const shortForm = "2006-Jan-02"
t, _ := time.Parse("2006-Jan-02", "2013-Feb-03")
s := &Server{
Name: "Zeynep",
ID: 789012,
Time: t,
}
m := Map(s)
// access them by the custom tags defined above
fmt.Printf("%v\n", m["server_name"])
fmt.Printf("%v\n", m["server_id"])
fmt.Printf("%v\n", m["time"].(time.Time))
// Output:
// Zeynep
// 789012
// 2013-02-03 00:00:00 +0000 UTC
}
func ExampleMap_omitEmpty() {
// By default field with struct types of zero values are processed too. We
// can stop processing them via "omitempty" tag option.
type Server struct {
Name string `structs:",omitempty"`
ID int32 `structs:"server_id,omitempty"`
Location string
}
// Only add location
s := &Server{
Location: "Tokyo",
}
m := Map(s)
// map contains only the Location field
fmt.Printf("%v\n", m)
// Output:
// map[Location:Tokyo]
}
func ExampleValues() {
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "Fatih",
ID: 135790,
Enabled: false,
}
m := Values(s)
fmt.Printf("Values: %+v\n", m)
// Output:
// Values: [Fatih 135790 false]
}
func ExampleValues_omitEmpty() {
// By default field with struct types of zero values are processed too. We
// can stop processing them via "omitempty" tag option.
type Server struct {
Name string `structs:",omitempty"`
ID int32 `structs:"server_id,omitempty"`
Location string
}
// Only add location
s := &Server{
Location: "Ankara",
}
m := Values(s)
// values contains only the Location field
fmt.Printf("Values: %+v\n", m)
// Output:
// Values: [Ankara]
}
func ExampleValues_tags() {
type Location struct {
City string
Country string
}
type Server struct {
Name string
ID int32
Enabled bool
Location Location `structs:"-"` // values from location are not included anymore
}
s := &Server{
Name: "Fatih",
ID: 135790,
Enabled: false,
Location: Location{City: "Ankara", Country: "Turkey"},
}
// Let get all values from the struct s. Note that we don't include values
// from the Location field
m := Values(s)
fmt.Printf("Values: %+v\n", m)
// Output:
// Values: [Fatih 135790 false]
}
func ExampleFields() {
type Access struct {
Name string
LastAccessed time.Time
Number int
}
s := &Access{
Name: "Fatih",
LastAccessed: time.Now(),
Number: 1234567,
}
fields := Fields(s)
for i, field := range fields {
fmt.Printf("[%d] %+v\n", i, field.Name())
}
// Output:
// [0] Name
// [1] LastAccessed
// [2] Number
}
func ExampleFields_nested() {
type Person struct {
Name string
Number int
}
type Access struct {
Person Person
HasPermission bool
LastAccessed time.Time
}
s := &Access{
Person: Person{Name: "fatih", Number: 1234567},
LastAccessed: time.Now(),
HasPermission: true,
}
// Let's get all fields from the struct s.
fields := Fields(s)
for _, field := range fields {
if field.Name() == "Person" {
fmt.Printf("Access.Person.Name: %+v\n", field.Field("Name").Value())
}
}
// Output:
// Access.Person.Name: fatih
}
func ExampleField() {
type Person struct {
Name string
Number int
}
type Access struct {
Person Person
HasPermission bool
LastAccessed time.Time
}
access := &Access{
Person: Person{Name: "fatih", Number: 1234567},
LastAccessed: time.Now(),
HasPermission: true,
}
// Create a new Struct type
s := New(access)
// Get the Field type for "Person" field
p := s.Field("Person")
// Get the underlying "Name field" and print the value of it
name := p.Field("Name")
fmt.Printf("Value of Person.Access.Name: %+v\n", name.Value())
// Output:
// Value of Person.Access.Name: fatih
}
func ExampleIsZero() {
type Server struct {
Name string
ID int32
Enabled bool
}
// Nothing is initalized
a := &Server{}
isZeroA := IsZero(a)
// Name and Enabled is initialized, but not ID
b := &Server{
Name: "Golang",
Enabled: true,
}
isZeroB := IsZero(b)
fmt.Printf("%#v\n", isZeroA)
fmt.Printf("%#v\n", isZeroB)
// Output:
// true
// false
}
func ExampleHasZero() {
// Let's define an Access struct. Note that the "Enabled" field is not
// going to be checked because we added the "structs" tag to the field.
type Access struct {
Name string
LastAccessed time.Time
Number int
Enabled bool `structs:"-"`
}
// Name and Number is not initialized.
a := &Access{
LastAccessed: time.Now(),
}
hasZeroA := HasZero(a)
// Name and Number is initialized.
b := &Access{
Name: "Fatih",
LastAccessed: time.Now(),
Number: 12345,
}
hasZeroB := HasZero(b)
fmt.Printf("%#v\n", hasZeroA)
fmt.Printf("%#v\n", hasZeroB)
// Output:
// true
// false
}

1453
vendor/github.com/fatih/structs/structs_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

32
vendor/github.com/fatih/structs/tags.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
package structs
import "strings"
// tagOptions contains a slice of tag options
type tagOptions []string
// Has returns true if the given optiton is available in tagOptions
func (t tagOptions) Has(opt string) bool {
for _, tagOpt := range t {
if tagOpt == opt {
return true
}
}
return false
}
// parseTag splits a struct field's tag into its name and a list of options
// which comes after a name. A tag is in the form of: "name,option1,option2".
// The name can be neglectected.
func parseTag(tag string) (string, tagOptions) {
// tag is one of followings:
// ""
// "name"
// "name,opt"
// "name,opt,opt2"
// ",opt"
res := strings.Split(tag, ",")
return res[0], res[1:]
}

46
vendor/github.com/fatih/structs/tags_test.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
package structs
import "testing"
func TestParseTag_Name(t *testing.T) {
tags := []struct {
tag string
has bool
}{
{"", false},
{"name", true},
{"name,opt", true},
{"name , opt, opt2", false}, // has a single whitespace
{", opt, opt2", false},
}
for _, tag := range tags {
name, _ := parseTag(tag.tag)
if (name != "name") && tag.has {
t.Errorf("Parse tag should return name: %#v", tag)
}
}
}
func TestParseTag_Opts(t *testing.T) {
tags := []struct {
opts string
has bool
}{
{"name", false},
{"name,opt", true},
{"name , opt, opt2", false}, // has a single whitespace
{",opt, opt2", true},
{", opt3, opt4", false},
}
// search for "opt"
for _, tag := range tags {
_, opts := parseTag(tag.opts)
if opts.Has("opt") != tag.has {
t.Errorf("Tag opts should have opt: %#v", tag)
}
}
}

21
vendor/github.com/gavv/httpexpect/.gometalinter generated vendored Normal file
View File

@ -0,0 +1,21 @@
{
"Deadline": "30s",
"LineLength": 90,
"Enable": [
"gotype",
"goimports",
"golint",
"gosimple",
"gofmt",
"vet",
"lll",
"staticcheck",
"ineffassign",
"deadcode",
"unused",
"unconvert",
"misspell",
"test",
"testify"
]
}

19
vendor/github.com/gavv/httpexpect/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,19 @@
language: go
sudo: false
go:
- 1.7
- 1.8
before_install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
- go get github.com/alecthomas/gometalinter
- ${GOPATH}/bin/gometalinter --install
script:
- go get -v -t . ./_examples
- go test -coverprofile profile.cov .
- go test ./_examples
- ${GOPATH}/bin/gometalinter --config .gometalinter
- ${GOPATH}/bin/goveralls -coverprofile profile.cov -service=travis-ci

21
vendor/github.com/gavv/httpexpect/LICENSE generated vendored Normal file
View 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.

15
vendor/github.com/gavv/httpexpect/Makefile generated vendored Normal file
View File

@ -0,0 +1,15 @@
all: update test check
update:
go get -u -t . ./_examples
test:
go test . ./_examples
check:
go get -u github.com/alecthomas/gometalinter
gometalinter --install
gometalinter --config .gometalinter
fmt:
gofmt -s -w . ./_examples

455
vendor/github.com/gavv/httpexpect/README.md generated vendored Normal file
View File

@ -0,0 +1,455 @@
# httpexpect [![GoDoc](https://godoc.org/github.com/gavv/httpexpect?status.svg)](https://godoc.org/github.com/gavv/httpexpect) [![Gitter](https://badges.gitter.im/gavv/httpexpect.svg)](https://gitter.im/gavv/httpexpect?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Travis](https://img.shields.io/travis/gavv/httpexpect.svg)](https://travis-ci.org/gavv/httpexpect) [![Coveralls](https://coveralls.io/repos/github/gavv/httpexpect/badge.svg?branch=master)](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.
* Create custom [request builders](#reusable-builders) that can be reused.
##### Response assertions
* Response status, predefined status ranges.
* Headers, cookies, payload: JSON, JSONP, forms, text.
* Round-trip time.
##### 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.
##### 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 [`v1`](http://gopkg.in/gavv/httpexpect.v1):
```go
import "gopkg.in/gavv/httpexpect.v1"
```
Development is done in `master` branch on github:
```go
import "github.com/gavv/httpexpect"
```
## 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.
* [`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)
```
##### 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)
```
##### 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)
* [`gabs`](https://github.com/Jeffail/gabs)
* [`gofight`](https://github.com/appleboy/gofight)
* [`baloo`](https://github.com/h2non/baloo)
* [`frisby`](https://github.com/verdverm/frisby)
* [`forest`](https://github.com/emicklei/forest)
* [`restit`](https://github.com/go-restit/restit)
* [`supertest`](https://github.com/haoxins/supertest)
* [`http-test`](https://github.com/vsco/http-test)
* [`go-json-rest/rest/test`](https://godoc.org/github.com/ant0ine/go-json-rest/rest/test)
## 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)

2
vendor/github.com/gavv/httpexpect/_examples/doc.go generated vendored Normal file
View File

@ -0,0 +1,2 @@
// Package examples demonstrates httpexpect usage.
package examples

49
vendor/github.com/gavv/httpexpect/_examples/echo.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
package examples
import (
"net/http"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
)
// EchoHandler creates http.Handler using echo framework.
//
// Routes:
// GET /login authenticate user and return JWT token
// GET /restricted/hello return "hello, world!" (requires authentication)
func EchoHandler() http.Handler {
e := echo.New()
e.POST("/login", func(ctx echo.Context) error {
username := ctx.FormValue("username")
password := ctx.FormValue("password")
if username == "ford" && password == "betelgeuse7" {
// create token
token := jwt.New(jwt.SigningMethodHS256)
// generate encoded token and send it as response
t, err := token.SignedString([]byte("secret"))
if err != nil {
return err
}
return ctx.JSON(http.StatusOK, map[string]string{
"token": t,
})
}
return echo.ErrUnauthorized
})
r := e.Group("/restricted")
r.Use(middleware.JWT([]byte("secret")))
r.GET("/hello", func(ctx echo.Context) error {
return ctx.String(http.StatusOK, "hello, world!")
})
return e
}

View File

@ -0,0 +1,87 @@
package examples
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gavv/httpexpect"
)
// Echo JWT token authentication tests.
//
// This test is executed for the EchoHandler() in two modes:
// - via http client
// - via http.Handler
func testEcho(e *httpexpect.Expect) {
type Login struct {
Username string `form:"username"`
Password string `form:"password"`
}
e.POST("/login").WithForm(Login{"ford", "<bad password>"}).
Expect().
Status(http.StatusUnauthorized)
r := e.POST("/login").WithForm(Login{"ford", "betelgeuse7"}).
Expect().
Status(http.StatusOK).JSON().Object()
r.Keys().ContainsOnly("token")
token := r.Value("token").String().Raw()
e.GET("/restricted/hello").
Expect().
Status(http.StatusBadRequest)
e.GET("/restricted/hello").WithHeader("Authorization", "Bearer <bad token>").
Expect().
Status(http.StatusUnauthorized)
e.GET("/restricted/hello").WithHeader("Authorization", "Bearer "+token).
Expect().
Status(http.StatusOK).Body().Equal("hello, world!")
auth := e.Builder(func(req *httpexpect.Request) {
req.WithHeader("Authorization", "Bearer "+token)
})
auth.GET("/restricted/hello").
Expect().
Status(http.StatusOK).Body().Equal("hello, world!")
}
func TestEchoClient(t *testing.T) {
handler := EchoHandler()
server := httptest.NewServer(handler)
defer server.Close()
e := httpexpect.WithConfig(httpexpect.Config{
BaseURL: server.URL,
Reporter: httpexpect.NewAssertReporter(t),
Printers: []httpexpect.Printer{
httpexpect.NewDebugPrinter(t, true),
},
})
testEcho(e)
}
func TestEchoHandler(t *testing.T) {
handler := EchoHandler()
e := httpexpect.WithConfig(httpexpect.Config{
Client: &http.Client{
Transport: httpexpect.NewBinder(handler),
Jar: httpexpect.NewJar(),
},
Reporter: httpexpect.NewAssertReporter(t),
Printers: []httpexpect.Printer{
httpexpect.NewDebugPrinter(t, true),
},
})
testEcho(e)
}

View File

@ -0,0 +1,23 @@
package examples
import (
"github.com/valyala/fasthttp"
)
// FastHTTPHandler creates fasthttp.RequestHandler.
//
// Routes:
// GET /ping return "pong"
func FastHTTPHandler() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
switch string(ctx.Path()) {
case "/ping":
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.SetContentType("text/plain")
ctx.SetBody([]byte("pong"))
default:
panic("unsupported path")
}
}
}

View File

@ -0,0 +1,29 @@
package examples
import (
"net/http"
"testing"
"github.com/gavv/httpexpect"
)
// fastHTTPTester returns a new Expect instance to test FastHTTPHandler().
func fastHTTPTester(t *testing.T) *httpexpect.Expect {
return httpexpect.WithConfig(httpexpect.Config{
// Pass requests directly to FastHTTPHandler.
Client: &http.Client{
Transport: httpexpect.NewFastBinder(FastHTTPHandler()),
Jar: httpexpect.NewJar(),
},
// Report errors using testify.
Reporter: httpexpect.NewAssertReporter(t),
})
}
func TestFastHTTP(t *testing.T) {
e := fastHTTPTester(t)
e.GET("/ping").Expect().
Status(200).
Text().Equal("pong")
}

85
vendor/github.com/gavv/httpexpect/_examples/fruits.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
package examples
import (
"encoding/json"
"net/http"
"path"
)
type (
fruitMap map[string]interface{}
)
// FruitsHandler creates http.Handler for the fruits server.
//
// Routes:
// GET /fruits get fruit list
// GET /fruits/{name} get fruit
// PUT /fruits/{name} add or update fruit
func FruitsHandler() http.Handler {
fruits := fruitMap{}
mux := http.NewServeMux()
mux.HandleFunc("/fruits", func(w http.ResponseWriter, r *http.Request) {
handleFruitList(fruits, w, r)
})
mux.HandleFunc("/fruits/", func(w http.ResponseWriter, r *http.Request) {
handleFruit(fruits, w, r)
})
return mux
}
func handleFruitList(fruits fruitMap, w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
ret := []string{}
for k := range fruits {
ret = append(ret, k)
}
b, err := json.Marshal(ret)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
w.Write(b)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
func handleFruit(fruits fruitMap, w http.ResponseWriter, r *http.Request) {
_, name := path.Split(r.URL.Path)
switch r.Method {
case "GET":
if data, ok := fruits[name]; ok {
b, err := json.Marshal(data)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
w.Write(b)
} else {
w.WriteHeader(http.StatusNotFound)
}
case "PUT":
var data map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
panic(err)
}
fruits[name] = data
w.WriteHeader(http.StatusNoContent)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}

View File

@ -0,0 +1,68 @@
package examples
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gavv/httpexpect"
)
func TestFruits(t *testing.T) {
handler := FruitsHandler()
server := httptest.NewServer(handler)
defer server.Close()
e := httpexpect.New(t, server.URL)
e.GET("/fruits").
Expect().
Status(http.StatusOK).JSON().Array().Empty()
orange := map[string]interface{}{
"weight": 100,
}
e.PUT("/fruits/orange").WithJSON(orange).
Expect().
Status(http.StatusNoContent).NoContent()
apple := map[string]interface{}{
"colors": []interface{}{"green", "red"},
"weight": 200,
}
e.PUT("/fruits/apple").WithJSON(apple).
Expect().
Status(http.StatusNoContent).NoContent()
e.GET("/fruits").
Expect().
Status(http.StatusOK).JSON().Array().ContainsOnly("orange", "apple")
e.GET("/fruits/orange").
Expect().
Status(http.StatusOK).JSON().Object().Equal(orange).NotEqual(apple)
e.GET("/fruits/orange").
Expect().
Status(http.StatusOK).
JSON().Object().ContainsKey("weight").ValueEqual("weight", 100)
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("weight").Number().Equal(200)
e.GET("/fruits/melon").
Expect().
Status(http.StatusNotFound)
}

22
vendor/github.com/gavv/httpexpect/_examples/gae.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
package examples
import (
"net/http"
"google.golang.org/appengine"
)
// GaeHandler creates http.Handler to run in the Google App Engine.
//
// Routes:
// GET /ping return "pong"
func GaeHandler() http.Handler {
m := http.NewServeMux()
m.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
_ = appengine.NewContext(r)
w.Write([]byte("pong"))
})
return m
}

View File

@ -0,0 +1,64 @@
package examples
import (
"net/http"
"os"
"testing"
"github.com/gavv/httpexpect"
"google.golang.org/appengine/aetest"
)
// init() is used by GAE to start serving the app
// added here for illustration purposes
//
// func init() {
// http.Handle("/", GaeHandler())
// }
// gaeInstance is our global dev_appserver instance.
var gaeInstance aetest.Instance
// TestMain is called first to create the gaeInstance.
func TestMain(m *testing.M) {
// INFO: Remove the return to actually run the tests.
// Requires installed Google Appengine SDK.
// https://cloud.google.com/appengine/downloads
return
var err error
gaeInstance, err = aetest.NewInstance(nil)
if err != nil {
panic(err)
}
c := m.Run() // call all actual tests
gaeInstance.Close()
os.Exit(c)
}
// gaeTester returns a new Expect instance to test GaeHandler().
func gaeTester(t *testing.T) *httpexpect.Expect {
return httpexpect.WithConfig(httpexpect.Config{
// Use gaeInstance to create requests.
// aetest.Instance is compatible with httpexpect.RequestFactory.
RequestFactory: gaeInstance,
// Pass requests directly to GaeHandler.
Client: &http.Client{
Transport: httpexpect.NewBinder(GaeHandler()),
Jar: httpexpect.NewJar(),
},
// Report errors using testify.
Reporter: httpexpect.NewAssertReporter(t),
})
}
func TestGae(t *testing.T) {
e := gaeTester(t)
e.GET("/ping").Expect().
Status(200).
Text().Equal("pong")
}

111
vendor/github.com/gavv/httpexpect/_examples/iris.go generated vendored Normal file
View File

@ -0,0 +1,111 @@
// +build go1.8
package examples
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
"gopkg.in/kataras/iris.v6/adaptors/sessions"
"gopkg.in/kataras/iris.v6/middleware/basicauth"
)
// IrisHandler tests iris v6's handler
func IrisHandler() http.Handler {
app := iris.New(iris.Configuration{VHost: "example.com"})
app.Adapt(iris.DevLogger())
app.Adapt(httprouter.New())
app.Adapt(sessions.New(sessions.Config{Cookie: "irissessionid"}))
app.Get("/things", func(c *iris.Context) {
c.JSON(iris.StatusOK, []interface{}{
iris.Map{
"name": "foo",
"description": "foo thing",
},
iris.Map{
"name": "bar",
"description": "bar thing",
},
})
})
app.Post("/redirect", func(c *iris.Context) {
c.Redirect("/things", iris.StatusFound)
})
app.Post("/params/:x/:y", func(c *iris.Context) {
c.JSON(iris.StatusOK, iris.Map{
"x": c.Param("x"),
"y": c.Param("y"),
"q": c.URLParam("q"),
"p1": c.FormValue("p1"),
"p2": c.FormValue("p2"),
})
})
auth := basicauth.Default(map[string]string{
"ford": "betelgeuse7",
})
app.Get("/auth", auth, func(c *iris.Context) {
c.Writef("authenticated!")
})
app.Post("/session/set", func(c *iris.Context) {
sess := iris.Map{}
if err := c.ReadJSON(&sess); err != nil {
panic(err.Error())
}
c.Session().Set("name", sess["name"])
})
app.Get("/session/get", func(c *iris.Context) {
name := c.Session().GetString("name")
c.JSON(iris.StatusOK, iris.Map{
"name": name,
})
})
app.Get("/stream", func(c *iris.Context) {
c.StreamWriter(func(w io.Writer) bool {
for i := 0; i < 10; i++ {
fmt.Fprintf(w, "%d", i)
}
// return true to continue, return false to stop and flush
return false
})
// if we had to write here then the StreamWriter callback should
// return true
})
app.Post("/stream", func(c *iris.Context) {
body, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.EmitError(iris.StatusBadRequest)
return
}
c.Write(body)
})
sub := app.Party("subdomain.")
sub.Post("/set", func(c *iris.Context) {
c.Session().Set("message", "hello from subdomain")
})
sub.Get("/get", func(c *iris.Context) {
c.Writef(c.Session().GetString("message"))
})
app.Boot()
return app.Router
}

View File

@ -0,0 +1,161 @@
// +build go1.8
package examples
import (
"net/http"
"strings"
"testing"
"github.com/gavv/httpexpect"
)
func irisTester(t *testing.T) *httpexpect.Expect {
handler := IrisHandler()
return httpexpect.WithConfig(httpexpect.Config{
BaseURL: "http://example.com",
Client: &http.Client{
Transport: httpexpect.NewBinder(handler),
Jar: httpexpect.NewJar(),
},
Reporter: httpexpect.NewAssertReporter(t),
Printers: []httpexpect.Printer{
httpexpect.NewDebugPrinter(t, true),
},
})
}
func TestIrisThings(t *testing.T) {
e := irisTester(t)
schema := `{
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"description": {"type": "string"}
},
"required": ["name", "description"]
}
}`
things := e.GET("/things").
Expect().
Status(http.StatusOK).JSON()
things.Schema(schema)
names := things.Path("$[*].name").Array()
names.Elements("foo", "bar")
for n, desc := range things.Path("$..description").Array().Iter() {
m := desc.String().Match("(.+) (.+)")
m.Index(1).Equal(names.Element(n).String().Raw())
m.Index(2).Equal("thing")
}
}
func TestIrisRedirect(t *testing.T) {
e := irisTester(t)
things := e.POST("/redirect").
Expect().
Status(http.StatusOK).JSON().Array()
things.Length().Equal(2)
things.Element(0).Object().ValueEqual("name", "foo")
things.Element(1).Object().ValueEqual("name", "bar")
}
func TestIrisParams(t *testing.T) {
e := irisTester(t)
type Form struct {
P1 string `form:"p1"`
P2 string `form:"p2"`
}
// POST /params/xxx/yyy?q=qqq
// Form: p1=P1&p2=P2
r := e.POST("/params/{x}/{y}", "xxx", "yyy").
WithQuery("q", "qqq").WithForm(Form{P1: "P1", P2: "P2"}).
Expect().
Status(http.StatusOK).JSON().Object()
r.Value("x").Equal("xxx")
r.Value("y").Equal("yyy")
r.Value("q").Equal("qqq")
r.ValueEqual("p1", "P1")
r.ValueEqual("p2", "P2")
}
func TestIrisAuth(t *testing.T) {
e := irisTester(t)
e.GET("/auth").
Expect().
Status(http.StatusUnauthorized)
e.GET("/auth").WithBasicAuth("ford", "<bad password>").
Expect().
Status(http.StatusUnauthorized)
e.GET("/auth").WithBasicAuth("ford", "betelgeuse7").
Expect().
Status(http.StatusOK).Body().Equal("authenticated!")
}
func TestIrisSession(t *testing.T) {
e := irisTester(t)
e.POST("/session/set").WithJSON(map[string]string{"name": "test"}).
Expect().
Status(http.StatusOK).Cookies().NotEmpty()
r := e.GET("/session/get").
Expect().
Status(http.StatusOK).JSON().Object()
r.Equal(map[string]string{
"name": "test",
})
}
func TestIrisStream(t *testing.T) {
e := irisTester(t)
e.GET("/stream").
Expect().
Status(http.StatusOK).
TransferEncoding("chunked"). // ensure server sent chunks
Body().Equal("0123456789")
// send chunks to server
e.POST("/stream").WithChunked(strings.NewReader("<long text>")).
Expect().
Status(http.StatusOK).Body().Equal("<long text>")
}
func TestIrisSubdomain(t *testing.T) {
e := irisTester(t)
sub := e.Builder(func(req *httpexpect.Request) {
req.WithURL("http://subdomain.127.0.0.1")
})
sub.POST("/set").
Expect().
Status(http.StatusOK)
sub.GET("/get").
Expect().
Status(http.StatusOK).
Body().Equal("hello from subdomain")
}

299
vendor/github.com/gavv/httpexpect/array.go generated vendored Normal file
View 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 another array.
// Before comparison, both arrays are converted to canonical form.
//
// value should be 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 another array.
// Before comparison, both arrays are converted to canonical form.
//
// value should be 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
}

454
vendor/github.com/gavv/httpexpect/array_test.go generated vendored Normal file
View File

@ -0,0 +1,454 @@
package httpexpect
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestArrayFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &Array{chain, nil}
value.chain.assertFailed(t)
value.Path("$").chain.assertFailed(t)
value.Schema("")
assert.False(t, value.Length() == nil)
assert.False(t, value.Element(0) == nil)
assert.False(t, value.Iter() == nil)
assert.True(t, len(value.Iter()) == 0)
value.Length().chain.assertFailed(t)
value.Element(0).chain.assertFailed(t)
value.First().chain.assertFailed(t)
value.Last().chain.assertFailed(t)
value.Empty()
value.NotEmpty()
value.Equal(nil)
value.NotEqual(nil)
value.Elements("foo")
value.Contains("foo")
value.NotContains("foo")
value.ContainsOnly("foo")
}
func TestArrayGetters(t *testing.T) {
reporter := newMockReporter(t)
a := []interface{}{"foo", 123.0}
value := NewArray(reporter, a)
assert.Equal(t, a, value.Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, a, value.Path("$").Raw())
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "array"}`)
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "object"}`)
value.chain.assertFailed(t)
value.chain.reset()
assert.Equal(t, 2.0, value.Length().Raw())
assert.Equal(t, "foo", value.Element(0).Raw())
assert.Equal(t, 123.0, value.Element(1).Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, nil, value.Element(2).Raw())
value.chain.assertFailed(t)
value.chain.reset()
it := value.Iter()
assert.Equal(t, 2, len(it))
assert.Equal(t, "foo", it[0].Raw())
assert.Equal(t, 123.0, it[1].Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, "foo", value.First().Raw())
assert.Equal(t, 123.0, value.Last().Raw())
value.chain.assertOK(t)
value.chain.reset()
}
func TestArrayEmpty(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewArray(reporter, nil)
_ = value1
value1.chain.assertFailed(t)
value1.chain.reset()
value2 := NewArray(reporter, []interface{}{})
value2.Empty()
value2.chain.assertOK(t)
value2.chain.reset()
value2.NotEmpty()
value2.chain.assertFailed(t)
value2.chain.reset()
value3 := NewArray(reporter, []interface{}{""})
value3.Empty()
value3.chain.assertFailed(t)
value3.chain.reset()
value3.NotEmpty()
value3.chain.assertOK(t)
value3.chain.reset()
}
func TestArrayEqualEmpty(t *testing.T) {
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{})
assert.Equal(t, []interface{}{}, value.Raw())
value.Equal([]interface{}{})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual([]interface{}{})
value.chain.assertFailed(t)
value.chain.reset()
value.Equal([]interface{}{""})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual([]interface{}{""})
value.chain.assertOK(t)
value.chain.reset()
}
func TestArrayEqualNotEmpty(t *testing.T) {
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{"foo", "bar"})
assert.Equal(t, []interface{}{"foo", "bar"}, value.Raw())
value.Equal([]interface{}{})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual([]interface{}{})
value.chain.assertOK(t)
value.chain.reset()
value.Equal([]interface{}{"foo"})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual([]interface{}{"foo"})
value.chain.assertOK(t)
value.chain.reset()
value.Equal([]interface{}{"bar", "foo"})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual([]interface{}{"bar", "foo"})
value.chain.assertOK(t)
value.chain.reset()
value.Equal([]interface{}{"foo", "bar"})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual([]interface{}{"foo", "bar"})
value.chain.assertFailed(t)
value.chain.reset()
}
func TestArrayEqualTypes(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewArray(reporter, []interface{}{"foo", "bar"})
value2 := NewArray(reporter, []interface{}{123, 456})
value3 := NewArray(reporter, []interface{}{
map[string]interface{}{
"foo": 123,
},
map[string]interface{}{
"foo": 456,
},
})
value1.Equal([]string{"foo", "bar"})
value1.chain.assertOK(t)
value1.chain.reset()
value1.Equal([]string{"bar", "foo"})
value1.chain.assertFailed(t)
value1.chain.reset()
value1.NotEqual([]string{"foo", "bar"})
value1.chain.assertFailed(t)
value1.chain.reset()
value1.NotEqual([]string{"bar", "foo"})
value1.chain.assertOK(t)
value1.chain.reset()
value2.Equal([]int{123, 456})
value2.chain.assertOK(t)
value2.chain.reset()
value2.Equal([]int{456, 123})
value2.chain.assertFailed(t)
value2.chain.reset()
value2.NotEqual([]int{123, 456})
value2.chain.assertFailed(t)
value2.chain.reset()
value2.NotEqual([]int{456, 123})
value2.chain.assertOK(t)
value2.chain.reset()
type S struct {
Foo int `json:"foo"`
}
value3.Equal([]S{{123}, {456}})
value3.chain.assertOK(t)
value3.chain.reset()
value3.Equal([]S{{456}, {123}})
value3.chain.assertFailed(t)
value3.chain.reset()
value3.NotEqual([]S{{123}, {456}})
value3.chain.assertFailed(t)
value3.chain.reset()
value3.NotEqual([]S{{456}, {123}})
value3.chain.assertOK(t)
value3.chain.reset()
}
func TestArrayElements(t *testing.T) {
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{123, "foo"})
value.Elements(123)
value.chain.assertFailed(t)
value.chain.reset()
value.Elements("foo")
value.chain.assertFailed(t)
value.chain.reset()
value.Elements("foo", 123)
value.chain.assertFailed(t)
value.chain.reset()
value.Elements(123, "foo", "foo")
value.chain.assertFailed(t)
value.chain.reset()
value.Elements(123, "foo")
value.chain.assertOK(t)
value.chain.reset()
}
func TestArrayContains(t *testing.T) {
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{123, "foo"})
value.Contains(123)
value.chain.assertOK(t)
value.chain.reset()
value.NotContains(123)
value.chain.assertFailed(t)
value.chain.reset()
value.Contains("foo", 123)
value.chain.assertOK(t)
value.chain.reset()
value.NotContains("foo", 123)
value.chain.assertFailed(t)
value.chain.reset()
value.Contains("foo", "foo")
value.chain.assertOK(t)
value.chain.reset()
value.NotContains("foo", "foo")
value.chain.assertFailed(t)
value.chain.reset()
value.Contains(123, "foo", "FOO")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContains(123, "foo", "FOO")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContains("FOO")
value.chain.assertOK(t)
value.chain.reset()
value.Contains([]interface{}{123, "foo"})
value.chain.assertFailed(t)
value.chain.reset()
value.NotContains([]interface{}{123, "foo"})
value.chain.assertOK(t)
value.chain.reset()
}
func TestArrayContainsOnly(t *testing.T) {
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{123, "foo"})
value.ContainsOnly(123)
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsOnly("foo")
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsOnly(123, "foo", "foo")
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsOnly(123, "foo")
value.chain.assertOK(t)
value.chain.reset()
value.ContainsOnly("foo", 123)
value.chain.assertOK(t)
value.chain.reset()
}
func TestArrayConvertEqual(t *testing.T) {
type (
myArray []interface{}
myInt int
)
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{123, 456})
assert.Equal(t, []interface{}{123.0, 456.0}, value.Raw())
value.Equal(myArray{myInt(123), 456.0})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(myArray{myInt(123), 456.0})
value.chain.assertFailed(t)
value.chain.reset()
value.Equal([]interface{}{"123", "456"})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual([]interface{}{"123", "456"})
value.chain.assertOK(t)
value.chain.reset()
value.Equal(nil)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(nil)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestArrayConvertElements(t *testing.T) {
type (
myInt int
)
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{123, 456})
assert.Equal(t, []interface{}{123.0, 456.0}, value.Raw())
value.Elements(myInt(123), 456.0)
value.chain.assertOK(t)
value.chain.reset()
value.Elements(func() {})
value.chain.assertFailed(t)
value.chain.reset()
}
func TestArrayConvertContains(t *testing.T) {
type (
myInt int
)
reporter := newMockReporter(t)
value := NewArray(reporter, []interface{}{123, 456})
assert.Equal(t, []interface{}{123.0, 456.0}, value.Raw())
value.Contains(myInt(123), 456.0)
value.chain.assertOK(t)
value.chain.reset()
value.NotContains(myInt(123), 456.0)
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsOnly(myInt(123), 456.0)
value.chain.assertOK(t)
value.chain.reset()
value.Contains("123")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContains("123")
value.chain.assertOK(t)
value.chain.reset()
value.ContainsOnly("123.0", "456.0")
value.chain.assertFailed(t)
value.chain.reset()
value.Contains(func() {})
value.chain.assertFailed(t)
value.chain.reset()
value.NotContains(func() {})
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsOnly(func() {})
value.chain.assertFailed(t)
value.chain.reset()
}

214
vendor/github.com/gavv/httpexpect/binder.go generated vendored Normal file
View File

@ -0,0 +1,214 @@
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.HeaderMap,
}
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) ConnectionState() tls.ConnectionState {
return *c.state
}

370
vendor/github.com/gavv/httpexpect/binder_test.go generated vendored Normal file
View File

@ -0,0 +1,370 @@
package httpexpect
import (
"bufio"
"crypto/tls"
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
)
type mockHandler struct {
t *testing.T
https bool
http10 bool
chunked bool
}
func (c *mockHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
body, err := ioutil.ReadAll(req.Body)
assert.True(c.t, err == nil)
if c.http10 {
assert.Equal(c.t, "HTTP/1.0", req.Proto)
assert.Equal(c.t, 1, req.ProtoMajor)
assert.Equal(c.t, 0, req.ProtoMinor)
} else {
assert.Equal(c.t, "HTTP/1.1", req.Proto)
assert.Equal(c.t, 1, req.ProtoMajor)
assert.Equal(c.t, 1, req.ProtoMinor)
}
if c.https {
assert.Equal(c.t, "https://example.com/path", req.URL.String())
} else {
assert.Equal(c.t, "http://example.com/path", req.URL.String())
}
assert.Equal(c.t, "/path", req.URL.RequestURI())
assert.Equal(c.t, "/path", req.RequestURI)
assert.Equal(c.t, "GET", req.Method)
assert.Equal(c.t, "body", string(body))
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte(`{"hello":"world"}`))
if c.chunked {
w.(http.Flusher).Flush()
}
assert.True(c.t, err == nil)
}
func TestBinder(t *testing.T) {
handler := &mockHandler{
t: t,
http10: true,
chunked: false,
}
client := &http.Client{
Transport: NewBinder(handler),
}
req, err := http.NewRequest("GET", "http://example.com/path", strings.NewReader("body"))
if err != nil {
t.Fatal(err)
}
req.ProtoMajor = 1
req.ProtoMinor = 0
req.Proto = ""
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
header := http.Header{
"Content-Type": {"application/json"},
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, header, resp.Header)
assert.Equal(t, `{"hello":"world"}`, string(b))
assert.Equal(t, []string(nil), resp.TransferEncoding)
}
func TestBinderTLS(t *testing.T) {
handler := &mockHandler{t: t}
httpClient := &http.Client{
Transport: &Binder{
Handler: handler,
TLS: nil,
},
}
tlsState := &tls.ConnectionState{}
httpsClient := &http.Client{
Transport: &Binder{
Handler: handler,
TLS: tlsState,
},
}
handler.https = false
req, _ := http.NewRequest("GET", "http://example.com/path", strings.NewReader("body"))
resp, err := httpClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.Nil(t, req.TLS)
handler.https = true
req, _ = http.NewRequest("GET", "https://example.com/path", strings.NewReader("body"))
resp, err = httpClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.Nil(t, req.TLS)
handler.https = false
req, _ = http.NewRequest("GET", "http://example.com/path", strings.NewReader("body"))
resp, err = httpsClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.Nil(t, req.TLS)
handler.https = true
req, _ = http.NewRequest("GET", "https://example.com/path", strings.NewReader("body"))
resp, err = httpsClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.NotNil(t, req.TLS)
assert.Equal(t, tlsState, req.TLS)
}
func TestBinderChunked(t *testing.T) {
handler := &mockHandler{
t: t,
chunked: true,
}
client := &http.Client{
Transport: NewBinder(handler),
}
req, err := http.NewRequest("GET", "http://example.com/path", strings.NewReader("body"))
if err != nil {
t.Fatal(err)
}
req.ContentLength = -1
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []string{"chunked"}, req.TransferEncoding)
assert.Equal(t, []string{"chunked"}, resp.TransferEncoding)
}
func TestFastBinder(t *testing.T) {
handler := func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "POST", string(ctx.Request.Header.Method()))
assert.Equal(t, "http://example.com/path", string(ctx.Request.Header.RequestURI()))
assert.Equal(t, "application/x-www-form-urlencoded",
string(ctx.Request.Header.ContentType()))
headers := map[string][]string{}
ctx.Request.Header.VisitAll(func(k, v []byte) {
headers[string(k)] = append(headers[string(k)], string(v))
})
expected := map[string][]string{
"Content-Type": {"application/x-www-form-urlencoded"},
"Content-Length": {"7"},
"Some-Header": {"foo", "bar"},
}
assert.Equal(t, expected, headers)
assert.Equal(t, "bar", string(ctx.FormValue("foo")))
assert.Equal(t, "foo=bar", string(ctx.Request.Body()))
ctx.Response.Header.Set("Content-Type", "application/json")
ctx.Response.SetBody([]byte(`{"hello":"world"}`))
}
client := &http.Client{
Transport: NewFastBinder(handler),
}
req, err := http.NewRequest(
"POST", "http://example.com/path", strings.NewReader("foo=bar"))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Some-Header", "foo")
req.Header.Add("Some-Header", "bar")
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
header := http.Header{
"Content-Type": {"application/json"},
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, header, resp.Header)
assert.Equal(t, `{"hello":"world"}`, string(b))
assert.Equal(t, []string(nil), resp.TransferEncoding)
}
func TestFastBinderTLS(t *testing.T) {
var isHTTPS, isTLS bool
tlsState := &tls.ConnectionState{}
handler := func(ctx *fasthttp.RequestCtx) {
isHTTPS = strings.HasPrefix(string(ctx.Request.Header.RequestURI()), "https://")
isTLS = ctx.IsTLS()
if isTLS {
assert.Equal(t, *tlsState, *ctx.TLSConnectionState())
}
}
httpClient := &http.Client{
Transport: &FastBinder{
Handler: handler,
TLS: nil,
},
}
httpsClient := &http.Client{
Transport: &FastBinder{
Handler: handler,
TLS: tlsState,
},
}
req, _ := http.NewRequest("GET", "http://example.com/path", strings.NewReader("body"))
resp, err := httpClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.False(t, isHTTPS)
assert.False(t, isTLS)
req, _ = http.NewRequest("GET", "https://example.com/path", strings.NewReader("body"))
resp, err = httpClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.True(t, isHTTPS)
assert.False(t, isTLS)
req, _ = http.NewRequest("GET", "http://example.com/path", strings.NewReader("body"))
resp, err = httpsClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.False(t, isHTTPS)
assert.False(t, isTLS)
req, _ = http.NewRequest("GET", "https://example.com/path", strings.NewReader("body"))
resp, err = httpsClient.Do(req)
assert.Nil(t, err)
assert.NotNil(t, resp)
assert.True(t, isHTTPS)
assert.True(t, isTLS)
}
func TestFastBinderChunked(t *testing.T) {
handler := func(ctx *fasthttp.RequestCtx) {
assert.Equal(t, "POST", string(ctx.Request.Header.Method()))
assert.Equal(t, "http://example.com/path", string(ctx.Request.Header.RequestURI()))
assert.Equal(t, "application/x-www-form-urlencoded",
string(ctx.Request.Header.ContentType()))
headers := map[string][]string{}
ctx.Request.Header.VisitAll(func(k, v []byte) {
headers[string(k)] = append(headers[string(k)], string(v))
})
expected := map[string][]string{
"Content-Type": {"application/x-www-form-urlencoded"},
"Transfer-Encoding": {"chunked"},
}
assert.Equal(t, expected, headers)
assert.Equal(t, "bar", string(ctx.FormValue("foo")))
assert.Equal(t, "foo=bar", string(ctx.Request.Body()))
ctx.Response.Header.Set("Content-Type", "application/json")
ctx.Response.SetBodyStreamWriter(func(w *bufio.Writer) {
w.WriteString(`[1, `)
w.Flush()
w.WriteString(`2]`)
})
}
client := &http.Client{
Transport: NewFastBinder(handler),
}
req, err := http.NewRequest(
"POST", "http://example.com/path", strings.NewReader("foo=bar"))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.ContentLength = -1
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []string{"chunked"}, resp.TransferEncoding)
}
func TestFastBinderEmptyResponse(t *testing.T) {
handler := func(*fasthttp.RequestCtx) {}
client := &http.Client{
Transport: NewFastBinder(handler),
}
req, err := http.NewRequest("POST", "http://example.com/path", nil)
if err != nil {
t.Fatal(err)
}
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
assert.False(t, resp.Body == nil)
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "", string(b))
}

82
vendor/github.com/gavv/httpexpect/boolean.go generated vendored Normal file
View 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)
}

111
vendor/github.com/gavv/httpexpect/boolean_test.go generated vendored Normal file
View File

@ -0,0 +1,111 @@
package httpexpect
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestBooleanFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &Boolean{chain, false}
value.chain.assertFailed(t)
value.Path("$").chain.assertFailed(t)
value.Schema("")
value.Equal(false)
value.NotEqual(false)
value.True()
value.False()
}
func TestBooleanGetters(t *testing.T) {
reporter := newMockReporter(t)
value := NewBoolean(reporter, true)
assert.Equal(t, true, value.Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, true, value.Path("$").Raw())
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "boolean"}`)
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "object"}`)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestBooleanTrue(t *testing.T) {
reporter := newMockReporter(t)
value := NewBoolean(reporter, true)
assert.Equal(t, true, value.Raw())
value.Equal(true)
value.chain.assertOK(t)
value.chain.reset()
value.Equal(false)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(false)
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(true)
value.chain.assertFailed(t)
value.chain.reset()
value.True()
value.chain.assertOK(t)
value.chain.reset()
value.False()
value.chain.assertFailed(t)
value.chain.reset()
}
func TestBooleanFalse(t *testing.T) {
reporter := newMockReporter(t)
value := NewBoolean(reporter, false)
assert.Equal(t, false, value.Raw())
value.Equal(true)
value.chain.assertFailed(t)
value.chain.reset()
value.Equal(false)
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(false)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(true)
value.chain.assertOK(t)
value.chain.reset()
value.True()
value.chain.assertFailed(t)
value.chain.reset()
value.False()
value.chain.assertOK(t)
value.chain.reset()
}

38
vendor/github.com/gavv/httpexpect/chain.go generated vendored Normal file
View 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")
}
}

64
vendor/github.com/gavv/httpexpect/chain_test.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
package httpexpect
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestChainFail(t *testing.T) {
chain := makeChain(newMockReporter(t))
assert.False(t, chain.failed())
chain.fail("fail")
assert.True(t, chain.failed())
chain.fail("fail")
assert.True(t, chain.failed())
}
func TestChainCopy(t *testing.T) {
chain1 := makeChain(newMockReporter(t))
chain2 := chain1
assert.False(t, chain1.failed())
assert.False(t, chain2.failed())
chain1.fail("fail")
assert.True(t, chain1.failed())
assert.False(t, chain2.failed())
chain2.fail("fail")
assert.True(t, chain1.failed())
assert.True(t, chain2.failed())
}
func TestChainReport(t *testing.T) {
r0 := newMockReporter(t)
chain := makeChain(r0)
r1 := newMockReporter(t)
chain.assertOK(r1)
assert.False(t, r1.reported)
chain.assertFailed(r1)
assert.True(t, r1.reported)
assert.False(t, chain.failed())
chain.fail("fail")
assert.True(t, r0.reported)
r2 := newMockReporter(t)
chain.assertFailed(r2)
assert.False(t, r2.reported)
chain.assertOK(r2)
assert.True(t, r2.reported)
}

105
vendor/github.com/gavv/httpexpect/cookie.go generated vendored Normal file
View File

@ -0,0 +1,105 @@
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}
}

54
vendor/github.com/gavv/httpexpect/cookie_test.go generated vendored Normal file
View File

@ -0,0 +1,54 @@
package httpexpect
import (
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestCookieFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &Cookie{chain, nil}
assert.True(t, value.Raw() == nil)
assert.True(t, value.Name() != nil)
assert.True(t, value.Value() != nil)
assert.True(t, value.Domain() != nil)
assert.True(t, value.Path() != nil)
assert.True(t, value.Expires() != nil)
}
func TestCookieGetters(t *testing.T) {
reporter := newMockReporter(t)
NewCookie(reporter, nil).chain.assertFailed(t)
value := NewCookie(reporter, &http.Cookie{
Name: "name",
Value: "value",
Domain: "example.com",
Path: "/path",
Expires: time.Unix(1234, 0),
})
value.chain.assertOK(t)
value.Name().chain.assertOK(t)
value.Value().chain.assertOK(t)
value.Domain().chain.assertOK(t)
value.Path().chain.assertOK(t)
value.Expires().chain.assertOK(t)
assert.Equal(t, "name", value.Name().Raw())
assert.Equal(t, "value", value.Value().Raw())
assert.Equal(t, "example.com", value.Domain().Raw())
assert.Equal(t, "/path", value.Path().Raw())
assert.True(t, time.Unix(1234, 0).Equal(value.Expires().Raw()))
value.chain.assertOK(t)
}

129
vendor/github.com/gavv/httpexpect/datetime.go generated vendored Normal file
View 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
}

134
vendor/github.com/gavv/httpexpect/datetime_test.go generated vendored Normal file
View File

@ -0,0 +1,134 @@
package httpexpect
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestDateTimeFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
ts := time.Unix(0, 0)
value := &DateTime{chain, ts}
value.chain.assertFailed(t)
value.Equal(ts)
value.NotEqual(ts)
value.Gt(ts)
value.Ge(ts)
value.Lt(ts)
value.Le(ts)
value.InRange(ts, ts)
}
func TestDateTimeEqual(t *testing.T) {
reporter := newMockReporter(t)
value := NewDateTime(reporter, time.Unix(0, 1234))
assert.True(t, time.Unix(0, 1234).Equal(value.Raw()))
value.Equal(time.Unix(0, 1234))
value.chain.assertOK(t)
value.chain.reset()
value.Equal(time.Unix(0, 4321))
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(time.Unix(0, 4321))
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(time.Unix(0, 1234))
value.chain.assertFailed(t)
value.chain.reset()
}
func TestDateTimeGreater(t *testing.T) {
reporter := newMockReporter(t)
value := NewDateTime(reporter, time.Unix(0, 1234))
value.Gt(time.Unix(0, 1234-1))
value.chain.assertOK(t)
value.chain.reset()
value.Gt(time.Unix(0, 1234))
value.chain.assertFailed(t)
value.chain.reset()
value.Ge(time.Unix(0, 1234-1))
value.chain.assertOK(t)
value.chain.reset()
value.Ge(time.Unix(0, 1234))
value.chain.assertOK(t)
value.chain.reset()
value.Ge(time.Unix(0, 1234+1))
value.chain.assertFailed(t)
value.chain.reset()
}
func TestDateTimeLesser(t *testing.T) {
reporter := newMockReporter(t)
value := NewDateTime(reporter, time.Unix(0, 1234))
value.Lt(time.Unix(0, 1234+1))
value.chain.assertOK(t)
value.chain.reset()
value.Lt(time.Unix(0, 1234))
value.chain.assertFailed(t)
value.chain.reset()
value.Le(time.Unix(0, 1234+1))
value.chain.assertOK(t)
value.chain.reset()
value.Le(time.Unix(0, 1234))
value.chain.assertOK(t)
value.chain.reset()
value.Le(time.Unix(0, 1234-1))
value.chain.assertFailed(t)
value.chain.reset()
}
func TestDateTimeInRange(t *testing.T) {
reporter := newMockReporter(t)
value := NewDateTime(reporter, time.Unix(0, 1234))
value.InRange(time.Unix(0, 1234), time.Unix(0, 1234))
value.chain.assertOK(t)
value.chain.reset()
value.InRange(time.Unix(0, 1234-1), time.Unix(0, 1234))
value.chain.assertOK(t)
value.chain.reset()
value.InRange(time.Unix(0, 1234), time.Unix(0, 1234+1))
value.chain.assertOK(t)
value.chain.reset()
value.InRange(time.Unix(0, 1234+1), time.Unix(0, 1234+2))
value.chain.assertFailed(t)
value.chain.reset()
value.InRange(time.Unix(0, 1234-2), time.Unix(0, 1234-1))
value.chain.assertFailed(t)
value.chain.reset()
value.InRange(time.Unix(0, 1234+1), time.Unix(0, 1234-1))
value.chain.assertFailed(t)
value.chain.reset()
}

376
vendor/github.com/gavv/httpexpect/expect.go generated vendored Normal file
View File

@ -0,0 +1,376 @@
// 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"
"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)
}
// 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
// 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, Binder, and FastBinder implement this interface.
type Client interface {
// Do sends request and returns response.
Do(*http.Request) (*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)
}
// 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(),
// }
//
// 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(),
}
}
return &Expect{
config: config,
builders: nil,
}
}
// 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
}
// 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)
}
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)
}

866
vendor/github.com/gavv/httpexpect/expect_test.go generated vendored Normal file
View File

@ -0,0 +1,866 @@
package httpexpect
import (
"bufio"
"crypto/tls"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
)
func TestExpectMethods(t *testing.T) {
client := &mockClient{}
reporter := NewAssertReporter(t)
config := Config{
BaseURL: "http://example.com",
Client: client,
Reporter: reporter,
}
var reqs [8]*Request
e := WithConfig(config)
reqs[0] = e.Request("METHOD", "/url")
reqs[1] = e.OPTIONS("/url")
reqs[2] = e.HEAD("/url")
reqs[3] = e.GET("/url")
reqs[4] = e.POST("/url")
reqs[5] = e.PUT("/url")
reqs[6] = e.PATCH("/url")
reqs[7] = e.DELETE("/url")
assert.Equal(t, "METHOD", reqs[0].http.Method)
assert.Equal(t, "OPTIONS", reqs[1].http.Method)
assert.Equal(t, "HEAD", reqs[2].http.Method)
assert.Equal(t, "GET", reqs[3].http.Method)
assert.Equal(t, "POST", reqs[4].http.Method)
assert.Equal(t, "PUT", reqs[5].http.Method)
assert.Equal(t, "PATCH", reqs[6].http.Method)
assert.Equal(t, "DELETE", reqs[7].http.Method)
}
func TestExpectBuilders(t *testing.T) {
client := &mockClient{}
reporter := NewAssertReporter(t)
config := Config{
Client: client,
Reporter: reporter,
}
e := WithConfig(config)
var reqs1 []*Request
e1 := e.Builder(func(r *Request) {
reqs1 = append(reqs1, r)
})
var reqs2 []*Request
e2 := e1.Builder(func(r *Request) {
reqs2 = append(reqs2, r)
})
e.Request("METHOD", "/url")
r1 := e1.Request("METHOD", "/url")
r2 := e2.Request("METHOD", "/url")
assert.Equal(t, 2, int(len(reqs1)))
assert.Equal(t, 1, int(len(reqs2)))
assert.Equal(t, r1, reqs1[0])
assert.Equal(t, r2, reqs1[1])
assert.Equal(t, r1, reqs2[0])
}
func TestExpectValues(t *testing.T) {
client := &mockClient{}
r := NewAssertReporter(t)
config := Config{
Client: client,
Reporter: r,
}
e := WithConfig(config)
m := map[string]interface{}{}
a := []interface{}{}
s := ""
n := 0.0
b := false
assert.Equal(t, NewValue(r, m), e.Value(m))
assert.Equal(t, NewObject(r, m), e.Object(m))
assert.Equal(t, NewArray(r, a), e.Array(a))
assert.Equal(t, NewString(r, s), e.String(s))
assert.Equal(t, NewNumber(r, n), e.Number(n))
assert.Equal(t, NewBoolean(r, b), e.Boolean(b))
}
func TestExpectTraverse(t *testing.T) {
client := &mockClient{}
reporter := NewAssertReporter(t)
config := Config{
BaseURL: "http://example.com",
Client: client,
Reporter: reporter,
}
data := map[string]interface{}{
"foo": []interface{}{"bar", 123, false, nil},
"bar": "hello",
"baz": 456,
}
resp := WithConfig(config).GET("/url").WithJSON(data).Expect()
m := resp.JSON().Object()
m.Equal(data)
m.ContainsKey("foo")
m.ContainsKey("bar")
m.ContainsKey("foo")
m.ValueEqual("foo", data["foo"])
m.ValueEqual("bar", data["bar"])
m.ValueEqual("baz", data["baz"])
m.Keys().ContainsOnly("foo", "bar", "baz")
m.Values().ContainsOnly(data["foo"], data["bar"], data["baz"])
m.Value("foo").Array().Elements("bar", 123, false, nil)
m.Value("bar").String().Equal("hello")
m.Value("baz").Number().Equal(456)
m.Value("foo").Array().Element(2).Boolean().False()
m.Value("foo").Array().Element(3).Null()
}
func TestExpectBranches(t *testing.T) {
client := &mockClient{}
config := Config{
BaseURL: "http://example.com",
Client: client,
Reporter: newMockReporter(t),
}
data := map[string]interface{}{
"foo": []interface{}{"bar", 123, false, nil},
"bar": "hello",
"baz": 456,
}
resp := WithConfig(config).GET("/url").WithJSON(data).Expect()
m1 := resp.JSON().Array()
m2 := resp.JSON().Object()
e1 := m2.Value("foo").Object()
e2 := m2.Value("foo").Array().Element(999).String()
e3 := m2.Value("foo").Array().Element(0).Number()
e4 := m2.Value("foo").Array().Element(0).String()
e4.Equal("bar")
m1.chain.assertFailed(t)
m2.chain.assertOK(t)
e1.chain.assertFailed(t)
e2.chain.assertFailed(t)
e3.chain.assertFailed(t)
e4.chain.assertOK(t)
}
func TestExpectStdCompat(_ *testing.T) {
New(&testing.T{}, "")
New(&testing.B{}, "")
New(testing.TB(&testing.T{}), "")
}
type testRequestFactory struct {
lastreq *http.Request
fail bool
}
func (f *testRequestFactory) NewRequest(
method, urlStr string, body io.Reader) (*http.Request, error) {
if f.fail {
return nil, errors.New("testRequestFactory")
}
f.lastreq = httptest.NewRequest(method, urlStr, body)
return f.lastreq, nil
}
func TestExpectRequestFactory(t *testing.T) {
e1 := WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
})
r1 := e1.Request("GET", "/")
r1.chain.assertOK(t)
assert.NotNil(t, r1.http)
f2 := &testRequestFactory{}
e2 := WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
RequestFactory: f2,
})
r2 := e2.Request("GET", "/")
r2.chain.assertOK(t)
assert.NotNil(t, f2.lastreq)
assert.True(t, f2.lastreq == r2.http)
f3 := &testRequestFactory{
fail: true,
}
e3 := WithConfig(Config{
BaseURL: "http://example.com",
Reporter: newMockReporter(t),
RequestFactory: f3,
})
r3 := e3.Request("GET", "/")
r3.chain.assertFailed(t)
assert.Nil(t, f3.lastreq)
}
func createBasicHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/foo", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"foo":123}`))
})
mux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
w.Write([]byte(`field1=` + r.FormValue("field1")))
w.Write([]byte(`&field2=` + r.PostFormValue("field2")))
})
mux.HandleFunc("/baz/qux", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`[true, false]`))
case "PUT":
decoder := json.NewDecoder(r.Body)
var m map[string]interface{}
if err := decoder.Decode(&m); err != nil {
w.WriteHeader(http.StatusBadRequest)
} else if m["test"] != "ok" {
w.WriteHeader(http.StatusBadRequest)
} else {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`ok`))
}
}
})
mux.HandleFunc("/wee", func(w http.ResponseWriter, r *http.Request) {
if u, p, ok := r.BasicAuth(); ok {
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
w.Write([]byte(`username=` + u))
w.Write([]byte(`&password=` + p))
} else {
w.WriteHeader(http.StatusBadRequest)
}
})
return mux
}
func testBasicHandler(e *Expect) {
e.GET("/foo")
e.GET("/foo").Expect()
e.GET("/foo").Expect().Status(http.StatusOK)
e.GET("/foo").Expect().
Status(http.StatusOK).JSON().Object().ValueEqual("foo", 123)
e.PUT("/bar").WithQuery("field1", "hello").WithFormField("field2", "world").
Expect().
Status(http.StatusOK).
Form().ValueEqual("field1", "hello").ValueEqual("field2", "world")
e.GET("/{a}/{b}", "baz", "qux").
Expect().
Status(http.StatusOK).JSON().Array().Elements(true, false)
e.PUT("/{a}/{b}").
WithPath("a", "baz").
WithPath("b", "qux").
WithJSON(map[string]string{"test": "ok"}).
Expect().
Status(http.StatusOK).Body().Equal("ok")
auth := e.Builder(func(req *Request) {
req.WithBasicAuth("john", "secret")
})
auth.PUT("/wee").
Expect().
Status(http.StatusOK).
Form().ValueEqual("username", "john").ValueEqual("password", "secret")
}
func TestExpectBasicHandlerLiveDefault(t *testing.T) {
handler := createBasicHandler()
server := httptest.NewServer(handler)
defer server.Close()
testBasicHandler(New(t, server.URL))
}
func TestExpectBasicHandlerLiveConfig(t *testing.T) {
handler := createBasicHandler()
server := httptest.NewServer(handler)
defer server.Close()
testBasicHandler(WithConfig(Config{
BaseURL: server.URL,
Reporter: NewAssertReporter(t),
Printers: []Printer{
NewCurlPrinter(t),
NewDebugPrinter(t, true),
},
}))
}
func TestExpectBasicHandlerLiveTLS(t *testing.T) {
handler := createBasicHandler()
server := httptest.NewTLSServer(handler)
defer server.Close()
testBasicHandler(WithConfig(Config{
BaseURL: server.URL,
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
},
}))
}
func TestExpectBasicHandlerLiveLongRun(t *testing.T) {
if testing.Short() {
return
}
handler := createBasicHandler()
server := httptest.NewServer(handler)
defer server.Close()
e := New(t, server.URL)
for i := 0; i < 2; i++ {
testBasicHandler(e)
}
}
func TestExpectBasicHandlerBinderStandard(t *testing.T) {
handler := createBasicHandler()
testBasicHandler(WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewBinder(handler),
},
}))
}
func TestExpectBasicHandlerBinderFast(t *testing.T) {
handler := fasthttpadaptor.NewFastHTTPHandler(createBasicHandler())
testBasicHandler(WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewFastBinder(handler),
},
}))
}
func createRedirectHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/foo", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte(`hello`))
})
mux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/foo", http.StatusFound)
})
return mux
}
func createRedirectFastHandler() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
switch string(ctx.Path()) {
case "/foo":
ctx.SetBody([]byte(`hello`))
case "/bar":
ctx.Redirect("/foo", http.StatusFound)
}
}
}
func testRedirectHandler(e *Expect) {
e.POST("/bar").
Expect().
Status(http.StatusOK).Body().Equal(`hello`)
}
func TestExpectRedirectHandlerLive(t *testing.T) {
handler := createRedirectHandler()
server := httptest.NewServer(handler)
defer server.Close()
testRedirectHandler(New(t, server.URL))
}
func TestExpectRedirectHandlerBinderStandard(t *testing.T) {
handler := createRedirectHandler()
testRedirectHandler(WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewBinder(handler),
},
}))
}
func TestExpectRedirectHandlerBinderFast(t *testing.T) {
handler := createRedirectFastHandler()
testRedirectHandler(WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewFastBinder(handler),
},
}))
}
func createAutoTLSHandler(https string) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/tls", func(w http.ResponseWriter, r *http.Request) {
if r.TLS == nil {
w.Write([]byte(`no`))
} else {
w.Write([]byte(`yes`))
}
})
mux.HandleFunc("/protected", func(w http.ResponseWriter, r *http.Request) {
if r.TLS == nil {
http.Redirect(w, r, https+r.RequestURI, http.StatusFound)
} else {
w.Write([]byte(`hello`))
}
})
return mux
}
func createAutoTLSFastHandler(https string) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
switch string(ctx.Path()) {
case "/tls":
if !ctx.IsTLS() {
ctx.SetBody([]byte(`no`))
} else {
ctx.SetBody([]byte(`yes`))
}
case "/protected":
if !ctx.IsTLS() {
ctx.Redirect(https+string(ctx.Request.RequestURI()), http.StatusFound)
} else {
ctx.SetBody([]byte(`hello`))
}
}
}
}
func testAutoTLSHandler(config Config) {
e := WithConfig(config)
tls := e.POST("/tls").
Expect().
Status(http.StatusOK).Body()
if strings.HasPrefix(config.BaseURL, "https://") {
tls.Equal(`yes`)
} else {
tls.Equal(`no`)
}
e.POST("/protected").
Expect().
Status(http.StatusOK).Body().Equal(`hello`)
}
func TestExpectAutoTLSHandlerLive(t *testing.T) {
httpsServ := httptest.NewTLSServer(createAutoTLSHandler(""))
defer httpsServ.Close()
httpServ := httptest.NewServer(createAutoTLSHandler(httpsServ.URL))
defer httpServ.Close()
assert.True(t, strings.HasPrefix(httpsServ.URL, "https://"))
assert.True(t, strings.HasPrefix(httpServ.URL, "http://"))
for _, url := range []string{httpsServ.URL, httpServ.URL} {
testAutoTLSHandler(Config{
BaseURL: url,
Reporter: NewRequireReporter(t),
Printers: []Printer{
NewDebugPrinter(t, true),
},
Client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
},
})
}
}
func TestExpectAutoTLSHandlerBinderStandard(t *testing.T) {
handler := createAutoTLSHandler("https://example.com")
for _, url := range []string{"https://example.com", "http://example.com"} {
testAutoTLSHandler(Config{
BaseURL: url,
Reporter: NewRequireReporter(t),
Printers: []Printer{
NewDebugPrinter(t, true),
},
Client: &http.Client{
Transport: &Binder{
Handler: handler,
TLS: &tls.ConnectionState{},
},
},
})
}
}
func TestExpectAutoTLSHandlerBinderFast(t *testing.T) {
handler := createAutoTLSFastHandler("https://example.com")
for _, url := range []string{"https://example.com", "http://example.com"} {
testAutoTLSHandler(Config{
BaseURL: url,
Reporter: NewRequireReporter(t),
Printers: []Printer{
NewDebugPrinter(t, true),
},
Client: &http.Client{
Transport: &FastBinder{
Handler: handler,
TLS: &tls.ConnectionState{},
},
},
})
}
}
func createChunkedHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.Proto != "HTTP/1.1" {
w.WriteHeader(http.StatusBadRequest)
} else if len(r.TransferEncoding) != 1 || r.TransferEncoding[0] != "chunked" {
w.WriteHeader(http.StatusBadRequest)
} else if r.PostFormValue("key") != "value" {
w.WriteHeader(http.StatusBadRequest)
} else {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`[1, `))
w.(http.Flusher).Flush()
w.Write([]byte(`2]`))
}
})
return mux
}
func createChunkedFastHandler(t *testing.T) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
headers := map[string][]string{}
ctx.Request.Header.VisitAll(func(k, v []byte) {
headers[string(k)] = append(headers[string(k)], string(v))
})
assert.Equal(t, []string{"chunked"}, headers["Transfer-Encoding"])
assert.Equal(t, "value", string(ctx.FormValue("key")))
assert.Equal(t, "key=value", string(ctx.Request.Body()))
ctx.Response.Header.Set("Content-Type", "application/json")
ctx.Response.SetBodyStreamWriter(func(w *bufio.Writer) {
w.WriteString(`[1, `)
w.Flush()
w.WriteString(`2]`)
})
}
}
func testChunkedHandler(e *Expect) {
e.PUT("/").
WithHeader("Content-Type", "application/x-www-form-urlencoded").
WithChunked(strings.NewReader("key=value")).
Expect().
Status(http.StatusOK).
ContentType("application/json").
TransferEncoding("chunked").
JSON().Array().Elements(1, 2)
}
func TestExpectChunkedHandlerLive(t *testing.T) {
handler := createChunkedHandler()
server := httptest.NewServer(handler)
defer server.Close()
testChunkedHandler(New(t, server.URL))
}
func TestExpectChunkedHandlerBinderStandard(t *testing.T) {
handler := createChunkedHandler()
testChunkedHandler(WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewBinder(handler),
},
}))
}
func TestExpectChunkedHandlerBinderFast(t *testing.T) {
handler := createChunkedFastHandler(t)
testChunkedHandler(WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewFastBinder(handler),
},
}))
}
func createCookieHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{
Name: "myname",
Value: "myvalue",
Path: "/",
Expires: time.Date(3000, 0, 0, 0, 0, 0, 0, time.UTC),
})
w.WriteHeader(http.StatusNoContent)
})
mux.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("myname")
if err != nil {
w.WriteHeader(http.StatusBadRequest)
} else {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte(cookie.Value))
}
})
return mux
}
func testCookieHandler(e *Expect, enabled bool) {
r := e.PUT("/set").Expect().Status(http.StatusNoContent)
r.Cookies().ContainsOnly("myname")
c := r.Cookie("myname")
c.Value().Equal("myvalue")
c.Path().Equal("/")
c.Expires().Equal(time.Date(3000, 0, 0, 0, 0, 0, 0, time.UTC))
if enabled {
e.GET("/get").Expect().Status(http.StatusOK).Text().Equal("myvalue")
} else {
e.GET("/get").Expect().Status(http.StatusBadRequest)
}
}
func TestExpectCookieHandlerLiveDisabled(t *testing.T) {
handler := createCookieHandler()
server := httptest.NewServer(handler)
defer server.Close()
e := WithConfig(Config{
BaseURL: server.URL,
Reporter: NewAssertReporter(t),
Client: &http.Client{
Jar: nil,
},
})
testCookieHandler(e, false)
}
func TestExpecCookieHandlerLiveEnabled(t *testing.T) {
handler := createCookieHandler()
server := httptest.NewServer(handler)
defer server.Close()
e := WithConfig(Config{
BaseURL: server.URL,
Reporter: NewAssertReporter(t),
Client: &http.Client{
Jar: NewJar(),
},
})
testCookieHandler(e, true)
}
func TestExpectCookieHandlerBinderStandardDisabled(t *testing.T) {
handler := createCookieHandler()
e := WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewBinder(handler),
Jar: nil,
},
})
testCookieHandler(e, false)
}
func TestExpectCookieHandlerBinderStandardEnabled(t *testing.T) {
handler := createCookieHandler()
e := WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewBinder(handler),
Jar: NewJar(),
},
})
testCookieHandler(e, true)
}
func TestExpectCookieHandlerBinderFastDisabled(t *testing.T) {
handler := fasthttpadaptor.NewFastHTTPHandler(createCookieHandler())
e := WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewFastBinder(handler),
Jar: nil,
},
})
testCookieHandler(e, false)
}
func TestExpectCookieHandlerBinderFastEnabled(t *testing.T) {
handler := fasthttpadaptor.NewFastHTTPHandler(createCookieHandler())
e := WithConfig(Config{
BaseURL: "http://example.com",
Reporter: NewAssertReporter(t),
Client: &http.Client{
Transport: NewFastBinder(handler),
Jar: NewJar(),
},
})
testCookieHandler(e, true)
}
func TestExpectStaticFastBinder(t *testing.T) {
tempdir, err := ioutil.TempDir("", "httpexpect")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempdir)
if err := ioutil.WriteFile(
path.Join(tempdir, "hello"), []byte("hello, world!"), 0666); err != nil {
t.Fatal(err)
}
fs := &fasthttp.FS{
Root: tempdir,
}
handler := fs.NewRequestHandler()
e := WithConfig(Config{
Client: &http.Client{
Transport: NewFastBinder(handler),
Jar: NewJar(),
},
Reporter: NewAssertReporter(t),
Printers: []Printer{
NewDebugPrinter(t, true),
},
})
e.GET("/hello").
Expect().
Status(http.StatusOK).
Text().Equal("hello, world!")
}

184
vendor/github.com/gavv/httpexpect/helpers.go generated vendored Normal file
View 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
}

137
vendor/github.com/gavv/httpexpect/helpers_test.go generated vendored Normal file
View File

@ -0,0 +1,137 @@
package httpexpect
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCanonNumber(t *testing.T) {
type (
myInt int
)
chain := makeChain(newMockReporter(t))
d1, ok := canonNumber(&chain, 123)
assert.True(t, ok)
assert.Equal(t, 123.0, d1)
chain.assertOK(t)
chain.reset()
d2, ok := canonNumber(&chain, 123.0)
assert.True(t, ok)
assert.Equal(t, 123.0, d2)
chain.assertOK(t)
chain.reset()
d3, ok := canonNumber(&chain, myInt(123))
assert.True(t, ok)
assert.Equal(t, 123.0, d3)
chain.assertOK(t)
chain.reset()
_, ok = canonNumber(&chain, "123")
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
_, ok = canonNumber(&chain, nil)
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
}
func TestCanonArray(t *testing.T) {
type (
myArray []interface{}
myInt int
)
chain := makeChain(newMockReporter(t))
d1, ok := canonArray(&chain, []interface{}{123.0, 456.0})
assert.True(t, ok)
assert.Equal(t, []interface{}{123.0, 456.0}, d1)
chain.assertOK(t)
chain.reset()
d2, ok := canonArray(&chain, myArray{myInt(123), 456.0})
assert.True(t, ok)
assert.Equal(t, []interface{}{123.0, 456.0}, d2)
chain.assertOK(t)
chain.reset()
_, ok = canonArray(&chain, "123")
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
_, ok = canonArray(&chain, func() {})
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
_, ok = canonArray(&chain, nil)
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
_, ok = canonArray(&chain, []interface{}(nil))
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
}
func TestCanonMap(t *testing.T) {
type (
myMap map[string]interface{}
myInt int
)
chain := makeChain(newMockReporter(t))
d1, ok := canonMap(&chain, map[string]interface{}{"foo": 123.0})
assert.True(t, ok)
assert.Equal(t, map[string]interface{}{"foo": 123.0}, d1)
chain.assertOK(t)
chain.reset()
d2, ok := canonMap(&chain, myMap{"foo": myInt(123)})
assert.True(t, ok)
assert.Equal(t, map[string]interface{}{"foo": 123.0}, d2)
chain.assertOK(t)
chain.reset()
_, ok = canonMap(&chain, "123")
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
_, ok = canonMap(&chain, func() {})
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
_, ok = canonMap(&chain, nil)
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
_, ok = canonMap(&chain, map[string]interface{}(nil))
assert.False(t, ok)
chain.assertFailed(t)
chain.reset()
}
func TestDiffErrors(t *testing.T) {
na := " (unavailable)"
assert.Equal(t, na, diffValues(map[string]interface{}{}, []interface{}{}))
assert.Equal(t, na, diffValues([]interface{}{}, map[string]interface{}{}))
assert.Equal(t, na, diffValues("foo", "bar"))
assert.Equal(t, na, diffValues(func() {}, func() {}))
assert.NotEqual(t, na, diffValues(map[string]interface{}{}, map[string]interface{}{}))
assert.NotEqual(t, na, diffValues([]interface{}{}, []interface{}{}))
}

198
vendor/github.com/gavv/httpexpect/match.go generated vendored Normal file
View 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{}
}

173
vendor/github.com/gavv/httpexpect/match_test.go generated vendored Normal file
View File

@ -0,0 +1,173 @@
package httpexpect
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestMatchFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &Match{chain, nil, nil}
value.chain.assertFailed(t)
assert.False(t, value.Length() == nil)
assert.False(t, value.Index(0) == nil)
assert.False(t, value.Name("") == nil)
value.Length().chain.assertFailed(t)
value.Index(0).chain.assertFailed(t)
value.Name("").chain.assertFailed(t)
value.Empty()
value.NotEmpty()
value.Values("")
value.NotValues("")
}
func TestMatchGetters(t *testing.T) {
reporter := newMockReporter(t)
matches := []string{"m0", "m1", "m2"}
names := []string{"", "n1", "n2"}
value := NewMatch(reporter, matches, names)
assert.Equal(t, matches, value.Raw())
assert.Equal(t, 3.0, value.Length().Raw())
assert.Equal(t, "m0", value.Index(0).Raw())
assert.Equal(t, "m1", value.Index(1).Raw())
assert.Equal(t, "m2", value.Index(2).Raw())
value.chain.assertOK(t)
assert.Equal(t, "m1", value.Name("n1").Raw())
assert.Equal(t, "m2", value.Name("n2").Raw())
value.chain.assertOK(t)
assert.Equal(t, "", value.Index(-1).Raw())
value.chain.assertFailed(t)
value.chain.reset()
assert.Equal(t, "", value.Index(3).Raw())
value.chain.assertFailed(t)
value.chain.reset()
assert.Equal(t, "", value.Name("").Raw())
value.chain.assertFailed(t)
value.chain.reset()
assert.Equal(t, "", value.Name("bad").Raw())
value.chain.assertFailed(t)
value.chain.reset()
}
func TestMatchEmpty(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewMatch(reporter, []string{"m"}, nil)
value2 := NewMatch(reporter, []string{}, nil)
value3 := NewMatch(reporter, nil, nil)
assert.Equal(t, []string{}, value2.Raw())
assert.Equal(t, []string{}, value3.Raw())
value1.Empty()
value1.chain.assertFailed(t)
value1.chain.reset()
value1.NotEmpty()
value1.chain.assertOK(t)
value1.chain.reset()
value2.Empty()
value2.chain.assertOK(t)
value2.chain.reset()
value2.NotEmpty()
value2.chain.assertFailed(t)
value2.chain.reset()
value3.Empty()
value3.chain.assertOK(t)
value3.chain.reset()
value3.NotEmpty()
value3.chain.assertFailed(t)
value3.chain.reset()
}
func TestMatchValues(t *testing.T) {
reporter := newMockReporter(t)
value := NewMatch(reporter, []string{"m0", "m1", "m2"}, nil)
value.Values("m1", "m2")
value.chain.assertOK(t)
value.chain.reset()
value.Values("m2", "m1")
value.chain.assertFailed(t)
value.chain.reset()
value.Values("m1")
value.chain.assertFailed(t)
value.chain.reset()
value.Values()
value.chain.assertFailed(t)
value.chain.reset()
value.NotValues("m1", "m2")
value.chain.assertFailed(t)
value.chain.reset()
value.NotValues("m2", "m1")
value.chain.assertOK(t)
value.chain.reset()
value.NotValues("m1")
value.chain.assertOK(t)
value.chain.reset()
value.NotValues()
value.chain.assertOK(t)
value.chain.reset()
}
func TestMatchValuesEmpty(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewMatch(reporter, nil, nil)
value2 := NewMatch(reporter, []string{}, nil)
value3 := NewMatch(reporter, []string{"m0"}, nil)
value1.Values()
value1.chain.assertOK(t)
value1.chain.reset()
value1.Values("")
value1.chain.assertFailed(t)
value1.chain.reset()
value2.Values()
value2.chain.assertOK(t)
value2.chain.reset()
value2.Values("")
value2.chain.assertFailed(t)
value2.chain.reset()
value3.Values()
value3.chain.assertOK(t)
value3.chain.reset()
value3.Values("m0")
value3.chain.assertFailed(t)
value3.chain.reset()
}

36
vendor/github.com/gavv/httpexpect/mocks_test.go generated vendored Normal file
View File

@ -0,0 +1,36 @@
package httpexpect
import (
"net/http"
"testing"
)
type mockClient struct {
req *http.Request
resp http.Response
err error
}
func (c *mockClient) Do(req *http.Request) (*http.Response, error) {
c.req = req
if c.err == nil {
c.resp.Header = c.req.Header
c.resp.Body = c.req.Body
return &c.resp, nil
}
return nil, c.err
}
type mockReporter struct {
testing *testing.T
reported bool
}
func newMockReporter(t *testing.T) *mockReporter {
return &mockReporter{t, false}
}
func (r *mockReporter) Errorf(message string, args ...interface{}) {
r.testing.Logf("Fail: "+message, args...)
r.reported = true
}

244
vendor/github.com/gavv/httpexpect/number.go generated vendored Normal file
View 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
}

339
vendor/github.com/gavv/httpexpect/number_test.go generated vendored Normal file
View File

@ -0,0 +1,339 @@
package httpexpect
import (
"math"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNumberFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &Number{chain, 0}
value.chain.assertFailed(t)
value.Path("$").chain.assertFailed(t)
value.Schema("")
value.Equal(0)
value.NotEqual(0)
value.Gt(0)
value.Ge(0)
value.Lt(0)
value.Le(0)
value.InRange(0, 0)
}
func TestNumberGetters(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 123.0)
assert.Equal(t, 123.0, value.Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, 123.0, value.Path("$").Raw())
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "number"}`)
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "object"}`)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberEqual(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
assert.Equal(t, 1234, int(value.Raw()))
value.Equal(1234)
value.chain.assertOK(t)
value.chain.reset()
value.Equal(4321)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(4321)
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(1234)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberEqualDelta(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234.5)
value.EqualDelta(1234.3, 0.3)
value.chain.assertOK(t)
value.chain.reset()
value.EqualDelta(1234.7, 0.3)
value.chain.assertOK(t)
value.chain.reset()
value.EqualDelta(1234.3, 0.1)
value.chain.assertFailed(t)
value.chain.reset()
value.EqualDelta(1234.7, 0.1)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqualDelta(1234.3, 0.3)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqualDelta(1234.7, 0.3)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqualDelta(1234.3, 0.1)
value.chain.assertOK(t)
value.chain.reset()
value.NotEqualDelta(1234.7, 0.1)
value.chain.assertOK(t)
value.chain.reset()
}
func TestNumberEqualNaN(t *testing.T) {
reporter := newMockReporter(t)
v1 := NewNumber(reporter, math.NaN())
v1.Equal(1234.5)
v1.chain.assertFailed(t)
v2 := NewNumber(reporter, 1234.5)
v2.Equal(math.NaN())
v2.chain.assertFailed(t)
v3 := NewNumber(reporter, math.NaN())
v3.EqualDelta(1234.0, 0.1)
v3.chain.assertFailed(t)
v4 := NewNumber(reporter, 1234.5)
v4.EqualDelta(math.NaN(), 0.1)
v4.chain.assertFailed(t)
v5 := NewNumber(reporter, 1234.5)
v5.EqualDelta(1234.5, math.NaN())
v5.chain.assertFailed(t)
v6 := NewNumber(reporter, math.NaN())
v6.NotEqualDelta(1234.0, 0.1)
v6.chain.assertFailed(t)
v7 := NewNumber(reporter, 1234.5)
v7.NotEqualDelta(math.NaN(), 0.1)
v7.chain.assertFailed(t)
v8 := NewNumber(reporter, 1234.5)
v8.NotEqualDelta(1234.5, math.NaN())
v8.chain.assertFailed(t)
}
func TestNumberGreater(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
value.Gt(1234 - 1)
value.chain.assertOK(t)
value.chain.reset()
value.Gt(1234)
value.chain.assertFailed(t)
value.chain.reset()
value.Ge(1234 - 1)
value.chain.assertOK(t)
value.chain.reset()
value.Ge(1234)
value.chain.assertOK(t)
value.chain.reset()
value.Ge(1234 + 1)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberLesser(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
value.Lt(1234 + 1)
value.chain.assertOK(t)
value.chain.reset()
value.Lt(1234)
value.chain.assertFailed(t)
value.chain.reset()
value.Le(1234 + 1)
value.chain.assertOK(t)
value.chain.reset()
value.Le(1234)
value.chain.assertOK(t)
value.chain.reset()
value.Le(1234 - 1)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberInRange(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
value.InRange(1234, 1234)
value.chain.assertOK(t)
value.chain.reset()
value.InRange(1234-1, 1234)
value.chain.assertOK(t)
value.chain.reset()
value.InRange(1234, 1234+1)
value.chain.assertOK(t)
value.chain.reset()
value.InRange(1234+1, 1234+2)
value.chain.assertFailed(t)
value.chain.reset()
value.InRange(1234-2, 1234-1)
value.chain.assertFailed(t)
value.chain.reset()
value.InRange(1234+1, 1234-1)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberConvertEqual(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
value.Equal(int64(1234))
value.chain.assertOK(t)
value.chain.reset()
value.Equal(float32(1234))
value.chain.assertOK(t)
value.chain.reset()
value.Equal("1234")
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(int64(4321))
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(float32(4321))
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual("4321")
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberConvertGreater(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
value.Gt(int64(1233))
value.chain.assertOK(t)
value.chain.reset()
value.Gt(float32(1233))
value.chain.assertOK(t)
value.chain.reset()
value.Gt("1233")
value.chain.assertFailed(t)
value.chain.reset()
value.Ge(int64(1233))
value.chain.assertOK(t)
value.chain.reset()
value.Ge(float32(1233))
value.chain.assertOK(t)
value.chain.reset()
value.Ge("1233")
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberConvertLesser(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
value.Lt(int64(1235))
value.chain.assertOK(t)
value.chain.reset()
value.Lt(float32(1235))
value.chain.assertOK(t)
value.chain.reset()
value.Lt("1235")
value.chain.assertFailed(t)
value.chain.reset()
value.Le(int64(1235))
value.chain.assertOK(t)
value.chain.reset()
value.Le(float32(1235))
value.chain.assertOK(t)
value.chain.reset()
value.Le("1235")
value.chain.assertFailed(t)
value.chain.reset()
}
func TestNumberConvertInRange(t *testing.T) {
reporter := newMockReporter(t)
value := NewNumber(reporter, 1234)
value.InRange(int64(1233), float32(1235))
value.chain.assertOK(t)
value.chain.reset()
value.InRange(int64(1233), "1235")
value.chain.assertFailed(t)
value.chain.reset()
value.InRange(nil, 1235)
value.chain.assertFailed(t)
value.chain.reset()
}

329
vendor/github.com/gavv/httpexpect/object.go generated vendored Normal file
View 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 another object.
// Before comparison, both objects are converted to canonical form.
//
// value should 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 another object.
// Before comparison, both objects are converted to canonical form.
//
// value should 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 sub-object.
// Before comparison, both objects are converted to canonical form.
//
// value should 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 sub-object exactly.
// Before comparison, both objects are converted to canonical form.
//
// value should 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 value.
// Before comparison, both values are converted to canonical form.
//
// value should 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 value.
// Before comparison, both values are converted to canonical form.
//
// value should 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
}

655
vendor/github.com/gavv/httpexpect/object_test.go generated vendored Normal file
View File

@ -0,0 +1,655 @@
package httpexpect
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestObjectFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &Object{chain, nil}
value.chain.assertFailed(t)
value.Path("$").chain.assertFailed(t)
value.Schema("")
assert.False(t, value.Keys() == nil)
assert.False(t, value.Values() == nil)
assert.False(t, value.Value("foo") == nil)
value.Keys().chain.assertFailed(t)
value.Values().chain.assertFailed(t)
value.Value("foo").chain.assertFailed(t)
value.Empty()
value.NotEmpty()
value.Equal(nil)
value.NotEqual(nil)
value.ContainsKey("foo")
value.NotContainsKey("foo")
value.ContainsMap(nil)
value.NotContainsMap(nil)
value.ValueEqual("foo", nil)
value.ValueNotEqual("foo", nil)
}
func TestObjectGetters(t *testing.T) {
reporter := newMockReporter(t)
m := map[string]interface{}{
"foo": 123.0,
"bar": []interface{}{"456", 789.0},
"baz": map[string]interface{}{
"a": "b",
},
}
value := NewObject(reporter, m)
keys := []interface{}{"foo", "bar", "baz"}
values := []interface{}{
123.0,
[]interface{}{"456", 789.0},
map[string]interface{}{
"a": "b",
},
}
assert.Equal(t, m, value.Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, m, value.Path("$").Raw())
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "object"}`)
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "array"}`)
value.chain.assertFailed(t)
value.chain.reset()
value.Keys().ContainsOnly(keys...)
value.chain.assertOK(t)
value.chain.reset()
value.Values().ContainsOnly(values...)
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, m["foo"], value.Value("foo").Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, m["bar"], value.Value("bar").Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, m["baz"], value.Value("baz").Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, nil, value.Value("BAZ").Raw())
value.chain.assertFailed(t)
value.chain.reset()
}
func TestObjectEmpty(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewObject(reporter, nil)
_ = value1
value1.chain.assertFailed(t)
value1.chain.reset()
value2 := NewObject(reporter, map[string]interface{}{})
value2.Empty()
value2.chain.assertOK(t)
value2.chain.reset()
value2.NotEmpty()
value2.chain.assertFailed(t)
value2.chain.reset()
value3 := NewObject(reporter, map[string]interface{}{"": nil})
value3.Empty()
value3.chain.assertFailed(t)
value3.chain.reset()
value3.NotEmpty()
value3.chain.assertOK(t)
value3.chain.reset()
}
func TestObjectEqualEmpty(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{})
assert.Equal(t, map[string]interface{}{}, value.Raw())
value.Equal(map[string]interface{}{})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{})
value.chain.assertFailed(t)
value.chain.reset()
value.Equal(map[string]interface{}{"": nil})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{"": nil})
value.chain.assertOK(t)
value.chain.reset()
}
func TestObjectEqual(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{"foo": 123.0})
assert.Equal(t, map[string]interface{}{"foo": 123.0}, value.Raw())
value.Equal(map[string]interface{}{})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{})
value.chain.assertOK(t)
value.chain.reset()
value.Equal(map[string]interface{}{"FOO": 123.0})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{"FOO": 123.0})
value.chain.assertOK(t)
value.chain.reset()
value.Equal(map[string]interface{}{"foo": 456.0})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{"foo": 456.0})
value.chain.assertOK(t)
value.chain.reset()
value.Equal(map[string]interface{}{"foo": 123.0})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{"foo": 123.0})
value.chain.assertFailed(t)
value.chain.reset()
value.Equal(nil)
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(nil)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestObjectEqualStruct(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": map[string]interface{}{
"baz": []interface{}{true, false},
},
})
type (
Bar struct {
Baz []bool `json:"baz"`
}
S struct {
Foo int `json:"foo"`
Bar Bar `json:"bar"`
}
)
s := S{
Foo: 123,
Bar: Bar{
Baz: []bool{true, false},
},
}
value.Equal(s)
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(s)
value.chain.assertFailed(t)
value.chain.reset()
value.Equal(S{})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(S{})
value.chain.assertOK(t)
value.chain.reset()
}
func TestObjectContainsKey(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{"foo": 123, "bar": ""})
value.ContainsKey("foo")
value.chain.assertOK(t)
value.chain.reset()
value.NotContainsKey("foo")
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsKey("bar")
value.chain.assertOK(t)
value.chain.reset()
value.NotContainsKey("bar")
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsKey("BAR")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsKey("BAR")
value.chain.assertOK(t)
value.chain.reset()
}
func TestObjectContainsMapSuccess(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": map[string]interface{}{
"b": 333,
"c": 444,
},
},
})
submap1 := map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
}
value.ContainsMap(submap1)
value.chain.assertOK(t)
value.chain.reset()
value.NotContainsMap(submap1)
value.chain.assertFailed(t)
value.chain.reset()
submap2 := map[string]interface{}{
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": map[string]interface{}{
"c": 444,
},
},
}
value.ContainsMap(submap2)
value.chain.assertOK(t)
value.chain.reset()
value.NotContainsMap(submap2)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestObjectContainsMapFailed(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": map[string]interface{}{
"b": 333,
"c": 444,
},
},
})
submap1 := map[string]interface{}{
"foo": 123,
"qux": 456,
}
value.ContainsMap(submap1)
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsMap(submap1)
value.chain.assertOK(t)
value.chain.reset()
submap2 := map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", "789"},
}
value.ContainsMap(submap2)
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsMap(submap2)
value.chain.assertOK(t)
value.chain.reset()
submap3 := map[string]interface{}{
"baz": map[string]interface{}{
"a": map[string]interface{}{
"b": "333",
"c": 444,
},
},
}
value.ContainsMap(submap3)
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsMap(submap3)
value.chain.assertOK(t)
value.chain.reset()
value.ContainsMap(nil)
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsMap(nil)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestObjectContainsMapStruct(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": map[string]interface{}{
"b": 333,
"c": 444,
},
},
})
type (
A struct {
B int `json:"b"`
}
Baz struct {
A A `json:"a"`
}
S struct {
Foo int `json:"foo"`
Baz Baz `json:"baz"`
}
)
submap := S{
Foo: 123,
Baz: Baz{
A: A{
B: 333,
},
},
}
value.ContainsMap(submap)
value.chain.assertOK(t)
value.chain.reset()
value.NotContainsMap(submap)
value.chain.assertFailed(t)
value.chain.reset()
value.ContainsMap(S{})
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsMap(S{})
value.chain.assertOK(t)
value.chain.reset()
}
func TestObjectValueEqual(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": "b",
},
})
value.ValueEqual("foo", 123)
value.chain.assertOK(t)
value.chain.reset()
value.ValueNotEqual("foo", 123)
value.chain.assertFailed(t)
value.chain.reset()
value.ValueEqual("bar", []interface{}{"456", 789})
value.chain.assertOK(t)
value.chain.reset()
value.ValueNotEqual("bar", []interface{}{"456", 789})
value.chain.assertFailed(t)
value.chain.reset()
value.ValueEqual("baz", map[string]interface{}{"a": "b"})
value.chain.assertOK(t)
value.chain.reset()
value.ValueNotEqual("baz", map[string]interface{}{"a": "b"})
value.chain.assertFailed(t)
value.chain.reset()
value.ValueEqual("baz", func() {})
value.chain.assertFailed(t)
value.chain.reset()
value.ValueNotEqual("baz", func() {})
value.chain.assertFailed(t)
value.chain.reset()
value.ValueEqual("BAZ", 777)
value.chain.assertFailed(t)
value.chain.reset()
value.ValueNotEqual("BAZ", 777)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestObjectValueEqualStruct(t *testing.T) {
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": map[string]interface{}{
"b": 333,
"c": 444,
},
},
})
type (
A struct {
B int `json:"b"`
C int `json:"c"`
}
Baz struct {
A A `json:"a"`
}
)
baz := Baz{
A: A{
B: 333,
C: 444,
},
}
value.ValueEqual("baz", baz)
value.chain.assertOK(t)
value.chain.reset()
value.ValueNotEqual("baz", baz)
value.chain.assertFailed(t)
value.chain.reset()
value.ValueEqual("baz", Baz{})
value.chain.assertFailed(t)
value.chain.reset()
value.ValueNotEqual("baz", Baz{})
value.chain.assertOK(t)
value.chain.reset()
}
func TestObjectConvertEqual(t *testing.T) {
type (
myMap map[string]interface{}
myInt int
)
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{"foo": 123})
value.Equal(map[string]interface{}{"foo": "123"})
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{"foo": "123"})
value.chain.assertOK(t)
value.chain.reset()
value.Equal(map[string]interface{}{"foo": 123.0})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{"foo": 123.0})
value.chain.assertFailed(t)
value.chain.reset()
value.Equal(map[string]interface{}{"foo": 123})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(map[string]interface{}{"foo": 123})
value.chain.assertFailed(t)
value.chain.reset()
value.Equal(myMap{"foo": myInt(123)})
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual(myMap{"foo": myInt(123)})
value.chain.assertFailed(t)
value.chain.reset()
}
func TestObjectConvertContainsMap(t *testing.T) {
type (
myArray []interface{}
myMap map[string]interface{}
myInt int
)
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": "b",
},
})
submap := myMap{
"foo": myInt(123),
"bar": myArray{"456", myInt(789)},
}
value.ContainsMap(submap)
value.chain.assertOK(t)
value.chain.reset()
value.NotContainsMap(submap)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestObjectConvertValueEqual(t *testing.T) {
type (
myArray []interface{}
myMap map[string]interface{}
myInt int
)
reporter := newMockReporter(t)
value := NewObject(reporter, map[string]interface{}{
"foo": 123,
"bar": []interface{}{"456", 789},
"baz": map[string]interface{}{
"a": "b",
},
})
value.ValueEqual("bar", myArray{"456", myInt(789)})
value.chain.assertOK(t)
value.chain.reset()
value.ValueNotEqual("bar", myArray{"456", myInt(789)})
value.chain.assertFailed(t)
value.chain.reset()
value.ValueEqual("baz", myMap{"a": "b"})
value.chain.assertOK(t)
value.chain.reset()
value.ValueNotEqual("baz", myMap{"a": "b"})
value.chain.assertFailed(t)
value.chain.reset()
}

100
vendor/github.com/gavv/httpexpect/printer.go generated vendored Normal file
View File

@ -0,0 +1,100 @@
package httpexpect
import (
"net/http"
"net/http/httputil"
"strings"
"time"
"github.com/moul/http2curl"
)
// 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])
}
// 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) {
}

44
vendor/github.com/gavv/httpexpect/printer_test.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
package httpexpect
import (
"bytes"
"io/ioutil"
"net/http"
"testing"
)
func TestCompactPrinter(t *testing.T) {
printer := NewCompactPrinter(t)
body1 := bytes.NewBufferString("body1")
body2 := bytes.NewBufferString("body2")
req1, _ := http.NewRequest("GET", "http://example.com", body1)
req2, _ := http.NewRequest("GET", "http://example.com", nil)
printer.Request(req1)
printer.Request(req2)
printer.Request(nil)
printer.Response(&http.Response{Body: ioutil.NopCloser(body2)}, 0)
printer.Response(&http.Response{}, 0)
printer.Response(nil, 0)
}
func TestDebugPrinter(t *testing.T) {
printer := NewDebugPrinter(t, true)
body1 := bytes.NewBufferString("body1")
body2 := bytes.NewBufferString("body2")
req1, _ := http.NewRequest("GET", "http://example.com", body1)
req2, _ := http.NewRequest("GET", "http://example.com", nil)
printer.Request(req1)
printer.Request(req2)
printer.Request(nil)
printer.Response(&http.Response{Body: ioutil.NopCloser(body2)}, 0)
printer.Response(&http.Response{}, 0)
printer.Response(nil, 0)
}

40
vendor/github.com/gavv/httpexpect/reporter.go generated vendored Normal file
View 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...))
}

912
vendor/github.com/gavv/httpexpect/request.go generated vendored Normal file
View File

@ -0,0 +1,912 @@
package httpexpect
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"os"
"reflect"
"sort"
"strings"
"time"
"github.com/ajg/form"
"github.com/fatih/structs"
"github.com/gavv/monotime"
"github.com/google/go-querystring/query"
"github.com/imkira/go-interpol"
)
// Request provides methods to incrementally build http.Request object,
// send it, and receive response.
type Request struct {
config Config
chain chain
http *http.Request
path string
query url.Values
form url.Values
formbuf *bytes.Buffer
multipart *multipart.Writer
forcetype bool
typesetter string
bodysetter string
}
// NewRequest returns a new Request object.
//
// method defines the HTTP method (GET, POST, PUT, etc.). path defines url path.
//
// Simple interpolation is allowed for {named} parameters in path:
// - if pathargs is given, it's used to substitute first len(pathargs) parameters,
// regardless of their names
// - if WithPath() or WithPathObject() is called, it's used to substitute given
// parameters by name
//
// For example:
// req := NewRequest(config, "POST", "/repos/{user}/{repo}", "gavv", "httpexpect")
// // path will be "/repos/gavv/httpexpect"
//
// Or:
// req := NewRequest(config, "POST", "/repos/{user}/{repo}")
// req.WithPath("user", "gavv")
// req.WithPath("repo", "httpexpect")
// // path will be "/repos/gavv/httpexpect"
//
// After interpolation, path is urlencoded and appended to Config.BaseURL,
// separated by slash. If BaseURL ends with a slash and path (after interpolation)
// starts with a slash, only single slash is inserted.
func NewRequest(config Config, method, path string, pathargs ...interface{}) *Request {
if config.RequestFactory == nil {
panic("config.RequestFactory == nil")
}
if config.Client == nil {
panic("config.Client == nil")
}
chain := makeChain(config.Reporter)
n := 0
path, err := interpol.WithFunc(path, func(k string, w io.Writer) error {
if n < len(pathargs) {
if pathargs[n] == nil {
chain.fail(
"\nunexpected nil argument for url path format string:\n"+
" Request(\"%s\", %v...)", method, pathargs)
} else {
w.Write([]byte(fmt.Sprint(pathargs[n])))
}
} else {
w.Write([]byte("{"))
w.Write([]byte(k))
w.Write([]byte("}"))
}
n++
return nil
})
if err != nil {
chain.fail(err.Error())
}
hr, err := config.RequestFactory.NewRequest(method, config.BaseURL, nil)
if err != nil {
chain.fail(err.Error())
}
return &Request{
config: config,
chain: chain,
path: path,
http: hr,
}
}
// WithClient sets client.
//
// The new client overwrites Config.Client. It will be use once to send the
// request and receive a response.
//
// Example:
// req := NewRequest(config, "GET", "/path")
// req.WithClient(&http.Client{
// Transport: &http.Transport{
// DisableCompression: true,
// },
// })
func (r *Request) WithClient(client Client) *Request {
if r.chain.failed() {
return r
}
if client == nil {
r.chain.fail("\nunexpected nil client in WithClient")
return r
}
r.config.Client = client
return r
}
// WithHandler configures client to invoke the given handler directly.
//
// If Config.Client is http.Client, then only its Transport field is overwritten
// because the client may contain some state shared among requests like a cookie
// jar. Otherwise, the whole client is overwritten with a new client.
//
// Example:
// req := NewRequest(config, "GET", "/path")
// req.WithHandler(myServer.someHandler)
func (r *Request) WithHandler(handler http.Handler) *Request {
if r.chain.failed() {
return r
}
if handler == nil {
r.chain.fail("\nunexpected nil handler in WithHandler")
return r
}
if client, ok := r.config.Client.(*http.Client); ok {
client.Transport = NewBinder(handler)
} else {
r.config.Client = &http.Client{
Transport: NewBinder(handler),
Jar: NewJar(),
}
}
return r
}
// WithPath substitutes named parameters in url path.
//
// value is converted to string using fmt.Sprint(). If there is no named
// parameter '{key}' in url path, failure is reported.
//
// Named parameters are case-insensitive.
//
// Example:
// req := NewRequest(config, "POST", "/repos/{user}/{repo}")
// req.WithPath("user", "gavv")
// req.WithPath("repo", "httpexpect")
// // path will be "/repos/gavv/httpexpect"
func (r *Request) WithPath(key string, value interface{}) *Request {
if r.chain.failed() {
return r
}
ok := false
path, err := interpol.WithFunc(r.path, func(k string, w io.Writer) error {
if strings.EqualFold(k, key) {
if value == nil {
r.chain.fail(
"\nunexpected nil argument for url path format string:\n"+
" WithPath(\"%s\", %v)", key, value)
} else {
w.Write([]byte(fmt.Sprint(value)))
ok = true
}
} else {
w.Write([]byte("{"))
w.Write([]byte(k))
w.Write([]byte("}"))
}
return nil
})
if err == nil {
r.path = path
} else {
r.chain.fail(err.Error())
return r
}
if !ok {
r.chain.fail("\nunexpected key for url path format string:\n"+
" WithPath(\"%s\", %v)\n\npath:\n %q",
key, value, r.path)
return r
}
return r
}
// WithPathObject substitutes multiple named parameters in url path.
//
// object should be map or struct. If object is struct, it's converted
// to map using https://github.com/fatih/structs. Structs may contain
// "path" struct tag, similar to "json" struct tag for json.Marshal().
//
// Each map value is converted to string using fmt.Sprint(). If there
// is no named parameter for some map '{key}' in url path, failure is
// reported.
//
// Named parameters are case-insensitive.
//
// Example:
// type MyPath struct {
// Login string `path:"user"`
// Repo string
// }
//
// req := NewRequest(config, "POST", "/repos/{user}/{repo}")
// req.WithPathObject(MyPath{"gavv", "httpexpect"})
// // path will be "/repos/gavv/httpexpect"
//
// req := NewRequest(config, "POST", "/repos/{user}/{repo}")
// req.WithPathObject(map[string]string{"user": "gavv", "repo": "httpexpect"})
// // path will be "/repos/gavv/httpexpect"
func (r *Request) WithPathObject(object interface{}) *Request {
if r.chain.failed() {
return r
}
if object == nil {
return r
}
var (
m map[string]interface{}
ok bool
)
if reflect.Indirect(reflect.ValueOf(object)).Kind() == reflect.Struct {
s := structs.New(object)
s.TagName = "path"
m = s.Map()
} else {
m, ok = canonMap(&r.chain, object)
if !ok {
return r
}
}
for k, v := range m {
r.WithPath(k, v)
}
return r
}
// WithQuery adds query parameter to request URL.
//
// value is converted to string using fmt.Sprint() and urlencoded.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithQuery("a", 123)
// req.WithQuery("b", "foo")
// // URL is now http://example.com/path?a=123&b=foo
func (r *Request) WithQuery(key string, value interface{}) *Request {
if r.chain.failed() {
return r
}
if r.query == nil {
r.query = make(url.Values)
}
r.query.Add(key, fmt.Sprint(value))
return r
}
// WithQueryObject adds multiple query parameters to request URL.
//
// object is converted to query string using github.com/google/go-querystring
// if it's a struct or pointer to struct, or github.com/ajg/form otherwise.
//
// Various object types are supported. Structs may contain "url" struct tag,
// similar to "json" struct tag for json.Marshal().
//
// Example:
// type MyURL struct {
// A int `url:"a"`
// B string `url:"b"`
// }
//
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithQueryObject(MyURL{A: 123, B: "foo"})
// // URL is now http://example.com/path?a=123&b=foo
//
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithQueryObject(map[string]interface{}{"a": 123, "b": "foo"})
// // URL is now http://example.com/path?a=123&b=foo
func (r *Request) WithQueryObject(object interface{}) *Request {
if r.chain.failed() {
return r
}
if object == nil {
return r
}
var (
q url.Values
err error
)
if reflect.Indirect(reflect.ValueOf(object)).Kind() == reflect.Struct {
q, err = query.Values(object)
if err != nil {
r.chain.fail(err.Error())
return r
}
} else {
q, err = form.EncodeToValues(object)
if err != nil {
r.chain.fail(err.Error())
return r
}
}
if r.query == nil {
r.query = make(url.Values)
}
for k, v := range q {
r.query[k] = append(r.query[k], v...)
}
return r
}
// WithQueryString parses given query string and adds it to request URL.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithQuery("a", 11)
// req.WithQueryString("b=22&c=33")
// // URL is now http://example.com/path?a=11&bb=22&c=33
func (r *Request) WithQueryString(query string) *Request {
if r.chain.failed() {
return r
}
v, err := url.ParseQuery(query)
if err != nil {
r.chain.fail(err.Error())
return r
}
if r.query == nil {
r.query = make(url.Values)
}
for k, v := range v {
r.query[k] = append(r.query[k], v...)
}
return r
}
// WithURL sets request URL.
//
// This URL overwrites Config.BaseURL. Request path passed to NewRequest()
// is appended to this URL, separated by slash if necessary.
//
// Example:
// req := NewRequest(config, "PUT", "/path")
// req.WithURL("http://example.com")
// // URL is now http://example.com/path
func (r *Request) WithURL(urlStr string) *Request {
if r.chain.failed() {
return r
}
if u, err := url.Parse(urlStr); err == nil {
r.http.URL = u
} else {
r.chain.fail(err.Error())
}
return r
}
// WithHeaders adds given headers to request.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithHeaders(map[string]string{
// "Content-Type": "application/json",
// })
func (r *Request) WithHeaders(headers map[string]string) *Request {
if r.chain.failed() {
return r
}
for k, v := range headers {
r.WithHeader(k, v)
}
return r
}
// WithHeader adds given single header to request.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithHeader("Content-Type": "application/json")
func (r *Request) WithHeader(k, v string) *Request {
if r.chain.failed() {
return r
}
switch http.CanonicalHeaderKey(k) {
case "Host":
r.http.Host = v
case "Content-Type":
if !r.forcetype {
delete(r.http.Header, "Content-Type")
}
r.forcetype = true
r.typesetter = "WithHeader"
r.http.Header.Add(k, v)
default:
r.http.Header.Add(k, v)
}
return r
}
// WithCookies adds given cookies to request.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithCookies(map[string]string{
// "foo": "aa",
// "bar": "bb",
// })
func (r *Request) WithCookies(cookies map[string]string) *Request {
if r.chain.failed() {
return r
}
for k, v := range cookies {
r.WithCookie(k, v)
}
return r
}
// WithCookie adds given single cookie to request.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithCookie("name", "value")
func (r *Request) WithCookie(k, v string) *Request {
if r.chain.failed() {
return r
}
r.http.AddCookie(&http.Cookie{
Name: k,
Value: v,
})
return r
}
// WithBasicAuth sets the request's Authorization header to use HTTP
// Basic Authentication with the provided username and password.
//
// With HTTP Basic Authentication the provided username and password
// are not encrypted.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithBasicAuth("john", "secret")
func (r *Request) WithBasicAuth(username, password string) *Request {
if r.chain.failed() {
return r
}
r.http.SetBasicAuth(username, password)
return r
}
// WithProto sets HTTP protocol version.
//
// proto should have form of "HTTP/{major}.{minor}", e.g. "HTTP/1.1".
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithProto("HTTP/2.0")
func (r *Request) WithProto(proto string) *Request {
if r.chain.failed() {
return r
}
major, minor, ok := http.ParseHTTPVersion(proto)
if !ok {
r.chain.fail(
"\nunexpected protocol version %q, expected \"HTTP/{major}.{minor}\"",
proto)
return r
}
r.http.ProtoMajor = major
r.http.ProtoMinor = minor
return r
}
// WithChunked enables chunked encoding and sets request body reader.
//
// Expect() will read all available data from given reader. Content-Length
// is not set, and "chunked" Transfer-Encoding is used.
//
// If protocol version is not at least HTTP/1.1 (required for chunked
// encoding), failure is reported.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/upload")
// fh, _ := os.Open("data")
// defer fh.Close()
// req.WithHeader("Content-Type": "application/octet-stream")
// req.WithChunked(fh)
func (r *Request) WithChunked(reader io.Reader) *Request {
if r.chain.failed() {
return r
}
if !r.http.ProtoAtLeast(1, 1) {
r.chain.fail("chunked Transfer-Encoding requires at least \"HTTP/1.1\","+
"but \"HTTP/%d.%d\" is enabled", r.http.ProtoMajor, r.http.ProtoMinor)
return r
}
r.setBody("WithChunked", reader, -1, false)
return r
}
// WithBytes sets request body to given slice of bytes.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithHeader("Content-Type": "application/json")
// req.WithBytes([]byte(`{"foo": 123}`))
func (r *Request) WithBytes(b []byte) *Request {
if r.chain.failed() {
return r
}
if b == nil {
r.setBody("WithBytes", nil, 0, false)
} else {
r.setBody("WithBytes", bytes.NewReader(b), len(b), false)
}
return r
}
// WithText sets Content-Type header to "text/plain; charset=utf-8" and
// sets body to given string.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithText("hello, world!")
func (r *Request) WithText(s string) *Request {
if r.chain.failed() {
return r
}
r.setType("WithText", "text/plain; charset=utf-8", false)
r.setBody("WithText", strings.NewReader(s), len(s), false)
return r
}
// WithJSON sets Content-Type header to "application/json; charset=utf-8"
// and sets body to object, marshaled using json.Marshal().
//
// Example:
// type MyJSON struct {
// Foo int `json:"foo"`
// }
//
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithJSON(MyJSON{Foo: 123})
//
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithJSON(map[string]interface{}{"foo": 123})
func (r *Request) WithJSON(object interface{}) *Request {
if r.chain.failed() {
return r
}
b, err := json.Marshal(object)
if err != nil {
r.chain.fail(err.Error())
return r
}
r.setType("WithJSON", "application/json; charset=utf-8", false)
r.setBody("WithJSON", bytes.NewReader(b), len(b), false)
return r
}
// WithForm sets Content-Type header to "application/x-www-form-urlencoded"
// or (if WithMultipart() was called) "multipart/form-data", converts given
// object to url.Values using github.com/ajg/form, and adds it to request body.
//
// Various object types are supported, including maps and structs. Structs may
// contain "form" struct tag, similar to "json" struct tag for json.Marshal().
// See https://github.com/ajg/form for details.
//
// Multiple WithForm(), WithFormField(), and WithFile() calls may be combined.
// If WithMultipart() is called, it should be called first.
//
// Example:
// type MyForm struct {
// Foo int `form:"foo"`
// }
//
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithForm(MyForm{Foo: 123})
//
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithForm(map[string]interface{}{"foo": 123})
func (r *Request) WithForm(object interface{}) *Request {
if r.chain.failed() {
return r
}
f, err := form.EncodeToValues(object)
if err != nil {
r.chain.fail(err.Error())
return r
}
if r.multipart != nil {
r.setType("WithForm", "multipart/form-data", false)
var keys []string
for k := range f {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
if err := r.multipart.WriteField(k, f[k][0]); err != nil {
r.chain.fail(err.Error())
return r
}
}
} else {
r.setType("WithForm", "application/x-www-form-urlencoded", false)
if r.form == nil {
r.form = make(url.Values)
}
for k, v := range f {
r.form[k] = append(r.form[k], v...)
}
}
return r
}
// WithFormField sets Content-Type header to "application/x-www-form-urlencoded"
// or (if WithMultipart() was called) "multipart/form-data", converts given
// value to string using fmt.Sprint(), and adds it to request body.
//
// Multiple WithForm(), WithFormField(), and WithFile() calls may be combined.
// If WithMultipart() is called, it should be called first.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithFormField("foo", 123).
// WithFormField("bar", 456)
func (r *Request) WithFormField(key string, value interface{}) *Request {
if r.chain.failed() {
return r
}
if r.multipart != nil {
r.setType("WithFormField", "multipart/form-data", false)
err := r.multipart.WriteField(key, fmt.Sprint(value))
if err != nil {
r.chain.fail(err.Error())
return r
}
} else {
r.setType("WithFormField", "application/x-www-form-urlencoded", false)
if r.form == nil {
r.form = make(url.Values)
}
r.form[key] = append(r.form[key], fmt.Sprint(value))
}
return r
}
// WithFile sets Content-Type header to "multipart/form-data", reads given
// file and adds its contents to request body.
//
// If reader is given, it's used to read file contents. Otherwise, os.Open()
// is used to read a file with given path.
//
// Multiple WithForm(), WithFormField(), and WithFile() calls may be combined.
// WithMultipart() should be called before WithFile(), otherwise WithFile()
// fails.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithFile("avatar", "./john.png")
//
// req := NewRequest(config, "PUT", "http://example.com/path")
// fh, _ := os.Open("./john.png")
// req.WithMultipart().
// WithFile("avatar", "john.png", fh)
// fh.Close()
func (r *Request) WithFile(key, path string, reader ...io.Reader) *Request {
if r.chain.failed() {
return r
}
r.setType("WithFile", "multipart/form-data", false)
if r.multipart == nil {
r.chain.fail("WithFile requires WithMultipart to be called first")
return r
}
wr, err := r.multipart.CreateFormFile(key, path)
if err != nil {
r.chain.fail(err.Error())
return r
}
var rd io.Reader
if len(reader) != 0 && reader[0] != nil {
rd = reader[0]
} else {
f, err := os.Open(path)
if err != nil {
r.chain.fail(err.Error())
return r
}
rd = f
defer f.Close()
}
if _, err := io.Copy(wr, rd); err != nil {
r.chain.fail(err.Error())
return r
}
return r
}
// WithFileBytes is like WithFile, but uses given slice of bytes as the
// file contents.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// fh, _ := os.Open("./john.png")
// b, _ := ioutil.ReadAll(fh)
// req.WithMultipart().
// WithFileBytes("avatar", "john.png", b)
// fh.Close()
func (r *Request) WithFileBytes(key, path string, data []byte) *Request {
if r.chain.failed() {
return r
}
return r.WithFile(key, path, bytes.NewReader(data))
}
// WithMultipart sets Content-Type header to "multipart/form-data".
//
// After this call, WithForm() and WithFormField() switch to multipart
// form instead of urlencoded form.
//
// If WithMultipart() is called, it should be called before WithForm(),
// WithFormField(), and WithFile().
//
// WithFile() always requires WithMultipart() to be called first.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithMultipart().
// WithForm(map[string]interface{}{"foo": 123})
func (r *Request) WithMultipart() *Request {
if r.chain.failed() {
return r
}
r.setType("WithMultipart", "multipart/form-data", false)
if r.multipart == nil {
r.formbuf = new(bytes.Buffer)
r.multipart = multipart.NewWriter(r.formbuf)
r.setBody("WithMultipart", r.formbuf, 0, false)
}
return r
}
// Expect constructs http.Request, sends it, receives http.Response, and
// returns a new Response object to inspect received response.
//
// Request is sent using Config.Client interface.
//
// Example:
// req := NewRequest(config, "PUT", "http://example.com/path")
// req.WithJSON(map[string]interface{}{"foo": 123})
// resp := req.Expect()
// resp.Status(http.StatusOK)
func (r *Request) Expect() *Response {
r.encodeRequest()
resp, elapsed := r.sendRequest()
return makeResponse(r.chain, resp, elapsed)
}
func (r *Request) encodeRequest() {
if r.chain.failed() {
return
}
r.http.URL.Path = concatPaths(r.http.URL.Path, r.path)
if r.query != nil {
r.http.URL.RawQuery = r.query.Encode()
}
if r.multipart != nil {
if err := r.multipart.Close(); err != nil {
r.chain.fail(err.Error())
return
}
r.setType("Expect", r.multipart.FormDataContentType(), true)
r.setBody("Expect", r.formbuf, r.formbuf.Len(), true)
} else if r.form != nil {
s := r.form.Encode()
r.setBody("WithForm or WithFormField", strings.NewReader(s), len(s), false)
}
}
func (r *Request) sendRequest() (resp *http.Response, elapsed time.Duration) {
if r.chain.failed() {
return
}
for _, printer := range r.config.Printers {
printer.Request(r.http)
}
start := monotime.Now()
resp, err := r.config.Client.Do(r.http)
elapsed = monotime.Since(start)
if err != nil {
r.chain.fail(err.Error())
return
}
for _, printer := range r.config.Printers {
printer.Response(resp, elapsed)
}
return
}
func (r *Request) setType(newSetter, newType string, overwrite bool) {
if r.forcetype {
return
}
if !overwrite {
previousType := r.http.Header.Get("Content-Type")
if previousType != "" && previousType != newType {
r.chain.fail(
"\nambiguous request \"Content-Type\" header values:\n %q (set by %s)\n\n"+
"and:\n %q (wanted by %s)",
previousType, r.typesetter,
newType, newSetter)
return
}
}
r.typesetter = newSetter
r.http.Header["Content-Type"] = []string{newType}
}
func (r *Request) setBody(setter string, reader io.Reader, len int, overwrite bool) {
if !overwrite && r.bodysetter != "" {
r.chain.fail(
"\nambiguous request body contents:\n set by %s\n overwritten by %s",
r.bodysetter, setter)
return
}
if len > 0 && reader == nil {
panic("invalid length")
}
if reader == nil {
r.http.Body = nil
r.http.ContentLength = 0
} else {
r.http.Body = ioutil.NopCloser(reader)
r.http.ContentLength = int64(len)
}
r.bodysetter = setter
}
func concatPaths(a, b string) string {
if a == "" {
return b
}
if b == "" {
return a
}
a = strings.TrimSuffix(a, "/")
b = strings.TrimPrefix(b, "/")
return a + "/" + b
}

1422
vendor/github.com/gavv/httpexpect/request_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

511
vendor/github.com/gavv/httpexpect/response.go generated vendored Normal file
View File

@ -0,0 +1,511 @@
package httpexpect
import (
"bytes"
"encoding/json"
"io/ioutil"
"mime"
"net/http"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/ajg/form"
)
// 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 {
chain chain
resp *http.Response
content []byte
cookies []*http.Cookie
time 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 duration is given, it defines response time to be reported by
// response.Duration().
func NewResponse(
reporter Reporter, response *http.Response, duration ...time.Duration) *Response {
var dr time.Duration
if len(duration) > 0 {
dr = duration[0]
}
return makeResponse(makeChain(reporter), response, dr)
}
func makeResponse(
chain chain, response *http.Response, duration time.Duration) *Response {
var content []byte
var cookies []*http.Cookie
if response != nil {
content = getContent(&chain, response)
cookies = response.Cookies()
} else {
chain.fail("expected non-nil response")
}
return &Response{
chain: chain,
resp: response,
content: content,
cookies: cookies,
time: duration,
}
}
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
}
// Duration returns a new Number object that may be used to inspect
// response time, in nanoseconds.
//
// Response time is a time interval starting just before request is sent
// and ending right after response is received, retrieved from monotonic
// clock source.
//
// Example:
// resp := NewResponse(t, response, time.Duration(10000000))
// resp.Duration().Equal(10 * time.Millisecond)
func (r *Response) Duration() *Number {
return &Number{r.chain, float64(r.time)}
}
// 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}
}
// 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
}
// 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!")
func (r *Response) Text() *String {
var content string
if !r.chain.failed() && r.checkContentType("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")
func (r *Response) Form() *Object {
object := r.getForm()
return &Object{r.chain, object}
}
func (r *Response) getForm() map[string]interface{} {
if r.chain.failed() {
return nil
}
if !r.checkContentType("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")
func (r *Response) JSON() *Value {
value := r.getJSON()
return &Value{r.chain, value}
}
func (r *Response) getJSON() interface{} {
if r.chain.failed() {
return nil
}
if !r.checkContentType("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")
func (r *Response) JSONP(callback string) *Value {
value := r.getJSONP(callback)
return &Value{r.chain, value}
}
var (
jsonp = regexp.MustCompile(`^\s*([^\s(]+)\s*\((.*)\)\s*;*\s*$`)
)
func (r *Response) getJSONP(callback string) interface{} {
if r.chain.failed() {
return nil
}
if !r.checkContentType("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) 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))
}
}

872
vendor/github.com/gavv/httpexpect/response_test.go generated vendored Normal file
View File

@ -0,0 +1,872 @@
package httpexpect
import (
"bytes"
"io/ioutil"
"net/http"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestResponseFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
resp := &Response{chain, nil, nil, nil, 0}
resp.chain.assertFailed(t)
assert.False(t, resp.Duration() == nil)
assert.False(t, resp.Headers() == nil)
assert.False(t, resp.Header("foo") == nil)
assert.False(t, resp.Cookies() == nil)
assert.False(t, resp.Cookie("foo") == nil)
assert.False(t, resp.Body() == nil)
assert.False(t, resp.JSON() == nil)
assert.False(t, resp.JSONP("") == nil)
resp.Headers().chain.assertFailed(t)
resp.Header("foo").chain.assertFailed(t)
resp.Cookies().chain.assertFailed(t)
resp.Cookie("foo").chain.assertFailed(t)
resp.Body().chain.assertFailed(t)
resp.Text().chain.assertFailed(t)
resp.JSON().chain.assertFailed(t)
resp.JSONP("").chain.assertFailed(t)
resp.Status(123)
resp.StatusRange(Status2xx)
resp.NoContent()
resp.ContentType("", "")
resp.ContentEncoding("")
resp.TransferEncoding("")
}
func TestResponseDuration(t *testing.T) {
reporter := newMockReporter(t)
duration := time.Duration(10000000)
resp := NewResponse(reporter, &http.Response{}, duration)
resp.chain.assertOK(t)
resp.chain.reset()
rt := resp.Duration()
assert.Equal(t, float64(duration), rt.Raw())
rt.Equal(10 * time.Millisecond)
rt.chain.assertOK(t)
}
func TestResponseStatusRange(t *testing.T) {
reporter := newMockReporter(t)
ranges := []StatusRange{
Status1xx,
Status2xx,
Status3xx,
Status4xx,
Status5xx,
}
cases := []struct {
Status int
Range StatusRange
}{
{99, StatusRange(-1)},
{100, Status1xx},
{199, Status1xx},
{200, Status2xx},
{299, Status2xx},
{300, Status3xx},
{399, Status3xx},
{400, Status4xx},
{499, Status4xx},
{500, Status5xx},
{599, Status5xx},
{600, StatusRange(-1)},
}
for _, test := range cases {
for _, r := range ranges {
resp := NewResponse(reporter, &http.Response{
StatusCode: test.Status,
})
resp.StatusRange(r)
if test.Range == r {
resp.chain.assertOK(t)
} else {
resp.chain.assertFailed(t)
}
}
}
}
func TestResponseHeaders(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"First-Header": {"foo"},
"Second-Header": {"bar"},
}
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: nil,
}
resp := NewResponse(reporter, httpResp)
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t, httpResp, resp.Raw())
resp.Status(http.StatusOK)
resp.chain.assertOK(t)
resp.chain.reset()
resp.Status(http.StatusNotFound)
resp.chain.assertFailed(t)
resp.chain.reset()
resp.Headers().Equal(headers).chain.assertOK(t)
for k, v := range headers {
for _, h := range []string{k, strings.ToLower(k), strings.ToUpper(k)} {
resp.Header(h).Equal(v[0]).chain.assertOK(t)
}
}
resp.Header("Bad-Header").Empty().chain.assertOK(t)
}
func TestResponseCookies(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Set-Cookie": {
"foo=aaa",
"bar=bbb; expires=Fri, 31 Dec 2010 23:59:59 GMT; " +
"path=/xxx; domain=example.com",
},
}
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: nil,
}
resp := NewResponse(reporter, httpResp)
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t, []interface{}{"foo", "bar"}, resp.Cookies().Raw())
resp.chain.assertOK(t)
c1 := resp.Cookie("foo")
resp.chain.assertOK(t)
assert.Equal(t, "foo", c1.Raw().Name)
assert.Equal(t, "aaa", c1.Raw().Value)
assert.Equal(t, "", c1.Raw().Domain)
assert.Equal(t, "", c1.Raw().Path)
c2 := resp.Cookie("bar")
resp.chain.assertOK(t)
assert.Equal(t, "bar", c2.Raw().Name)
assert.Equal(t, "bbb", c2.Raw().Value)
assert.Equal(t, "example.com", c2.Raw().Domain)
assert.Equal(t, "/xxx", c2.Raw().Path)
assert.True(t, time.Date(2010, 12, 31, 23, 59, 59, 0, time.UTC).
Equal(c2.Raw().Expires))
c3 := resp.Cookie("baz")
resp.chain.assertFailed(t)
c3.chain.assertFailed(t)
assert.True(t, c3.Raw() == nil)
}
func TestResponseNoCookies(t *testing.T) {
reporter := newMockReporter(t)
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: nil,
Body: nil,
}
resp := NewResponse(reporter, httpResp)
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t, []interface{}{}, resp.Cookies().Raw())
resp.chain.assertOK(t)
c := resp.Cookie("foo")
resp.chain.assertFailed(t)
c.chain.assertFailed(t)
assert.True(t, c.Raw() == nil)
}
func TestResponseBody(t *testing.T) {
reporter := newMockReporter(t)
httpResp := &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewBufferString("body")),
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, "body", resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
}
func TestResponseNoContentEmpty(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {""},
}
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, "", resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
resp.NoContent()
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("")
resp.chain.assertOK(t)
resp.chain.reset()
resp.Text()
resp.chain.assertFailed(t)
resp.chain.reset()
resp.Form()
resp.chain.assertFailed(t)
resp.chain.reset()
resp.JSON()
resp.chain.assertFailed(t)
resp.chain.reset()
resp.JSONP("")
resp.chain.assertFailed(t)
resp.chain.reset()
}
func TestResponseNoContentNil(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {""},
}
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: nil,
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, "", resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
resp.NoContent()
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("")
resp.chain.assertOK(t)
resp.chain.reset()
resp.Text()
resp.chain.assertFailed(t)
resp.chain.reset()
resp.Form()
resp.chain.assertFailed(t)
resp.chain.reset()
resp.JSON()
resp.chain.assertFailed(t)
resp.chain.reset()
resp.JSONP("")
resp.chain.assertFailed(t)
resp.chain.reset()
}
func TestResponseNoContentFailed(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"text/plain; charset=utf-8"},
}
body := ``
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, body, resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
resp.NoContent()
resp.chain.assertFailed(t)
resp.chain.reset()
}
func TestResponseContentType(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"text/plain; charset=utf-8"},
}
resp := NewResponse(reporter, &http.Response{
Header: http.Header(headers),
})
resp.ContentType("text/plain")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain", "utf-8")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain", "UTF-8")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("bad")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.ContentType("text/plain", "bad")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.ContentType("")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.ContentType("text/plain", "")
resp.chain.assertFailed(t)
resp.chain.reset()
}
func TestResponseContentTypeEmptyCharset(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"text/plain"},
}
resp := NewResponse(reporter, &http.Response{
Header: http.Header(headers),
})
resp.ContentType("text/plain")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain", "")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain", "utf-8")
resp.chain.assertFailed(t)
resp.chain.reset()
}
func TestResponseContentTypeInvalid(t *testing.T) {
reporter := newMockReporter(t)
headers1 := map[string][]string{
"Content-Type": {";"},
}
headers2 := map[string][]string{
"Content-Type": {"charset=utf-8"},
}
resp1 := NewResponse(reporter, &http.Response{
Header: http.Header(headers1),
})
resp2 := NewResponse(reporter, &http.Response{
Header: http.Header(headers2),
})
resp1.ContentType("")
resp1.chain.assertFailed(t)
resp1.chain.reset()
resp1.ContentType("", "")
resp1.chain.assertFailed(t)
resp1.chain.reset()
resp2.ContentType("")
resp2.chain.assertFailed(t)
resp2.chain.reset()
resp2.ContentType("", "")
resp2.chain.assertFailed(t)
resp2.chain.reset()
}
func TestResponseContentEncoding(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Encoding": {"gzip", "deflate"},
}
resp := NewResponse(reporter, &http.Response{
Header: http.Header(headers),
})
resp.ContentEncoding("gzip", "deflate")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentEncoding("deflate", "gzip")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.ContentEncoding("gzip")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.ContentEncoding()
resp.chain.assertFailed(t)
resp.chain.reset()
}
func TestResponseTransferEncoding(t *testing.T) {
reporter := newMockReporter(t)
resp := NewResponse(reporter, &http.Response{
TransferEncoding: []string{"foo", "bar"},
})
resp.TransferEncoding("foo", "bar")
resp.chain.assertOK(t)
resp.chain.reset()
resp.TransferEncoding("foo")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.TransferEncoding()
resp.chain.assertFailed(t)
resp.chain.reset()
}
func TestResponseText(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"text/plain; charset=utf-8"},
}
body := `hello, world!`
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, body, resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain", "utf-8")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("application/json")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.Text()
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t, "hello, world!", resp.Text().Raw())
}
func TestResponseForm(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/x-www-form-urlencoded"},
}
body := `a=1&b=2`
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, body, resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("application/x-www-form-urlencoded")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("application/x-www-form-urlencoded", "")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.Form()
resp.chain.assertOK(t)
resp.chain.reset()
expected := map[string]interface{}{
"a": "1",
"b": "2",
}
assert.Equal(t, expected, resp.Form().Raw())
}
func TestResponseFormBadBody(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/x-www-form-urlencoded"},
}
body := "%"
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.Form()
resp.chain.assertFailed(t)
resp.chain.reset()
assert.True(t, resp.Form().Raw() == nil)
}
func TestResponseFormBadType(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"bad"},
}
body := "foo=bar"
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.Form()
resp.chain.assertFailed(t)
resp.chain.reset()
assert.True(t, resp.Form().Raw() == nil)
}
func TestResponseJSON(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/json; charset=utf-8"},
}
body := `{"key": "value"}`
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, body, resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("application/json")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("application/json", "utf-8")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.JSON()
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t,
map[string]interface{}{"key": "value"}, resp.JSON().Object().Raw())
}
func TestResponseJSONBadBody(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/json; charset=utf-8"},
}
body := "{"
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.JSON()
resp.chain.assertFailed(t)
resp.chain.reset()
assert.True(t, resp.JSON().Raw() == nil)
}
func TestResponseJSONCharsetEmpty(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/json"},
}
body := `{"key": "value"}`
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.JSON()
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t,
map[string]interface{}{"key": "value"}, resp.JSON().Object().Raw())
}
func TestResponseJSONCharsetBad(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/json; charset=bad"},
}
body := `{"key": "value"}`
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.JSON()
resp.chain.assertFailed(t)
resp.chain.reset()
assert.Equal(t, nil, resp.JSON().Raw())
}
func TestResponseJSONP(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/javascript; charset=utf-8"},
}
body1 := `foo({"key": "value"})`
body2 := `foo({"key": "value"});`
body3 := ` foo ( {"key": "value"} ) ; `
for _, body := range []string{body1, body2, body3} {
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
assert.Equal(t, body, resp.Body().Raw())
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("application/javascript")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("application/javascript", "utf-8")
resp.chain.assertOK(t)
resp.chain.reset()
resp.ContentType("text/plain")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.JSONP("foo")
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t,
map[string]interface{}{"key": "value"}, resp.JSONP("foo").Object().Raw())
resp.JSONP("fo")
resp.chain.assertFailed(t)
resp.chain.reset()
resp.JSONP("")
resp.chain.assertFailed(t)
resp.chain.reset()
}
}
func TestResponseJSONPBadBody(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/javascript; charset=utf-8"},
}
body1 := `foo`
body2 := `foo();`
body3 := `foo(`
body4 := `foo({);`
for _, body := range []string{body1, body2, body3, body4} {
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.JSONP("foo")
resp.chain.assertFailed(t)
resp.chain.reset()
assert.True(t, resp.JSONP("foo").Raw() == nil)
}
}
func TestResponseJSONPCharsetEmpty(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/javascript"},
}
body := `foo({"key": "value"})`
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.JSONP("foo")
resp.chain.assertOK(t)
resp.chain.reset()
assert.Equal(t,
map[string]interface{}{"key": "value"}, resp.JSONP("foo").Object().Raw())
}
func TestResponseJSONPCharsetBad(t *testing.T) {
reporter := newMockReporter(t)
headers := map[string][]string{
"Content-Type": {"application/javascript; charset=bad"},
}
body := `foo({"key": "value"})`
httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}
resp := NewResponse(reporter, httpResp)
resp.JSONP("foo")
resp.chain.assertFailed(t)
resp.chain.reset()
assert.Equal(t, nil, resp.JSONP("foo").Raw())
}

320
vendor/github.com/gavv/httpexpect/string.go generated vendored Normal file
View 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 another str.
//
// 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 another str.
//
// 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 another string under Unicode case-folding
// (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 another string under Unicode
// case-folding (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 substr.
//
// 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 given substr.
//
// 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 substring under Unicode case-folding
// (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 substring under Unicode
// case-folding (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
}

309
vendor/github.com/gavv/httpexpect/string_test.go generated vendored Normal file
View File

@ -0,0 +1,309 @@
package httpexpect
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestStringFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &String{chain, ""}
value.Path("$").chain.assertFailed(t)
value.Schema("")
value.DateTime()
value.Empty()
value.NotEmpty()
value.Equal("")
value.NotEqual("")
value.EqualFold("")
value.NotEqualFold("")
value.Contains("")
value.NotContains("")
value.ContainsFold("")
value.NotContainsFold("")
}
func TestStringGetters(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "foo")
assert.Equal(t, "foo", value.Raw())
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, "foo", value.Path("$").Raw())
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "string"}`)
value.chain.assertOK(t)
value.chain.reset()
value.Schema(`{"type": "object"}`)
value.chain.assertFailed(t)
value.chain.reset()
}
func TestStringEmpty(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewString(reporter, "")
value1.Empty()
value1.chain.assertOK(t)
value1.chain.reset()
value1.NotEmpty()
value1.chain.assertFailed(t)
value1.chain.reset()
value2 := NewString(reporter, "a")
value2.Empty()
value2.chain.assertFailed(t)
value2.chain.reset()
value2.NotEmpty()
value2.chain.assertOK(t)
value2.chain.reset()
}
func TestStringEqual(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "foo")
assert.Equal(t, "foo", value.Raw())
value.Equal("foo")
value.chain.assertOK(t)
value.chain.reset()
value.Equal("FOO")
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqual("FOO")
value.chain.assertOK(t)
value.chain.reset()
value.NotEqual("foo")
value.chain.assertFailed(t)
value.chain.reset()
}
func TestStringEqualFold(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "foo")
value.EqualFold("foo")
value.chain.assertOK(t)
value.chain.reset()
value.EqualFold("FOO")
value.chain.assertOK(t)
value.chain.reset()
value.EqualFold("foo2")
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqualFold("foo")
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqualFold("FOO")
value.chain.assertFailed(t)
value.chain.reset()
value.NotEqualFold("foo2")
value.chain.assertOK(t)
value.chain.reset()
}
func TestStringContains(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "11-foo-22")
value.Contains("foo")
value.chain.assertOK(t)
value.chain.reset()
value.Contains("FOO")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContains("FOO")
value.chain.assertOK(t)
value.chain.reset()
value.NotContains("foo")
value.chain.assertFailed(t)
value.chain.reset()
}
func TestStringContainsFold(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "11-foo-22")
value.ContainsFold("foo")
value.chain.assertOK(t)
value.chain.reset()
value.ContainsFold("FOO")
value.chain.assertOK(t)
value.chain.reset()
value.ContainsFold("foo3")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsFold("foo")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsFold("FOO")
value.chain.assertFailed(t)
value.chain.reset()
value.NotContainsFold("foo3")
value.chain.assertOK(t)
value.chain.reset()
}
func TestStringLength(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "1234567")
num := value.Length()
value.chain.assertOK(t)
num.chain.assertOK(t)
assert.Equal(t, 7.0, num.Raw())
}
func TestStringDateTime(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewString(reporter, "Tue, 15 Nov 1994 08:12:31 GMT")
dt1 := value1.DateTime()
value1.chain.assertOK(t)
dt1.chain.assertOK(t)
assert.True(t, time.Date(1994, 11, 15, 8, 12, 31, 0, time.UTC).Equal(dt1.Raw()))
value2 := NewString(reporter, "15 Nov 94 08:12 GMT")
dt2 := value2.DateTime(time.RFC822)
value2.chain.assertOK(t)
dt2.chain.assertOK(t)
assert.True(t, time.Date(1994, 11, 15, 8, 12, 0, 0, time.UTC).Equal(dt2.Raw()))
value3 := NewString(reporter, "bad")
dt3 := value3.DateTime()
value3.chain.assertFailed(t)
dt3.chain.assertFailed(t)
assert.True(t, time.Unix(0, 0).Equal(dt3.Raw()))
}
func TestStringMatchOne(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "http://example.com/users/john")
m1 := value.Match(`http://(?P<host>.+)/users/(?P<user>.+)`)
m1.chain.assertOK(t)
assert.Equal(t,
[]string{"http://example.com/users/john", "example.com", "john"},
m1.submatches)
m2 := value.Match(`http://(.+)/users/(.+)`)
m2.chain.assertOK(t)
assert.Equal(t,
[]string{"http://example.com/users/john", "example.com", "john"},
m2.submatches)
}
func TestStringMatchAll(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter,
"http://example.com/users/john http://example.com/users/bob")
m := value.MatchAll(`http://(\S+)/users/(\S+)`)
assert.Equal(t, 2, len(m))
m[0].chain.assertOK(t)
m[1].chain.assertOK(t)
assert.Equal(t,
[]string{"http://example.com/users/john", "example.com", "john"},
m[0].submatches)
assert.Equal(t,
[]string{"http://example.com/users/bob", "example.com", "bob"},
m[1].submatches)
}
func TestStringMatchStatus(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "a")
value.Match(`a`)
value.chain.assertOK(t)
value.chain.reset()
value.MatchAll(`a`)
value.chain.assertOK(t)
value.chain.reset()
value.NotMatch(`a`)
value.chain.assertFailed(t)
value.chain.reset()
value.Match(`[^a]`)
value.chain.assertFailed(t)
value.chain.reset()
value.MatchAll(`[^a]`)
value.chain.assertFailed(t)
value.chain.reset()
value.NotMatch(`[^a]`)
value.chain.assertOK(t)
value.chain.reset()
assert.Equal(t, []string{}, value.Match(`[^a]`).submatches)
assert.Equal(t, []Match{}, value.MatchAll(`[^a]`))
}
func TestStringMatchInvalid(t *testing.T) {
reporter := newMockReporter(t)
value := NewString(reporter, "a")
value.Match(`[`)
value.chain.assertFailed(t)
value.chain.reset()
value.MatchAll(`[`)
value.chain.assertFailed(t)
value.chain.reset()
value.NotMatch(`[`)
value.chain.assertFailed(t)
value.chain.reset()
}

286
vendor/github.com/gavv/httpexpect/value.go generated vendored Normal file
View 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 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 another value.
// 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 another value.
// 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
}

465
vendor/github.com/gavv/httpexpect/value_test.go generated vendored Normal file
View File

@ -0,0 +1,465 @@
package httpexpect
import (
"encoding/json"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestValueFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))
chain.fail("fail")
value := &Value{chain, nil}
value.chain.assertFailed(t)
value.Path("$").chain.assertFailed(t)
value.Schema("")
assert.False(t, value.Object() == nil)
assert.False(t, value.Array() == nil)
assert.False(t, value.String() == nil)
assert.False(t, value.Number() == nil)
assert.False(t, value.Boolean() == nil)
assert.False(t, value.Path("/") == nil)
value.Object().chain.assertFailed(t)
value.Array().chain.assertFailed(t)
value.String().chain.assertFailed(t)
value.Number().chain.assertFailed(t)
value.Boolean().chain.assertFailed(t)
value.Null()
value.NotNull()
value.Equal(nil)
value.NotEqual(nil)
}
func TestValueCastNull(t *testing.T) {
reporter := newMockReporter(t)
var data interface{}
NewValue(reporter, data).Object().chain.assertFailed(t)
NewValue(reporter, data).Array().chain.assertFailed(t)
NewValue(reporter, data).String().chain.assertFailed(t)
NewValue(reporter, data).Number().chain.assertFailed(t)
NewValue(reporter, data).Boolean().chain.assertFailed(t)
NewValue(reporter, data).NotNull().chain.assertFailed(t)
NewValue(reporter, data).Null().chain.assertOK(t)
}
func TestValueCastIndirectNull(t *testing.T) {
reporter := newMockReporter(t)
var data []interface{}
NewValue(reporter, data).Object().chain.assertFailed(t)
NewValue(reporter, data).Array().chain.assertFailed(t)
NewValue(reporter, data).String().chain.assertFailed(t)
NewValue(reporter, data).Number().chain.assertFailed(t)
NewValue(reporter, data).Boolean().chain.assertFailed(t)
NewValue(reporter, data).NotNull().chain.assertFailed(t)
NewValue(reporter, data).Null().chain.assertOK(t)
}
func TestValueCastBad(t *testing.T) {
reporter := newMockReporter(t)
data := func() {}
NewValue(reporter, data).Object().chain.assertFailed(t)
NewValue(reporter, data).Array().chain.assertFailed(t)
NewValue(reporter, data).String().chain.assertFailed(t)
NewValue(reporter, data).Number().chain.assertFailed(t)
NewValue(reporter, data).Boolean().chain.assertFailed(t)
NewValue(reporter, data).NotNull().chain.assertFailed(t)
NewValue(reporter, data).Null().chain.assertFailed(t)
}
func TestValueCastObject(t *testing.T) {
reporter := newMockReporter(t)
data := map[string]interface{}{}
NewValue(reporter, data).Object().chain.assertOK(t)
NewValue(reporter, data).Array().chain.assertFailed(t)
NewValue(reporter, data).String().chain.assertFailed(t)
NewValue(reporter, data).Number().chain.assertFailed(t)
NewValue(reporter, data).Boolean().chain.assertFailed(t)
NewValue(reporter, data).NotNull().chain.assertOK(t)
NewValue(reporter, data).Null().chain.assertFailed(t)
}
func TestValueCastArray(t *testing.T) {
reporter := newMockReporter(t)
data := []interface{}{}
NewValue(reporter, data).Object().chain.assertFailed(t)
NewValue(reporter, data).Array().chain.assertOK(t)
NewValue(reporter, data).String().chain.assertFailed(t)
NewValue(reporter, data).Number().chain.assertFailed(t)
NewValue(reporter, data).Boolean().chain.assertFailed(t)
NewValue(reporter, data).NotNull().chain.assertOK(t)
NewValue(reporter, data).Null().chain.assertFailed(t)
}
func TestValueCastString(t *testing.T) {
reporter := newMockReporter(t)
data := ""
NewValue(reporter, data).Object().chain.assertFailed(t)
NewValue(reporter, data).Array().chain.assertFailed(t)
NewValue(reporter, data).String().chain.assertOK(t)
NewValue(reporter, data).Number().chain.assertFailed(t)
NewValue(reporter, data).Boolean().chain.assertFailed(t)
NewValue(reporter, data).NotNull().chain.assertOK(t)
NewValue(reporter, data).Null().chain.assertFailed(t)
}
func TestValueCastNumber(t *testing.T) {
reporter := newMockReporter(t)
data := 0.0
NewValue(reporter, data).Object().chain.assertFailed(t)
NewValue(reporter, data).Array().chain.assertFailed(t)
NewValue(reporter, data).String().chain.assertFailed(t)
NewValue(reporter, data).Number().chain.assertOK(t)
NewValue(reporter, data).Boolean().chain.assertFailed(t)
NewValue(reporter, data).NotNull().chain.assertOK(t)
NewValue(reporter, data).Null().chain.assertFailed(t)
}
func TestValueCastBoolean(t *testing.T) {
reporter := newMockReporter(t)
data := false
NewValue(reporter, data).Object().chain.assertFailed(t)
NewValue(reporter, data).Array().chain.assertFailed(t)
NewValue(reporter, data).String().chain.assertFailed(t)
NewValue(reporter, data).Number().chain.assertFailed(t)
NewValue(reporter, data).Boolean().chain.assertOK(t)
NewValue(reporter, data).NotNull().chain.assertOK(t)
NewValue(reporter, data).Null().chain.assertFailed(t)
}
func TestValueGetObject(t *testing.T) {
type (
myMap map[string]interface{}
)
reporter := newMockReporter(t)
data1 := map[string]interface{}{"foo": 123.0}
value1 := NewValue(reporter, data1)
inner1 := value1.Object()
inner1.chain.assertOK(t)
inner1.chain.reset()
assert.Equal(t, data1, inner1.Raw())
data2 := myMap{"foo": 123.0}
value2 := NewValue(reporter, data2)
inner2 := value2.Object()
inner2.chain.assertOK(t)
inner2.chain.reset()
assert.Equal(t, map[string]interface{}(data2), inner2.Raw())
}
func TestValueGetArray(t *testing.T) {
type (
myArray []interface{}
)
reporter := newMockReporter(t)
data1 := []interface{}{"foo", 123.0}
value1 := NewValue(reporter, data1)
inner1 := value1.Array()
inner1.chain.assertOK(t)
inner1.chain.reset()
assert.Equal(t, data1, inner1.Raw())
data2 := myArray{"foo", 123.0}
value2 := NewValue(reporter, data2)
inner2 := value2.Array()
inner2.chain.assertOK(t)
inner2.chain.reset()
assert.Equal(t, []interface{}(data2), inner2.Raw())
}
func TestValueGetString(t *testing.T) {
reporter := newMockReporter(t)
value := NewValue(reporter, "foo")
inner := value.String()
inner.chain.assertOK(t)
inner.chain.reset()
assert.Equal(t, "foo", inner.Raw())
}
func TestValueGetNumber(t *testing.T) {
type (
myInt int
)
reporter := newMockReporter(t)
data1 := 123.0
value1 := NewValue(reporter, data1)
inner1 := value1.Number()
inner1.chain.assertOK(t)
inner1.chain.reset()
assert.Equal(t, data1, inner1.Raw())
data2 := 123
value2 := NewValue(reporter, data2)
inner2 := value2.Number()
inner2.chain.assertOK(t)
inner2.chain.reset()
assert.Equal(t, float64(data2), inner2.Raw())
data3 := myInt(123)
value3 := NewValue(reporter, data3)
inner3 := value3.Number()
inner3.chain.assertOK(t)
inner3.chain.reset()
assert.Equal(t, float64(data3), inner3.Raw())
}
func TestValueGetBoolean(t *testing.T) {
reporter := newMockReporter(t)
value1 := NewValue(reporter, true)
inner1 := value1.Boolean()
inner1.chain.assertOK(t)
inner1.chain.reset()
assert.Equal(t, true, inner1.Raw())
value2 := NewValue(reporter, false)
inner2 := value2.Boolean()
inner2.chain.assertOK(t)
inner2.chain.reset()
assert.Equal(t, false, inner2.Raw())
}
func TestValueEqual(t *testing.T) {
reporter := newMockReporter(t)
data1 := map[string]interface{}{"foo": "bar"}
data2 := "baz"
NewValue(reporter, data1).Equal(data1).chain.assertOK(t)
NewValue(reporter, data2).Equal(data2).chain.assertOK(t)
NewValue(reporter, data1).NotEqual(data1).chain.assertFailed(t)
NewValue(reporter, data2).NotEqual(data2).chain.assertFailed(t)
NewValue(reporter, data1).Equal(data2).chain.assertFailed(t)
NewValue(reporter, data2).Equal(data1).chain.assertFailed(t)
NewValue(reporter, data1).NotEqual(data2).chain.assertOK(t)
NewValue(reporter, data2).NotEqual(data1).chain.assertOK(t)
NewValue(reporter, nil).Equal(nil).chain.assertOK(t)
NewValue(reporter, nil).Equal(map[string]interface{}(nil)).chain.assertOK(t)
NewValue(reporter, nil).Equal(map[string]interface{}{}).chain.assertFailed(t)
NewValue(reporter, data1).Equal(func() {}).chain.assertFailed(t)
NewValue(reporter, data1).NotEqual(func() {}).chain.assertFailed(t)
}
func TestValuePathObject(t *testing.T) {
reporter := newMockReporter(t)
user0 := map[string]interface{}{"name": "john"}
user1 := map[string]interface{}{"name": "bob"}
data := map[string]interface{}{
"users": []interface{}{
user0,
user1,
},
}
value := NewValue(reporter, data)
assert.Equal(t, data, value.Path("$").Raw())
assert.Equal(t, data["users"], value.Path("$.users").Raw())
assert.Equal(t, user0, value.Path("$.users[0]").Raw())
assert.Equal(t, "john", value.Path("$.users[0].name").Raw())
assert.Equal(t, []interface{}{"john", "bob"}, value.Path("$.users[*].name").Raw())
assert.Equal(t, []interface{}{"john", "bob"}, value.Path("$..name").Raw())
value.chain.assertOK(t)
names := value.Path("$..name").Array().Iter()
names[0].String().Equal("john").chain.assertOK(t)
names[1].String().Equal("bob").chain.assertOK(t)
value.chain.assertOK(t)
for _, key := range []string{"$.bad", "!"} {
bad := value.Path(key)
assert.True(t, bad != nil)
assert.True(t, bad.Raw() == nil)
value.chain.assertFailed(t)
value.chain.reset()
}
}
func TestValuePathArray(t *testing.T) {
reporter := newMockReporter(t)
user0 := map[string]interface{}{"name": "john"}
user1 := map[string]interface{}{"name": "bob"}
data := []interface{}{
user0,
user1,
}
value := NewValue(reporter, data)
assert.Equal(t, data, value.Path("$").Raw())
assert.Equal(t, user0, value.Path("$[0]").Raw())
assert.Equal(t, "john", value.Path("$[0].name").Raw())
assert.Equal(t, []interface{}{"john", "bob"}, value.Path("$[*].name").Raw())
assert.Equal(t, []interface{}{"john", "bob"}, value.Path("$..name").Raw())
value.chain.assertOK(t)
}
func TestValuePathString(t *testing.T) {
reporter := newMockReporter(t)
data := "foo"
value := NewValue(reporter, data)
assert.Equal(t, data, value.Path("$").Raw())
value.chain.assertOK(t)
}
func TestValuePathNumber(t *testing.T) {
reporter := newMockReporter(t)
data := 123
value := NewValue(reporter, data)
assert.Equal(t, float64(data), value.Path("$").Raw())
value.chain.assertOK(t)
}
func TestValuePathBoolean(t *testing.T) {
reporter := newMockReporter(t)
data := true
value := NewValue(reporter, data)
assert.Equal(t, data, value.Path("$").Raw())
value.chain.assertOK(t)
}
func TestValuePathNull(t *testing.T) {
reporter := newMockReporter(t)
value := NewValue(reporter, nil)
assert.Equal(t, nil, value.Path("$").Raw())
value.chain.assertOK(t)
}
func TestValuePathError(t *testing.T) {
reporter := newMockReporter(t)
data := "foo"
value := NewValue(reporter, data)
for _, key := range []string{"$.bad", "!"} {
bad := value.Path(key)
assert.True(t, bad != nil)
assert.True(t, bad.Raw() == nil)
value.chain.assertFailed(t)
}
}
func TestValueSchema(t *testing.T) {
reporter := newMockReporter(t)
schema := `{
"type": "object",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "integer"
}
},
"require": ["foo", "bar"]
}`
data1 := map[string]interface{}{
"foo": "a",
"bar": 1,
}
data2 := map[string]interface{}{
"foo": "a",
"bar": "b",
}
NewValue(reporter, data1).Schema(schema).chain.assertOK(t)
NewValue(reporter, data2).Schema(schema).chain.assertFailed(t)
NewValue(reporter, data1).Schema([]byte(schema)).chain.assertOK(t)
NewValue(reporter, data2).Schema([]byte(schema)).chain.assertFailed(t)
var b interface{}
json.Unmarshal([]byte(schema), &b)
NewValue(reporter, data1).Schema(b).chain.assertOK(t)
NewValue(reporter, data2).Schema(b).chain.assertFailed(t)
tmp, _ := ioutil.TempFile("", "httpexpect")
defer os.Remove(tmp.Name())
tmp.Write([]byte(schema))
tmp.Close()
url := "file://" + tmp.Name()
NewValue(reporter, data1).Schema(url).chain.assertOK(t)
NewValue(reporter, data2).Schema(url).chain.assertFailed(t)
NewValue(reporter, data1).Schema("file:///bad/path").chain.assertFailed(t)
NewValue(reporter, data1).Schema("{ bad json").chain.assertFailed(t)
}

Some files were not shown because too many files have changed in this diff Show More