├── .gitignore ├── .travis.yml ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── Makefile ├── README.md ├── client.go ├── client_test.go ├── doc.go ├── errors.go ├── errors_test.go ├── types.go ├── types_test.go └── vendor └── github.com ├── google └── go-cmp │ ├── .travis.yml │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── README.md │ ├── cmp │ ├── cmpopts │ │ ├── equate.go │ │ ├── ignore.go │ │ ├── sort.go │ │ ├── struct_filter.go │ │ ├── util_test.go │ │ └── xform.go │ ├── compare.go │ ├── compare_test.go │ ├── example_reporter_test.go │ ├── example_test.go │ ├── export_panic.go │ ├── export_unsafe.go │ ├── internal │ │ ├── diff │ │ │ ├── debug_disable.go │ │ │ ├── debug_enable.go │ │ │ ├── diff.go │ │ │ └── diff_test.go │ │ ├── flags │ │ │ ├── flags.go │ │ │ ├── toolchain_legacy.go │ │ │ └── toolchain_recent.go │ │ ├── function │ │ │ ├── func.go │ │ │ └── func_test.go │ │ ├── testprotos │ │ │ └── protos.go │ │ ├── teststructs │ │ │ ├── project1.go │ │ │ ├── project2.go │ │ │ ├── project3.go │ │ │ ├── project4.go │ │ │ └── structs.go │ │ └── value │ │ │ ├── pointer_purego.go │ │ │ ├── pointer_unsafe.go │ │ │ ├── sort.go │ │ │ ├── sort_test.go │ │ │ ├── zero.go │ │ │ └── zero_test.go │ ├── options.go │ ├── options_test.go │ ├── path.go │ ├── report.go │ ├── report_compare.go │ ├── report_reflect.go │ ├── report_slices.go │ ├── report_text.go │ └── report_value.go │ └── go.mod └── pkg └── errors ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── appveyor.yml ├── bench_test.go ├── errors.go ├── errors_test.go ├── example_test.go ├── format_test.go ├── stack.go └── stack_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, 2019 Tim Heckman 2 | # Use of this source code is governed by the MIT License that can be found in 3 | # the LICENSE file at the root of this repository. 4 | 5 | language: go 6 | go: 7 | - 1.12.x 8 | - 1.13.x 9 | env: 10 | - GO111MODULE=off 11 | sudo: false 12 | notifications: 13 | email: 14 | on_success: never 15 | on_failure: always 16 | before_install: make prebuild 17 | install: dep ensure 18 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | name = "github.com/google/go-cmp" 6 | packages = [ 7 | "cmp", 8 | "cmp/internal/diff", 9 | "cmp/internal/flags", 10 | "cmp/internal/function", 11 | "cmp/internal/value" 12 | ] 13 | revision = "2d0692c2e9617365a95b295612ac0d4415ba4627" 14 | version = "v0.3.1" 15 | 16 | [[projects]] 17 | name = "github.com/pkg/errors" 18 | packages = ["."] 19 | revision = "645ef00459ed84a119197bfb8d8205042c6df63d" 20 | version = "v0.8.0" 21 | 22 | [solve-meta] 23 | analyzer-name = "dep" 24 | analyzer-version = 1 25 | inputs-digest = "0af4645a5e35ef4f963e9427c4cb010cbdafb554b5438bf64e0e77e4276cade5" 26 | solver-name = "gps-cdcl" 27 | solver-version = 1 28 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | 22 | 23 | [[constraint]] 24 | name = "github.com/pkg/errors" 25 | version = "0.8.0" 26 | 27 | [[constraint]] 28 | name = "github.com/google/go-cmp" 29 | version = "0.3.1" 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017, 2019 Tim Heckman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, 2019 Tim Heckman 2 | # Use of this source code is governed by the MIT License that can be found in 3 | # the LICENSE file at the root of this repository. 4 | 5 | test: vet lint staticcheck tests 6 | 7 | prebuild: 8 | go get -u github.com/golang/dep/cmd/dep \ 9 | golang.org/x/lint/golint \ 10 | honnef.co/go/tools/cmd/staticcheck \ 11 | golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow 12 | 13 | # this needs to be updated when a future version of 1.13.x includes: 14 | # https://github.com/golang/go/issues/34053 15 | # 16 | # original line now removed: 17 | # go vet -vettool=$(shell which shadow) ./... 18 | vet: 19 | go vet ./... 20 | shadow ./... 21 | 22 | lint: 23 | golint -set_exit_status 24 | 25 | staticcheck: 26 | staticcheck ./... 27 | 28 | tests: 29 | go test -race -covermode atomic -cover -coverprofile profile.out ./... 30 | go tool cover -func=profile.out 31 | 32 | .PHONY: test prebuild vet lint staticcheck tests 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ipdata 2 | [![License](https://img.shields.io/github/license/theckman/go-ipdata.svg)](https://github.com/theckman/go-ipdata/blob/master/LICENSE) 3 | [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/theckman/go-ipdata) 4 | [![Latest Git Tag](https://img.shields.io/github/tag/theckman/go-ipdata.svg)](https://github.com/theckman/go-ipdata/releases) 5 | [![Travis master Build Status](https://img.shields.io/travis/theckman/go-ipdata/master.svg?label=TravisCI)](https://travis-ci.org/theckman/go-ipdata/branches) 6 | [![Go Cover Test Coverage](https://gocover.io/_badge/github.com/theckman/go-ipdata?v0)](https://gocover.io/github.com/theckman/go-ipdata) 7 | [![Go Report Card](https://goreportcard.com/badge/github.com/theckman/go-ipdata)](https://goreportcard.com/report/github.com/theckman/go-ipdata) 8 | 9 | Package ipdata is a client for the https://ipdata.co API. It provides functions 10 | for looking up data, as well as parsing the data in a programmatic way. The 11 | simplest usage is to build a new client and then use the `Lookup` method. 12 | 13 | ## License 14 | This code is released under the MIT License. Please see the 15 | [LICENSE](https://github.com/theckman/go-ipdata/blob/master/LICENSE) for the 16 | full content of the license. 17 | 18 | ## Contributing 19 | If you'd like to contribute to this project, I welcome any pull requests against 20 | this repo. The only ask is that a GitHub issue be opened detailing the desired 21 | functionality before making any pull requests. 22 | 23 | ## Usage 24 | The service provided by `ipdata` requires an API key before making API calls. 25 | Attempts to create a client without one will fail, as would attempts to contact 26 | the API. You can get an API key from https://ipdata.co/. 27 | 28 | Here is a simple example of using the library: 29 | 30 | ```Go 31 | import ( 32 | "github.com/ipdata/go" 33 | "fmt" 34 | ) 35 | 36 | ipd, _ := ipdata.NewClient("EXAMPLE_API_KEY") 37 | 38 | data, err := ipd.Lookup("8.8.8.8") 39 | if err != nil { 40 | // handle error 41 | } 42 | 43 | fmt.Printf("%s (%s)\n", data.IP, data.ASN) 44 | ``` 45 | 46 | Errors returned from the lookup function calls may be of type `Error`, which 47 | includes the message from the API and the HTTP status code. The `Error()` method 48 | on this type only returns the message and not the status code. To maintain 49 | compatibility with Go 1.12.x, this is still using github.com/pkg/errors for 50 | error management: 51 | 52 | ```Go 53 | import "github.com/pkg/errors" 54 | 55 | data, err := ipd.Lookup("8.8.8.8") 56 | if err != nil { 57 | // do a type assertion on the error 58 | rerr, ok := errors.Cause(err).(ipdata.Error) 59 | 60 | if !ok { 61 | // this wasn't a failure from rate limiting 62 | } 63 | 64 | fmt.Println("%d: %s", rerr.Code(), rerr.Error()) 65 | } 66 | ``` 67 | 68 | ## Contributors 69 | 70 | - [Tim Heckman](https://github.com/theckman/) - Created the first version of this library 71 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, 2019 Tim Heckman 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file at the root of this repository. 4 | 5 | package ipdata 6 | 7 | import ( 8 | "bytes" 9 | "context" 10 | "encoding/json" 11 | "fmt" 12 | "io" 13 | "io/ioutil" 14 | "net" 15 | "net/http" 16 | "net/url" 17 | "runtime" 18 | "time" 19 | 20 | "github.com/pkg/errors" 21 | ) 22 | 23 | // Version is the package version 24 | const Version = "0.7.1" 25 | 26 | // fqpn is the Fully Qualified Package Name for use in the client's User-Agent 27 | const fqpn = "github.com/theckman/go-ipdata" 28 | 29 | const ( 30 | apiEndpoint = "https://api.ipdata.co/" 31 | apiAuthParam = "api-key" 32 | ) 33 | 34 | var userAgent = fmt.Sprintf( 35 | "go-ipdata/%s (%s) Go-http-client/%s (%s %s)", 36 | Version, fqpn, runtime.Version(), runtime.GOOS, runtime.GOARCH, 37 | ) 38 | 39 | var errAPIKey = errors.New("apiKey cannot be an empty string") 40 | 41 | // Client is the struct to represent the functionality presented by the 42 | // https://ipdata.co API. 43 | type Client struct { 44 | c *http.Client // http client 45 | e string // api endpoint 46 | k string // api key 47 | } 48 | 49 | // NewClient takes an optional API key and returns a Client. If you do not have 50 | // an API key use an empty string (""). 51 | func NewClient(apiKey string) (Client, error) { 52 | if len(apiKey) == 0 { 53 | return Client{}, errAPIKey 54 | } 55 | 56 | return Client{ 57 | c: newHTTPClient(), 58 | e: apiEndpoint, 59 | k: apiKey, 60 | }, nil 61 | } 62 | 63 | type apiErr struct { 64 | Message string `json:"message"` 65 | } 66 | 67 | // RawLookup uses the internal mechanics to make an HTTP request to the API and 68 | // returns the HTTP response. This allows consumers of the API to implement 69 | // their own behaviors. If an API error occurs, the error value will be of type 70 | // Error. 71 | func (c Client) RawLookup(ip string) (*http.Response, error) { 72 | return c.RawLookupWithContext(context.Background(), ip) 73 | } 74 | 75 | // RawLookupWithContext is a RawLookup that uses a provided context.Context. 76 | func (c Client) RawLookupWithContext(ctx context.Context, ip string) (*http.Response, error) { 77 | // build request 78 | req, err := newGetRequestWithContext(ctx, c.e+ip, c.k) 79 | if err != nil { 80 | return nil, errors.Wrapf(err, "error building request to look up %s", ip) 81 | } 82 | 83 | // action request 84 | resp, err := c.c.Do(req) 85 | if err != nil { 86 | return nil, errors.Wrapf(err, "http request to %q failed", req.URL.Scheme+"://"+req.URL.Host+req.URL.Path) 87 | } 88 | 89 | switch resp.StatusCode { 90 | case http.StatusOK: // 200 91 | // we can try and parse 92 | return resp, nil 93 | default: 94 | // provide response body as error to consumer 95 | body, err := ioutil.ReadAll(resp.Body) 96 | if err != nil { 97 | return nil, errors.Wrapf(err, "failed to read body from response with status code %q: %s", resp.Status, err) 98 | } 99 | 100 | var a apiErr 101 | 102 | if err := json.Unmarshal(body, &a); err != nil { 103 | return nil, errors.Errorf("request for %q failed (unexpected response): %s: %v", ip, resp.Status, err) 104 | } 105 | 106 | return nil, newError(a.Message, resp.StatusCode) 107 | } 108 | } 109 | 110 | func decodeIP(r io.Reader) (IP, error) { 111 | body, err := ioutil.ReadAll(r) 112 | if err != nil { 113 | return IP{}, err 114 | } 115 | 116 | ip := IP{} 117 | 118 | if err := json.Unmarshal(body, &ip); err != nil { 119 | return IP{}, fmt.Errorf("failed to parse JSON: %s", err) 120 | } 121 | 122 | return ip, nil 123 | } 124 | 125 | // Lookup takes an IP address to look up the details for. An empty string means 126 | // you want the information about the current node's pubilc IP address. If an 127 | // API error occurs, the error value will be of type Error. 128 | func (c Client) Lookup(ip string) (IP, error) { 129 | return c.LookupWithContext(context.Background(), ip) 130 | } 131 | 132 | // LookupWithContext is a Lookup that uses a provided context.Context. 133 | func (c Client) LookupWithContext(ctx context.Context, ip string) (IP, error) { 134 | resp, err := c.RawLookupWithContext(ctx, ip) 135 | if err != nil { 136 | return IP{}, err 137 | } 138 | 139 | defer func() { 140 | _, _ = io.Copy(ioutil.Discard, resp.Body) 141 | _ = resp.Body.Close() 142 | }() 143 | 144 | pip, err := decodeIP(resp.Body) 145 | if err != nil { 146 | return IP{}, err 147 | } 148 | 149 | return pip, nil 150 | } 151 | 152 | func newGetRequestWithContext(ctx context.Context, urlStr, apiKey string) (*http.Request, error) { 153 | if len(urlStr) == 0 { 154 | return nil, errors.New("url cannot be an empty string") 155 | } 156 | 157 | if len(apiKey) == 0 { 158 | return nil, errAPIKey 159 | } 160 | 161 | req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlStr, nil) 162 | if err != nil { 163 | return nil, err 164 | } 165 | 166 | req.Header.Set("User-Agent", userAgent) 167 | req.Header.Set("Accept", "application/json") 168 | 169 | q := url.Values{apiAuthParam: []string{apiKey}} 170 | req.URL.RawQuery = q.Encode() 171 | 172 | return req, nil 173 | } 174 | 175 | // RawBulkLookup takes a set of IP addresses, and returns the response from the 176 | // API. 177 | func (c *Client) RawBulkLookup(ips []string) (*http.Response, error) { 178 | return c.RawBulkLookupWithContext(context.Background(), ips) 179 | } 180 | 181 | // RawBulkLookupWithContext is a RawBulkLookup with a provided context.Context. 182 | func (c *Client) RawBulkLookupWithContext(ctx context.Context, ips []string) (*http.Response, error) { 183 | // build request 184 | req, err := newBulkPostRequestWithContext(ctx, c.e+"bulk", c.k, ips) 185 | if err != nil { 186 | return nil, errors.Wrap(err, "error building bulk lookup request") 187 | } 188 | 189 | // action request 190 | resp, err := c.c.Do(req) 191 | if err != nil { 192 | return nil, errors.Wrapf(err, "http request to %q failed", req.URL.Scheme+"://"+req.URL.Host+req.URL.Path) 193 | } 194 | 195 | switch resp.StatusCode { 196 | case http.StatusOK: // 200 197 | // we can try and parse 198 | return resp, nil 199 | default: 200 | // provide response body as error to consumer 201 | body, err := ioutil.ReadAll(resp.Body) 202 | if err != nil { 203 | return nil, errors.Wrapf(err, "failed to read body from response with status code %q: %s", resp.Status, err) 204 | } 205 | 206 | var a apiErr 207 | 208 | if err := json.Unmarshal(body, &a); err != nil { 209 | return nil, errors.Errorf("request failed (unexpected response): %s: %v", resp.Status, err) 210 | } 211 | 212 | return nil, newError(a.Message, resp.StatusCode) 213 | } 214 | } 215 | 216 | func newBulkPostRequestWithContext(ctx context.Context, urlStr, apiKey string, ips []string) (*http.Request, error) { 217 | if len(urlStr) == 0 { 218 | return nil, errors.New("url cannot be an empty string") 219 | } 220 | 221 | if len(apiKey) == 0 { 222 | return nil, errAPIKey 223 | } 224 | 225 | if len(ips) == 0 { 226 | return nil, errors.New("must provide at least one IP") 227 | } 228 | 229 | if err := ctx.Err(); err != nil { 230 | return nil, err 231 | } 232 | 233 | buf := &bytes.Buffer{} 234 | if err := json.NewEncoder(buf).Encode(ips); err != nil { 235 | return nil, errors.Wrap(err, "failed to encode JSON") 236 | } 237 | 238 | req, err := http.NewRequestWithContext(ctx, http.MethodPost, urlStr, buf) 239 | if err != nil { 240 | return nil, err 241 | } 242 | 243 | req.Header.Set("User-Agent", userAgent) 244 | req.Header.Set("Accept", "application/json") 245 | req.Header.Set("Content-Type", "application/json") 246 | 247 | q := url.Values{apiAuthParam: []string{apiKey}} 248 | req.URL.RawQuery = q.Encode() 249 | 250 | return req, nil 251 | } 252 | 253 | // BulkLookup takes a set of IP addresses, and returns a set of results from the 254 | // API. If the request failed, or something was wrong with one of the inputs, 255 | // the error value will be of type Error. If err is non-nil, the []*IP slice may 256 | // contain data (if it was able to process some of the inputs). The error value 257 | // will contain the index of the first error in the bulk response. 258 | // 259 | // Please note, any IPs that had a failed lookup will be a nil entry in the 260 | // slice when an error is returned. So if you start to use the []*IP when err != 261 | // nil, you will need to add explicit nil checks to avoid pointer derefence 262 | // panics. 263 | func (c *Client) BulkLookup(ips []string) ([]*IP, error) { 264 | return c.BulkLookupWithContext(context.Background(), ips) 265 | } 266 | 267 | // BulkLookupWithContext is a BulkLookup with a provided context.Context. 268 | func (c *Client) BulkLookupWithContext(ctx context.Context, ips []string) ([]*IP, error) { 269 | resp, err := c.RawBulkLookupWithContext(ctx, ips) 270 | if err != nil { 271 | return nil, err 272 | } 273 | 274 | defer func() { 275 | _, _ = io.Copy(ioutil.Discard, resp.Body) 276 | _ = resp.Body.Close() 277 | }() 278 | 279 | body, err := ioutil.ReadAll(resp.Body) 280 | if err != nil { 281 | return nil, errors.Wrap(err, "failed to read response body") 282 | } 283 | 284 | var bip []bulkIP 285 | 286 | if err := json.Unmarshal(body, &bip); err != nil { 287 | return nil, errors.Wrap(err, "failed to parse JSON") 288 | } 289 | 290 | res := make([]*IP, len(bip)) 291 | var retErr error 292 | 293 | for i, ip := range bip { 294 | if len(ip.Message) > 0 && retErr == nil { 295 | retErr = Error{ 296 | m: ip.Message, 297 | c: resp.StatusCode, 298 | i: i, 299 | } 300 | continue 301 | } 302 | 303 | res[i] = bulkToIP(ip) 304 | } 305 | 306 | if retErr != nil { 307 | return res, retErr 308 | } 309 | 310 | return res, nil // avoid nil interface check problem 311 | } 312 | 313 | func newHTTPClient() *http.Client { 314 | return &http.Client{ 315 | Transport: &http.Transport{ 316 | Proxy: http.ProxyFromEnvironment, 317 | DialContext: (&net.Dialer{ 318 | Timeout: 30 * time.Second, 319 | KeepAlive: 30 * time.Second, 320 | DualStack: true, 321 | }).DialContext, 322 | MaxIdleConns: 100, 323 | IdleConnTimeout: 60 * time.Second, 324 | TLSHandshakeTimeout: 10 * time.Second, 325 | ExpectContinueTimeout: 2 * time.Second, 326 | MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, 327 | }, 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Tim Heckman 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file at the root of this repository. 4 | 5 | // Package ipdata is a client for the https://ipdata.co API. It provides 6 | // functions for looking up data, as well as parsing the data in a programmatic 7 | // way. The simplest usage is to build a new client and then use the Lookup 8 | // method. 9 | // 10 | // If you have any problems with this client, please raise an issue on GitHub: 11 | // 12 | // * https://github.com/theckman/go-ipdata/issues 13 | // 14 | // Example usage: 15 | // 16 | // import "github.com/theckman/go-ipdata" 17 | // 18 | // ipd := ipdata.NewClient("") // API key is optional 19 | // data, err := ipd.Lookup("8.8.8.8") 20 | package ipdata 21 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, 2019 Tim Heckman 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file at the root of this repository. 4 | 5 | package ipdata 6 | 7 | // Error represents an error returned from the ipdata.co API. This error value 8 | // will be used whenever the HTTP request to the API completed, but the HTTP 9 | // status code indicated failure. The Error() method will return the JSON 10 | // message sent by the API, if present, and Code() returns the numeric HTTP 11 | // status code. 12 | type Error struct { 13 | m string 14 | c int 15 | i int 16 | } 17 | 18 | func newError(message string, code int) Error { 19 | return Error{ 20 | m: message, 21 | c: code, 22 | i: -1, 23 | } 24 | } 25 | 26 | // Error returns the message JSON field sent from the ipdata.co API. This also 27 | // satisfies the error interface. 28 | func (e Error) Error() string { 29 | return e.m 30 | } 31 | 32 | // Code returns the HTTP Status code returned from the ipdata.co API. 33 | func (e Error) Code() int { 34 | return e.c 35 | } 36 | 37 | // Index returns the index first item in a BulkLookup that encountered an error. 38 | func (e Error) Index() int { 39 | return e.i 40 | } 41 | -------------------------------------------------------------------------------- /errors_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Tim Heckman 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file at the root of this repository. 4 | 5 | package ipdata 6 | 7 | import "testing" 8 | 9 | func TestError(t *testing.T) { 10 | const wantStr = "test" 11 | const wantCode = 42 12 | const wantIndex = 84 13 | 14 | ev := Error{ 15 | m: "test", 16 | c: 42, 17 | i: 84, 18 | } 19 | 20 | if got := ev.Error(); got != wantStr { 21 | t.Fatalf("ev.Error() = %q, want %q", got, wantStr) 22 | } 23 | 24 | if got := ev.Code(); got != wantCode { 25 | t.Fatalf("ev.Code() = %d, want %d", got, wantCode) 26 | } 27 | 28 | if got := ev.Index(); got != wantIndex { 29 | t.Fatalf("ev.Index() = %d, want %d", got, wantIndex) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, 2019 Tim Heckman 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file at the root of this repository. 4 | 5 | package ipdata 6 | 7 | // IP is a struct that represents the JSON response from the https://ipdata.co 8 | // API. 9 | type IP struct { 10 | IP string `json:"ip"` 11 | ASN ASN `json:"asn"` 12 | Organization string `json:"organisation"` 13 | 14 | City string `json:"city"` 15 | Region string `json:"region"` 16 | RegionCode string `json:"region_code"` 17 | Postal string `json:"postal"` 18 | 19 | CountryName string `json:"country_name"` 20 | CountryCode string `json:"country_code"` 21 | 22 | Flag string `json:"flag"` 23 | EmojiFlag string `json:"emoji_flag"` 24 | EmojiUnicode string `json:"emoji_unicode"` 25 | 26 | ContinentName string `json:"continent_name"` 27 | ContinentCode string `json:"continent_code"` 28 | 29 | Latitude float64 `json:"latitude"` 30 | Longitude float64 `json:"longitude"` 31 | 32 | CallingCode string `json:"calling_code"` 33 | 34 | IsEU bool `json:"is_eu"` 35 | 36 | Languages []Language `json:"language,omitempty"` 37 | 38 | Currency *Currency `json:"currency,omitempty"` 39 | 40 | Carrier *Carrier `json:"carrier,omitempty"` 41 | 42 | TimeZone *TimeZone `json:"time_zone,omitempty"` 43 | 44 | Threat *Threat `json:"threat,omitempty"` 45 | } 46 | 47 | func (ip IP) String() string { 48 | return ip.IP 49 | } 50 | 51 | // ASN represents the Autonomous System Number data returned from the API. 52 | type ASN struct { 53 | ASN string `json:"asn"` 54 | Name string `json:"name"` 55 | Domain string `json:"domain"` 56 | Route string `json:"route"` 57 | Type string `json:"type"` 58 | } 59 | 60 | // Carrier represents the carrier data returned from the API. 61 | type Carrier struct { 62 | Name string `json:"name"` 63 | MCC string `json:"mcc"` 64 | MNC string `json:"mnc"` 65 | } 66 | 67 | // Language represents the language object within the JSON response from the 68 | // API. This provides information about the language(s) where that IP resides. 69 | type Language struct { 70 | Name string `json:"name"` 71 | Native string `json:"native"` 72 | } 73 | 74 | // Currency represents the currency object within the JSON response from the 75 | // API. This provides information about the currency where that IP resides. 76 | type Currency struct { 77 | Name string `json:"name"` 78 | Code string `json:"code"` 79 | Symbol string `json:"symbol"` 80 | Native string `json:"native"` 81 | Plural string `json:"plural"` 82 | } 83 | 84 | // TimeZone represents the time_zone object within the JSON response from the 85 | // API. This provides information about the timezone where that IP resides. 86 | type TimeZone struct { 87 | Name string `json:"name"` 88 | Abbreviation string `json:"abbr"` 89 | Offset string `json:"offset"` 90 | IsDST bool `json:"is_dst"` 91 | CurrentTime string `json:"current_time,omitempty"` 92 | } 93 | 94 | // Threat represents the threat object within the JSON response from the API. 95 | // This provides information about what type of threat this IP may be. 96 | type Threat struct { 97 | IsTOR bool `json:"is_tor"` 98 | IsVPN bool `json:"is_vpn"` 99 | IsICloudRelay bool `json:"is_icloud_relay"` 100 | IsProxy bool `json:"is_proxy"` 101 | IsDatacenter bool `json:"is_datacenter"` 102 | IsAnonymous bool `json:"is_anonymous"` 103 | IsKnownAttacker bool `json:"is_known_attacker"` 104 | IsKnownAbuser bool `json:"is_known_abuser"` 105 | IsThreat bool `json:"is_threat"` 106 | IsBogon bool `json:"is_bogon"` 107 | Blocklists []Blocklist `json:"blocklists"` 108 | Scores Scores `json:"scores"` 109 | } 110 | 111 | type Blocklist struct { 112 | Name string `json:"name"` 113 | Site string `json:"site"` 114 | Type string `json:"type"` 115 | } 116 | 117 | 118 | type Scores struct { 119 | VPNScore int `json:"vpn_score"` 120 | ProxyScore int `json:"proxy_score"` 121 | ThreatScore int `json:"threat_score"` 122 | TrustScore int `json:"trust_score"` 123 | } 124 | 125 | type bulkIP struct { 126 | IP string `json:"ip"` 127 | ASN ASN `json:"asn"` 128 | Organization string `json:"organisation"` 129 | 130 | City string `json:"city"` 131 | Region string `json:"region"` 132 | Postal string `json:"postal"` 133 | 134 | CountryName string `json:"country_name"` 135 | CountryCode string `json:"country_code"` 136 | 137 | Flag string `json:"flag"` 138 | EmojiFlag string `json:"emoji_flag"` 139 | EmojiUnicode string `json:"emoji_unicode"` 140 | 141 | ContinentName string `json:"continent_name"` 142 | ContinentCode string `json:"continent_code"` 143 | 144 | Latitude float64 `json:"latitude"` 145 | Longitude float64 `json:"longitude"` 146 | 147 | CallingCode string `json:"calling_code"` 148 | 149 | IsEU bool `json:"is_eu"` 150 | 151 | Languages []Language `json:"language,omitempty"` 152 | 153 | Currency *Currency `json:"currency,omitempty"` 154 | 155 | TimeZone *TimeZone `json:"time_zone,omitempty"` 156 | 157 | Threat *Threat `json:"threat,omitempty"` 158 | 159 | Message string `json:"message"` 160 | } 161 | 162 | func bulkToIP(bip bulkIP) *IP { 163 | ip := IP{ 164 | IP: bip.IP, 165 | ASN: bip.ASN, 166 | Organization: bip.Organization, 167 | City: bip.City, 168 | Region: bip.Region, 169 | Postal: bip.Postal, 170 | CountryName: bip.CountryName, 171 | CountryCode: bip.CountryCode, 172 | Flag: bip.Flag, 173 | EmojiFlag: bip.EmojiFlag, 174 | EmojiUnicode: bip.EmojiUnicode, 175 | ContinentName: bip.ContinentName, 176 | ContinentCode: bip.ContinentCode, 177 | Latitude: bip.Latitude, 178 | Longitude: bip.Longitude, 179 | CallingCode: bip.CallingCode, 180 | IsEU: bip.IsEU, 181 | Currency: bip.Currency, 182 | TimeZone: bip.TimeZone, 183 | Threat: bip.Threat, 184 | } 185 | 186 | if len(bip.Languages) > 0 { 187 | ip.Languages = bip.Languages 188 | } 189 | 190 | return &ip 191 | } 192 | -------------------------------------------------------------------------------- /types_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Tim Heckman 2 | // Use of this source code is governed by the MIT License that can be found in 3 | // the LICENSE file at the root of this repository. 4 | 5 | package ipdata 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/google/go-cmp/cmp" 11 | ) 12 | 13 | func Test_IP_String(t *testing.T) { 14 | ip := IP{IP: "8.8.8.8"} 15 | if ip.String() != "8.8.8.8" { 16 | t.Errorf("ip.String() = %q, want %q", ip.String(), "8.8.8.8") 17 | } 18 | } 19 | 20 | func Test_bulkToIP(t *testing.T) { 21 | bip := bulkIP{ 22 | IP: "76.14.47.42", 23 | ASN: ASN{ 24 | ASN: "AS11404", 25 | Name: "vanoppen.biz LLC", 26 | Domain: "wavebroadband.com", 27 | Route: "76.14.0.0/17", 28 | Type: "isp", 29 | }, 30 | Organization: "vanoppen.biz LLC", 31 | City: "San Francisco", 32 | Region: "California", 33 | Postal: "94132", 34 | CountryName: "United States", 35 | CountryCode: "US", 36 | Flag: tjFlagURL, 37 | EmojiUnicode: `U+1F1FA U+1F1F8`, 38 | ContinentName: "North America", 39 | ContinentCode: "NA", 40 | Latitude: 37.723, 41 | Longitude: -122.4842, 42 | CallingCode: "1", 43 | IsEU: true, 44 | Languages: []Language{{Name: "English (US)", Native: "en-us"}}, 45 | Currency: &Currency{ 46 | Name: "US Dollar", 47 | Code: "USD", 48 | Symbol: "$", 49 | Native: "$", 50 | Plural: "US dollars", 51 | }, 52 | TimeZone: &TimeZone{ 53 | Name: "America/Los_Angeles", 54 | Abbreviation: "PST", 55 | Offset: "-0800", 56 | IsDST: false, 57 | CurrentTime: "2019-02-27T15:00:32.745936-08:00", 58 | }, 59 | Threat: &Threat{ 60 | IsTOR: false, 61 | IsProxy: false, 62 | IsAnonymous: false, 63 | IsKnownAttacker: false, 64 | IsKnownAbuser: false, 65 | IsThreat: true, 66 | IsBogon: false, 67 | }, 68 | } 69 | 70 | ip := &IP{ 71 | IP: "76.14.47.42", 72 | ASN: ASN{ 73 | ASN: "AS11404", 74 | Name: "vanoppen.biz LLC", 75 | Domain: "wavebroadband.com", 76 | Route: "76.14.0.0/17", 77 | Type: "isp", 78 | }, 79 | Organization: "vanoppen.biz LLC", 80 | City: "San Francisco", 81 | Region: "California", 82 | Postal: "94132", 83 | CountryName: "United States", 84 | CountryCode: "US", 85 | Flag: tjFlagURL, 86 | EmojiUnicode: `U+1F1FA U+1F1F8`, 87 | ContinentName: "North America", 88 | ContinentCode: "NA", 89 | Latitude: 37.723, 90 | Longitude: -122.4842, 91 | CallingCode: "1", 92 | IsEU: true, 93 | Languages: []Language{{Name: "English (US)", Native: "en-us"}}, 94 | Currency: &Currency{ 95 | Name: "US Dollar", 96 | Code: "USD", 97 | Symbol: "$", 98 | Native: "$", 99 | Plural: "US dollars", 100 | }, 101 | TimeZone: &TimeZone{ 102 | Name: "America/Los_Angeles", 103 | Abbreviation: "PST", 104 | Offset: "-0800", 105 | IsDST: false, 106 | CurrentTime: "2019-02-27T15:00:32.745936-08:00", 107 | }, 108 | Threat: &Threat{ 109 | IsTOR: false, 110 | IsProxy: false, 111 | IsAnonymous: false, 112 | IsKnownAttacker: false, 113 | IsKnownAbuser: false, 114 | IsThreat: true, 115 | IsBogon: false, 116 | }, 117 | } 118 | 119 | got := bulkToIP(bip) 120 | if diff := cmp.Diff(ip, got); diff != "" { 121 | t.Fatalf("IP differs: (-want +got)\n%s", diff) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | matrix: 4 | include: 5 | - go: 1.8.x 6 | script: 7 | - go test -v -race ./... 8 | - go: 1.9.x 9 | script: 10 | - go test -v -race ./... 11 | - go: 1.10.x 12 | script: 13 | - go test -v -race ./... 14 | - go: 1.11.x 15 | script: 16 | - go test -v -race ./... 17 | - go: 1.12.x 18 | script: 19 | - diff -u <(echo -n) <(gofmt -d .) 20 | - go test -v -race ./... 21 | - go: master 22 | script: 23 | - go test -v -race ./... 24 | allow_failures: 25 | - go: master 26 | fast_finish: true 27 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/README.md: -------------------------------------------------------------------------------- 1 | # Package for equality of Go values 2 | 3 | [![GoDoc](https://godoc.org/github.com/google/go-cmp/cmp?status.svg)][godoc] 4 | [![Build Status](https://travis-ci.org/google/go-cmp.svg?branch=master)][travis] 5 | 6 | This package is intended to be a more powerful and safer alternative to 7 | `reflect.DeepEqual` for comparing whether two values are semantically equal. 8 | 9 | The primary features of `cmp` are: 10 | 11 | * When the default behavior of equality does not suit the needs of the test, 12 | custom equality functions can override the equality operation. 13 | For example, an equality function may report floats as equal so long as they 14 | are within some tolerance of each other. 15 | 16 | * Types that have an `Equal` method may use that method to determine equality. 17 | This allows package authors to determine the equality operation for the types 18 | that they define. 19 | 20 | * If no custom equality functions are used and no `Equal` method is defined, 21 | equality is determined by recursively comparing the primitive kinds on both 22 | values, much like `reflect.DeepEqual`. Unlike `reflect.DeepEqual`, unexported 23 | fields are not compared by default; they result in panics unless suppressed 24 | by using an `Ignore` option (see `cmpopts.IgnoreUnexported`) or explicitly 25 | compared using the `AllowUnexported` option. 26 | 27 | See the [GoDoc documentation][godoc] for more information. 28 | 29 | This is not an official Google product. 30 | 31 | [godoc]: https://godoc.org/github.com/google/go-cmp/cmp 32 | [travis]: https://travis-ci.org/google/go-cmp 33 | 34 | ## Install 35 | 36 | ``` 37 | go get -u github.com/google/go-cmp/cmp 38 | ``` 39 | 40 | ## License 41 | 42 | BSD - See [LICENSE][license] file 43 | 44 | [license]: https://github.com/google/go-cmp/blob/master/LICENSE 45 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // Package cmpopts provides common options for the cmp package. 6 | package cmpopts 7 | 8 | import ( 9 | "math" 10 | "reflect" 11 | 12 | "github.com/google/go-cmp/cmp" 13 | ) 14 | 15 | func equateAlways(_, _ interface{}) bool { return true } 16 | 17 | // EquateEmpty returns a Comparer option that determines all maps and slices 18 | // with a length of zero to be equal, regardless of whether they are nil. 19 | // 20 | // EquateEmpty can be used in conjunction with SortSlices and SortMaps. 21 | func EquateEmpty() cmp.Option { 22 | return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways)) 23 | } 24 | 25 | func isEmpty(x, y interface{}) bool { 26 | vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) 27 | return (x != nil && y != nil && vx.Type() == vy.Type()) && 28 | (vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) && 29 | (vx.Len() == 0 && vy.Len() == 0) 30 | } 31 | 32 | // EquateApprox returns a Comparer option that determines float32 or float64 33 | // values to be equal if they are within a relative fraction or absolute margin. 34 | // This option is not used when either x or y is NaN or infinite. 35 | // 36 | // The fraction determines that the difference of two values must be within the 37 | // smaller fraction of the two values, while the margin determines that the two 38 | // values must be within some absolute margin. 39 | // To express only a fraction or only a margin, use 0 for the other parameter. 40 | // The fraction and margin must be non-negative. 41 | // 42 | // The mathematical expression used is equivalent to: 43 | // |x-y| ≤ max(fraction*min(|x|, |y|), margin) 44 | // 45 | // EquateApprox can be used in conjunction with EquateNaNs. 46 | func EquateApprox(fraction, margin float64) cmp.Option { 47 | if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) { 48 | panic("margin or fraction must be a non-negative number") 49 | } 50 | a := approximator{fraction, margin} 51 | return cmp.Options{ 52 | cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)), 53 | cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)), 54 | } 55 | } 56 | 57 | type approximator struct{ frac, marg float64 } 58 | 59 | func areRealF64s(x, y float64) bool { 60 | return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0) 61 | } 62 | func areRealF32s(x, y float32) bool { 63 | return areRealF64s(float64(x), float64(y)) 64 | } 65 | func (a approximator) compareF64(x, y float64) bool { 66 | relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y)) 67 | return math.Abs(x-y) <= math.Max(a.marg, relMarg) 68 | } 69 | func (a approximator) compareF32(x, y float32) bool { 70 | return a.compareF64(float64(x), float64(y)) 71 | } 72 | 73 | // EquateNaNs returns a Comparer option that determines float32 and float64 74 | // NaN values to be equal. 75 | // 76 | // EquateNaNs can be used in conjunction with EquateApprox. 77 | func EquateNaNs() cmp.Option { 78 | return cmp.Options{ 79 | cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)), 80 | cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)), 81 | } 82 | } 83 | 84 | func areNaNsF64s(x, y float64) bool { 85 | return math.IsNaN(x) && math.IsNaN(y) 86 | } 87 | func areNaNsF32s(x, y float32) bool { 88 | return areNaNsF64s(float64(x), float64(y)) 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmpopts 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | "unicode" 11 | "unicode/utf8" 12 | 13 | "github.com/google/go-cmp/cmp" 14 | "github.com/google/go-cmp/cmp/internal/function" 15 | ) 16 | 17 | // IgnoreFields returns an Option that ignores exported fields of the 18 | // given names on a single struct type. 19 | // The struct type is specified by passing in a value of that type. 20 | // 21 | // The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a 22 | // specific sub-field that is embedded or nested within the parent struct. 23 | // 24 | // This does not handle unexported fields; use IgnoreUnexported instead. 25 | func IgnoreFields(typ interface{}, names ...string) cmp.Option { 26 | sf := newStructFilter(typ, names...) 27 | return cmp.FilterPath(sf.filter, cmp.Ignore()) 28 | } 29 | 30 | // IgnoreTypes returns an Option that ignores all values assignable to 31 | // certain types, which are specified by passing in a value of each type. 32 | func IgnoreTypes(typs ...interface{}) cmp.Option { 33 | tf := newTypeFilter(typs...) 34 | return cmp.FilterPath(tf.filter, cmp.Ignore()) 35 | } 36 | 37 | type typeFilter []reflect.Type 38 | 39 | func newTypeFilter(typs ...interface{}) (tf typeFilter) { 40 | for _, typ := range typs { 41 | t := reflect.TypeOf(typ) 42 | if t == nil { 43 | // This occurs if someone tries to pass in sync.Locker(nil) 44 | panic("cannot determine type; consider using IgnoreInterfaces") 45 | } 46 | tf = append(tf, t) 47 | } 48 | return tf 49 | } 50 | func (tf typeFilter) filter(p cmp.Path) bool { 51 | if len(p) < 1 { 52 | return false 53 | } 54 | t := p.Last().Type() 55 | for _, ti := range tf { 56 | if t.AssignableTo(ti) { 57 | return true 58 | } 59 | } 60 | return false 61 | } 62 | 63 | // IgnoreInterfaces returns an Option that ignores all values or references of 64 | // values assignable to certain interface types. These interfaces are specified 65 | // by passing in an anonymous struct with the interface types embedded in it. 66 | // For example, to ignore sync.Locker, pass in struct{sync.Locker}{}. 67 | func IgnoreInterfaces(ifaces interface{}) cmp.Option { 68 | tf := newIfaceFilter(ifaces) 69 | return cmp.FilterPath(tf.filter, cmp.Ignore()) 70 | } 71 | 72 | type ifaceFilter []reflect.Type 73 | 74 | func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) { 75 | t := reflect.TypeOf(ifaces) 76 | if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct { 77 | panic("input must be an anonymous struct") 78 | } 79 | for i := 0; i < t.NumField(); i++ { 80 | fi := t.Field(i) 81 | switch { 82 | case !fi.Anonymous: 83 | panic("struct cannot have named fields") 84 | case fi.Type.Kind() != reflect.Interface: 85 | panic("embedded field must be an interface type") 86 | case fi.Type.NumMethod() == 0: 87 | // This matches everything; why would you ever want this? 88 | panic("cannot ignore empty interface") 89 | default: 90 | tf = append(tf, fi.Type) 91 | } 92 | } 93 | return tf 94 | } 95 | func (tf ifaceFilter) filter(p cmp.Path) bool { 96 | if len(p) < 1 { 97 | return false 98 | } 99 | t := p.Last().Type() 100 | for _, ti := range tf { 101 | if t.AssignableTo(ti) { 102 | return true 103 | } 104 | if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) { 105 | return true 106 | } 107 | } 108 | return false 109 | } 110 | 111 | // IgnoreUnexported returns an Option that only ignores the immediate unexported 112 | // fields of a struct, including anonymous fields of unexported types. 113 | // In particular, unexported fields within the struct's exported fields 114 | // of struct types, including anonymous fields, will not be ignored unless the 115 | // type of the field itself is also passed to IgnoreUnexported. 116 | // 117 | // Avoid ignoring unexported fields of a type which you do not control (i.e. a 118 | // type from another repository), as changes to the implementation of such types 119 | // may change how the comparison behaves. Prefer a custom Comparer instead. 120 | func IgnoreUnexported(typs ...interface{}) cmp.Option { 121 | ux := newUnexportedFilter(typs...) 122 | return cmp.FilterPath(ux.filter, cmp.Ignore()) 123 | } 124 | 125 | type unexportedFilter struct{ m map[reflect.Type]bool } 126 | 127 | func newUnexportedFilter(typs ...interface{}) unexportedFilter { 128 | ux := unexportedFilter{m: make(map[reflect.Type]bool)} 129 | for _, typ := range typs { 130 | t := reflect.TypeOf(typ) 131 | if t == nil || t.Kind() != reflect.Struct { 132 | panic(fmt.Sprintf("invalid struct type: %T", typ)) 133 | } 134 | ux.m[t] = true 135 | } 136 | return ux 137 | } 138 | func (xf unexportedFilter) filter(p cmp.Path) bool { 139 | sf, ok := p.Index(-1).(cmp.StructField) 140 | if !ok { 141 | return false 142 | } 143 | return xf.m[p.Index(-2).Type()] && !isExported(sf.Name()) 144 | } 145 | 146 | // isExported reports whether the identifier is exported. 147 | func isExported(id string) bool { 148 | r, _ := utf8.DecodeRuneInString(id) 149 | return unicode.IsUpper(r) 150 | } 151 | 152 | // IgnoreSliceElements returns an Option that ignores elements of []V. 153 | // The discard function must be of the form "func(T) bool" which is used to 154 | // ignore slice elements of type V, where V is assignable to T. 155 | // Elements are ignored if the function reports true. 156 | func IgnoreSliceElements(discardFunc interface{}) cmp.Option { 157 | vf := reflect.ValueOf(discardFunc) 158 | if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() { 159 | panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) 160 | } 161 | return cmp.FilterPath(func(p cmp.Path) bool { 162 | si, ok := p.Index(-1).(cmp.SliceIndex) 163 | if !ok { 164 | return false 165 | } 166 | if !si.Type().AssignableTo(vf.Type().In(0)) { 167 | return false 168 | } 169 | vx, vy := si.Values() 170 | if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() { 171 | return true 172 | } 173 | if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() { 174 | return true 175 | } 176 | return false 177 | }, cmp.Ignore()) 178 | } 179 | 180 | // IgnoreMapEntries returns an Option that ignores entries of map[K]V. 181 | // The discard function must be of the form "func(T, R) bool" which is used to 182 | // ignore map entries of type K and V, where K and V are assignable to T and R. 183 | // Entries are ignored if the function reports true. 184 | func IgnoreMapEntries(discardFunc interface{}) cmp.Option { 185 | vf := reflect.ValueOf(discardFunc) 186 | if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() { 187 | panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) 188 | } 189 | return cmp.FilterPath(func(p cmp.Path) bool { 190 | mi, ok := p.Index(-1).(cmp.MapIndex) 191 | if !ok { 192 | return false 193 | } 194 | if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) { 195 | return false 196 | } 197 | k := mi.Key() 198 | vx, vy := mi.Values() 199 | if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() { 200 | return true 201 | } 202 | if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() { 203 | return true 204 | } 205 | return false 206 | }, cmp.Ignore()) 207 | } 208 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmpopts 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | "sort" 11 | 12 | "github.com/google/go-cmp/cmp" 13 | "github.com/google/go-cmp/cmp/internal/function" 14 | ) 15 | 16 | // SortSlices returns a Transformer option that sorts all []V. 17 | // The less function must be of the form "func(T, T) bool" which is used to 18 | // sort any slice with element type V that is assignable to T. 19 | // 20 | // The less function must be: 21 | // • Deterministic: less(x, y) == less(x, y) 22 | // • Irreflexive: !less(x, x) 23 | // • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) 24 | // 25 | // The less function does not have to be "total". That is, if !less(x, y) and 26 | // !less(y, x) for two elements x and y, their relative order is maintained. 27 | // 28 | // SortSlices can be used in conjunction with EquateEmpty. 29 | func SortSlices(lessFunc interface{}) cmp.Option { 30 | vf := reflect.ValueOf(lessFunc) 31 | if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { 32 | panic(fmt.Sprintf("invalid less function: %T", lessFunc)) 33 | } 34 | ss := sliceSorter{vf.Type().In(0), vf} 35 | return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort)) 36 | } 37 | 38 | type sliceSorter struct { 39 | in reflect.Type // T 40 | fnc reflect.Value // func(T, T) bool 41 | } 42 | 43 | func (ss sliceSorter) filter(x, y interface{}) bool { 44 | vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) 45 | if !(x != nil && y != nil && vx.Type() == vy.Type()) || 46 | !(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) || 47 | (vx.Len() <= 1 && vy.Len() <= 1) { 48 | return false 49 | } 50 | // Check whether the slices are already sorted to avoid an infinite 51 | // recursion cycle applying the same transform to itself. 52 | ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) }) 53 | ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) }) 54 | return !ok1 || !ok2 55 | } 56 | func (ss sliceSorter) sort(x interface{}) interface{} { 57 | src := reflect.ValueOf(x) 58 | dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len()) 59 | for i := 0; i < src.Len(); i++ { 60 | dst.Index(i).Set(src.Index(i)) 61 | } 62 | sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) }) 63 | ss.checkSort(dst) 64 | return dst.Interface() 65 | } 66 | func (ss sliceSorter) checkSort(v reflect.Value) { 67 | start := -1 // Start of a sequence of equal elements. 68 | for i := 1; i < v.Len(); i++ { 69 | if ss.less(v, i-1, i) { 70 | // Check that first and last elements in v[start:i] are equal. 71 | if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) { 72 | panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i))) 73 | } 74 | start = -1 75 | } else if start == -1 { 76 | start = i 77 | } 78 | } 79 | } 80 | func (ss sliceSorter) less(v reflect.Value, i, j int) bool { 81 | vx, vy := v.Index(i), v.Index(j) 82 | return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool() 83 | } 84 | 85 | // SortMaps returns a Transformer option that flattens map[K]V types to be a 86 | // sorted []struct{K, V}. The less function must be of the form 87 | // "func(T, T) bool" which is used to sort any map with key K that is 88 | // assignable to T. 89 | // 90 | // Flattening the map into a slice has the property that cmp.Equal is able to 91 | // use Comparers on K or the K.Equal method if it exists. 92 | // 93 | // The less function must be: 94 | // • Deterministic: less(x, y) == less(x, y) 95 | // • Irreflexive: !less(x, x) 96 | // • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) 97 | // • Total: if x != y, then either less(x, y) or less(y, x) 98 | // 99 | // SortMaps can be used in conjunction with EquateEmpty. 100 | func SortMaps(lessFunc interface{}) cmp.Option { 101 | vf := reflect.ValueOf(lessFunc) 102 | if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { 103 | panic(fmt.Sprintf("invalid less function: %T", lessFunc)) 104 | } 105 | ms := mapSorter{vf.Type().In(0), vf} 106 | return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort)) 107 | } 108 | 109 | type mapSorter struct { 110 | in reflect.Type // T 111 | fnc reflect.Value // func(T, T) bool 112 | } 113 | 114 | func (ms mapSorter) filter(x, y interface{}) bool { 115 | vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) 116 | return (x != nil && y != nil && vx.Type() == vy.Type()) && 117 | (vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) && 118 | (vx.Len() != 0 || vy.Len() != 0) 119 | } 120 | func (ms mapSorter) sort(x interface{}) interface{} { 121 | src := reflect.ValueOf(x) 122 | outType := reflect.StructOf([]reflect.StructField{ 123 | {Name: "K", Type: src.Type().Key()}, 124 | {Name: "V", Type: src.Type().Elem()}, 125 | }) 126 | dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len()) 127 | for i, k := range src.MapKeys() { 128 | v := reflect.New(outType).Elem() 129 | v.Field(0).Set(k) 130 | v.Field(1).Set(src.MapIndex(k)) 131 | dst.Index(i).Set(v) 132 | } 133 | sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) }) 134 | ms.checkSort(dst) 135 | return dst.Interface() 136 | } 137 | func (ms mapSorter) checkSort(v reflect.Value) { 138 | for i := 1; i < v.Len(); i++ { 139 | if !ms.less(v, i-1, i) { 140 | panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i))) 141 | } 142 | } 143 | } 144 | func (ms mapSorter) less(v reflect.Value, i, j int) bool { 145 | vx, vy := v.Index(i).Field(0), v.Index(j).Field(0) 146 | return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool() 147 | } 148 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmpopts 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | "strings" 11 | 12 | "github.com/google/go-cmp/cmp" 13 | ) 14 | 15 | // filterField returns a new Option where opt is only evaluated on paths that 16 | // include a specific exported field on a single struct type. 17 | // The struct type is specified by passing in a value of that type. 18 | // 19 | // The name may be a dot-delimited string (e.g., "Foo.Bar") to select a 20 | // specific sub-field that is embedded or nested within the parent struct. 21 | func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option { 22 | // TODO: This is currently unexported over concerns of how helper filters 23 | // can be composed together easily. 24 | // TODO: Add tests for FilterField. 25 | 26 | sf := newStructFilter(typ, name) 27 | return cmp.FilterPath(sf.filter, opt) 28 | } 29 | 30 | type structFilter struct { 31 | t reflect.Type // The root struct type to match on 32 | ft fieldTree // Tree of fields to match on 33 | } 34 | 35 | func newStructFilter(typ interface{}, names ...string) structFilter { 36 | // TODO: Perhaps allow * as a special identifier to allow ignoring any 37 | // number of path steps until the next field match? 38 | // This could be useful when a concrete struct gets transformed into 39 | // an anonymous struct where it is not possible to specify that by type, 40 | // but the transformer happens to provide guarantees about the names of 41 | // the transformed fields. 42 | 43 | t := reflect.TypeOf(typ) 44 | if t == nil || t.Kind() != reflect.Struct { 45 | panic(fmt.Sprintf("%T must be a struct", typ)) 46 | } 47 | var ft fieldTree 48 | for _, name := range names { 49 | cname, err := canonicalName(t, name) 50 | if err != nil { 51 | panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err)) 52 | } 53 | ft.insert(cname) 54 | } 55 | return structFilter{t, ft} 56 | } 57 | 58 | func (sf structFilter) filter(p cmp.Path) bool { 59 | for i, ps := range p { 60 | if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) { 61 | return true 62 | } 63 | } 64 | return false 65 | } 66 | 67 | // fieldTree represents a set of dot-separated identifiers. 68 | // 69 | // For example, inserting the following selectors: 70 | // Foo 71 | // Foo.Bar.Baz 72 | // Foo.Buzz 73 | // Nuka.Cola.Quantum 74 | // 75 | // Results in a tree of the form: 76 | // {sub: { 77 | // "Foo": {ok: true, sub: { 78 | // "Bar": {sub: { 79 | // "Baz": {ok: true}, 80 | // }}, 81 | // "Buzz": {ok: true}, 82 | // }}, 83 | // "Nuka": {sub: { 84 | // "Cola": {sub: { 85 | // "Quantum": {ok: true}, 86 | // }}, 87 | // }}, 88 | // }} 89 | type fieldTree struct { 90 | ok bool // Whether this is a specified node 91 | sub map[string]fieldTree // The sub-tree of fields under this node 92 | } 93 | 94 | // insert inserts a sequence of field accesses into the tree. 95 | func (ft *fieldTree) insert(cname []string) { 96 | if ft.sub == nil { 97 | ft.sub = make(map[string]fieldTree) 98 | } 99 | if len(cname) == 0 { 100 | ft.ok = true 101 | return 102 | } 103 | sub := ft.sub[cname[0]] 104 | sub.insert(cname[1:]) 105 | ft.sub[cname[0]] = sub 106 | } 107 | 108 | // matchPrefix reports whether any selector in the fieldTree matches 109 | // the start of path p. 110 | func (ft fieldTree) matchPrefix(p cmp.Path) bool { 111 | for _, ps := range p { 112 | switch ps := ps.(type) { 113 | case cmp.StructField: 114 | ft = ft.sub[ps.Name()] 115 | if ft.ok { 116 | return true 117 | } 118 | if len(ft.sub) == 0 { 119 | return false 120 | } 121 | case cmp.Indirect: 122 | default: 123 | return false 124 | } 125 | } 126 | return false 127 | } 128 | 129 | // canonicalName returns a list of identifiers where any struct field access 130 | // through an embedded field is expanded to include the names of the embedded 131 | // types themselves. 132 | // 133 | // For example, suppose field "Foo" is not directly in the parent struct, 134 | // but actually from an embedded struct of type "Bar". Then, the canonical name 135 | // of "Foo" is actually "Bar.Foo". 136 | // 137 | // Suppose field "Foo" is not directly in the parent struct, but actually 138 | // a field in two different embedded structs of types "Bar" and "Baz". 139 | // Then the selector "Foo" causes a panic since it is ambiguous which one it 140 | // refers to. The user must specify either "Bar.Foo" or "Baz.Foo". 141 | func canonicalName(t reflect.Type, sel string) ([]string, error) { 142 | var name string 143 | sel = strings.TrimPrefix(sel, ".") 144 | if sel == "" { 145 | return nil, fmt.Errorf("name must not be empty") 146 | } 147 | if i := strings.IndexByte(sel, '.'); i < 0 { 148 | name, sel = sel, "" 149 | } else { 150 | name, sel = sel[:i], sel[i:] 151 | } 152 | 153 | // Type must be a struct or pointer to struct. 154 | if t.Kind() == reflect.Ptr { 155 | t = t.Elem() 156 | } 157 | if t.Kind() != reflect.Struct { 158 | return nil, fmt.Errorf("%v must be a struct", t) 159 | } 160 | 161 | // Find the canonical name for this current field name. 162 | // If the field exists in an embedded struct, then it will be expanded. 163 | if !isExported(name) { 164 | // Disallow unexported fields: 165 | // * To discourage people from actually touching unexported fields 166 | // * FieldByName is buggy (https://golang.org/issue/4876) 167 | return []string{name}, fmt.Errorf("name must be exported") 168 | } 169 | sf, ok := t.FieldByName(name) 170 | if !ok { 171 | return []string{name}, fmt.Errorf("does not exist") 172 | } 173 | var ss []string 174 | for i := range sf.Index { 175 | ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name) 176 | } 177 | if sel == "" { 178 | return ss, nil 179 | } 180 | ssPost, err := canonicalName(sf.Type, sel) 181 | return append(ss, ssPost...), err 182 | } 183 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmpopts 6 | 7 | import ( 8 | "github.com/google/go-cmp/cmp" 9 | ) 10 | 11 | type xformFilter struct{ xform cmp.Option } 12 | 13 | func (xf xformFilter) filter(p cmp.Path) bool { 14 | for _, ps := range p { 15 | if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform { 16 | return false 17 | } 18 | } 19 | return true 20 | } 21 | 22 | // AcyclicTransformer returns a Transformer with a filter applied that ensures 23 | // that the transformer cannot be recursively applied upon its own output. 24 | // 25 | // An example use case is a transformer that splits a string by lines: 26 | // AcyclicTransformer("SplitLines", func(s string) []string{ 27 | // return strings.Split(s, "\n") 28 | // }) 29 | // 30 | // Had this been an unfiltered Transformer instead, this would result in an 31 | // infinite cycle converting a string to []string to [][]string and so on. 32 | func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option { 33 | xf := xformFilter{cmp.Transformer(name, xformFunc)} 34 | return cmp.FilterPath(xf.filter, xf.xform) 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/example_reporter_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp_test 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | 11 | "github.com/google/go-cmp/cmp" 12 | ) 13 | 14 | // DiffReporter is a simple custom reporter that only records differences 15 | // detected during comparison. 16 | type DiffReporter struct { 17 | path cmp.Path 18 | diffs []string 19 | } 20 | 21 | func (r *DiffReporter) PushStep(ps cmp.PathStep) { 22 | r.path = append(r.path, ps) 23 | } 24 | 25 | func (r *DiffReporter) Report(rs cmp.Result) { 26 | if !rs.Equal() { 27 | vx, vy := r.path.Last().Values() 28 | r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy)) 29 | } 30 | } 31 | 32 | func (r *DiffReporter) PopStep() { 33 | r.path = r.path[:len(r.path)-1] 34 | } 35 | 36 | func (r *DiffReporter) String() string { 37 | return strings.Join(r.diffs, "\n") 38 | } 39 | 40 | func ExampleReporter() { 41 | x, y := MakeGatewayInfo() 42 | 43 | var r DiffReporter 44 | cmp.Equal(x, y, cmp.Reporter(&r)) 45 | fmt.Print(r.String()) 46 | 47 | // Output: 48 | // {cmp_test.Gateway}.IPAddress: 49 | // -: 192.168.0.1 50 | // +: 192.168.0.2 51 | // 52 | // {cmp_test.Gateway}.Clients[4].IPAddress: 53 | // -: 192.168.0.219 54 | // +: 192.168.0.221 55 | // 56 | // {cmp_test.Gateway}.Clients[5->?]: 57 | // -: {Hostname:americano IPAddress:192.168.0.188 LastSeen:2009-11-10 23:03:05 +0000 UTC} 58 | // +: 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/export_panic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build purego 6 | 7 | package cmp 8 | 9 | import "reflect" 10 | 11 | const supportAllowUnexported = false 12 | 13 | func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value { 14 | panic("retrieveUnexportedField is not implemented") 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/export_unsafe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build !purego 6 | 7 | package cmp 8 | 9 | import ( 10 | "reflect" 11 | "unsafe" 12 | ) 13 | 14 | const supportAllowUnexported = true 15 | 16 | // retrieveUnexportedField uses unsafe to forcibly retrieve any field from 17 | // a struct such that the value has read-write permissions. 18 | // 19 | // The parent struct, v, must be addressable, while f must be a StructField 20 | // describing the field to retrieve. 21 | func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value { 22 | return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem() 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build !cmp_debug 6 | 7 | package diff 8 | 9 | var debug debugger 10 | 11 | type debugger struct{} 12 | 13 | func (debugger) Begin(_, _ int, f EqualFunc, _, _ *EditScript) EqualFunc { 14 | return f 15 | } 16 | func (debugger) Update() {} 17 | func (debugger) Finish() {} 18 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build cmp_debug 6 | 7 | package diff 8 | 9 | import ( 10 | "fmt" 11 | "strings" 12 | "sync" 13 | "time" 14 | ) 15 | 16 | // The algorithm can be seen running in real-time by enabling debugging: 17 | // go test -tags=cmp_debug -v 18 | // 19 | // Example output: 20 | // === RUN TestDifference/#34 21 | // ┌───────────────────────────────┐ 22 | // │ \ · · · · · · · · · · · · · · │ 23 | // │ · # · · · · · · · · · · · · · │ 24 | // │ · \ · · · · · · · · · · · · · │ 25 | // │ · · \ · · · · · · · · · · · · │ 26 | // │ · · · X # · · · · · · · · · · │ 27 | // │ · · · # \ · · · · · · · · · · │ 28 | // │ · · · · · # # · · · · · · · · │ 29 | // │ · · · · · # \ · · · · · · · · │ 30 | // │ · · · · · · · \ · · · · · · · │ 31 | // │ · · · · · · · · \ · · · · · · │ 32 | // │ · · · · · · · · · \ · · · · · │ 33 | // │ · · · · · · · · · · \ · · # · │ 34 | // │ · · · · · · · · · · · \ # # · │ 35 | // │ · · · · · · · · · · · # # # · │ 36 | // │ · · · · · · · · · · # # # # · │ 37 | // │ · · · · · · · · · # # # # # · │ 38 | // │ · · · · · · · · · · · · · · \ │ 39 | // └───────────────────────────────┘ 40 | // [.Y..M.XY......YXYXY.|] 41 | // 42 | // The grid represents the edit-graph where the horizontal axis represents 43 | // list X and the vertical axis represents list Y. The start of the two lists 44 | // is the top-left, while the ends are the bottom-right. The '·' represents 45 | // an unexplored node in the graph. The '\' indicates that the two symbols 46 | // from list X and Y are equal. The 'X' indicates that two symbols are similar 47 | // (but not exactly equal) to each other. The '#' indicates that the two symbols 48 | // are different (and not similar). The algorithm traverses this graph trying to 49 | // make the paths starting in the top-left and the bottom-right connect. 50 | // 51 | // The series of '.', 'X', 'Y', and 'M' characters at the bottom represents 52 | // the currently established path from the forward and reverse searches, 53 | // separated by a '|' character. 54 | 55 | const ( 56 | updateDelay = 100 * time.Millisecond 57 | finishDelay = 500 * time.Millisecond 58 | ansiTerminal = true // ANSI escape codes used to move terminal cursor 59 | ) 60 | 61 | var debug debugger 62 | 63 | type debugger struct { 64 | sync.Mutex 65 | p1, p2 EditScript 66 | fwdPath, revPath *EditScript 67 | grid []byte 68 | lines int 69 | } 70 | 71 | func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc { 72 | dbg.Lock() 73 | dbg.fwdPath, dbg.revPath = p1, p2 74 | top := "┌─" + strings.Repeat("──", nx) + "┐\n" 75 | row := "│ " + strings.Repeat("· ", nx) + "│\n" 76 | btm := "└─" + strings.Repeat("──", nx) + "┘\n" 77 | dbg.grid = []byte(top + strings.Repeat(row, ny) + btm) 78 | dbg.lines = strings.Count(dbg.String(), "\n") 79 | fmt.Print(dbg) 80 | 81 | // Wrap the EqualFunc so that we can intercept each result. 82 | return func(ix, iy int) (r Result) { 83 | cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("· ")*ix:][:len("·")] 84 | for i := range cell { 85 | cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot 86 | } 87 | switch r = f(ix, iy); { 88 | case r.Equal(): 89 | cell[0] = '\\' 90 | case r.Similar(): 91 | cell[0] = 'X' 92 | default: 93 | cell[0] = '#' 94 | } 95 | return 96 | } 97 | } 98 | 99 | func (dbg *debugger) Update() { 100 | dbg.print(updateDelay) 101 | } 102 | 103 | func (dbg *debugger) Finish() { 104 | dbg.print(finishDelay) 105 | dbg.Unlock() 106 | } 107 | 108 | func (dbg *debugger) String() string { 109 | dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0] 110 | for i := len(*dbg.revPath) - 1; i >= 0; i-- { 111 | dbg.p2 = append(dbg.p2, (*dbg.revPath)[i]) 112 | } 113 | return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2) 114 | } 115 | 116 | func (dbg *debugger) print(d time.Duration) { 117 | if ansiTerminal { 118 | fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor 119 | } 120 | fmt.Print(dbg) 121 | time.Sleep(d) 122 | } 123 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package flags 6 | 7 | // Deterministic controls whether the output of Diff should be deterministic. 8 | // This is only used for testing. 9 | var Deterministic bool 10 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build !go1.10 6 | 7 | package flags 8 | 9 | // AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. 10 | const AtLeastGo110 = false 11 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build go1.10 6 | 7 | package flags 8 | 9 | // AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. 10 | const AtLeastGo110 = true 11 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/function/func.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // Package function provides functionality for identifying function types. 6 | package function 7 | 8 | import ( 9 | "reflect" 10 | "regexp" 11 | "runtime" 12 | "strings" 13 | ) 14 | 15 | type funcType int 16 | 17 | const ( 18 | _ funcType = iota 19 | 20 | tbFunc // func(T) bool 21 | ttbFunc // func(T, T) bool 22 | trbFunc // func(T, R) bool 23 | tibFunc // func(T, I) bool 24 | trFunc // func(T) R 25 | 26 | Equal = ttbFunc // func(T, T) bool 27 | EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool 28 | Transformer = trFunc // func(T) R 29 | ValueFilter = ttbFunc // func(T, T) bool 30 | Less = ttbFunc // func(T, T) bool 31 | ValuePredicate = tbFunc // func(T) bool 32 | KeyValuePredicate = trbFunc // func(T, R) bool 33 | ) 34 | 35 | var boolType = reflect.TypeOf(true) 36 | 37 | // IsType reports whether the reflect.Type is of the specified function type. 38 | func IsType(t reflect.Type, ft funcType) bool { 39 | if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { 40 | return false 41 | } 42 | ni, no := t.NumIn(), t.NumOut() 43 | switch ft { 44 | case tbFunc: // func(T) bool 45 | if ni == 1 && no == 1 && t.Out(0) == boolType { 46 | return true 47 | } 48 | case ttbFunc: // func(T, T) bool 49 | if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { 50 | return true 51 | } 52 | case trbFunc: // func(T, R) bool 53 | if ni == 2 && no == 1 && t.Out(0) == boolType { 54 | return true 55 | } 56 | case tibFunc: // func(T, I) bool 57 | if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { 58 | return true 59 | } 60 | case trFunc: // func(T) R 61 | if ni == 1 && no == 1 { 62 | return true 63 | } 64 | } 65 | return false 66 | } 67 | 68 | var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) 69 | 70 | // NameOf returns the name of the function value. 71 | func NameOf(v reflect.Value) string { 72 | fnc := runtime.FuncForPC(v.Pointer()) 73 | if fnc == nil { 74 | return "" 75 | } 76 | fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" 77 | 78 | // Method closures have a "-fm" suffix. 79 | fullName = strings.TrimSuffix(fullName, "-fm") 80 | 81 | var name string 82 | for len(fullName) > 0 { 83 | inParen := strings.HasSuffix(fullName, ")") 84 | fullName = strings.TrimSuffix(fullName, ")") 85 | 86 | s := lastIdentRx.FindString(fullName) 87 | if s == "" { 88 | break 89 | } 90 | name = s + "." + name 91 | fullName = strings.TrimSuffix(fullName, s) 92 | 93 | if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { 94 | fullName = fullName[:i] 95 | } 96 | fullName = strings.TrimSuffix(fullName, ".") 97 | } 98 | return strings.TrimSuffix(name, ".") 99 | } 100 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/function/func_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package function 6 | 7 | import ( 8 | "bytes" 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | type myType struct{ bytes.Buffer } 14 | 15 | func (myType) valueMethod() {} 16 | func (myType) ValueMethod() {} 17 | 18 | func (*myType) pointerMethod() {} 19 | func (*myType) PointerMethod() {} 20 | 21 | func TestNameOf(t *testing.T) { 22 | tests := []struct { 23 | fnc interface{} 24 | want string 25 | }{ 26 | {TestNameOf, "function.TestNameOf"}, 27 | {func() {}, "function.TestNameOf.func1"}, 28 | {(myType).valueMethod, "function.myType.valueMethod"}, 29 | {(myType).ValueMethod, "function.myType.ValueMethod"}, 30 | {(myType{}).valueMethod, "function.myType.valueMethod"}, 31 | {(myType{}).ValueMethod, "function.myType.ValueMethod"}, 32 | {(*myType).valueMethod, "function.myType.valueMethod"}, 33 | {(*myType).ValueMethod, "function.myType.ValueMethod"}, 34 | {(&myType{}).valueMethod, "function.myType.valueMethod"}, 35 | {(&myType{}).ValueMethod, "function.myType.ValueMethod"}, 36 | {(*myType).pointerMethod, "function.myType.pointerMethod"}, 37 | {(*myType).PointerMethod, "function.myType.PointerMethod"}, 38 | {(&myType{}).pointerMethod, "function.myType.pointerMethod"}, 39 | {(&myType{}).PointerMethod, "function.myType.PointerMethod"}, 40 | {(*myType).Write, "function.myType.Write"}, 41 | {(&myType{}).Write, "bytes.Buffer.Write"}, 42 | } 43 | for _, tt := range tests { 44 | t.Run("", func(t *testing.T) { 45 | got := NameOf(reflect.ValueOf(tt.fnc)) 46 | if got != tt.want { 47 | t.Errorf("NameOf() = %v, want %v", got, tt.want) 48 | } 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/testprotos/protos.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package testprotos 6 | 7 | func Equal(x, y Message) bool { 8 | if x == nil || y == nil { 9 | return x == nil && y == nil 10 | } 11 | return x.String() == y.String() 12 | } 13 | 14 | type Message interface { 15 | Proto() 16 | String() string 17 | } 18 | 19 | type proto interface { 20 | Proto() 21 | } 22 | 23 | type notComparable struct { 24 | unexportedField func() 25 | } 26 | 27 | type Stringer struct{ X string } 28 | 29 | func (s *Stringer) String() string { return s.X } 30 | 31 | // Project1 protocol buffers 32 | type ( 33 | Eagle_States int 34 | Eagle_MissingCalls int 35 | Dreamer_States int 36 | Dreamer_MissingCalls int 37 | Slap_States int 38 | Goat_States int 39 | Donkey_States int 40 | SummerType int 41 | 42 | Eagle struct { 43 | proto 44 | notComparable 45 | Stringer 46 | } 47 | Dreamer struct { 48 | proto 49 | notComparable 50 | Stringer 51 | } 52 | Slap struct { 53 | proto 54 | notComparable 55 | Stringer 56 | } 57 | Goat struct { 58 | proto 59 | notComparable 60 | Stringer 61 | } 62 | Donkey struct { 63 | proto 64 | notComparable 65 | Stringer 66 | } 67 | ) 68 | 69 | // Project2 protocol buffers 70 | type ( 71 | Germ struct { 72 | proto 73 | notComparable 74 | Stringer 75 | } 76 | Dish struct { 77 | proto 78 | notComparable 79 | Stringer 80 | } 81 | ) 82 | 83 | // Project3 protocol buffers 84 | type ( 85 | Dirt struct { 86 | proto 87 | notComparable 88 | Stringer 89 | } 90 | Wizard struct { 91 | proto 92 | notComparable 93 | Stringer 94 | } 95 | Sadistic struct { 96 | proto 97 | notComparable 98 | Stringer 99 | } 100 | ) 101 | 102 | // Project4 protocol buffers 103 | type ( 104 | HoneyStatus int 105 | PoisonType int 106 | MetaData struct { 107 | proto 108 | notComparable 109 | Stringer 110 | } 111 | Restrictions struct { 112 | proto 113 | notComparable 114 | Stringer 115 | } 116 | ) 117 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/teststructs/project1.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package teststructs 6 | 7 | import ( 8 | "time" 9 | 10 | pb "github.com/google/go-cmp/cmp/internal/testprotos" 11 | ) 12 | 13 | // This is an sanitized example of equality from a real use-case. 14 | // The original equality function was as follows: 15 | /* 16 | func equalEagle(x, y Eagle) bool { 17 | if x.Name != y.Name && 18 | !reflect.DeepEqual(x.Hounds, y.Hounds) && 19 | x.Desc != y.Desc && 20 | x.DescLong != y.DescLong && 21 | x.Prong != y.Prong && 22 | x.StateGoverner != y.StateGoverner && 23 | x.PrankRating != y.PrankRating && 24 | x.FunnyPrank != y.FunnyPrank && 25 | !pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) { 26 | return false 27 | } 28 | 29 | if len(x.Dreamers) != len(y.Dreamers) { 30 | return false 31 | } 32 | for i := range x.Dreamers { 33 | if !equalDreamer(x.Dreamers[i], y.Dreamers[i]) { 34 | return false 35 | } 36 | } 37 | if len(x.Slaps) != len(y.Slaps) { 38 | return false 39 | } 40 | for i := range x.Slaps { 41 | if !equalSlap(x.Slaps[i], y.Slaps[i]) { 42 | return false 43 | } 44 | } 45 | return true 46 | } 47 | func equalDreamer(x, y Dreamer) bool { 48 | if x.Name != y.Name || 49 | x.Desc != y.Desc || 50 | x.DescLong != y.DescLong || 51 | x.ContSlapsInterval != y.ContSlapsInterval || 52 | x.Ornamental != y.Ornamental || 53 | x.Amoeba != y.Amoeba || 54 | x.Heroes != y.Heroes || 55 | x.FloppyDisk != y.FloppyDisk || 56 | x.MightiestDuck != y.MightiestDuck || 57 | x.FunnyPrank != y.FunnyPrank || 58 | !pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) { 59 | 60 | return false 61 | } 62 | if len(x.Animal) != len(y.Animal) { 63 | return false 64 | } 65 | for i := range x.Animal { 66 | vx := x.Animal[i] 67 | vy := y.Animal[i] 68 | if reflect.TypeOf(x.Animal) != reflect.TypeOf(y.Animal) { 69 | return false 70 | } 71 | switch vx.(type) { 72 | case Goat: 73 | if !equalGoat(vx.(Goat), vy.(Goat)) { 74 | return false 75 | } 76 | case Donkey: 77 | if !equalDonkey(vx.(Donkey), vy.(Donkey)) { 78 | return false 79 | } 80 | default: 81 | panic(fmt.Sprintf("unknown type: %T", vx)) 82 | } 83 | } 84 | if len(x.PreSlaps) != len(y.PreSlaps) { 85 | return false 86 | } 87 | for i := range x.PreSlaps { 88 | if !equalSlap(x.PreSlaps[i], y.PreSlaps[i]) { 89 | return false 90 | } 91 | } 92 | if len(x.ContSlaps) != len(y.ContSlaps) { 93 | return false 94 | } 95 | for i := range x.ContSlaps { 96 | if !equalSlap(x.ContSlaps[i], y.ContSlaps[i]) { 97 | return false 98 | } 99 | } 100 | return true 101 | } 102 | func equalSlap(x, y Slap) bool { 103 | return x.Name == y.Name && 104 | x.Desc == y.Desc && 105 | x.DescLong == y.DescLong && 106 | pb.Equal(x.Args, y.Args) && 107 | x.Tense == y.Tense && 108 | x.Interval == y.Interval && 109 | x.Homeland == y.Homeland && 110 | x.FunnyPrank == y.FunnyPrank && 111 | pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) 112 | } 113 | func equalGoat(x, y Goat) bool { 114 | if x.Target != y.Target || 115 | x.FunnyPrank != y.FunnyPrank || 116 | !pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) { 117 | return false 118 | } 119 | if len(x.Slaps) != len(y.Slaps) { 120 | return false 121 | } 122 | for i := range x.Slaps { 123 | if !equalSlap(x.Slaps[i], y.Slaps[i]) { 124 | return false 125 | } 126 | } 127 | return true 128 | } 129 | func equalDonkey(x, y Donkey) bool { 130 | return x.Pause == y.Pause && 131 | x.Sleep == y.Sleep && 132 | x.FunnyPrank == y.FunnyPrank && 133 | pb.Equal(x.Immutable.Proto(), y.Immutable.Proto()) 134 | } 135 | */ 136 | 137 | type Eagle struct { 138 | Name string 139 | Hounds []string 140 | Desc string 141 | DescLong string 142 | Dreamers []Dreamer 143 | Prong int64 144 | Slaps []Slap 145 | StateGoverner string 146 | PrankRating string 147 | FunnyPrank string 148 | Immutable *EagleImmutable 149 | } 150 | 151 | type EagleImmutable struct { 152 | ID string 153 | State *pb.Eagle_States 154 | MissingCall *pb.Eagle_MissingCalls 155 | Birthday time.Time 156 | Death time.Time 157 | Started time.Time 158 | LastUpdate time.Time 159 | Creator string 160 | empty bool 161 | } 162 | 163 | type Dreamer struct { 164 | Name string 165 | Desc string 166 | DescLong string 167 | PreSlaps []Slap 168 | ContSlaps []Slap 169 | ContSlapsInterval int32 170 | Animal []interface{} // Could be either Goat or Donkey 171 | Ornamental bool 172 | Amoeba int64 173 | Heroes int32 174 | FloppyDisk int32 175 | MightiestDuck bool 176 | FunnyPrank string 177 | Immutable *DreamerImmutable 178 | } 179 | 180 | type DreamerImmutable struct { 181 | ID string 182 | State *pb.Dreamer_States 183 | MissingCall *pb.Dreamer_MissingCalls 184 | Calls int32 185 | Started time.Time 186 | Stopped time.Time 187 | LastUpdate time.Time 188 | empty bool 189 | } 190 | 191 | type Slap struct { 192 | Name string 193 | Desc string 194 | DescLong string 195 | Args pb.Message 196 | Tense int32 197 | Interval int32 198 | Homeland uint32 199 | FunnyPrank string 200 | Immutable *SlapImmutable 201 | } 202 | 203 | type SlapImmutable struct { 204 | ID string 205 | Out pb.Message 206 | MildSlap bool 207 | PrettyPrint string 208 | State *pb.Slap_States 209 | Started time.Time 210 | Stopped time.Time 211 | LastUpdate time.Time 212 | LoveRadius *LoveRadius 213 | empty bool 214 | } 215 | 216 | type Goat struct { 217 | Target string 218 | Slaps []Slap 219 | FunnyPrank string 220 | Immutable *GoatImmutable 221 | } 222 | 223 | type GoatImmutable struct { 224 | ID string 225 | State *pb.Goat_States 226 | Started time.Time 227 | Stopped time.Time 228 | LastUpdate time.Time 229 | empty bool 230 | } 231 | type Donkey struct { 232 | Pause bool 233 | Sleep int32 234 | FunnyPrank string 235 | Immutable *DonkeyImmutable 236 | } 237 | 238 | type DonkeyImmutable struct { 239 | ID string 240 | State *pb.Donkey_States 241 | Started time.Time 242 | Stopped time.Time 243 | LastUpdate time.Time 244 | empty bool 245 | } 246 | 247 | type LoveRadius struct { 248 | Summer *SummerLove 249 | empty bool 250 | } 251 | 252 | type SummerLove struct { 253 | Summary *SummerLoveSummary 254 | empty bool 255 | } 256 | 257 | type SummerLoveSummary struct { 258 | Devices []string 259 | ChangeType []pb.SummerType 260 | empty bool 261 | } 262 | 263 | func (EagleImmutable) Proto() *pb.Eagle { return nil } 264 | func (DreamerImmutable) Proto() *pb.Dreamer { return nil } 265 | func (SlapImmutable) Proto() *pb.Slap { return nil } 266 | func (GoatImmutable) Proto() *pb.Goat { return nil } 267 | func (DonkeyImmutable) Proto() *pb.Donkey { return nil } 268 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/teststructs/project2.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package teststructs 6 | 7 | import ( 8 | "time" 9 | 10 | pb "github.com/google/go-cmp/cmp/internal/testprotos" 11 | ) 12 | 13 | // This is an sanitized example of equality from a real use-case. 14 | // The original equality function was as follows: 15 | /* 16 | func equalBatch(b1, b2 *GermBatch) bool { 17 | for _, b := range []*GermBatch{b1, b2} { 18 | for _, l := range b.DirtyGerms { 19 | sort.Slice(l, func(i, j int) bool { return l[i].String() < l[j].String() }) 20 | } 21 | for _, l := range b.CleanGerms { 22 | sort.Slice(l, func(i, j int) bool { return l[i].String() < l[j].String() }) 23 | } 24 | } 25 | if !pb.DeepEqual(b1.DirtyGerms, b2.DirtyGerms) || 26 | !pb.DeepEqual(b1.CleanGerms, b2.CleanGerms) || 27 | !pb.DeepEqual(b1.GermMap, b2.GermMap) { 28 | return false 29 | } 30 | if len(b1.DishMap) != len(b2.DishMap) { 31 | return false 32 | } 33 | for id := range b1.DishMap { 34 | kpb1, err1 := b1.DishMap[id].Proto() 35 | kpb2, err2 := b2.DishMap[id].Proto() 36 | if !pb.Equal(kpb1, kpb2) || !reflect.DeepEqual(err1, err2) { 37 | return false 38 | } 39 | } 40 | return b1.HasPreviousResult == b2.HasPreviousResult && 41 | b1.DirtyID == b2.DirtyID && 42 | b1.CleanID == b2.CleanID && 43 | b1.GermStrain == b2.GermStrain && 44 | b1.TotalDirtyGerms == b2.TotalDirtyGerms && 45 | b1.InfectedAt.Equal(b2.InfectedAt) 46 | } 47 | */ 48 | 49 | type GermBatch struct { 50 | DirtyGerms, CleanGerms map[int32][]*pb.Germ 51 | GermMap map[int32]*pb.Germ 52 | DishMap map[int32]*Dish 53 | HasPreviousResult bool 54 | DirtyID, CleanID int32 55 | GermStrain int32 56 | TotalDirtyGerms int 57 | InfectedAt time.Time 58 | } 59 | 60 | type Dish struct { 61 | pb *pb.Dish 62 | err error 63 | } 64 | 65 | func CreateDish(m *pb.Dish, err error) *Dish { 66 | return &Dish{pb: m, err: err} 67 | } 68 | 69 | func (d *Dish) Proto() (*pb.Dish, error) { 70 | if d.err != nil { 71 | return nil, d.err 72 | } 73 | return d.pb, nil 74 | } 75 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/teststructs/project3.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package teststructs 6 | 7 | import ( 8 | "sync" 9 | 10 | pb "github.com/google/go-cmp/cmp/internal/testprotos" 11 | ) 12 | 13 | // This is an sanitized example of equality from a real use-case. 14 | // The original equality function was as follows: 15 | /* 16 | func equalDirt(x, y *Dirt) bool { 17 | if !reflect.DeepEqual(x.table, y.table) || 18 | !reflect.DeepEqual(x.ts, y.ts) || 19 | x.Discord != y.Discord || 20 | !pb.Equal(&x.Proto, &y.Proto) || 21 | len(x.wizard) != len(y.wizard) || 22 | len(x.sadistic) != len(y.sadistic) || 23 | x.lastTime != y.lastTime { 24 | return false 25 | } 26 | for k, vx := range x.wizard { 27 | vy, ok := y.wizard[k] 28 | if !ok || !pb.Equal(vx, vy) { 29 | return false 30 | } 31 | } 32 | for k, vx := range x.sadistic { 33 | vy, ok := y.sadistic[k] 34 | if !ok || !pb.Equal(vx, vy) { 35 | return false 36 | } 37 | } 38 | return true 39 | } 40 | */ 41 | 42 | type FakeMutex struct { 43 | sync.Locker 44 | x struct{} 45 | } 46 | 47 | type Dirt struct { 48 | table Table // Always concrete type of MockTable 49 | ts Timestamp 50 | Discord DiscordState 51 | Proto pb.Dirt 52 | wizard map[string]*pb.Wizard 53 | sadistic map[string]*pb.Sadistic 54 | lastTime int64 55 | mu FakeMutex 56 | } 57 | 58 | type DiscordState int 59 | 60 | type Timestamp int64 61 | 62 | func (d *Dirt) SetTable(t Table) { d.table = t } 63 | func (d *Dirt) SetTimestamp(t Timestamp) { d.ts = t } 64 | func (d *Dirt) SetWizard(m map[string]*pb.Wizard) { d.wizard = m } 65 | func (d *Dirt) SetSadistic(m map[string]*pb.Sadistic) { d.sadistic = m } 66 | func (d *Dirt) SetLastTime(t int64) { d.lastTime = t } 67 | 68 | type Table interface { 69 | Operation1() error 70 | Operation2() error 71 | Operation3() error 72 | } 73 | 74 | type MockTable struct { 75 | state []string 76 | } 77 | 78 | func CreateMockTable(s []string) *MockTable { return &MockTable{s} } 79 | func (mt *MockTable) Operation1() error { return nil } 80 | func (mt *MockTable) Operation2() error { return nil } 81 | func (mt *MockTable) Operation3() error { return nil } 82 | func (mt *MockTable) State() []string { return mt.state } 83 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/teststructs/project4.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package teststructs 6 | 7 | import ( 8 | "time" 9 | 10 | pb "github.com/google/go-cmp/cmp/internal/testprotos" 11 | ) 12 | 13 | // This is an sanitized example of equality from a real use-case. 14 | // The original equality function was as follows: 15 | /* 16 | func equalCartel(x, y Cartel) bool { 17 | if !(equalHeadquarter(x.Headquarter, y.Headquarter) && 18 | x.Source() == y.Source() && 19 | x.CreationDate().Equal(y.CreationDate()) && 20 | x.Boss() == y.Boss() && 21 | x.LastCrimeDate().Equal(y.LastCrimeDate())) { 22 | return false 23 | } 24 | if len(x.Poisons()) != len(y.Poisons()) { 25 | return false 26 | } 27 | for i := range x.Poisons() { 28 | if !equalPoison(*x.Poisons()[i], *y.Poisons()[i]) { 29 | return false 30 | } 31 | } 32 | return true 33 | } 34 | func equalHeadquarter(x, y Headquarter) bool { 35 | xr, yr := x.Restrictions(), y.Restrictions() 36 | return x.ID() == y.ID() && 37 | x.Location() == y.Location() && 38 | reflect.DeepEqual(x.SubDivisions(), y.SubDivisions()) && 39 | x.IncorporatedDate().Equal(y.IncorporatedDate()) && 40 | pb.Equal(x.MetaData(), y.MetaData()) && 41 | bytes.Equal(x.PrivateMessage(), y.PrivateMessage()) && 42 | bytes.Equal(x.PublicMessage(), y.PublicMessage()) && 43 | x.HorseBack() == y.HorseBack() && 44 | x.Rattle() == y.Rattle() && 45 | x.Convulsion() == y.Convulsion() && 46 | x.Expansion() == y.Expansion() && 47 | x.Status() == y.Status() && 48 | pb.Equal(&xr, &yr) && 49 | x.CreationTime().Equal(y.CreationTime()) 50 | } 51 | func equalPoison(x, y Poison) bool { 52 | return x.PoisonType() == y.PoisonType() && 53 | x.Expiration().Equal(y.Expiration()) && 54 | x.Manufacturer() == y.Manufacturer() && 55 | x.Potency() == y.Potency() 56 | } 57 | */ 58 | 59 | type Cartel struct { 60 | Headquarter 61 | source string 62 | creationDate time.Time 63 | boss string 64 | lastCrimeDate time.Time 65 | poisons []*Poison 66 | } 67 | 68 | func (p Cartel) Source() string { return p.source } 69 | func (p Cartel) CreationDate() time.Time { return p.creationDate } 70 | func (p Cartel) Boss() string { return p.boss } 71 | func (p Cartel) LastCrimeDate() time.Time { return p.lastCrimeDate } 72 | func (p Cartel) Poisons() []*Poison { return p.poisons } 73 | 74 | func (p *Cartel) SetSource(x string) { p.source = x } 75 | func (p *Cartel) SetCreationDate(x time.Time) { p.creationDate = x } 76 | func (p *Cartel) SetBoss(x string) { p.boss = x } 77 | func (p *Cartel) SetLastCrimeDate(x time.Time) { p.lastCrimeDate = x } 78 | func (p *Cartel) SetPoisons(x []*Poison) { p.poisons = x } 79 | 80 | type Headquarter struct { 81 | id uint64 82 | location string 83 | subDivisions []string 84 | incorporatedDate time.Time 85 | metaData *pb.MetaData 86 | privateMessage []byte 87 | publicMessage []byte 88 | horseBack string 89 | rattle string 90 | convulsion bool 91 | expansion uint64 92 | status pb.HoneyStatus 93 | restrictions pb.Restrictions 94 | creationTime time.Time 95 | } 96 | 97 | func (hq Headquarter) ID() uint64 { return hq.id } 98 | func (hq Headquarter) Location() string { return hq.location } 99 | func (hq Headquarter) SubDivisions() []string { return hq.subDivisions } 100 | func (hq Headquarter) IncorporatedDate() time.Time { return hq.incorporatedDate } 101 | func (hq Headquarter) MetaData() *pb.MetaData { return hq.metaData } 102 | func (hq Headquarter) PrivateMessage() []byte { return hq.privateMessage } 103 | func (hq Headquarter) PublicMessage() []byte { return hq.publicMessage } 104 | func (hq Headquarter) HorseBack() string { return hq.horseBack } 105 | func (hq Headquarter) Rattle() string { return hq.rattle } 106 | func (hq Headquarter) Convulsion() bool { return hq.convulsion } 107 | func (hq Headquarter) Expansion() uint64 { return hq.expansion } 108 | func (hq Headquarter) Status() pb.HoneyStatus { return hq.status } 109 | func (hq Headquarter) Restrictions() pb.Restrictions { return hq.restrictions } 110 | func (hq Headquarter) CreationTime() time.Time { return hq.creationTime } 111 | 112 | func (hq *Headquarter) SetID(x uint64) { hq.id = x } 113 | func (hq *Headquarter) SetLocation(x string) { hq.location = x } 114 | func (hq *Headquarter) SetSubDivisions(x []string) { hq.subDivisions = x } 115 | func (hq *Headquarter) SetIncorporatedDate(x time.Time) { hq.incorporatedDate = x } 116 | func (hq *Headquarter) SetMetaData(x *pb.MetaData) { hq.metaData = x } 117 | func (hq *Headquarter) SetPrivateMessage(x []byte) { hq.privateMessage = x } 118 | func (hq *Headquarter) SetPublicMessage(x []byte) { hq.publicMessage = x } 119 | func (hq *Headquarter) SetHorseBack(x string) { hq.horseBack = x } 120 | func (hq *Headquarter) SetRattle(x string) { hq.rattle = x } 121 | func (hq *Headquarter) SetConvulsion(x bool) { hq.convulsion = x } 122 | func (hq *Headquarter) SetExpansion(x uint64) { hq.expansion = x } 123 | func (hq *Headquarter) SetStatus(x pb.HoneyStatus) { hq.status = x } 124 | func (hq *Headquarter) SetRestrictions(x pb.Restrictions) { hq.restrictions = x } 125 | func (hq *Headquarter) SetCreationTime(x time.Time) { hq.creationTime = x } 126 | 127 | type Poison struct { 128 | poisonType pb.PoisonType 129 | expiration time.Time 130 | manufacturer string 131 | potency int 132 | } 133 | 134 | func (p Poison) PoisonType() pb.PoisonType { return p.poisonType } 135 | func (p Poison) Expiration() time.Time { return p.expiration } 136 | func (p Poison) Manufacturer() string { return p.manufacturer } 137 | func (p Poison) Potency() int { return p.potency } 138 | 139 | func (p *Poison) SetPoisonType(x pb.PoisonType) { p.poisonType = x } 140 | func (p *Poison) SetExpiration(x time.Time) { p.expiration = x } 141 | func (p *Poison) SetManufacturer(x string) { p.manufacturer = x } 142 | func (p *Poison) SetPotency(x int) { p.potency = x } 143 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/teststructs/structs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package teststructs 6 | 7 | type InterfaceA interface { 8 | InterfaceA() 9 | } 10 | 11 | type ( 12 | StructA struct{ X string } // Equal method on value receiver 13 | StructB struct{ X string } // Equal method on pointer receiver 14 | StructC struct{ X string } // Equal method (with interface argument) on value receiver 15 | StructD struct{ X string } // Equal method (with interface argument) on pointer receiver 16 | StructE struct{ X string } // Equal method (with interface argument on value receiver) on pointer receiver 17 | StructF struct{ X string } // Equal method (with interface argument on pointer receiver) on value receiver 18 | 19 | // These embed the above types as a value. 20 | StructA1 struct { 21 | StructA 22 | X string 23 | } 24 | StructB1 struct { 25 | StructB 26 | X string 27 | } 28 | StructC1 struct { 29 | StructC 30 | X string 31 | } 32 | StructD1 struct { 33 | StructD 34 | X string 35 | } 36 | StructE1 struct { 37 | StructE 38 | X string 39 | } 40 | StructF1 struct { 41 | StructF 42 | X string 43 | } 44 | 45 | // These embed the above types as a pointer. 46 | StructA2 struct { 47 | *StructA 48 | X string 49 | } 50 | StructB2 struct { 51 | *StructB 52 | X string 53 | } 54 | StructC2 struct { 55 | *StructC 56 | X string 57 | } 58 | StructD2 struct { 59 | *StructD 60 | X string 61 | } 62 | StructE2 struct { 63 | *StructE 64 | X string 65 | } 66 | StructF2 struct { 67 | *StructF 68 | X string 69 | } 70 | 71 | StructNo struct{ X string } // Equal method (with interface argument) on non-satisfying receiver 72 | 73 | AssignA func() int 74 | AssignB struct{ A int } 75 | AssignC chan bool 76 | AssignD <-chan bool 77 | ) 78 | 79 | func (x StructA) Equal(y StructA) bool { return true } 80 | func (x *StructB) Equal(y *StructB) bool { return true } 81 | func (x StructC) Equal(y InterfaceA) bool { return true } 82 | func (x StructC) InterfaceA() {} 83 | func (x *StructD) Equal(y InterfaceA) bool { return true } 84 | func (x *StructD) InterfaceA() {} 85 | func (x *StructE) Equal(y InterfaceA) bool { return true } 86 | func (x StructE) InterfaceA() {} 87 | func (x StructF) Equal(y InterfaceA) bool { return true } 88 | func (x *StructF) InterfaceA() {} 89 | func (x StructNo) Equal(y InterfaceA) bool { return true } 90 | 91 | func (x AssignA) Equal(y func() int) bool { return true } 92 | func (x AssignB) Equal(y struct{ A int }) bool { return true } 93 | func (x AssignC) Equal(y chan bool) bool { return true } 94 | func (x AssignD) Equal(y <-chan bool) bool { return true } 95 | 96 | var _ = func( 97 | a StructA, b StructB, c StructC, d StructD, e StructE, f StructF, 98 | ap *StructA, bp *StructB, cp *StructC, dp *StructD, ep *StructE, fp *StructF, 99 | a1 StructA1, b1 StructB1, c1 StructC1, d1 StructD1, e1 StructE1, f1 StructF1, 100 | a2 StructA2, b2 StructB2, c2 StructC2, d2 StructD2, e2 StructE2, f2 StructF1, 101 | ) { 102 | a.Equal(a) 103 | b.Equal(&b) 104 | c.Equal(c) 105 | d.Equal(&d) 106 | e.Equal(e) 107 | f.Equal(&f) 108 | 109 | ap.Equal(*ap) 110 | bp.Equal(bp) 111 | cp.Equal(*cp) 112 | dp.Equal(dp) 113 | ep.Equal(*ep) 114 | fp.Equal(fp) 115 | 116 | a1.Equal(a1.StructA) 117 | b1.Equal(&b1.StructB) 118 | c1.Equal(c1) 119 | d1.Equal(&d1) 120 | e1.Equal(e1) 121 | f1.Equal(&f1) 122 | 123 | a2.Equal(*a2.StructA) 124 | b2.Equal(b2.StructB) 125 | c2.Equal(c2) 126 | d2.Equal(&d2) 127 | e2.Equal(e2) 128 | f2.Equal(&f2) 129 | } 130 | 131 | type ( 132 | privateStruct struct{ Public, private int } 133 | PublicStruct struct{ Public, private int } 134 | ParentStructA struct{ privateStruct } 135 | ParentStructB struct{ PublicStruct } 136 | ParentStructC struct { 137 | privateStruct 138 | Public, private int 139 | } 140 | ParentStructD struct { 141 | PublicStruct 142 | Public, private int 143 | } 144 | ParentStructE struct { 145 | privateStruct 146 | PublicStruct 147 | } 148 | ParentStructF struct { 149 | privateStruct 150 | PublicStruct 151 | Public, private int 152 | } 153 | ParentStructG struct { 154 | *privateStruct 155 | } 156 | ParentStructH struct { 157 | *PublicStruct 158 | } 159 | ParentStructI struct { 160 | *privateStruct 161 | *PublicStruct 162 | } 163 | ParentStructJ struct { 164 | *privateStruct 165 | *PublicStruct 166 | Public PublicStruct 167 | private privateStruct 168 | } 169 | ) 170 | 171 | func NewParentStructG() *ParentStructG { 172 | return &ParentStructG{new(privateStruct)} 173 | } 174 | func NewParentStructH() *ParentStructH { 175 | return &ParentStructH{new(PublicStruct)} 176 | } 177 | func NewParentStructI() *ParentStructI { 178 | return &ParentStructI{new(privateStruct), new(PublicStruct)} 179 | } 180 | func NewParentStructJ() *ParentStructJ { 181 | return &ParentStructJ{ 182 | privateStruct: new(privateStruct), PublicStruct: new(PublicStruct), 183 | } 184 | } 185 | func (s *privateStruct) SetPrivate(i int) { s.private = i } 186 | func (s *PublicStruct) SetPrivate(i int) { s.private = i } 187 | func (s *ParentStructC) SetPrivate(i int) { s.private = i } 188 | func (s *ParentStructD) SetPrivate(i int) { s.private = i } 189 | func (s *ParentStructF) SetPrivate(i int) { s.private = i } 190 | func (s *ParentStructA) PrivateStruct() *privateStruct { return &s.privateStruct } 191 | func (s *ParentStructC) PrivateStruct() *privateStruct { return &s.privateStruct } 192 | func (s *ParentStructE) PrivateStruct() *privateStruct { return &s.privateStruct } 193 | func (s *ParentStructF) PrivateStruct() *privateStruct { return &s.privateStruct } 194 | func (s *ParentStructG) PrivateStruct() *privateStruct { return s.privateStruct } 195 | func (s *ParentStructI) PrivateStruct() *privateStruct { return s.privateStruct } 196 | func (s *ParentStructJ) PrivateStruct() *privateStruct { return s.privateStruct } 197 | func (s *ParentStructJ) Private() *privateStruct { return &s.private } 198 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build purego 6 | 7 | package value 8 | 9 | import "reflect" 10 | 11 | // Pointer is an opaque typed pointer and is guaranteed to be comparable. 12 | type Pointer struct { 13 | p uintptr 14 | t reflect.Type 15 | } 16 | 17 | // PointerOf returns a Pointer from v, which must be a 18 | // reflect.Ptr, reflect.Slice, or reflect.Map. 19 | func PointerOf(v reflect.Value) Pointer { 20 | // NOTE: Storing a pointer as an uintptr is technically incorrect as it 21 | // assumes that the GC implementation does not use a moving collector. 22 | return Pointer{v.Pointer(), v.Type()} 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | // +build !purego 6 | 7 | package value 8 | 9 | import ( 10 | "reflect" 11 | "unsafe" 12 | ) 13 | 14 | // Pointer is an opaque typed pointer and is guaranteed to be comparable. 15 | type Pointer struct { 16 | p unsafe.Pointer 17 | t reflect.Type 18 | } 19 | 20 | // PointerOf returns a Pointer from v, which must be a 21 | // reflect.Ptr, reflect.Slice, or reflect.Map. 22 | func PointerOf(v reflect.Value) Pointer { 23 | // The proper representation of a pointer is unsafe.Pointer, 24 | // which is necessary if the GC ever uses a moving collector. 25 | return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/value/sort.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package value 6 | 7 | import ( 8 | "fmt" 9 | "math" 10 | "reflect" 11 | "sort" 12 | ) 13 | 14 | // SortKeys sorts a list of map keys, deduplicating keys if necessary. 15 | // The type of each value must be comparable. 16 | func SortKeys(vs []reflect.Value) []reflect.Value { 17 | if len(vs) == 0 { 18 | return vs 19 | } 20 | 21 | // Sort the map keys. 22 | sort.SliceStable(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) }) 23 | 24 | // Deduplicate keys (fails for NaNs). 25 | vs2 := vs[:1] 26 | for _, v := range vs[1:] { 27 | if isLess(vs2[len(vs2)-1], v) { 28 | vs2 = append(vs2, v) 29 | } 30 | } 31 | return vs2 32 | } 33 | 34 | // isLess is a generic function for sorting arbitrary map keys. 35 | // The inputs must be of the same type and must be comparable. 36 | func isLess(x, y reflect.Value) bool { 37 | switch x.Type().Kind() { 38 | case reflect.Bool: 39 | return !x.Bool() && y.Bool() 40 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 41 | return x.Int() < y.Int() 42 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 43 | return x.Uint() < y.Uint() 44 | case reflect.Float32, reflect.Float64: 45 | // NOTE: This does not sort -0 as less than +0 46 | // since Go maps treat -0 and +0 as equal keys. 47 | fx, fy := x.Float(), y.Float() 48 | return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy) 49 | case reflect.Complex64, reflect.Complex128: 50 | cx, cy := x.Complex(), y.Complex() 51 | rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy) 52 | if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) { 53 | return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy) 54 | } 55 | return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry) 56 | case reflect.Ptr, reflect.UnsafePointer, reflect.Chan: 57 | return x.Pointer() < y.Pointer() 58 | case reflect.String: 59 | return x.String() < y.String() 60 | case reflect.Array: 61 | for i := 0; i < x.Len(); i++ { 62 | if isLess(x.Index(i), y.Index(i)) { 63 | return true 64 | } 65 | if isLess(y.Index(i), x.Index(i)) { 66 | return false 67 | } 68 | } 69 | return false 70 | case reflect.Struct: 71 | for i := 0; i < x.NumField(); i++ { 72 | if isLess(x.Field(i), y.Field(i)) { 73 | return true 74 | } 75 | if isLess(y.Field(i), x.Field(i)) { 76 | return false 77 | } 78 | } 79 | return false 80 | case reflect.Interface: 81 | vx, vy := x.Elem(), y.Elem() 82 | if !vx.IsValid() || !vy.IsValid() { 83 | return !vx.IsValid() && vy.IsValid() 84 | } 85 | tx, ty := vx.Type(), vy.Type() 86 | if tx == ty { 87 | return isLess(x.Elem(), y.Elem()) 88 | } 89 | if tx.Kind() != ty.Kind() { 90 | return vx.Kind() < vy.Kind() 91 | } 92 | if tx.String() != ty.String() { 93 | return tx.String() < ty.String() 94 | } 95 | if tx.PkgPath() != ty.PkgPath() { 96 | return tx.PkgPath() < ty.PkgPath() 97 | } 98 | // This can happen in rare situations, so we fallback to just comparing 99 | // the unique pointer for a reflect.Type. This guarantees deterministic 100 | // ordering within a program, but it is obviously not stable. 101 | return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer() 102 | default: 103 | // Must be Func, Map, or Slice; which are not comparable. 104 | panic(fmt.Sprintf("%T is not comparable", x.Type())) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/value/sort_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package value_test 6 | 7 | import ( 8 | "math" 9 | "reflect" 10 | "testing" 11 | 12 | "github.com/google/go-cmp/cmp" 13 | "github.com/google/go-cmp/cmp/internal/value" 14 | ) 15 | 16 | func TestSortKeys(t *testing.T) { 17 | type ( 18 | MyString string 19 | MyArray [2]int 20 | MyStruct struct { 21 | A MyString 22 | B MyArray 23 | C chan float64 24 | } 25 | EmptyStruct struct{} 26 | ) 27 | 28 | opts := []cmp.Option{ 29 | cmp.Comparer(func(x, y float64) bool { 30 | if math.IsNaN(x) && math.IsNaN(y) { 31 | return true 32 | } 33 | return x == y 34 | }), 35 | cmp.Comparer(func(x, y complex128) bool { 36 | rx, ix, ry, iy := real(x), imag(x), real(y), imag(y) 37 | if math.IsNaN(rx) && math.IsNaN(ry) { 38 | rx, ry = 0, 0 39 | } 40 | if math.IsNaN(ix) && math.IsNaN(iy) { 41 | ix, iy = 0, 0 42 | } 43 | return rx == ry && ix == iy 44 | }), 45 | cmp.Comparer(func(x, y chan bool) bool { return true }), 46 | cmp.Comparer(func(x, y chan int) bool { return true }), 47 | cmp.Comparer(func(x, y chan float64) bool { return true }), 48 | cmp.Comparer(func(x, y chan interface{}) bool { return true }), 49 | cmp.Comparer(func(x, y *int) bool { return true }), 50 | } 51 | 52 | tests := []struct { 53 | in map[interface{}]bool // Set of keys to sort 54 | want []interface{} 55 | }{{ 56 | in: map[interface{}]bool{1: true, 2: true, 3: true}, 57 | want: []interface{}{1, 2, 3}, 58 | }, { 59 | in: map[interface{}]bool{ 60 | nil: true, 61 | true: true, 62 | false: true, 63 | -5: true, 64 | -55: true, 65 | -555: true, 66 | uint(1): true, 67 | uint(11): true, 68 | uint(111): true, 69 | "abc": true, 70 | "abcd": true, 71 | "abcde": true, 72 | "foo": true, 73 | "bar": true, 74 | MyString("abc"): true, 75 | MyString("abcd"): true, 76 | MyString("abcde"): true, 77 | new(int): true, 78 | new(int): true, 79 | make(chan bool): true, 80 | make(chan bool): true, 81 | make(chan int): true, 82 | make(chan interface{}): true, 83 | math.Inf(+1): true, 84 | math.Inf(-1): true, 85 | 1.2345: true, 86 | 12.345: true, 87 | 123.45: true, 88 | 1234.5: true, 89 | 0 + 0i: true, 90 | 1 + 0i: true, 91 | 2 + 0i: true, 92 | 0 + 1i: true, 93 | 0 + 2i: true, 94 | 0 + 3i: true, 95 | [2]int{2, 3}: true, 96 | [2]int{4, 0}: true, 97 | [2]int{2, 4}: true, 98 | MyArray([2]int{2, 4}): true, 99 | EmptyStruct{}: true, 100 | MyStruct{ 101 | "bravo", [2]int{2, 3}, make(chan float64), 102 | }: true, 103 | MyStruct{ 104 | "alpha", [2]int{3, 3}, make(chan float64), 105 | }: true, 106 | }, 107 | want: []interface{}{ 108 | nil, false, true, 109 | -555, -55, -5, uint(1), uint(11), uint(111), 110 | math.Inf(-1), 1.2345, 12.345, 123.45, 1234.5, math.Inf(+1), 111 | (0 + 0i), (0 + 1i), (0 + 2i), (0 + 3i), (1 + 0i), (2 + 0i), 112 | [2]int{2, 3}, [2]int{2, 4}, [2]int{4, 0}, MyArray([2]int{2, 4}), 113 | make(chan bool), make(chan bool), make(chan int), make(chan interface{}), 114 | new(int), new(int), 115 | "abc", "abcd", "abcde", "bar", "foo", 116 | MyString("abc"), MyString("abcd"), MyString("abcde"), 117 | EmptyStruct{}, 118 | MyStruct{"alpha", [2]int{3, 3}, make(chan float64)}, 119 | MyStruct{"bravo", [2]int{2, 3}, make(chan float64)}, 120 | }, 121 | }, { 122 | // NaN values cannot be properly deduplicated. 123 | // This is okay since map entries with NaN in the keys cannot be 124 | // retrieved anyways. 125 | in: map[interface{}]bool{ 126 | math.NaN(): true, 127 | math.NaN(): true, 128 | complex(0, math.NaN()): true, 129 | complex(0, math.NaN()): true, 130 | complex(math.NaN(), 0): true, 131 | complex(math.NaN(), 0): true, 132 | complex(math.NaN(), math.NaN()): true, 133 | }, 134 | want: []interface{}{ 135 | math.NaN(), 136 | complex(math.NaN(), math.NaN()), 137 | complex(math.NaN(), 0), 138 | complex(0, math.NaN()), 139 | }, 140 | }} 141 | 142 | for i, tt := range tests { 143 | // Intentionally pass the map via an unexported field to detect panics. 144 | // Unfortunately, we cannot actually test the keys without using unsafe. 145 | v := reflect.ValueOf(struct{ x map[interface{}]bool }{tt.in}).Field(0) 146 | value.SortKeys(append(v.MapKeys(), v.MapKeys()...)) 147 | 148 | // Try again, with keys that have read-write access in reflect. 149 | v = reflect.ValueOf(tt.in) 150 | keys := append(v.MapKeys(), v.MapKeys()...) 151 | var got []interface{} 152 | for _, k := range value.SortKeys(keys) { 153 | got = append(got, k.Interface()) 154 | } 155 | if d := cmp.Diff(got, tt.want, opts...); d != "" { 156 | t.Errorf("test %d, Sort() mismatch (-got +want):\n%s", i, d) 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/value/zero.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package value 6 | 7 | import ( 8 | "math" 9 | "reflect" 10 | ) 11 | 12 | // IsZero reports whether v is the zero value. 13 | // This does not rely on Interface and so can be used on unexported fields. 14 | func IsZero(v reflect.Value) bool { 15 | switch v.Kind() { 16 | case reflect.Bool: 17 | return v.Bool() == false 18 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 19 | return v.Int() == 0 20 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 21 | return v.Uint() == 0 22 | case reflect.Float32, reflect.Float64: 23 | return math.Float64bits(v.Float()) == 0 24 | case reflect.Complex64, reflect.Complex128: 25 | return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0 26 | case reflect.String: 27 | return v.String() == "" 28 | case reflect.UnsafePointer: 29 | return v.Pointer() == 0 30 | case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: 31 | return v.IsNil() 32 | case reflect.Array: 33 | for i := 0; i < v.Len(); i++ { 34 | if !IsZero(v.Index(i)) { 35 | return false 36 | } 37 | } 38 | return true 39 | case reflect.Struct: 40 | for i := 0; i < v.NumField(); i++ { 41 | if !IsZero(v.Field(i)) { 42 | return false 43 | } 44 | } 45 | return true 46 | } 47 | return false 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/internal/value/zero_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package value 6 | 7 | import ( 8 | "archive/tar" 9 | "math" 10 | "reflect" 11 | "testing" 12 | ) 13 | 14 | func TestIsZero(t *testing.T) { 15 | tests := []struct { 16 | in interface{} 17 | want bool 18 | }{ 19 | {0, true}, 20 | {1, false}, 21 | {"", true}, 22 | {"foo", false}, 23 | {[]byte(nil), true}, 24 | {[]byte{}, false}, 25 | {map[string]bool(nil), true}, 26 | {map[string]bool{}, false}, 27 | {tar.Header{}, true}, 28 | {&tar.Header{}, false}, 29 | {tar.Header{Name: "foo"}, false}, 30 | {(chan bool)(nil), true}, 31 | {make(chan bool), false}, 32 | {(func(*testing.T))(nil), true}, 33 | {TestIsZero, false}, 34 | {[...]int{0, 0, 0}, true}, 35 | {[...]int{0, 1, 0}, false}, 36 | {math.Copysign(0, +1), true}, 37 | {math.Copysign(0, -1), false}, 38 | {complex(math.Copysign(0, +1), math.Copysign(0, +1)), true}, 39 | {complex(math.Copysign(0, -1), math.Copysign(0, +1)), false}, 40 | {complex(math.Copysign(0, +1), math.Copysign(0, -1)), false}, 41 | {complex(math.Copysign(0, -1), math.Copysign(0, -1)), false}, 42 | } 43 | 44 | for _, tt := range tests { 45 | t.Run("", func(t *testing.T) { 46 | got := IsZero(reflect.ValueOf(tt.in)) 47 | if got != tt.want { 48 | t.Errorf("IsZero(%v) = %v, want %v", tt.in, got, tt.want) 49 | } 50 | }) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/options_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | import ( 8 | "io" 9 | "reflect" 10 | "strings" 11 | "testing" 12 | 13 | ts "github.com/google/go-cmp/cmp/internal/teststructs" 14 | ) 15 | 16 | // Test that the creation of Option values with non-sensible inputs produces 17 | // a run-time panic with a decent error message 18 | func TestOptionPanic(t *testing.T) { 19 | type myBool bool 20 | tests := []struct { 21 | label string // Test description 22 | fnc interface{} // Option function to call 23 | args []interface{} // Arguments to pass in 24 | wantPanic string // Expected panic message 25 | }{{ 26 | label: "AllowUnexported", 27 | fnc: AllowUnexported, 28 | args: []interface{}{}, 29 | }, { 30 | label: "AllowUnexported", 31 | fnc: AllowUnexported, 32 | args: []interface{}{1}, 33 | wantPanic: "invalid struct type", 34 | }, { 35 | label: "AllowUnexported", 36 | fnc: AllowUnexported, 37 | args: []interface{}{ts.StructA{}}, 38 | }, { 39 | label: "AllowUnexported", 40 | fnc: AllowUnexported, 41 | args: []interface{}{ts.StructA{}, ts.StructB{}, ts.StructA{}}, 42 | }, { 43 | label: "AllowUnexported", 44 | fnc: AllowUnexported, 45 | args: []interface{}{ts.StructA{}, &ts.StructB{}, ts.StructA{}}, 46 | wantPanic: "invalid struct type", 47 | }, { 48 | label: "Comparer", 49 | fnc: Comparer, 50 | args: []interface{}{5}, 51 | wantPanic: "invalid comparer function", 52 | }, { 53 | label: "Comparer", 54 | fnc: Comparer, 55 | args: []interface{}{func(x, y interface{}) bool { return true }}, 56 | }, { 57 | label: "Comparer", 58 | fnc: Comparer, 59 | args: []interface{}{func(x, y io.Reader) bool { return true }}, 60 | }, { 61 | label: "Comparer", 62 | fnc: Comparer, 63 | args: []interface{}{func(x, y io.Reader) myBool { return true }}, 64 | wantPanic: "invalid comparer function", 65 | }, { 66 | label: "Comparer", 67 | fnc: Comparer, 68 | args: []interface{}{func(x string, y interface{}) bool { return true }}, 69 | wantPanic: "invalid comparer function", 70 | }, { 71 | label: "Comparer", 72 | fnc: Comparer, 73 | args: []interface{}{(func(int, int) bool)(nil)}, 74 | wantPanic: "invalid comparer function", 75 | }, { 76 | label: "Transformer", 77 | fnc: Transformer, 78 | args: []interface{}{"", 0}, 79 | wantPanic: "invalid transformer function", 80 | }, { 81 | label: "Transformer", 82 | fnc: Transformer, 83 | args: []interface{}{"", func(int) int { return 0 }}, 84 | }, { 85 | label: "Transformer", 86 | fnc: Transformer, 87 | args: []interface{}{"", func(bool) bool { return true }}, 88 | }, { 89 | label: "Transformer", 90 | fnc: Transformer, 91 | args: []interface{}{"", func(int) bool { return true }}, 92 | }, { 93 | label: "Transformer", 94 | fnc: Transformer, 95 | args: []interface{}{"", func(int, int) bool { return true }}, 96 | wantPanic: "invalid transformer function", 97 | }, { 98 | label: "Transformer", 99 | fnc: Transformer, 100 | args: []interface{}{"", (func(int) uint)(nil)}, 101 | wantPanic: "invalid transformer function", 102 | }, { 103 | label: "Transformer", 104 | fnc: Transformer, 105 | args: []interface{}{"Func", func(Path) Path { return nil }}, 106 | }, { 107 | label: "Transformer", 108 | fnc: Transformer, 109 | args: []interface{}{"世界", func(int) bool { return true }}, 110 | }, { 111 | label: "Transformer", 112 | fnc: Transformer, 113 | args: []interface{}{"/*", func(int) bool { return true }}, 114 | wantPanic: "invalid name", 115 | }, { 116 | label: "Transformer", 117 | fnc: Transformer, 118 | args: []interface{}{"_", func(int) bool { return true }}, 119 | }, { 120 | label: "FilterPath", 121 | fnc: FilterPath, 122 | args: []interface{}{(func(Path) bool)(nil), Ignore()}, 123 | wantPanic: "invalid path filter function", 124 | }, { 125 | label: "FilterPath", 126 | fnc: FilterPath, 127 | args: []interface{}{func(Path) bool { return true }, Ignore()}, 128 | }, { 129 | label: "FilterPath", 130 | fnc: FilterPath, 131 | args: []interface{}{func(Path) bool { return true }, Reporter(&defaultReporter{})}, 132 | wantPanic: "invalid option type", 133 | }, { 134 | label: "FilterPath", 135 | fnc: FilterPath, 136 | args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Ignore()}}, 137 | }, { 138 | label: "FilterPath", 139 | fnc: FilterPath, 140 | args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}}, 141 | wantPanic: "invalid option type", 142 | }, { 143 | label: "FilterValues", 144 | fnc: FilterValues, 145 | args: []interface{}{0, Ignore()}, 146 | wantPanic: "invalid values filter function", 147 | }, { 148 | label: "FilterValues", 149 | fnc: FilterValues, 150 | args: []interface{}{func(x, y int) bool { return true }, Ignore()}, 151 | }, { 152 | label: "FilterValues", 153 | fnc: FilterValues, 154 | args: []interface{}{func(x, y interface{}) bool { return true }, Ignore()}, 155 | }, { 156 | label: "FilterValues", 157 | fnc: FilterValues, 158 | args: []interface{}{func(x, y interface{}) myBool { return true }, Ignore()}, 159 | wantPanic: "invalid values filter function", 160 | }, { 161 | label: "FilterValues", 162 | fnc: FilterValues, 163 | args: []interface{}{func(x io.Reader, y interface{}) bool { return true }, Ignore()}, 164 | wantPanic: "invalid values filter function", 165 | }, { 166 | label: "FilterValues", 167 | fnc: FilterValues, 168 | args: []interface{}{(func(int, int) bool)(nil), Ignore()}, 169 | wantPanic: "invalid values filter function", 170 | }, { 171 | label: "FilterValues", 172 | fnc: FilterValues, 173 | args: []interface{}{func(int, int) bool { return true }, Reporter(&defaultReporter{})}, 174 | wantPanic: "invalid option type", 175 | }, { 176 | label: "FilterValues", 177 | fnc: FilterValues, 178 | args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Ignore()}}, 179 | }, { 180 | label: "FilterValues", 181 | fnc: FilterValues, 182 | args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}}, 183 | wantPanic: "invalid option type", 184 | }} 185 | 186 | for _, tt := range tests { 187 | t.Run(tt.label, func(t *testing.T) { 188 | var gotPanic string 189 | func() { 190 | defer func() { 191 | if ex := recover(); ex != nil { 192 | if s, ok := ex.(string); ok { 193 | gotPanic = s 194 | } else { 195 | panic(ex) 196 | } 197 | } 198 | }() 199 | var vargs []reflect.Value 200 | for _, arg := range tt.args { 201 | vargs = append(vargs, reflect.ValueOf(arg)) 202 | } 203 | reflect.ValueOf(tt.fnc).Call(vargs) 204 | }() 205 | if tt.wantPanic == "" { 206 | if gotPanic != "" { 207 | t.Fatalf("unexpected panic message: %s", gotPanic) 208 | } 209 | } else { 210 | if !strings.Contains(gotPanic, tt.wantPanic) { 211 | t.Fatalf("panic message:\ngot: %s\nwant: %s", gotPanic, tt.wantPanic) 212 | } 213 | } 214 | }) 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/path.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | "strings" 11 | "unicode" 12 | "unicode/utf8" 13 | ) 14 | 15 | // Path is a list of PathSteps describing the sequence of operations to get 16 | // from some root type to the current position in the value tree. 17 | // The first Path element is always an operation-less PathStep that exists 18 | // simply to identify the initial type. 19 | // 20 | // When traversing structs with embedded structs, the embedded struct will 21 | // always be accessed as a field before traversing the fields of the 22 | // embedded struct themselves. That is, an exported field from the 23 | // embedded struct will never be accessed directly from the parent struct. 24 | type Path []PathStep 25 | 26 | // PathStep is a union-type for specific operations to traverse 27 | // a value's tree structure. Users of this package never need to implement 28 | // these types as values of this type will be returned by this package. 29 | // 30 | // Implementations of this interface are 31 | // StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. 32 | type PathStep interface { 33 | String() string 34 | 35 | // Type is the resulting type after performing the path step. 36 | Type() reflect.Type 37 | 38 | // Values is the resulting values after performing the path step. 39 | // The type of each valid value is guaranteed to be identical to Type. 40 | // 41 | // In some cases, one or both may be invalid or have restrictions: 42 | // • For StructField, both are not interface-able if the current field 43 | // is unexported and the struct type is not explicitly permitted by 44 | // AllowUnexported to traverse unexported fields. 45 | // • For SliceIndex, one may be invalid if an element is missing from 46 | // either the x or y slice. 47 | // • For MapIndex, one may be invalid if an entry is missing from 48 | // either the x or y map. 49 | // 50 | // The provided values must not be mutated. 51 | Values() (vx, vy reflect.Value) 52 | } 53 | 54 | var ( 55 | _ PathStep = StructField{} 56 | _ PathStep = SliceIndex{} 57 | _ PathStep = MapIndex{} 58 | _ PathStep = Indirect{} 59 | _ PathStep = TypeAssertion{} 60 | _ PathStep = Transform{} 61 | ) 62 | 63 | func (pa *Path) push(s PathStep) { 64 | *pa = append(*pa, s) 65 | } 66 | 67 | func (pa *Path) pop() { 68 | *pa = (*pa)[:len(*pa)-1] 69 | } 70 | 71 | // Last returns the last PathStep in the Path. 72 | // If the path is empty, this returns a non-nil PathStep that reports a nil Type. 73 | func (pa Path) Last() PathStep { 74 | return pa.Index(-1) 75 | } 76 | 77 | // Index returns the ith step in the Path and supports negative indexing. 78 | // A negative index starts counting from the tail of the Path such that -1 79 | // refers to the last step, -2 refers to the second-to-last step, and so on. 80 | // If index is invalid, this returns a non-nil PathStep that reports a nil Type. 81 | func (pa Path) Index(i int) PathStep { 82 | if i < 0 { 83 | i = len(pa) + i 84 | } 85 | if i < 0 || i >= len(pa) { 86 | return pathStep{} 87 | } 88 | return pa[i] 89 | } 90 | 91 | // String returns the simplified path to a node. 92 | // The simplified path only contains struct field accesses. 93 | // 94 | // For example: 95 | // MyMap.MySlices.MyField 96 | func (pa Path) String() string { 97 | var ss []string 98 | for _, s := range pa { 99 | if _, ok := s.(StructField); ok { 100 | ss = append(ss, s.String()) 101 | } 102 | } 103 | return strings.TrimPrefix(strings.Join(ss, ""), ".") 104 | } 105 | 106 | // GoString returns the path to a specific node using Go syntax. 107 | // 108 | // For example: 109 | // (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField 110 | func (pa Path) GoString() string { 111 | var ssPre, ssPost []string 112 | var numIndirect int 113 | for i, s := range pa { 114 | var nextStep PathStep 115 | if i+1 < len(pa) { 116 | nextStep = pa[i+1] 117 | } 118 | switch s := s.(type) { 119 | case Indirect: 120 | numIndirect++ 121 | pPre, pPost := "(", ")" 122 | switch nextStep.(type) { 123 | case Indirect: 124 | continue // Next step is indirection, so let them batch up 125 | case StructField: 126 | numIndirect-- // Automatic indirection on struct fields 127 | case nil: 128 | pPre, pPost = "", "" // Last step; no need for parenthesis 129 | } 130 | if numIndirect > 0 { 131 | ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect)) 132 | ssPost = append(ssPost, pPost) 133 | } 134 | numIndirect = 0 135 | continue 136 | case Transform: 137 | ssPre = append(ssPre, s.trans.name+"(") 138 | ssPost = append(ssPost, ")") 139 | continue 140 | } 141 | ssPost = append(ssPost, s.String()) 142 | } 143 | for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 { 144 | ssPre[i], ssPre[j] = ssPre[j], ssPre[i] 145 | } 146 | return strings.Join(ssPre, "") + strings.Join(ssPost, "") 147 | } 148 | 149 | type pathStep struct { 150 | typ reflect.Type 151 | vx, vy reflect.Value 152 | } 153 | 154 | func (ps pathStep) Type() reflect.Type { return ps.typ } 155 | func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy } 156 | func (ps pathStep) String() string { 157 | if ps.typ == nil { 158 | return "" 159 | } 160 | s := ps.typ.String() 161 | if s == "" || strings.ContainsAny(s, "{}\n") { 162 | return "root" // Type too simple or complex to print 163 | } 164 | return fmt.Sprintf("{%s}", s) 165 | } 166 | 167 | // StructField represents a struct field access on a field called Name. 168 | type StructField struct{ *structField } 169 | type structField struct { 170 | pathStep 171 | name string 172 | idx int 173 | 174 | // These fields are used for forcibly accessing an unexported field. 175 | // pvx, pvy, and field are only valid if unexported is true. 176 | unexported bool 177 | mayForce bool // Forcibly allow visibility 178 | pvx, pvy reflect.Value // Parent values 179 | field reflect.StructField // Field information 180 | } 181 | 182 | func (sf StructField) Type() reflect.Type { return sf.typ } 183 | func (sf StructField) Values() (vx, vy reflect.Value) { 184 | if !sf.unexported { 185 | return sf.vx, sf.vy // CanInterface reports true 186 | } 187 | 188 | // Forcibly obtain read-write access to an unexported struct field. 189 | if sf.mayForce { 190 | vx = retrieveUnexportedField(sf.pvx, sf.field) 191 | vy = retrieveUnexportedField(sf.pvy, sf.field) 192 | return vx, vy // CanInterface reports true 193 | } 194 | return sf.vx, sf.vy // CanInterface reports false 195 | } 196 | func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } 197 | 198 | // Name is the field name. 199 | func (sf StructField) Name() string { return sf.name } 200 | 201 | // Index is the index of the field in the parent struct type. 202 | // See reflect.Type.Field. 203 | func (sf StructField) Index() int { return sf.idx } 204 | 205 | // SliceIndex is an index operation on a slice or array at some index Key. 206 | type SliceIndex struct{ *sliceIndex } 207 | type sliceIndex struct { 208 | pathStep 209 | xkey, ykey int 210 | } 211 | 212 | func (si SliceIndex) Type() reflect.Type { return si.typ } 213 | func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy } 214 | func (si SliceIndex) String() string { 215 | switch { 216 | case si.xkey == si.ykey: 217 | return fmt.Sprintf("[%d]", si.xkey) 218 | case si.ykey == -1: 219 | // [5->?] means "I don't know where X[5] went" 220 | return fmt.Sprintf("[%d->?]", si.xkey) 221 | case si.xkey == -1: 222 | // [?->3] means "I don't know where Y[3] came from" 223 | return fmt.Sprintf("[?->%d]", si.ykey) 224 | default: 225 | // [5->3] means "X[5] moved to Y[3]" 226 | return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) 227 | } 228 | } 229 | 230 | // Key is the index key; it may return -1 if in a split state 231 | func (si SliceIndex) Key() int { 232 | if si.xkey != si.ykey { 233 | return -1 234 | } 235 | return si.xkey 236 | } 237 | 238 | // SplitKeys are the indexes for indexing into slices in the 239 | // x and y values, respectively. These indexes may differ due to the 240 | // insertion or removal of an element in one of the slices, causing 241 | // all of the indexes to be shifted. If an index is -1, then that 242 | // indicates that the element does not exist in the associated slice. 243 | // 244 | // Key is guaranteed to return -1 if and only if the indexes returned 245 | // by SplitKeys are not the same. SplitKeys will never return -1 for 246 | // both indexes. 247 | func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } 248 | 249 | // MapIndex is an index operation on a map at some index Key. 250 | type MapIndex struct{ *mapIndex } 251 | type mapIndex struct { 252 | pathStep 253 | key reflect.Value 254 | } 255 | 256 | func (mi MapIndex) Type() reflect.Type { return mi.typ } 257 | func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy } 258 | func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) } 259 | 260 | // Key is the value of the map key. 261 | func (mi MapIndex) Key() reflect.Value { return mi.key } 262 | 263 | // Indirect represents pointer indirection on the parent type. 264 | type Indirect struct{ *indirect } 265 | type indirect struct { 266 | pathStep 267 | } 268 | 269 | func (in Indirect) Type() reflect.Type { return in.typ } 270 | func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } 271 | func (in Indirect) String() string { return "*" } 272 | 273 | // TypeAssertion represents a type assertion on an interface. 274 | type TypeAssertion struct{ *typeAssertion } 275 | type typeAssertion struct { 276 | pathStep 277 | } 278 | 279 | func (ta TypeAssertion) Type() reflect.Type { return ta.typ } 280 | func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } 281 | func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) } 282 | 283 | // Transform is a transformation from the parent type to the current type. 284 | type Transform struct{ *transform } 285 | type transform struct { 286 | pathStep 287 | trans *transformer 288 | } 289 | 290 | func (tf Transform) Type() reflect.Type { return tf.typ } 291 | func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } 292 | func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } 293 | 294 | // Name is the name of the Transformer. 295 | func (tf Transform) Name() string { return tf.trans.name } 296 | 297 | // Func is the function pointer to the transformer function. 298 | func (tf Transform) Func() reflect.Value { return tf.trans.fnc } 299 | 300 | // Option returns the originally constructed Transformer option. 301 | // The == operator can be used to detect the exact option used. 302 | func (tf Transform) Option() Option { return tf.trans } 303 | 304 | // isExported reports whether the identifier is exported. 305 | func isExported(id string) bool { 306 | r, _ := utf8.DecodeRuneInString(id) 307 | return unicode.IsUpper(r) 308 | } 309 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/report.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | // defaultReporter implements the reporter interface. 8 | // 9 | // As Equal serially calls the PushStep, Report, and PopStep methods, the 10 | // defaultReporter constructs a tree-based representation of the compared value 11 | // and the result of each comparison (see valueNode). 12 | // 13 | // When the String method is called, the FormatDiff method transforms the 14 | // valueNode tree into a textNode tree, which is a tree-based representation 15 | // of the textual output (see textNode). 16 | // 17 | // Lastly, the textNode.String method produces the final report as a string. 18 | type defaultReporter struct { 19 | root *valueNode 20 | curr *valueNode 21 | } 22 | 23 | func (r *defaultReporter) PushStep(ps PathStep) { 24 | r.curr = r.curr.PushStep(ps) 25 | if r.root == nil { 26 | r.root = r.curr 27 | } 28 | } 29 | func (r *defaultReporter) Report(rs Result) { 30 | r.curr.Report(rs) 31 | } 32 | func (r *defaultReporter) PopStep() { 33 | r.curr = r.curr.PopStep() 34 | } 35 | 36 | // String provides a full report of the differences detected as a structured 37 | // literal in pseudo-Go syntax. String may only be called after the entire tree 38 | // has been traversed. 39 | func (r *defaultReporter) String() string { 40 | assert(r.root != nil && r.curr == nil) 41 | if r.root.NumDiff == 0 { 42 | return "" 43 | } 44 | return formatOptions{}.FormatDiff(r.root).String() 45 | } 46 | 47 | func assert(ok bool) { 48 | if !ok { 49 | panic("assertion failure") 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/report_compare.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | 11 | "github.com/google/go-cmp/cmp/internal/value" 12 | ) 13 | 14 | // TODO: Enforce limits? 15 | // * Enforce maximum number of records to print per node? 16 | // * Enforce maximum size in bytes allowed? 17 | // * As a heuristic, use less verbosity for equal nodes than unequal nodes. 18 | // TODO: Enforce unique outputs? 19 | // * Avoid Stringer methods if it results in same output? 20 | // * Print pointer address if outputs still equal? 21 | 22 | // numContextRecords is the number of surrounding equal records to print. 23 | const numContextRecords = 2 24 | 25 | type diffMode byte 26 | 27 | const ( 28 | diffUnknown diffMode = 0 29 | diffIdentical diffMode = ' ' 30 | diffRemoved diffMode = '-' 31 | diffInserted diffMode = '+' 32 | ) 33 | 34 | type typeMode int 35 | 36 | const ( 37 | // emitType always prints the type. 38 | emitType typeMode = iota 39 | // elideType never prints the type. 40 | elideType 41 | // autoType prints the type only for composite kinds 42 | // (i.e., structs, slices, arrays, and maps). 43 | autoType 44 | ) 45 | 46 | type formatOptions struct { 47 | // DiffMode controls the output mode of FormatDiff. 48 | // 49 | // If diffUnknown, then produce a diff of the x and y values. 50 | // If diffIdentical, then emit values as if they were equal. 51 | // If diffRemoved, then only emit x values (ignoring y values). 52 | // If diffInserted, then only emit y values (ignoring x values). 53 | DiffMode diffMode 54 | 55 | // TypeMode controls whether to print the type for the current node. 56 | // 57 | // As a general rule of thumb, we always print the type of the next node 58 | // after an interface, and always elide the type of the next node after 59 | // a slice or map node. 60 | TypeMode typeMode 61 | 62 | // formatValueOptions are options specific to printing reflect.Values. 63 | formatValueOptions 64 | } 65 | 66 | func (opts formatOptions) WithDiffMode(d diffMode) formatOptions { 67 | opts.DiffMode = d 68 | return opts 69 | } 70 | func (opts formatOptions) WithTypeMode(t typeMode) formatOptions { 71 | opts.TypeMode = t 72 | return opts 73 | } 74 | 75 | // FormatDiff converts a valueNode tree into a textNode tree, where the later 76 | // is a textual representation of the differences detected in the former. 77 | func (opts formatOptions) FormatDiff(v *valueNode) textNode { 78 | // Check whether we have specialized formatting for this node. 79 | // This is not necessary, but helpful for producing more readable outputs. 80 | if opts.CanFormatDiffSlice(v) { 81 | return opts.FormatDiffSlice(v) 82 | } 83 | 84 | // For leaf nodes, format the value based on the reflect.Values alone. 85 | if v.MaxDepth == 0 { 86 | switch opts.DiffMode { 87 | case diffUnknown, diffIdentical: 88 | // Format Equal. 89 | if v.NumDiff == 0 { 90 | outx := opts.FormatValue(v.ValueX, visitedPointers{}) 91 | outy := opts.FormatValue(v.ValueY, visitedPointers{}) 92 | if v.NumIgnored > 0 && v.NumSame == 0 { 93 | return textEllipsis 94 | } else if outx.Len() < outy.Len() { 95 | return outx 96 | } else { 97 | return outy 98 | } 99 | } 100 | 101 | // Format unequal. 102 | assert(opts.DiffMode == diffUnknown) 103 | var list textList 104 | outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, visitedPointers{}) 105 | outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, visitedPointers{}) 106 | if outx != nil { 107 | list = append(list, textRecord{Diff: '-', Value: outx}) 108 | } 109 | if outy != nil { 110 | list = append(list, textRecord{Diff: '+', Value: outy}) 111 | } 112 | return opts.WithTypeMode(emitType).FormatType(v.Type, list) 113 | case diffRemoved: 114 | return opts.FormatValue(v.ValueX, visitedPointers{}) 115 | case diffInserted: 116 | return opts.FormatValue(v.ValueY, visitedPointers{}) 117 | default: 118 | panic("invalid diff mode") 119 | } 120 | } 121 | 122 | // Descend into the child value node. 123 | if v.TransformerName != "" { 124 | out := opts.WithTypeMode(emitType).FormatDiff(v.Value) 125 | out = textWrap{"Inverse(" + v.TransformerName + ", ", out, ")"} 126 | return opts.FormatType(v.Type, out) 127 | } else { 128 | switch k := v.Type.Kind(); k { 129 | case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map: 130 | return opts.FormatType(v.Type, opts.formatDiffList(v.Records, k)) 131 | case reflect.Ptr: 132 | return textWrap{"&", opts.FormatDiff(v.Value), ""} 133 | case reflect.Interface: 134 | return opts.WithTypeMode(emitType).FormatDiff(v.Value) 135 | default: 136 | panic(fmt.Sprintf("%v cannot have children", k)) 137 | } 138 | } 139 | } 140 | 141 | func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) textNode { 142 | // Derive record name based on the data structure kind. 143 | var name string 144 | var formatKey func(reflect.Value) string 145 | switch k { 146 | case reflect.Struct: 147 | name = "field" 148 | opts = opts.WithTypeMode(autoType) 149 | formatKey = func(v reflect.Value) string { return v.String() } 150 | case reflect.Slice, reflect.Array: 151 | name = "element" 152 | opts = opts.WithTypeMode(elideType) 153 | formatKey = func(reflect.Value) string { return "" } 154 | case reflect.Map: 155 | name = "entry" 156 | opts = opts.WithTypeMode(elideType) 157 | formatKey = formatMapKey 158 | } 159 | 160 | // Handle unification. 161 | switch opts.DiffMode { 162 | case diffIdentical, diffRemoved, diffInserted: 163 | var list textList 164 | var deferredEllipsis bool // Add final "..." to indicate records were dropped 165 | for _, r := range recs { 166 | // Elide struct fields that are zero value. 167 | if k == reflect.Struct { 168 | var isZero bool 169 | switch opts.DiffMode { 170 | case diffIdentical: 171 | isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY) 172 | case diffRemoved: 173 | isZero = value.IsZero(r.Value.ValueX) 174 | case diffInserted: 175 | isZero = value.IsZero(r.Value.ValueY) 176 | } 177 | if isZero { 178 | continue 179 | } 180 | } 181 | // Elide ignored nodes. 182 | if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 { 183 | deferredEllipsis = !(k == reflect.Slice || k == reflect.Array) 184 | if !deferredEllipsis { 185 | list.AppendEllipsis(diffStats{}) 186 | } 187 | continue 188 | } 189 | if out := opts.FormatDiff(r.Value); out != nil { 190 | list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) 191 | } 192 | } 193 | if deferredEllipsis { 194 | list.AppendEllipsis(diffStats{}) 195 | } 196 | return textWrap{"{", list, "}"} 197 | case diffUnknown: 198 | default: 199 | panic("invalid diff mode") 200 | } 201 | 202 | // Handle differencing. 203 | var list textList 204 | groups := coalesceAdjacentRecords(name, recs) 205 | for i, ds := range groups { 206 | // Handle equal records. 207 | if ds.NumDiff() == 0 { 208 | // Compute the number of leading and trailing records to print. 209 | var numLo, numHi int 210 | numEqual := ds.NumIgnored + ds.NumIdentical 211 | for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 { 212 | if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { 213 | break 214 | } 215 | numLo++ 216 | } 217 | for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { 218 | if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { 219 | break 220 | } 221 | numHi++ 222 | } 223 | if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 { 224 | numHi++ // Avoid pointless coalescing of a single equal record 225 | } 226 | 227 | // Format the equal values. 228 | for _, r := range recs[:numLo] { 229 | out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) 230 | list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) 231 | } 232 | if numEqual > numLo+numHi { 233 | ds.NumIdentical -= numLo + numHi 234 | list.AppendEllipsis(ds) 235 | } 236 | for _, r := range recs[numEqual-numHi : numEqual] { 237 | out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) 238 | list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) 239 | } 240 | recs = recs[numEqual:] 241 | continue 242 | } 243 | 244 | // Handle unequal records. 245 | for _, r := range recs[:ds.NumDiff()] { 246 | switch { 247 | case opts.CanFormatDiffSlice(r.Value): 248 | out := opts.FormatDiffSlice(r.Value) 249 | list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) 250 | case r.Value.NumChildren == r.Value.MaxDepth: 251 | outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value) 252 | outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value) 253 | if outx != nil { 254 | list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx}) 255 | } 256 | if outy != nil { 257 | list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy}) 258 | } 259 | default: 260 | out := opts.FormatDiff(r.Value) 261 | list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) 262 | } 263 | } 264 | recs = recs[ds.NumDiff():] 265 | } 266 | assert(len(recs) == 0) 267 | return textWrap{"{", list, "}"} 268 | } 269 | 270 | // coalesceAdjacentRecords coalesces the list of records into groups of 271 | // adjacent equal, or unequal counts. 272 | func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) { 273 | var prevCase int // Arbitrary index into which case last occurred 274 | lastStats := func(i int) *diffStats { 275 | if prevCase != i { 276 | groups = append(groups, diffStats{Name: name}) 277 | prevCase = i 278 | } 279 | return &groups[len(groups)-1] 280 | } 281 | for _, r := range recs { 282 | switch rv := r.Value; { 283 | case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0: 284 | lastStats(1).NumIgnored++ 285 | case rv.NumDiff == 0: 286 | lastStats(1).NumIdentical++ 287 | case rv.NumDiff > 0 && !rv.ValueY.IsValid(): 288 | lastStats(2).NumRemoved++ 289 | case rv.NumDiff > 0 && !rv.ValueX.IsValid(): 290 | lastStats(2).NumInserted++ 291 | default: 292 | lastStats(2).NumModified++ 293 | } 294 | } 295 | return groups 296 | } 297 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/report_reflect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | "strconv" 11 | "strings" 12 | "unicode" 13 | 14 | "github.com/google/go-cmp/cmp/internal/flags" 15 | "github.com/google/go-cmp/cmp/internal/value" 16 | ) 17 | 18 | type formatValueOptions struct { 19 | // AvoidStringer controls whether to avoid calling custom stringer 20 | // methods like error.Error or fmt.Stringer.String. 21 | AvoidStringer bool 22 | 23 | // ShallowPointers controls whether to avoid descending into pointers. 24 | // Useful when printing map keys, where pointer comparison is performed 25 | // on the pointer address rather than the pointed-at value. 26 | ShallowPointers bool 27 | 28 | // PrintAddresses controls whether to print the address of all pointers, 29 | // slice elements, and maps. 30 | PrintAddresses bool 31 | } 32 | 33 | // FormatType prints the type as if it were wrapping s. 34 | // This may return s as-is depending on the current type and TypeMode mode. 35 | func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode { 36 | // Check whether to emit the type or not. 37 | switch opts.TypeMode { 38 | case autoType: 39 | switch t.Kind() { 40 | case reflect.Struct, reflect.Slice, reflect.Array, reflect.Map: 41 | if s.Equal(textNil) { 42 | return s 43 | } 44 | default: 45 | return s 46 | } 47 | case elideType: 48 | return s 49 | } 50 | 51 | // Determine the type label, applying special handling for unnamed types. 52 | typeName := t.String() 53 | if t.Name() == "" { 54 | // According to Go grammar, certain type literals contain symbols that 55 | // do not strongly bind to the next lexicographical token (e.g., *T). 56 | switch t.Kind() { 57 | case reflect.Chan, reflect.Func, reflect.Ptr: 58 | typeName = "(" + typeName + ")" 59 | } 60 | typeName = strings.Replace(typeName, "struct {", "struct{", -1) 61 | typeName = strings.Replace(typeName, "interface {", "interface{", -1) 62 | } 63 | 64 | // Avoid wrap the value in parenthesis if unnecessary. 65 | if s, ok := s.(textWrap); ok { 66 | hasParens := strings.HasPrefix(s.Prefix, "(") && strings.HasSuffix(s.Suffix, ")") 67 | hasBraces := strings.HasPrefix(s.Prefix, "{") && strings.HasSuffix(s.Suffix, "}") 68 | if hasParens || hasBraces { 69 | return textWrap{typeName, s, ""} 70 | } 71 | } 72 | return textWrap{typeName + "(", s, ")"} 73 | } 74 | 75 | // FormatValue prints the reflect.Value, taking extra care to avoid descending 76 | // into pointers already in m. As pointers are visited, m is also updated. 77 | func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out textNode) { 78 | if !v.IsValid() { 79 | return nil 80 | } 81 | t := v.Type() 82 | 83 | // Check whether there is an Error or String method to call. 84 | if !opts.AvoidStringer && v.CanInterface() { 85 | // Avoid calling Error or String methods on nil receivers since many 86 | // implementations crash when doing so. 87 | if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() { 88 | switch v := v.Interface().(type) { 89 | case error: 90 | return textLine("e" + formatString(v.Error())) 91 | case fmt.Stringer: 92 | return textLine("s" + formatString(v.String())) 93 | } 94 | } 95 | } 96 | 97 | // Check whether to explicitly wrap the result with the type. 98 | var skipType bool 99 | defer func() { 100 | if !skipType { 101 | out = opts.FormatType(t, out) 102 | } 103 | }() 104 | 105 | var ptr string 106 | switch t.Kind() { 107 | case reflect.Bool: 108 | return textLine(fmt.Sprint(v.Bool())) 109 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 110 | return textLine(fmt.Sprint(v.Int())) 111 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 112 | // Unnamed uints are usually bytes or words, so use hexadecimal. 113 | if t.PkgPath() == "" || t.Kind() == reflect.Uintptr { 114 | return textLine(formatHex(v.Uint())) 115 | } 116 | return textLine(fmt.Sprint(v.Uint())) 117 | case reflect.Float32, reflect.Float64: 118 | return textLine(fmt.Sprint(v.Float())) 119 | case reflect.Complex64, reflect.Complex128: 120 | return textLine(fmt.Sprint(v.Complex())) 121 | case reflect.String: 122 | return textLine(formatString(v.String())) 123 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: 124 | return textLine(formatPointer(v)) 125 | case reflect.Struct: 126 | var list textList 127 | for i := 0; i < v.NumField(); i++ { 128 | vv := v.Field(i) 129 | if value.IsZero(vv) { 130 | continue // Elide fields with zero values 131 | } 132 | s := opts.WithTypeMode(autoType).FormatValue(vv, m) 133 | list = append(list, textRecord{Key: t.Field(i).Name, Value: s}) 134 | } 135 | return textWrap{"{", list, "}"} 136 | case reflect.Slice: 137 | if v.IsNil() { 138 | return textNil 139 | } 140 | if opts.PrintAddresses { 141 | ptr = formatPointer(v) 142 | } 143 | fallthrough 144 | case reflect.Array: 145 | var list textList 146 | for i := 0; i < v.Len(); i++ { 147 | vi := v.Index(i) 148 | if vi.CanAddr() { // Check for cyclic elements 149 | p := vi.Addr() 150 | if m.Visit(p) { 151 | var out textNode 152 | out = textLine(formatPointer(p)) 153 | out = opts.WithTypeMode(emitType).FormatType(p.Type(), out) 154 | out = textWrap{"*", out, ""} 155 | list = append(list, textRecord{Value: out}) 156 | continue 157 | } 158 | } 159 | s := opts.WithTypeMode(elideType).FormatValue(vi, m) 160 | list = append(list, textRecord{Value: s}) 161 | } 162 | return textWrap{ptr + "{", list, "}"} 163 | case reflect.Map: 164 | if v.IsNil() { 165 | return textNil 166 | } 167 | if m.Visit(v) { 168 | return textLine(formatPointer(v)) 169 | } 170 | 171 | var list textList 172 | for _, k := range value.SortKeys(v.MapKeys()) { 173 | sk := formatMapKey(k) 174 | sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), m) 175 | list = append(list, textRecord{Key: sk, Value: sv}) 176 | } 177 | if opts.PrintAddresses { 178 | ptr = formatPointer(v) 179 | } 180 | return textWrap{ptr + "{", list, "}"} 181 | case reflect.Ptr: 182 | if v.IsNil() { 183 | return textNil 184 | } 185 | if m.Visit(v) || opts.ShallowPointers { 186 | return textLine(formatPointer(v)) 187 | } 188 | if opts.PrintAddresses { 189 | ptr = formatPointer(v) 190 | } 191 | skipType = true // Let the underlying value print the type instead 192 | return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), m), ""} 193 | case reflect.Interface: 194 | if v.IsNil() { 195 | return textNil 196 | } 197 | // Interfaces accept different concrete types, 198 | // so configure the underlying value to explicitly print the type. 199 | skipType = true // Print the concrete type instead 200 | return opts.WithTypeMode(emitType).FormatValue(v.Elem(), m) 201 | default: 202 | panic(fmt.Sprintf("%v kind not handled", v.Kind())) 203 | } 204 | } 205 | 206 | // formatMapKey formats v as if it were a map key. 207 | // The result is guaranteed to be a single line. 208 | func formatMapKey(v reflect.Value) string { 209 | var opts formatOptions 210 | opts.TypeMode = elideType 211 | opts.ShallowPointers = true 212 | s := opts.FormatValue(v, visitedPointers{}).String() 213 | return strings.TrimSpace(s) 214 | } 215 | 216 | // formatString prints s as a double-quoted or backtick-quoted string. 217 | func formatString(s string) string { 218 | // Use quoted string if it the same length as a raw string literal. 219 | // Otherwise, attempt to use the raw string form. 220 | qs := strconv.Quote(s) 221 | if len(qs) == 1+len(s)+1 { 222 | return qs 223 | } 224 | 225 | // Disallow newlines to ensure output is a single line. 226 | // Only allow printable runes for readability purposes. 227 | rawInvalid := func(r rune) bool { 228 | return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t') 229 | } 230 | if strings.IndexFunc(s, rawInvalid) < 0 { 231 | return "`" + s + "`" 232 | } 233 | return qs 234 | } 235 | 236 | // formatHex prints u as a hexadecimal integer in Go notation. 237 | func formatHex(u uint64) string { 238 | var f string 239 | switch { 240 | case u <= 0xff: 241 | f = "0x%02x" 242 | case u <= 0xffff: 243 | f = "0x%04x" 244 | case u <= 0xffffff: 245 | f = "0x%06x" 246 | case u <= 0xffffffff: 247 | f = "0x%08x" 248 | case u <= 0xffffffffff: 249 | f = "0x%010x" 250 | case u <= 0xffffffffffff: 251 | f = "0x%012x" 252 | case u <= 0xffffffffffffff: 253 | f = "0x%014x" 254 | case u <= 0xffffffffffffffff: 255 | f = "0x%016x" 256 | } 257 | return fmt.Sprintf(f, u) 258 | } 259 | 260 | // formatPointer prints the address of the pointer. 261 | func formatPointer(v reflect.Value) string { 262 | p := v.Pointer() 263 | if flags.Deterministic { 264 | p = 0xdeadf00f // Only used for stable testing purposes 265 | } 266 | return fmt.Sprintf("⟪0x%x⟫", p) 267 | } 268 | 269 | type visitedPointers map[value.Pointer]struct{} 270 | 271 | // Visit inserts pointer v into the visited map and reports whether it had 272 | // already been visited before. 273 | func (m visitedPointers) Visit(v reflect.Value) bool { 274 | p := value.PointerOf(v) 275 | _, visited := m[p] 276 | m[p] = struct{}{} 277 | return visited 278 | } 279 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/report_slices.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "reflect" 11 | "strings" 12 | "unicode" 13 | "unicode/utf8" 14 | 15 | "github.com/google/go-cmp/cmp/internal/diff" 16 | ) 17 | 18 | // CanFormatDiffSlice reports whether we support custom formatting for nodes 19 | // that are slices of primitive kinds or strings. 20 | func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { 21 | switch { 22 | case opts.DiffMode != diffUnknown: 23 | return false // Must be formatting in diff mode 24 | case v.NumDiff == 0: 25 | return false // No differences detected 26 | case v.NumIgnored+v.NumCompared+v.NumTransformed > 0: 27 | // TODO: Handle the case where someone uses bytes.Equal on a large slice. 28 | return false // Some custom option was used to determined equality 29 | case !v.ValueX.IsValid() || !v.ValueY.IsValid(): 30 | return false // Both values must be valid 31 | } 32 | 33 | switch t := v.Type; t.Kind() { 34 | case reflect.String: 35 | case reflect.Array, reflect.Slice: 36 | // Only slices of primitive types have specialized handling. 37 | switch t.Elem().Kind() { 38 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 39 | reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 40 | reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: 41 | default: 42 | return false 43 | } 44 | 45 | // If a sufficient number of elements already differ, 46 | // use specialized formatting even if length requirement is not met. 47 | if v.NumDiff > v.NumSame { 48 | return true 49 | } 50 | default: 51 | return false 52 | } 53 | 54 | // Use specialized string diffing for longer slices or strings. 55 | const minLength = 64 56 | return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength 57 | } 58 | 59 | // FormatDiffSlice prints a diff for the slices (or strings) represented by v. 60 | // This provides custom-tailored logic to make printing of differences in 61 | // textual strings and slices of primitive kinds more readable. 62 | func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { 63 | assert(opts.DiffMode == diffUnknown) 64 | t, vx, vy := v.Type, v.ValueX, v.ValueY 65 | 66 | // Auto-detect the type of the data. 67 | var isLinedText, isText, isBinary bool 68 | var sx, sy string 69 | switch { 70 | case t.Kind() == reflect.String: 71 | sx, sy = vx.String(), vy.String() 72 | isText = true // Initial estimate, verify later 73 | case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)): 74 | sx, sy = string(vx.Bytes()), string(vy.Bytes()) 75 | isBinary = true // Initial estimate, verify later 76 | case t.Kind() == reflect.Array: 77 | // Arrays need to be addressable for slice operations to work. 78 | vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem() 79 | vx2.Set(vx) 80 | vy2.Set(vy) 81 | vx, vy = vx2, vy2 82 | } 83 | if isText || isBinary { 84 | var numLines, lastLineIdx, maxLineLen int 85 | isBinary = false 86 | for i, r := range sx + sy { 87 | if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError { 88 | isBinary = true 89 | break 90 | } 91 | if r == '\n' { 92 | if maxLineLen < i-lastLineIdx { 93 | maxLineLen = i - lastLineIdx 94 | } 95 | lastLineIdx = i + 1 96 | numLines++ 97 | } 98 | } 99 | isText = !isBinary 100 | isLinedText = isText && numLines >= 4 && maxLineLen <= 256 101 | } 102 | 103 | // Format the string into printable records. 104 | var list textList 105 | var delim string 106 | switch { 107 | // If the text appears to be multi-lined text, 108 | // then perform differencing across individual lines. 109 | case isLinedText: 110 | ssx := strings.Split(sx, "\n") 111 | ssy := strings.Split(sy, "\n") 112 | list = opts.formatDiffSlice( 113 | reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line", 114 | func(v reflect.Value, d diffMode) textRecord { 115 | s := formatString(v.Index(0).String()) 116 | return textRecord{Diff: d, Value: textLine(s)} 117 | }, 118 | ) 119 | delim = "\n" 120 | // If the text appears to be single-lined text, 121 | // then perform differencing in approximately fixed-sized chunks. 122 | // The output is printed as quoted strings. 123 | case isText: 124 | list = opts.formatDiffSlice( 125 | reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte", 126 | func(v reflect.Value, d diffMode) textRecord { 127 | s := formatString(v.String()) 128 | return textRecord{Diff: d, Value: textLine(s)} 129 | }, 130 | ) 131 | delim = "" 132 | // If the text appears to be binary data, 133 | // then perform differencing in approximately fixed-sized chunks. 134 | // The output is inspired by hexdump. 135 | case isBinary: 136 | list = opts.formatDiffSlice( 137 | reflect.ValueOf(sx), reflect.ValueOf(sy), 16, "byte", 138 | func(v reflect.Value, d diffMode) textRecord { 139 | var ss []string 140 | for i := 0; i < v.Len(); i++ { 141 | ss = append(ss, formatHex(v.Index(i).Uint())) 142 | } 143 | s := strings.Join(ss, ", ") 144 | comment := commentString(fmt.Sprintf("%c|%v|", d, formatASCII(v.String()))) 145 | return textRecord{Diff: d, Value: textLine(s), Comment: comment} 146 | }, 147 | ) 148 | // For all other slices of primitive types, 149 | // then perform differencing in approximately fixed-sized chunks. 150 | // The size of each chunk depends on the width of the element kind. 151 | default: 152 | var chunkSize int 153 | if t.Elem().Kind() == reflect.Bool { 154 | chunkSize = 16 155 | } else { 156 | switch t.Elem().Bits() { 157 | case 8: 158 | chunkSize = 16 159 | case 16: 160 | chunkSize = 12 161 | case 32: 162 | chunkSize = 8 163 | default: 164 | chunkSize = 8 165 | } 166 | } 167 | list = opts.formatDiffSlice( 168 | vx, vy, chunkSize, t.Elem().Kind().String(), 169 | func(v reflect.Value, d diffMode) textRecord { 170 | var ss []string 171 | for i := 0; i < v.Len(); i++ { 172 | switch t.Elem().Kind() { 173 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 174 | ss = append(ss, fmt.Sprint(v.Index(i).Int())) 175 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 176 | ss = append(ss, formatHex(v.Index(i).Uint())) 177 | case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: 178 | ss = append(ss, fmt.Sprint(v.Index(i).Interface())) 179 | } 180 | } 181 | s := strings.Join(ss, ", ") 182 | return textRecord{Diff: d, Value: textLine(s)} 183 | }, 184 | ) 185 | } 186 | 187 | // Wrap the output with appropriate type information. 188 | var out textNode = textWrap{"{", list, "}"} 189 | if !isText { 190 | // The "{...}" byte-sequence literal is not valid Go syntax for strings. 191 | // Emit the type for extra clarity (e.g. "string{...}"). 192 | if t.Kind() == reflect.String { 193 | opts = opts.WithTypeMode(emitType) 194 | } 195 | return opts.FormatType(t, out) 196 | } 197 | switch t.Kind() { 198 | case reflect.String: 199 | out = textWrap{"strings.Join(", out, fmt.Sprintf(", %q)", delim)} 200 | if t != reflect.TypeOf(string("")) { 201 | out = opts.FormatType(t, out) 202 | } 203 | case reflect.Slice: 204 | out = textWrap{"bytes.Join(", out, fmt.Sprintf(", %q)", delim)} 205 | if t != reflect.TypeOf([]byte(nil)) { 206 | out = opts.FormatType(t, out) 207 | } 208 | } 209 | return out 210 | } 211 | 212 | // formatASCII formats s as an ASCII string. 213 | // This is useful for printing binary strings in a semi-legible way. 214 | func formatASCII(s string) string { 215 | b := bytes.Repeat([]byte{'.'}, len(s)) 216 | for i := 0; i < len(s); i++ { 217 | if ' ' <= s[i] && s[i] <= '~' { 218 | b[i] = s[i] 219 | } 220 | } 221 | return string(b) 222 | } 223 | 224 | func (opts formatOptions) formatDiffSlice( 225 | vx, vy reflect.Value, chunkSize int, name string, 226 | makeRec func(reflect.Value, diffMode) textRecord, 227 | ) (list textList) { 228 | es := diff.Difference(vx.Len(), vy.Len(), func(ix int, iy int) diff.Result { 229 | return diff.BoolResult(vx.Index(ix).Interface() == vy.Index(iy).Interface()) 230 | }) 231 | 232 | appendChunks := func(v reflect.Value, d diffMode) int { 233 | n0 := v.Len() 234 | for v.Len() > 0 { 235 | n := chunkSize 236 | if n > v.Len() { 237 | n = v.Len() 238 | } 239 | list = append(list, makeRec(v.Slice(0, n), d)) 240 | v = v.Slice(n, v.Len()) 241 | } 242 | return n0 - v.Len() 243 | } 244 | 245 | groups := coalesceAdjacentEdits(name, es) 246 | groups = coalesceInterveningIdentical(groups, chunkSize/4) 247 | for i, ds := range groups { 248 | // Print equal. 249 | if ds.NumDiff() == 0 { 250 | // Compute the number of leading and trailing equal bytes to print. 251 | var numLo, numHi int 252 | numEqual := ds.NumIgnored + ds.NumIdentical 253 | for numLo < chunkSize*numContextRecords && numLo+numHi < numEqual && i != 0 { 254 | numLo++ 255 | } 256 | for numHi < chunkSize*numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { 257 | numHi++ 258 | } 259 | if numEqual-(numLo+numHi) <= chunkSize && ds.NumIgnored == 0 { 260 | numHi = numEqual - numLo // Avoid pointless coalescing of single equal row 261 | } 262 | 263 | // Print the equal bytes. 264 | appendChunks(vx.Slice(0, numLo), diffIdentical) 265 | if numEqual > numLo+numHi { 266 | ds.NumIdentical -= numLo + numHi 267 | list.AppendEllipsis(ds) 268 | } 269 | appendChunks(vx.Slice(numEqual-numHi, numEqual), diffIdentical) 270 | vx = vx.Slice(numEqual, vx.Len()) 271 | vy = vy.Slice(numEqual, vy.Len()) 272 | continue 273 | } 274 | 275 | // Print unequal. 276 | nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved) 277 | vx = vx.Slice(nx, vx.Len()) 278 | ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted) 279 | vy = vy.Slice(ny, vy.Len()) 280 | } 281 | assert(vx.Len() == 0 && vy.Len() == 0) 282 | return list 283 | } 284 | 285 | // coalesceAdjacentEdits coalesces the list of edits into groups of adjacent 286 | // equal or unequal counts. 287 | func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) { 288 | var prevCase int // Arbitrary index into which case last occurred 289 | lastStats := func(i int) *diffStats { 290 | if prevCase != i { 291 | groups = append(groups, diffStats{Name: name}) 292 | prevCase = i 293 | } 294 | return &groups[len(groups)-1] 295 | } 296 | for _, e := range es { 297 | switch e { 298 | case diff.Identity: 299 | lastStats(1).NumIdentical++ 300 | case diff.UniqueX: 301 | lastStats(2).NumRemoved++ 302 | case diff.UniqueY: 303 | lastStats(2).NumInserted++ 304 | case diff.Modified: 305 | lastStats(2).NumModified++ 306 | } 307 | } 308 | return groups 309 | } 310 | 311 | // coalesceInterveningIdentical coalesces sufficiently short (<= windowSize) 312 | // equal groups into adjacent unequal groups that currently result in a 313 | // dual inserted/removed printout. This acts as a high-pass filter to smooth 314 | // out high-frequency changes within the windowSize. 315 | func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats { 316 | groups, groupsOrig := groups[:0], groups 317 | for i, ds := range groupsOrig { 318 | if len(groups) >= 2 && ds.NumDiff() > 0 { 319 | prev := &groups[len(groups)-2] // Unequal group 320 | curr := &groups[len(groups)-1] // Equal group 321 | next := &groupsOrig[i] // Unequal group 322 | hadX, hadY := prev.NumRemoved > 0, prev.NumInserted > 0 323 | hasX, hasY := next.NumRemoved > 0, next.NumInserted > 0 324 | if ((hadX || hasX) && (hadY || hasY)) && curr.NumIdentical <= windowSize { 325 | *prev = prev.Append(*curr).Append(*next) 326 | groups = groups[:len(groups)-1] // Truncate off equal group 327 | continue 328 | } 329 | } 330 | groups = append(groups, ds) 331 | } 332 | return groups 333 | } 334 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/report_text.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "math/rand" 11 | "strings" 12 | "time" 13 | 14 | "github.com/google/go-cmp/cmp/internal/flags" 15 | ) 16 | 17 | var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 18 | 19 | type indentMode int 20 | 21 | func (n indentMode) appendIndent(b []byte, d diffMode) []byte { 22 | // The output of Diff is documented as being unstable to provide future 23 | // flexibility in changing the output for more humanly readable reports. 24 | // This logic intentionally introduces instability to the exact output 25 | // so that users can detect accidental reliance on stability early on, 26 | // rather than much later when an actual change to the format occurs. 27 | if flags.Deterministic || randBool { 28 | // Use regular spaces (U+0020). 29 | switch d { 30 | case diffUnknown, diffIdentical: 31 | b = append(b, " "...) 32 | case diffRemoved: 33 | b = append(b, "- "...) 34 | case diffInserted: 35 | b = append(b, "+ "...) 36 | } 37 | } else { 38 | // Use non-breaking spaces (U+00a0). 39 | switch d { 40 | case diffUnknown, diffIdentical: 41 | b = append(b, "  "...) 42 | case diffRemoved: 43 | b = append(b, "- "...) 44 | case diffInserted: 45 | b = append(b, "+ "...) 46 | } 47 | } 48 | return repeatCount(n).appendChar(b, '\t') 49 | } 50 | 51 | type repeatCount int 52 | 53 | func (n repeatCount) appendChar(b []byte, c byte) []byte { 54 | for ; n > 0; n-- { 55 | b = append(b, c) 56 | } 57 | return b 58 | } 59 | 60 | // textNode is a simplified tree-based representation of structured text. 61 | // Possible node types are textWrap, textList, or textLine. 62 | type textNode interface { 63 | // Len reports the length in bytes of a single-line version of the tree. 64 | // Nested textRecord.Diff and textRecord.Comment fields are ignored. 65 | Len() int 66 | // Equal reports whether the two trees are structurally identical. 67 | // Nested textRecord.Diff and textRecord.Comment fields are compared. 68 | Equal(textNode) bool 69 | // String returns the string representation of the text tree. 70 | // It is not guaranteed that len(x.String()) == x.Len(), 71 | // nor that x.String() == y.String() implies that x.Equal(y). 72 | String() string 73 | 74 | // formatCompactTo formats the contents of the tree as a single-line string 75 | // to the provided buffer. Any nested textRecord.Diff and textRecord.Comment 76 | // fields are ignored. 77 | // 78 | // However, not all nodes in the tree should be collapsed as a single-line. 79 | // If a node can be collapsed as a single-line, it is replaced by a textLine 80 | // node. Since the top-level node cannot replace itself, this also returns 81 | // the current node itself. 82 | // 83 | // This does not mutate the receiver. 84 | formatCompactTo([]byte, diffMode) ([]byte, textNode) 85 | // formatExpandedTo formats the contents of the tree as a multi-line string 86 | // to the provided buffer. In order for column alignment to operate well, 87 | // formatCompactTo must be called before calling formatExpandedTo. 88 | formatExpandedTo([]byte, diffMode, indentMode) []byte 89 | } 90 | 91 | // textWrap is a wrapper that concatenates a prefix and/or a suffix 92 | // to the underlying node. 93 | type textWrap struct { 94 | Prefix string // e.g., "bytes.Buffer{" 95 | Value textNode // textWrap | textList | textLine 96 | Suffix string // e.g., "}" 97 | } 98 | 99 | func (s textWrap) Len() int { 100 | return len(s.Prefix) + s.Value.Len() + len(s.Suffix) 101 | } 102 | func (s1 textWrap) Equal(s2 textNode) bool { 103 | if s2, ok := s2.(textWrap); ok { 104 | return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix 105 | } 106 | return false 107 | } 108 | func (s textWrap) String() string { 109 | var d diffMode 110 | var n indentMode 111 | _, s2 := s.formatCompactTo(nil, d) 112 | b := n.appendIndent(nil, d) // Leading indent 113 | b = s2.formatExpandedTo(b, d, n) // Main body 114 | b = append(b, '\n') // Trailing newline 115 | return string(b) 116 | } 117 | func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { 118 | n0 := len(b) // Original buffer length 119 | b = append(b, s.Prefix...) 120 | b, s.Value = s.Value.formatCompactTo(b, d) 121 | b = append(b, s.Suffix...) 122 | if _, ok := s.Value.(textLine); ok { 123 | return b, textLine(b[n0:]) 124 | } 125 | return b, s 126 | } 127 | func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { 128 | b = append(b, s.Prefix...) 129 | b = s.Value.formatExpandedTo(b, d, n) 130 | b = append(b, s.Suffix...) 131 | return b 132 | } 133 | 134 | // textList is a comma-separated list of textWrap or textLine nodes. 135 | // The list may be formatted as multi-lines or single-line at the discretion 136 | // of the textList.formatCompactTo method. 137 | type textList []textRecord 138 | type textRecord struct { 139 | Diff diffMode // e.g., 0 or '-' or '+' 140 | Key string // e.g., "MyField" 141 | Value textNode // textWrap | textLine 142 | Comment fmt.Stringer // e.g., "6 identical fields" 143 | } 144 | 145 | // AppendEllipsis appends a new ellipsis node to the list if none already 146 | // exists at the end. If cs is non-zero it coalesces the statistics with the 147 | // previous diffStats. 148 | func (s *textList) AppendEllipsis(ds diffStats) { 149 | hasStats := ds != diffStats{} 150 | if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) { 151 | if hasStats { 152 | *s = append(*s, textRecord{Value: textEllipsis, Comment: ds}) 153 | } else { 154 | *s = append(*s, textRecord{Value: textEllipsis}) 155 | } 156 | return 157 | } 158 | if hasStats { 159 | (*s)[len(*s)-1].Comment = (*s)[len(*s)-1].Comment.(diffStats).Append(ds) 160 | } 161 | } 162 | 163 | func (s textList) Len() (n int) { 164 | for i, r := range s { 165 | n += len(r.Key) 166 | if r.Key != "" { 167 | n += len(": ") 168 | } 169 | n += r.Value.Len() 170 | if i < len(s)-1 { 171 | n += len(", ") 172 | } 173 | } 174 | return n 175 | } 176 | 177 | func (s1 textList) Equal(s2 textNode) bool { 178 | if s2, ok := s2.(textList); ok { 179 | if len(s1) != len(s2) { 180 | return false 181 | } 182 | for i := range s1 { 183 | r1, r2 := s1[i], s2[i] 184 | if !(r1.Diff == r2.Diff && r1.Key == r2.Key && r1.Value.Equal(r2.Value) && r1.Comment == r2.Comment) { 185 | return false 186 | } 187 | } 188 | return true 189 | } 190 | return false 191 | } 192 | 193 | func (s textList) String() string { 194 | return textWrap{"{", s, "}"}.String() 195 | } 196 | 197 | func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { 198 | s = append(textList(nil), s...) // Avoid mutating original 199 | 200 | // Determine whether we can collapse this list as a single line. 201 | n0 := len(b) // Original buffer length 202 | var multiLine bool 203 | for i, r := range s { 204 | if r.Diff == diffInserted || r.Diff == diffRemoved { 205 | multiLine = true 206 | } 207 | b = append(b, r.Key...) 208 | if r.Key != "" { 209 | b = append(b, ": "...) 210 | } 211 | b, s[i].Value = r.Value.formatCompactTo(b, d|r.Diff) 212 | if _, ok := s[i].Value.(textLine); !ok { 213 | multiLine = true 214 | } 215 | if r.Comment != nil { 216 | multiLine = true 217 | } 218 | if i < len(s)-1 { 219 | b = append(b, ", "...) 220 | } 221 | } 222 | // Force multi-lined output when printing a removed/inserted node that 223 | // is sufficiently long. 224 | if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > 80 { 225 | multiLine = true 226 | } 227 | if !multiLine { 228 | return b, textLine(b[n0:]) 229 | } 230 | return b, s 231 | } 232 | 233 | func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { 234 | alignKeyLens := s.alignLens( 235 | func(r textRecord) bool { 236 | _, isLine := r.Value.(textLine) 237 | return r.Key == "" || !isLine 238 | }, 239 | func(r textRecord) int { return len(r.Key) }, 240 | ) 241 | alignValueLens := s.alignLens( 242 | func(r textRecord) bool { 243 | _, isLine := r.Value.(textLine) 244 | return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil 245 | }, 246 | func(r textRecord) int { return len(r.Value.(textLine)) }, 247 | ) 248 | 249 | // Format the list as a multi-lined output. 250 | n++ 251 | for i, r := range s { 252 | b = n.appendIndent(append(b, '\n'), d|r.Diff) 253 | if r.Key != "" { 254 | b = append(b, r.Key+": "...) 255 | } 256 | b = alignKeyLens[i].appendChar(b, ' ') 257 | 258 | b = r.Value.formatExpandedTo(b, d|r.Diff, n) 259 | if !r.Value.Equal(textEllipsis) { 260 | b = append(b, ',') 261 | } 262 | b = alignValueLens[i].appendChar(b, ' ') 263 | 264 | if r.Comment != nil { 265 | b = append(b, " // "+r.Comment.String()...) 266 | } 267 | } 268 | n-- 269 | 270 | return n.appendIndent(append(b, '\n'), d) 271 | } 272 | 273 | func (s textList) alignLens( 274 | skipFunc func(textRecord) bool, 275 | lenFunc func(textRecord) int, 276 | ) []repeatCount { 277 | var startIdx, endIdx, maxLen int 278 | lens := make([]repeatCount, len(s)) 279 | for i, r := range s { 280 | if skipFunc(r) { 281 | for j := startIdx; j < endIdx && j < len(s); j++ { 282 | lens[j] = repeatCount(maxLen - lenFunc(s[j])) 283 | } 284 | startIdx, endIdx, maxLen = i+1, i+1, 0 285 | } else { 286 | if maxLen < lenFunc(r) { 287 | maxLen = lenFunc(r) 288 | } 289 | endIdx = i + 1 290 | } 291 | } 292 | for j := startIdx; j < endIdx && j < len(s); j++ { 293 | lens[j] = repeatCount(maxLen - lenFunc(s[j])) 294 | } 295 | return lens 296 | } 297 | 298 | // textLine is a single-line segment of text and is always a leaf node 299 | // in the textNode tree. 300 | type textLine []byte 301 | 302 | var ( 303 | textNil = textLine("nil") 304 | textEllipsis = textLine("...") 305 | ) 306 | 307 | func (s textLine) Len() int { 308 | return len(s) 309 | } 310 | func (s1 textLine) Equal(s2 textNode) bool { 311 | if s2, ok := s2.(textLine); ok { 312 | return bytes.Equal([]byte(s1), []byte(s2)) 313 | } 314 | return false 315 | } 316 | func (s textLine) String() string { 317 | return string(s) 318 | } 319 | func (s textLine) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { 320 | return append(b, s...), s 321 | } 322 | func (s textLine) formatExpandedTo(b []byte, _ diffMode, _ indentMode) []byte { 323 | return append(b, s...) 324 | } 325 | 326 | type diffStats struct { 327 | Name string 328 | NumIgnored int 329 | NumIdentical int 330 | NumRemoved int 331 | NumInserted int 332 | NumModified int 333 | } 334 | 335 | func (s diffStats) NumDiff() int { 336 | return s.NumRemoved + s.NumInserted + s.NumModified 337 | } 338 | 339 | func (s diffStats) Append(ds diffStats) diffStats { 340 | assert(s.Name == ds.Name) 341 | s.NumIgnored += ds.NumIgnored 342 | s.NumIdentical += ds.NumIdentical 343 | s.NumRemoved += ds.NumRemoved 344 | s.NumInserted += ds.NumInserted 345 | s.NumModified += ds.NumModified 346 | return s 347 | } 348 | 349 | // String prints a humanly-readable summary of coalesced records. 350 | // 351 | // Example: 352 | // diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields" 353 | func (s diffStats) String() string { 354 | var ss []string 355 | var sum int 356 | labels := [...]string{"ignored", "identical", "removed", "inserted", "modified"} 357 | counts := [...]int{s.NumIgnored, s.NumIdentical, s.NumRemoved, s.NumInserted, s.NumModified} 358 | for i, n := range counts { 359 | if n > 0 { 360 | ss = append(ss, fmt.Sprintf("%d %v", n, labels[i])) 361 | } 362 | sum += n 363 | } 364 | 365 | // Pluralize the name (adjusting for some obscure English grammar rules). 366 | name := s.Name 367 | if sum > 1 { 368 | name += "s" 369 | if strings.HasSuffix(name, "ys") { 370 | name = name[:len(name)-2] + "ies" // e.g., "entrys" => "entries" 371 | } 372 | } 373 | 374 | // Format the list according to English grammar (with Oxford comma). 375 | switch n := len(ss); n { 376 | case 0: 377 | return "" 378 | case 1, 2: 379 | return strings.Join(ss, " and ") + " " + name 380 | default: 381 | return strings.Join(ss[:n-1], ", ") + ", and " + ss[n-1] + " " + name 382 | } 383 | } 384 | 385 | type commentString string 386 | 387 | func (s commentString) String() string { return string(s) } 388 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/cmp/report_value.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.md file. 4 | 5 | package cmp 6 | 7 | import "reflect" 8 | 9 | // valueNode represents a single node within a report, which is a 10 | // structured representation of the value tree, containing information 11 | // regarding which nodes are equal or not. 12 | type valueNode struct { 13 | parent *valueNode 14 | 15 | Type reflect.Type 16 | ValueX reflect.Value 17 | ValueY reflect.Value 18 | 19 | // NumSame is the number of leaf nodes that are equal. 20 | // All descendants are equal only if NumDiff is 0. 21 | NumSame int 22 | // NumDiff is the number of leaf nodes that are not equal. 23 | NumDiff int 24 | // NumIgnored is the number of leaf nodes that are ignored. 25 | NumIgnored int 26 | // NumCompared is the number of leaf nodes that were compared 27 | // using an Equal method or Comparer function. 28 | NumCompared int 29 | // NumTransformed is the number of non-leaf nodes that were transformed. 30 | NumTransformed int 31 | // NumChildren is the number of transitive descendants of this node. 32 | // This counts from zero; thus, leaf nodes have no descendants. 33 | NumChildren int 34 | // MaxDepth is the maximum depth of the tree. This counts from zero; 35 | // thus, leaf nodes have a depth of zero. 36 | MaxDepth int 37 | 38 | // Records is a list of struct fields, slice elements, or map entries. 39 | Records []reportRecord // If populated, implies Value is not populated 40 | 41 | // Value is the result of a transformation, pointer indirect, of 42 | // type assertion. 43 | Value *valueNode // If populated, implies Records is not populated 44 | 45 | // TransformerName is the name of the transformer. 46 | TransformerName string // If non-empty, implies Value is populated 47 | } 48 | type reportRecord struct { 49 | Key reflect.Value // Invalid for slice element 50 | Value *valueNode 51 | } 52 | 53 | func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) { 54 | vx, vy := ps.Values() 55 | child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy} 56 | switch s := ps.(type) { 57 | case StructField: 58 | assert(parent.Value == nil) 59 | parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child}) 60 | case SliceIndex: 61 | assert(parent.Value == nil) 62 | parent.Records = append(parent.Records, reportRecord{Value: child}) 63 | case MapIndex: 64 | assert(parent.Value == nil) 65 | parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child}) 66 | case Indirect: 67 | assert(parent.Value == nil && parent.Records == nil) 68 | parent.Value = child 69 | case TypeAssertion: 70 | assert(parent.Value == nil && parent.Records == nil) 71 | parent.Value = child 72 | case Transform: 73 | assert(parent.Value == nil && parent.Records == nil) 74 | parent.Value = child 75 | parent.TransformerName = s.Name() 76 | parent.NumTransformed++ 77 | default: 78 | assert(parent == nil) // Must be the root step 79 | } 80 | return child 81 | } 82 | 83 | func (r *valueNode) Report(rs Result) { 84 | assert(r.MaxDepth == 0) // May only be called on leaf nodes 85 | 86 | if rs.ByIgnore() { 87 | r.NumIgnored++ 88 | } else { 89 | if rs.Equal() { 90 | r.NumSame++ 91 | } else { 92 | r.NumDiff++ 93 | } 94 | } 95 | assert(r.NumSame+r.NumDiff+r.NumIgnored == 1) 96 | 97 | if rs.ByMethod() { 98 | r.NumCompared++ 99 | } 100 | if rs.ByFunc() { 101 | r.NumCompared++ 102 | } 103 | assert(r.NumCompared <= 1) 104 | } 105 | 106 | func (child *valueNode) PopStep() (parent *valueNode) { 107 | if child.parent == nil { 108 | return nil 109 | } 110 | parent = child.parent 111 | parent.NumSame += child.NumSame 112 | parent.NumDiff += child.NumDiff 113 | parent.NumIgnored += child.NumIgnored 114 | parent.NumCompared += child.NumCompared 115 | parent.NumTransformed += child.NumTransformed 116 | parent.NumChildren += child.NumChildren + 1 117 | if parent.MaxDepth < child.MaxDepth+1 { 118 | parent.MaxDepth = child.MaxDepth + 1 119 | } 120 | return parent 121 | } 122 | -------------------------------------------------------------------------------- /vendor/github.com/google/go-cmp/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/google/go-cmp 2 | 3 | go 1.8 4 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go_import_path: github.com/pkg/errors 3 | go: 4 | - 1.4.3 5 | - 1.5.4 6 | - 1.6.2 7 | - 1.7.1 8 | - tip 9 | 10 | script: 11 | - go test -v ./... 12 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Dave Cheney 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/README.md: -------------------------------------------------------------------------------- 1 | # errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) 2 | 3 | Package errors provides simple error handling primitives. 4 | 5 | `go get github.com/pkg/errors` 6 | 7 | The traditional error handling idiom in Go is roughly akin to 8 | ```go 9 | if err != nil { 10 | return err 11 | } 12 | ``` 13 | which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. 14 | 15 | ## Adding context to an error 16 | 17 | The errors.Wrap function returns a new error that adds context to the original error. For example 18 | ```go 19 | _, err := ioutil.ReadAll(r) 20 | if err != nil { 21 | return errors.Wrap(err, "read failed") 22 | } 23 | ``` 24 | ## Retrieving the cause of an error 25 | 26 | Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. 27 | ```go 28 | type causer interface { 29 | Cause() error 30 | } 31 | ``` 32 | `errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: 33 | ```go 34 | switch err := errors.Cause(err).(type) { 35 | case *MyError: 36 | // handle specifically 37 | default: 38 | // unknown error 39 | } 40 | ``` 41 | 42 | [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). 43 | 44 | ## Contributing 45 | 46 | We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. 47 | 48 | Before proposing a change, please discuss your change by raising an issue. 49 | 50 | ## Licence 51 | 52 | BSD-2-Clause 53 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: build-{build}.{branch} 2 | 3 | clone_folder: C:\gopath\src\github.com\pkg\errors 4 | shallow_clone: true # for startup speed 5 | 6 | environment: 7 | GOPATH: C:\gopath 8 | 9 | platform: 10 | - x64 11 | 12 | # http://www.appveyor.com/docs/installed-software 13 | install: 14 | # some helpful output for debugging builds 15 | - go version 16 | - go env 17 | # pre-installed MinGW at C:\MinGW is 32bit only 18 | # but MSYS2 at C:\msys64 has mingw64 19 | - set PATH=C:\msys64\mingw64\bin;%PATH% 20 | - gcc --version 21 | - g++ --version 22 | 23 | build_script: 24 | - go install -v ./... 25 | 26 | test_script: 27 | - set PATH=C:\gopath\bin;%PATH% 28 | - go test -v ./... 29 | 30 | #artifacts: 31 | # - path: '%GOPATH%\bin\*.exe' 32 | deploy: off 33 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/bench_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package errors 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | 9 | stderrors "errors" 10 | ) 11 | 12 | func noErrors(at, depth int) error { 13 | if at >= depth { 14 | return stderrors.New("no error") 15 | } 16 | return noErrors(at+1, depth) 17 | } 18 | func yesErrors(at, depth int) error { 19 | if at >= depth { 20 | return New("ye error") 21 | } 22 | return yesErrors(at+1, depth) 23 | } 24 | 25 | func BenchmarkErrors(b *testing.B) { 26 | var toperr error 27 | type run struct { 28 | stack int 29 | std bool 30 | } 31 | runs := []run{ 32 | {10, false}, 33 | {10, true}, 34 | {100, false}, 35 | {100, true}, 36 | {1000, false}, 37 | {1000, true}, 38 | } 39 | for _, r := range runs { 40 | part := "pkg/errors" 41 | if r.std { 42 | part = "errors" 43 | } 44 | name := fmt.Sprintf("%s-stack-%d", part, r.stack) 45 | b.Run(name, func(b *testing.B) { 46 | var err error 47 | f := yesErrors 48 | if r.std { 49 | f = noErrors 50 | } 51 | b.ReportAllocs() 52 | for i := 0; i < b.N; i++ { 53 | err = f(0, r.stack) 54 | } 55 | b.StopTimer() 56 | toperr = err 57 | }) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/errors.go: -------------------------------------------------------------------------------- 1 | // Package errors provides simple error handling primitives. 2 | // 3 | // The traditional error handling idiom in Go is roughly akin to 4 | // 5 | // if err != nil { 6 | // return err 7 | // } 8 | // 9 | // which applied recursively up the call stack results in error reports 10 | // without context or debugging information. The errors package allows 11 | // programmers to add context to the failure path in their code in a way 12 | // that does not destroy the original value of the error. 13 | // 14 | // Adding context to an error 15 | // 16 | // The errors.Wrap function returns a new error that adds context to the 17 | // original error by recording a stack trace at the point Wrap is called, 18 | // and the supplied message. For example 19 | // 20 | // _, err := ioutil.ReadAll(r) 21 | // if err != nil { 22 | // return errors.Wrap(err, "read failed") 23 | // } 24 | // 25 | // If additional control is required the errors.WithStack and errors.WithMessage 26 | // functions destructure errors.Wrap into its component operations of annotating 27 | // an error with a stack trace and an a message, respectively. 28 | // 29 | // Retrieving the cause of an error 30 | // 31 | // Using errors.Wrap constructs a stack of errors, adding context to the 32 | // preceding error. Depending on the nature of the error it may be necessary 33 | // to reverse the operation of errors.Wrap to retrieve the original error 34 | // for inspection. Any error value which implements this interface 35 | // 36 | // type causer interface { 37 | // Cause() error 38 | // } 39 | // 40 | // can be inspected by errors.Cause. errors.Cause will recursively retrieve 41 | // the topmost error which does not implement causer, which is assumed to be 42 | // the original cause. For example: 43 | // 44 | // switch err := errors.Cause(err).(type) { 45 | // case *MyError: 46 | // // handle specifically 47 | // default: 48 | // // unknown error 49 | // } 50 | // 51 | // causer interface is not exported by this package, but is considered a part 52 | // of stable public API. 53 | // 54 | // Formatted printing of errors 55 | // 56 | // All error values returned from this package implement fmt.Formatter and can 57 | // be formatted by the fmt package. The following verbs are supported 58 | // 59 | // %s print the error. If the error has a Cause it will be 60 | // printed recursively 61 | // %v see %s 62 | // %+v extended format. Each Frame of the error's StackTrace will 63 | // be printed in detail. 64 | // 65 | // Retrieving the stack trace of an error or wrapper 66 | // 67 | // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are 68 | // invoked. This information can be retrieved with the following interface. 69 | // 70 | // type stackTracer interface { 71 | // StackTrace() errors.StackTrace 72 | // } 73 | // 74 | // Where errors.StackTrace is defined as 75 | // 76 | // type StackTrace []Frame 77 | // 78 | // The Frame type represents a call site in the stack trace. Frame supports 79 | // the fmt.Formatter interface that can be used for printing information about 80 | // the stack trace of this error. For example: 81 | // 82 | // if err, ok := err.(stackTracer); ok { 83 | // for _, f := range err.StackTrace() { 84 | // fmt.Printf("%+s:%d", f) 85 | // } 86 | // } 87 | // 88 | // stackTracer interface is not exported by this package, but is considered a part 89 | // of stable public API. 90 | // 91 | // See the documentation for Frame.Format for more details. 92 | package errors 93 | 94 | import ( 95 | "fmt" 96 | "io" 97 | ) 98 | 99 | // New returns an error with the supplied message. 100 | // New also records the stack trace at the point it was called. 101 | func New(message string) error { 102 | return &fundamental{ 103 | msg: message, 104 | stack: callers(), 105 | } 106 | } 107 | 108 | // Errorf formats according to a format specifier and returns the string 109 | // as a value that satisfies error. 110 | // Errorf also records the stack trace at the point it was called. 111 | func Errorf(format string, args ...interface{}) error { 112 | return &fundamental{ 113 | msg: fmt.Sprintf(format, args...), 114 | stack: callers(), 115 | } 116 | } 117 | 118 | // fundamental is an error that has a message and a stack, but no caller. 119 | type fundamental struct { 120 | msg string 121 | *stack 122 | } 123 | 124 | func (f *fundamental) Error() string { return f.msg } 125 | 126 | func (f *fundamental) Format(s fmt.State, verb rune) { 127 | switch verb { 128 | case 'v': 129 | if s.Flag('+') { 130 | io.WriteString(s, f.msg) 131 | f.stack.Format(s, verb) 132 | return 133 | } 134 | fallthrough 135 | case 's': 136 | io.WriteString(s, f.msg) 137 | case 'q': 138 | fmt.Fprintf(s, "%q", f.msg) 139 | } 140 | } 141 | 142 | // WithStack annotates err with a stack trace at the point WithStack was called. 143 | // If err is nil, WithStack returns nil. 144 | func WithStack(err error) error { 145 | if err == nil { 146 | return nil 147 | } 148 | return &withStack{ 149 | err, 150 | callers(), 151 | } 152 | } 153 | 154 | type withStack struct { 155 | error 156 | *stack 157 | } 158 | 159 | func (w *withStack) Cause() error { return w.error } 160 | 161 | func (w *withStack) Format(s fmt.State, verb rune) { 162 | switch verb { 163 | case 'v': 164 | if s.Flag('+') { 165 | fmt.Fprintf(s, "%+v", w.Cause()) 166 | w.stack.Format(s, verb) 167 | return 168 | } 169 | fallthrough 170 | case 's': 171 | io.WriteString(s, w.Error()) 172 | case 'q': 173 | fmt.Fprintf(s, "%q", w.Error()) 174 | } 175 | } 176 | 177 | // Wrap returns an error annotating err with a stack trace 178 | // at the point Wrap is called, and the supplied message. 179 | // If err is nil, Wrap returns nil. 180 | func Wrap(err error, message string) error { 181 | if err == nil { 182 | return nil 183 | } 184 | err = &withMessage{ 185 | cause: err, 186 | msg: message, 187 | } 188 | return &withStack{ 189 | err, 190 | callers(), 191 | } 192 | } 193 | 194 | // Wrapf returns an error annotating err with a stack trace 195 | // at the point Wrapf is call, and the format specifier. 196 | // If err is nil, Wrapf returns nil. 197 | func Wrapf(err error, format string, args ...interface{}) error { 198 | if err == nil { 199 | return nil 200 | } 201 | err = &withMessage{ 202 | cause: err, 203 | msg: fmt.Sprintf(format, args...), 204 | } 205 | return &withStack{ 206 | err, 207 | callers(), 208 | } 209 | } 210 | 211 | // WithMessage annotates err with a new message. 212 | // If err is nil, WithMessage returns nil. 213 | func WithMessage(err error, message string) error { 214 | if err == nil { 215 | return nil 216 | } 217 | return &withMessage{ 218 | cause: err, 219 | msg: message, 220 | } 221 | } 222 | 223 | type withMessage struct { 224 | cause error 225 | msg string 226 | } 227 | 228 | func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } 229 | func (w *withMessage) Cause() error { return w.cause } 230 | 231 | func (w *withMessage) Format(s fmt.State, verb rune) { 232 | switch verb { 233 | case 'v': 234 | if s.Flag('+') { 235 | fmt.Fprintf(s, "%+v\n", w.Cause()) 236 | io.WriteString(s, w.msg) 237 | return 238 | } 239 | fallthrough 240 | case 's', 'q': 241 | io.WriteString(s, w.Error()) 242 | } 243 | } 244 | 245 | // Cause returns the underlying cause of the error, if possible. 246 | // An error value has a cause if it implements the following 247 | // interface: 248 | // 249 | // type causer interface { 250 | // Cause() error 251 | // } 252 | // 253 | // If the error does not implement Cause, the original error will 254 | // be returned. If the error is nil, nil will be returned without further 255 | // investigation. 256 | func Cause(err error) error { 257 | type causer interface { 258 | Cause() error 259 | } 260 | 261 | for err != nil { 262 | cause, ok := err.(causer) 263 | if !ok { 264 | break 265 | } 266 | err = cause.Cause() 267 | } 268 | return err 269 | } 270 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/errors_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "reflect" 8 | "testing" 9 | ) 10 | 11 | func TestNew(t *testing.T) { 12 | tests := []struct { 13 | err string 14 | want error 15 | }{ 16 | {"", fmt.Errorf("")}, 17 | {"foo", fmt.Errorf("foo")}, 18 | {"foo", New("foo")}, 19 | {"string with format specifiers: %v", errors.New("string with format specifiers: %v")}, 20 | } 21 | 22 | for _, tt := range tests { 23 | got := New(tt.err) 24 | if got.Error() != tt.want.Error() { 25 | t.Errorf("New.Error(): got: %q, want %q", got, tt.want) 26 | } 27 | } 28 | } 29 | 30 | func TestWrapNil(t *testing.T) { 31 | got := Wrap(nil, "no error") 32 | if got != nil { 33 | t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got) 34 | } 35 | } 36 | 37 | func TestWrap(t *testing.T) { 38 | tests := []struct { 39 | err error 40 | message string 41 | want string 42 | }{ 43 | {io.EOF, "read error", "read error: EOF"}, 44 | {Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"}, 45 | } 46 | 47 | for _, tt := range tests { 48 | got := Wrap(tt.err, tt.message).Error() 49 | if got != tt.want { 50 | t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want) 51 | } 52 | } 53 | } 54 | 55 | type nilError struct{} 56 | 57 | func (nilError) Error() string { return "nil error" } 58 | 59 | func TestCause(t *testing.T) { 60 | x := New("error") 61 | tests := []struct { 62 | err error 63 | want error 64 | }{{ 65 | // nil error is nil 66 | err: nil, 67 | want: nil, 68 | }, { 69 | // explicit nil error is nil 70 | err: (error)(nil), 71 | want: nil, 72 | }, { 73 | // typed nil is nil 74 | err: (*nilError)(nil), 75 | want: (*nilError)(nil), 76 | }, { 77 | // uncaused error is unaffected 78 | err: io.EOF, 79 | want: io.EOF, 80 | }, { 81 | // caused error returns cause 82 | err: Wrap(io.EOF, "ignored"), 83 | want: io.EOF, 84 | }, { 85 | err: x, // return from errors.New 86 | want: x, 87 | }, { 88 | WithMessage(nil, "whoops"), 89 | nil, 90 | }, { 91 | WithMessage(io.EOF, "whoops"), 92 | io.EOF, 93 | }, { 94 | WithStack(nil), 95 | nil, 96 | }, { 97 | WithStack(io.EOF), 98 | io.EOF, 99 | }} 100 | 101 | for i, tt := range tests { 102 | got := Cause(tt.err) 103 | if !reflect.DeepEqual(got, tt.want) { 104 | t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want) 105 | } 106 | } 107 | } 108 | 109 | func TestWrapfNil(t *testing.T) { 110 | got := Wrapf(nil, "no error") 111 | if got != nil { 112 | t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got) 113 | } 114 | } 115 | 116 | func TestWrapf(t *testing.T) { 117 | tests := []struct { 118 | err error 119 | message string 120 | want string 121 | }{ 122 | {io.EOF, "read error", "read error: EOF"}, 123 | {Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"}, 124 | {Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"}, 125 | } 126 | 127 | for _, tt := range tests { 128 | got := Wrapf(tt.err, tt.message).Error() 129 | if got != tt.want { 130 | t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want) 131 | } 132 | } 133 | } 134 | 135 | func TestErrorf(t *testing.T) { 136 | tests := []struct { 137 | err error 138 | want string 139 | }{ 140 | {Errorf("read error without format specifiers"), "read error without format specifiers"}, 141 | {Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"}, 142 | } 143 | 144 | for _, tt := range tests { 145 | got := tt.err.Error() 146 | if got != tt.want { 147 | t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want) 148 | } 149 | } 150 | } 151 | 152 | func TestWithStackNil(t *testing.T) { 153 | got := WithStack(nil) 154 | if got != nil { 155 | t.Errorf("WithStack(nil): got %#v, expected nil", got) 156 | } 157 | } 158 | 159 | func TestWithStack(t *testing.T) { 160 | tests := []struct { 161 | err error 162 | want string 163 | }{ 164 | {io.EOF, "EOF"}, 165 | {WithStack(io.EOF), "EOF"}, 166 | } 167 | 168 | for _, tt := range tests { 169 | got := WithStack(tt.err).Error() 170 | if got != tt.want { 171 | t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want) 172 | } 173 | } 174 | } 175 | 176 | func TestWithMessageNil(t *testing.T) { 177 | got := WithMessage(nil, "no error") 178 | if got != nil { 179 | t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got) 180 | } 181 | } 182 | 183 | func TestWithMessage(t *testing.T) { 184 | tests := []struct { 185 | err error 186 | message string 187 | want string 188 | }{ 189 | {io.EOF, "read error", "read error: EOF"}, 190 | {WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"}, 191 | } 192 | 193 | for _, tt := range tests { 194 | got := WithMessage(tt.err, tt.message).Error() 195 | if got != tt.want { 196 | t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want) 197 | } 198 | } 199 | 200 | } 201 | 202 | // errors.New, etc values are not expected to be compared by value 203 | // but the change in errors#27 made them incomparable. Assert that 204 | // various kinds of errors have a functional equality operator, even 205 | // if the result of that equality is always false. 206 | func TestErrorEquality(t *testing.T) { 207 | vals := []error{ 208 | nil, 209 | io.EOF, 210 | errors.New("EOF"), 211 | New("EOF"), 212 | Errorf("EOF"), 213 | Wrap(io.EOF, "EOF"), 214 | Wrapf(io.EOF, "EOF%d", 2), 215 | WithMessage(nil, "whoops"), 216 | WithMessage(io.EOF, "whoops"), 217 | WithStack(io.EOF), 218 | WithStack(nil), 219 | } 220 | 221 | for i := range vals { 222 | for j := range vals { 223 | _ = vals[i] == vals[j] // mustn't panic 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/example_test.go: -------------------------------------------------------------------------------- 1 | package errors_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | func ExampleNew() { 10 | err := errors.New("whoops") 11 | fmt.Println(err) 12 | 13 | // Output: whoops 14 | } 15 | 16 | func ExampleNew_printf() { 17 | err := errors.New("whoops") 18 | fmt.Printf("%+v", err) 19 | 20 | // Example output: 21 | // whoops 22 | // github.com/pkg/errors_test.ExampleNew_printf 23 | // /home/dfc/src/github.com/pkg/errors/example_test.go:17 24 | // testing.runExample 25 | // /home/dfc/go/src/testing/example.go:114 26 | // testing.RunExamples 27 | // /home/dfc/go/src/testing/example.go:38 28 | // testing.(*M).Run 29 | // /home/dfc/go/src/testing/testing.go:744 30 | // main.main 31 | // /github.com/pkg/errors/_test/_testmain.go:106 32 | // runtime.main 33 | // /home/dfc/go/src/runtime/proc.go:183 34 | // runtime.goexit 35 | // /home/dfc/go/src/runtime/asm_amd64.s:2059 36 | } 37 | 38 | func ExampleWithMessage() { 39 | cause := errors.New("whoops") 40 | err := errors.WithMessage(cause, "oh noes") 41 | fmt.Println(err) 42 | 43 | // Output: oh noes: whoops 44 | } 45 | 46 | func ExampleWithStack() { 47 | cause := errors.New("whoops") 48 | err := errors.WithStack(cause) 49 | fmt.Println(err) 50 | 51 | // Output: whoops 52 | } 53 | 54 | func ExampleWithStack_printf() { 55 | cause := errors.New("whoops") 56 | err := errors.WithStack(cause) 57 | fmt.Printf("%+v", err) 58 | 59 | // Example Output: 60 | // whoops 61 | // github.com/pkg/errors_test.ExampleWithStack_printf 62 | // /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55 63 | // testing.runExample 64 | // /usr/lib/go/src/testing/example.go:114 65 | // testing.RunExamples 66 | // /usr/lib/go/src/testing/example.go:38 67 | // testing.(*M).Run 68 | // /usr/lib/go/src/testing/testing.go:744 69 | // main.main 70 | // github.com/pkg/errors/_test/_testmain.go:106 71 | // runtime.main 72 | // /usr/lib/go/src/runtime/proc.go:183 73 | // runtime.goexit 74 | // /usr/lib/go/src/runtime/asm_amd64.s:2086 75 | // github.com/pkg/errors_test.ExampleWithStack_printf 76 | // /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56 77 | // testing.runExample 78 | // /usr/lib/go/src/testing/example.go:114 79 | // testing.RunExamples 80 | // /usr/lib/go/src/testing/example.go:38 81 | // testing.(*M).Run 82 | // /usr/lib/go/src/testing/testing.go:744 83 | // main.main 84 | // github.com/pkg/errors/_test/_testmain.go:106 85 | // runtime.main 86 | // /usr/lib/go/src/runtime/proc.go:183 87 | // runtime.goexit 88 | // /usr/lib/go/src/runtime/asm_amd64.s:2086 89 | } 90 | 91 | func ExampleWrap() { 92 | cause := errors.New("whoops") 93 | err := errors.Wrap(cause, "oh noes") 94 | fmt.Println(err) 95 | 96 | // Output: oh noes: whoops 97 | } 98 | 99 | func fn() error { 100 | e1 := errors.New("error") 101 | e2 := errors.Wrap(e1, "inner") 102 | e3 := errors.Wrap(e2, "middle") 103 | return errors.Wrap(e3, "outer") 104 | } 105 | 106 | func ExampleCause() { 107 | err := fn() 108 | fmt.Println(err) 109 | fmt.Println(errors.Cause(err)) 110 | 111 | // Output: outer: middle: inner: error 112 | // error 113 | } 114 | 115 | func ExampleWrap_extended() { 116 | err := fn() 117 | fmt.Printf("%+v\n", err) 118 | 119 | // Example output: 120 | // error 121 | // github.com/pkg/errors_test.fn 122 | // /home/dfc/src/github.com/pkg/errors/example_test.go:47 123 | // github.com/pkg/errors_test.ExampleCause_printf 124 | // /home/dfc/src/github.com/pkg/errors/example_test.go:63 125 | // testing.runExample 126 | // /home/dfc/go/src/testing/example.go:114 127 | // testing.RunExamples 128 | // /home/dfc/go/src/testing/example.go:38 129 | // testing.(*M).Run 130 | // /home/dfc/go/src/testing/testing.go:744 131 | // main.main 132 | // /github.com/pkg/errors/_test/_testmain.go:104 133 | // runtime.main 134 | // /home/dfc/go/src/runtime/proc.go:183 135 | // runtime.goexit 136 | // /home/dfc/go/src/runtime/asm_amd64.s:2059 137 | // github.com/pkg/errors_test.fn 138 | // /home/dfc/src/github.com/pkg/errors/example_test.go:48: inner 139 | // github.com/pkg/errors_test.fn 140 | // /home/dfc/src/github.com/pkg/errors/example_test.go:49: middle 141 | // github.com/pkg/errors_test.fn 142 | // /home/dfc/src/github.com/pkg/errors/example_test.go:50: outer 143 | } 144 | 145 | func ExampleWrapf() { 146 | cause := errors.New("whoops") 147 | err := errors.Wrapf(cause, "oh noes #%d", 2) 148 | fmt.Println(err) 149 | 150 | // Output: oh noes #2: whoops 151 | } 152 | 153 | func ExampleErrorf_extended() { 154 | err := errors.Errorf("whoops: %s", "foo") 155 | fmt.Printf("%+v", err) 156 | 157 | // Example output: 158 | // whoops: foo 159 | // github.com/pkg/errors_test.ExampleErrorf 160 | // /home/dfc/src/github.com/pkg/errors/example_test.go:101 161 | // testing.runExample 162 | // /home/dfc/go/src/testing/example.go:114 163 | // testing.RunExamples 164 | // /home/dfc/go/src/testing/example.go:38 165 | // testing.(*M).Run 166 | // /home/dfc/go/src/testing/testing.go:744 167 | // main.main 168 | // /github.com/pkg/errors/_test/_testmain.go:102 169 | // runtime.main 170 | // /home/dfc/go/src/runtime/proc.go:183 171 | // runtime.goexit 172 | // /home/dfc/go/src/runtime/asm_amd64.s:2059 173 | } 174 | 175 | func Example_stackTrace() { 176 | type stackTracer interface { 177 | StackTrace() errors.StackTrace 178 | } 179 | 180 | err, ok := errors.Cause(fn()).(stackTracer) 181 | if !ok { 182 | panic("oops, err does not implement stackTracer") 183 | } 184 | 185 | st := err.StackTrace() 186 | fmt.Printf("%+v", st[0:2]) // top two frames 187 | 188 | // Example output: 189 | // github.com/pkg/errors_test.fn 190 | // /home/dfc/src/github.com/pkg/errors/example_test.go:47 191 | // github.com/pkg/errors_test.Example_stackTrace 192 | // /home/dfc/src/github.com/pkg/errors/example_test.go:127 193 | } 194 | 195 | func ExampleCause_printf() { 196 | err := errors.Wrap(func() error { 197 | return func() error { 198 | return errors.Errorf("hello %s", fmt.Sprintf("world")) 199 | }() 200 | }(), "failed") 201 | 202 | fmt.Printf("%v", err) 203 | 204 | // Output: failed: hello world 205 | } 206 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/stack.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "path" 7 | "runtime" 8 | "strings" 9 | ) 10 | 11 | // Frame represents a program counter inside a stack frame. 12 | type Frame uintptr 13 | 14 | // pc returns the program counter for this frame; 15 | // multiple frames may have the same PC value. 16 | func (f Frame) pc() uintptr { return uintptr(f) - 1 } 17 | 18 | // file returns the full path to the file that contains the 19 | // function for this Frame's pc. 20 | func (f Frame) file() string { 21 | fn := runtime.FuncForPC(f.pc()) 22 | if fn == nil { 23 | return "unknown" 24 | } 25 | file, _ := fn.FileLine(f.pc()) 26 | return file 27 | } 28 | 29 | // line returns the line number of source code of the 30 | // function for this Frame's pc. 31 | func (f Frame) line() int { 32 | fn := runtime.FuncForPC(f.pc()) 33 | if fn == nil { 34 | return 0 35 | } 36 | _, line := fn.FileLine(f.pc()) 37 | return line 38 | } 39 | 40 | // Format formats the frame according to the fmt.Formatter interface. 41 | // 42 | // %s source file 43 | // %d source line 44 | // %n function name 45 | // %v equivalent to %s:%d 46 | // 47 | // Format accepts flags that alter the printing of some verbs, as follows: 48 | // 49 | // %+s path of source file relative to the compile time GOPATH 50 | // %+v equivalent to %+s:%d 51 | func (f Frame) Format(s fmt.State, verb rune) { 52 | switch verb { 53 | case 's': 54 | switch { 55 | case s.Flag('+'): 56 | pc := f.pc() 57 | fn := runtime.FuncForPC(pc) 58 | if fn == nil { 59 | io.WriteString(s, "unknown") 60 | } else { 61 | file, _ := fn.FileLine(pc) 62 | fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) 63 | } 64 | default: 65 | io.WriteString(s, path.Base(f.file())) 66 | } 67 | case 'd': 68 | fmt.Fprintf(s, "%d", f.line()) 69 | case 'n': 70 | name := runtime.FuncForPC(f.pc()).Name() 71 | io.WriteString(s, funcname(name)) 72 | case 'v': 73 | f.Format(s, 's') 74 | io.WriteString(s, ":") 75 | f.Format(s, 'd') 76 | } 77 | } 78 | 79 | // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). 80 | type StackTrace []Frame 81 | 82 | func (st StackTrace) Format(s fmt.State, verb rune) { 83 | switch verb { 84 | case 'v': 85 | switch { 86 | case s.Flag('+'): 87 | for _, f := range st { 88 | fmt.Fprintf(s, "\n%+v", f) 89 | } 90 | case s.Flag('#'): 91 | fmt.Fprintf(s, "%#v", []Frame(st)) 92 | default: 93 | fmt.Fprintf(s, "%v", []Frame(st)) 94 | } 95 | case 's': 96 | fmt.Fprintf(s, "%s", []Frame(st)) 97 | } 98 | } 99 | 100 | // stack represents a stack of program counters. 101 | type stack []uintptr 102 | 103 | func (s *stack) Format(st fmt.State, verb rune) { 104 | switch verb { 105 | case 'v': 106 | switch { 107 | case st.Flag('+'): 108 | for _, pc := range *s { 109 | f := Frame(pc) 110 | fmt.Fprintf(st, "\n%+v", f) 111 | } 112 | } 113 | } 114 | } 115 | 116 | func (s *stack) StackTrace() StackTrace { 117 | f := make([]Frame, len(*s)) 118 | for i := 0; i < len(f); i++ { 119 | f[i] = Frame((*s)[i]) 120 | } 121 | return f 122 | } 123 | 124 | func callers() *stack { 125 | const depth = 32 126 | var pcs [depth]uintptr 127 | n := runtime.Callers(3, pcs[:]) 128 | var st stack = pcs[0:n] 129 | return &st 130 | } 131 | 132 | // funcname removes the path prefix component of a function's name reported by func.Name(). 133 | func funcname(name string) string { 134 | i := strings.LastIndex(name, "/") 135 | name = name[i+1:] 136 | i = strings.Index(name, ".") 137 | return name[i+1:] 138 | } 139 | 140 | func trimGOPATH(name, file string) string { 141 | // Here we want to get the source file path relative to the compile time 142 | // GOPATH. As of Go 1.6.x there is no direct way to know the compiled 143 | // GOPATH at runtime, but we can infer the number of path segments in the 144 | // GOPATH. We note that fn.Name() returns the function name qualified by 145 | // the import path, which does not include the GOPATH. Thus we can trim 146 | // segments from the beginning of the file path until the number of path 147 | // separators remaining is one more than the number of path separators in 148 | // the function name. For example, given: 149 | // 150 | // GOPATH /home/user 151 | // file /home/user/src/pkg/sub/file.go 152 | // fn.Name() pkg/sub.Type.Method 153 | // 154 | // We want to produce: 155 | // 156 | // pkg/sub/file.go 157 | // 158 | // From this we can easily see that fn.Name() has one less path separator 159 | // than our desired output. We count separators from the end of the file 160 | // path until it finds two more than in the function name and then move 161 | // one character forward to preserve the initial path segment without a 162 | // leading separator. 163 | const sep = "/" 164 | goal := strings.Count(name, sep) + 2 165 | i := len(file) 166 | for n := 0; n < goal; n++ { 167 | i = strings.LastIndex(file[:i], sep) 168 | if i == -1 { 169 | // not enough separators found, set i so that the slice expression 170 | // below leaves file unmodified 171 | i = -len(sep) 172 | break 173 | } 174 | } 175 | // get back to 0 or trim the leading separator 176 | file = file[i+len(sep):] 177 | return file 178 | } 179 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/stack_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "testing" 7 | ) 8 | 9 | var initpc, _, _, _ = runtime.Caller(0) 10 | 11 | func TestFrameLine(t *testing.T) { 12 | var tests = []struct { 13 | Frame 14 | want int 15 | }{{ 16 | Frame(initpc), 17 | 9, 18 | }, { 19 | func() Frame { 20 | var pc, _, _, _ = runtime.Caller(0) 21 | return Frame(pc) 22 | }(), 23 | 20, 24 | }, { 25 | func() Frame { 26 | var pc, _, _, _ = runtime.Caller(1) 27 | return Frame(pc) 28 | }(), 29 | 28, 30 | }, { 31 | Frame(0), // invalid PC 32 | 0, 33 | }} 34 | 35 | for _, tt := range tests { 36 | got := tt.Frame.line() 37 | want := tt.want 38 | if want != got { 39 | t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got) 40 | } 41 | } 42 | } 43 | 44 | type X struct{} 45 | 46 | func (x X) val() Frame { 47 | var pc, _, _, _ = runtime.Caller(0) 48 | return Frame(pc) 49 | } 50 | 51 | func (x *X) ptr() Frame { 52 | var pc, _, _, _ = runtime.Caller(0) 53 | return Frame(pc) 54 | } 55 | 56 | func TestFrameFormat(t *testing.T) { 57 | var tests = []struct { 58 | Frame 59 | format string 60 | want string 61 | }{{ 62 | Frame(initpc), 63 | "%s", 64 | "stack_test.go", 65 | }, { 66 | Frame(initpc), 67 | "%+s", 68 | "github.com/pkg/errors.init\n" + 69 | "\t.+/github.com/pkg/errors/stack_test.go", 70 | }, { 71 | Frame(0), 72 | "%s", 73 | "unknown", 74 | }, { 75 | Frame(0), 76 | "%+s", 77 | "unknown", 78 | }, { 79 | Frame(initpc), 80 | "%d", 81 | "9", 82 | }, { 83 | Frame(0), 84 | "%d", 85 | "0", 86 | }, { 87 | Frame(initpc), 88 | "%n", 89 | "init", 90 | }, { 91 | func() Frame { 92 | var x X 93 | return x.ptr() 94 | }(), 95 | "%n", 96 | `\(\*X\).ptr`, 97 | }, { 98 | func() Frame { 99 | var x X 100 | return x.val() 101 | }(), 102 | "%n", 103 | "X.val", 104 | }, { 105 | Frame(0), 106 | "%n", 107 | "", 108 | }, { 109 | Frame(initpc), 110 | "%v", 111 | "stack_test.go:9", 112 | }, { 113 | Frame(initpc), 114 | "%+v", 115 | "github.com/pkg/errors.init\n" + 116 | "\t.+/github.com/pkg/errors/stack_test.go:9", 117 | }, { 118 | Frame(0), 119 | "%v", 120 | "unknown:0", 121 | }} 122 | 123 | for i, tt := range tests { 124 | testFormatRegexp(t, i, tt.Frame, tt.format, tt.want) 125 | } 126 | } 127 | 128 | func TestFuncname(t *testing.T) { 129 | tests := []struct { 130 | name, want string 131 | }{ 132 | {"", ""}, 133 | {"runtime.main", "main"}, 134 | {"github.com/pkg/errors.funcname", "funcname"}, 135 | {"funcname", "funcname"}, 136 | {"io.copyBuffer", "copyBuffer"}, 137 | {"main.(*R).Write", "(*R).Write"}, 138 | } 139 | 140 | for _, tt := range tests { 141 | got := funcname(tt.name) 142 | want := tt.want 143 | if got != want { 144 | t.Errorf("funcname(%q): want: %q, got %q", tt.name, want, got) 145 | } 146 | } 147 | } 148 | 149 | func TestTrimGOPATH(t *testing.T) { 150 | var tests = []struct { 151 | Frame 152 | want string 153 | }{{ 154 | Frame(initpc), 155 | "github.com/pkg/errors/stack_test.go", 156 | }} 157 | 158 | for i, tt := range tests { 159 | pc := tt.Frame.pc() 160 | fn := runtime.FuncForPC(pc) 161 | file, _ := fn.FileLine(pc) 162 | got := trimGOPATH(fn.Name(), file) 163 | testFormatRegexp(t, i, got, "%s", tt.want) 164 | } 165 | } 166 | 167 | func TestStackTrace(t *testing.T) { 168 | tests := []struct { 169 | err error 170 | want []string 171 | }{{ 172 | New("ooh"), []string{ 173 | "github.com/pkg/errors.TestStackTrace\n" + 174 | "\t.+/github.com/pkg/errors/stack_test.go:172", 175 | }, 176 | }, { 177 | Wrap(New("ooh"), "ahh"), []string{ 178 | "github.com/pkg/errors.TestStackTrace\n" + 179 | "\t.+/github.com/pkg/errors/stack_test.go:177", // this is the stack of Wrap, not New 180 | }, 181 | }, { 182 | Cause(Wrap(New("ooh"), "ahh")), []string{ 183 | "github.com/pkg/errors.TestStackTrace\n" + 184 | "\t.+/github.com/pkg/errors/stack_test.go:182", // this is the stack of New 185 | }, 186 | }, { 187 | func() error { return New("ooh") }(), []string{ 188 | `github.com/pkg/errors.(func·009|TestStackTrace.func1)` + 189 | "\n\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New 190 | "github.com/pkg/errors.TestStackTrace\n" + 191 | "\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New's caller 192 | }, 193 | }, { 194 | Cause(func() error { 195 | return func() error { 196 | return Errorf("hello %s", fmt.Sprintf("world")) 197 | }() 198 | }()), []string{ 199 | `github.com/pkg/errors.(func·010|TestStackTrace.func2.1)` + 200 | "\n\t.+/github.com/pkg/errors/stack_test.go:196", // this is the stack of Errorf 201 | `github.com/pkg/errors.(func·011|TestStackTrace.func2)` + 202 | "\n\t.+/github.com/pkg/errors/stack_test.go:197", // this is the stack of Errorf's caller 203 | "github.com/pkg/errors.TestStackTrace\n" + 204 | "\t.+/github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller 205 | }, 206 | }} 207 | for i, tt := range tests { 208 | x, ok := tt.err.(interface { 209 | StackTrace() StackTrace 210 | }) 211 | if !ok { 212 | t.Errorf("expected %#v to implement StackTrace() StackTrace", tt.err) 213 | continue 214 | } 215 | st := x.StackTrace() 216 | for j, want := range tt.want { 217 | testFormatRegexp(t, i, st[j], "%+v", want) 218 | } 219 | } 220 | } 221 | 222 | func stackTrace() StackTrace { 223 | const depth = 8 224 | var pcs [depth]uintptr 225 | n := runtime.Callers(1, pcs[:]) 226 | var st stack = pcs[0:n] 227 | return st.StackTrace() 228 | } 229 | 230 | func TestStackTraceFormat(t *testing.T) { 231 | tests := []struct { 232 | StackTrace 233 | format string 234 | want string 235 | }{{ 236 | nil, 237 | "%s", 238 | `\[\]`, 239 | }, { 240 | nil, 241 | "%v", 242 | `\[\]`, 243 | }, { 244 | nil, 245 | "%+v", 246 | "", 247 | }, { 248 | nil, 249 | "%#v", 250 | `\[\]errors.Frame\(nil\)`, 251 | }, { 252 | make(StackTrace, 0), 253 | "%s", 254 | `\[\]`, 255 | }, { 256 | make(StackTrace, 0), 257 | "%v", 258 | `\[\]`, 259 | }, { 260 | make(StackTrace, 0), 261 | "%+v", 262 | "", 263 | }, { 264 | make(StackTrace, 0), 265 | "%#v", 266 | `\[\]errors.Frame{}`, 267 | }, { 268 | stackTrace()[:2], 269 | "%s", 270 | `\[stack_test.go stack_test.go\]`, 271 | }, { 272 | stackTrace()[:2], 273 | "%v", 274 | `\[stack_test.go:225 stack_test.go:272\]`, 275 | }, { 276 | stackTrace()[:2], 277 | "%+v", 278 | "\n" + 279 | "github.com/pkg/errors.stackTrace\n" + 280 | "\t.+/github.com/pkg/errors/stack_test.go:225\n" + 281 | "github.com/pkg/errors.TestStackTraceFormat\n" + 282 | "\t.+/github.com/pkg/errors/stack_test.go:276", 283 | }, { 284 | stackTrace()[:2], 285 | "%#v", 286 | `\[\]errors.Frame{stack_test.go:225, stack_test.go:284}`, 287 | }} 288 | 289 | for i, tt := range tests { 290 | testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want) 291 | } 292 | } 293 | --------------------------------------------------------------------------------