mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
Selective export (#770)
This commit is contained in:
13
vendor/github.com/stretchr/objx/.codeclimate.yml
generated
vendored
Normal file
13
vendor/github.com/stretchr/objx/.codeclimate.yml
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
engines:
|
||||
gofmt:
|
||||
enabled: true
|
||||
golint:
|
||||
enabled: true
|
||||
govet:
|
||||
enabled: true
|
||||
|
||||
exclude_patterns:
|
||||
- ".github/"
|
||||
- "vendor/"
|
||||
- "codegen/"
|
||||
- "doc.go"
|
||||
11
vendor/github.com/stretchr/objx/.gitignore
generated
vendored
Normal file
11
vendor/github.com/stretchr/objx/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
25
vendor/github.com/stretchr/objx/.travis.yml
generated
vendored
Normal file
25
vendor/github.com/stretchr/objx/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.8
|
||||
- 1.9
|
||||
- tip
|
||||
|
||||
env:
|
||||
global:
|
||||
- CC_TEST_REPORTER_ID=68feaa3410049ce73e145287acbcdacc525087a30627f96f04e579e75bd71c00
|
||||
|
||||
before_script:
|
||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||
- chmod +x ./cc-test-reporter
|
||||
- ./cc-test-reporter before-build
|
||||
|
||||
install:
|
||||
- go get github.com/go-task/task/cmd/task
|
||||
|
||||
script:
|
||||
- task dl-deps
|
||||
- task lint
|
||||
- task test-coverage
|
||||
|
||||
after_script:
|
||||
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||
30
vendor/github.com/stretchr/objx/Gopkg.lock
generated
vendored
Normal file
30
vendor/github.com/stretchr/objx/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"require"
|
||||
]
|
||||
revision = "b91bfb9ebec76498946beb6af7c0230c7cc7ba6c"
|
||||
version = "v1.2.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "2d160a7dea4ffd13c6c31dab40373822f9d78c73beba016d662bef8f7a998876"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
8
vendor/github.com/stretchr/objx/Gopkg.toml
generated
vendored
Normal file
8
vendor/github.com/stretchr/objx/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
[prune]
|
||||
unused-packages = true
|
||||
non-go = true
|
||||
go-tests = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "~1.2.0"
|
||||
22
vendor/github.com/stretchr/objx/LICENSE
generated
vendored
Normal file
22
vendor/github.com/stretchr/objx/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014 Stretchr, Inc.
|
||||
Copyright (c) 2017-2018 objx contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
80
vendor/github.com/stretchr/objx/README.md
generated
vendored
Normal file
80
vendor/github.com/stretchr/objx/README.md
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
# Objx
|
||||
[](https://travis-ci.org/stretchr/objx)
|
||||
[](https://goreportcard.com/report/github.com/stretchr/objx)
|
||||
[](https://codeclimate.com/github/stretchr/objx/maintainability)
|
||||
[](https://codeclimate.com/github/stretchr/objx/test_coverage)
|
||||
[](https://sourcegraph.com/github.com/stretchr/objx)
|
||||
[](https://godoc.org/github.com/stretchr/objx)
|
||||
|
||||
Objx - Go package for dealing with maps, slices, JSON and other data.
|
||||
|
||||
Get started:
|
||||
|
||||
- Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date)
|
||||
- Check out the API Documentation http://godoc.org/github.com/stretchr/objx
|
||||
|
||||
## Overview
|
||||
Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc.
|
||||
|
||||
### Pattern
|
||||
Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going:
|
||||
|
||||
m, err := objx.FromJSON(json)
|
||||
|
||||
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking.
|
||||
|
||||
Use `Get` to access the value you're interested in. You can use dot and array
|
||||
notation too:
|
||||
|
||||
m.Get("places[0].latlng")
|
||||
|
||||
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
|
||||
|
||||
if m.Get("code").IsStr() { // Your code... }
|
||||
|
||||
Or you can just assume the type, and use one of the strong type methods to extract the real value:
|
||||
|
||||
m.Get("code").Int()
|
||||
|
||||
If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value.
|
||||
|
||||
Get("code").Int(-1)
|
||||
|
||||
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below.
|
||||
|
||||
### Reading data
|
||||
A simple example of how to use Objx:
|
||||
|
||||
// Use MustFromJSON to make an objx.Map from some JSON
|
||||
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
|
||||
|
||||
// Get the details
|
||||
name := m.Get("name").Str()
|
||||
age := m.Get("age").Int()
|
||||
|
||||
// Get their nickname (or use their name if they don't have one)
|
||||
nickname := m.Get("nickname").Str(name)
|
||||
|
||||
### Ranging
|
||||
Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect:
|
||||
|
||||
m := objx.MustFromJSON(json)
|
||||
for key, value := range m {
|
||||
// Your code...
|
||||
}
|
||||
|
||||
## Installation
|
||||
To install Objx, use go get:
|
||||
|
||||
go get github.com/stretchr/objx
|
||||
|
||||
### Staying up to date
|
||||
To update Objx to the latest version, run:
|
||||
|
||||
go get -u github.com/stretchr/objx
|
||||
|
||||
### Supported go versions
|
||||
We support the lastest two major Go versions, which are 1.8 and 1.9 at the moment.
|
||||
|
||||
## Contributing
|
||||
Please feel free to submit issues, fork the repository and send pull requests!
|
||||
32
vendor/github.com/stretchr/objx/Taskfile.yml
generated
vendored
Normal file
32
vendor/github.com/stretchr/objx/Taskfile.yml
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
default:
|
||||
deps: [test]
|
||||
|
||||
dl-deps:
|
||||
desc: Downloads cli dependencies
|
||||
cmds:
|
||||
- go get -u github.com/golang/lint/golint
|
||||
- go get -u github.com/golang/dep/cmd/dep
|
||||
|
||||
update-deps:
|
||||
desc: Updates dependencies
|
||||
cmds:
|
||||
- dep ensure
|
||||
- dep ensure -update
|
||||
|
||||
lint:
|
||||
desc: Runs golint
|
||||
cmds:
|
||||
- go fmt $(go list ./... | grep -v /vendor/)
|
||||
- go vet $(go list ./... | grep -v /vendor/)
|
||||
- golint $(ls *.go | grep -v "doc.go")
|
||||
silent: true
|
||||
|
||||
test:
|
||||
desc: Runs go tests
|
||||
cmds:
|
||||
- go test -race .
|
||||
|
||||
test-coverage:
|
||||
desc: Runs go tests and calucates test coverage
|
||||
cmds:
|
||||
- go test -coverprofile=c.out .
|
||||
148
vendor/github.com/stretchr/objx/accessors.go
generated
vendored
Normal file
148
vendor/github.com/stretchr/objx/accessors.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package objx
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// arrayAccesRegexString is the regex used to extract the array number
|
||||
// from the access path
|
||||
const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
|
||||
|
||||
// arrayAccesRegex is the compiled arrayAccesRegexString
|
||||
var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
|
||||
|
||||
// Get gets the value using the specified selector and
|
||||
// returns it inside a new Obj object.
|
||||
//
|
||||
// If it cannot find the value, Get will return a nil
|
||||
// value inside an instance of Obj.
|
||||
//
|
||||
// Get can only operate directly on map[string]interface{} and []interface.
|
||||
//
|
||||
// Example
|
||||
//
|
||||
// To access the title of the third chapter of the second book, do:
|
||||
//
|
||||
// o.Get("books[1].chapters[2].title")
|
||||
func (m Map) Get(selector string) *Value {
|
||||
rawObj := access(m, selector, nil, false)
|
||||
return &Value{data: rawObj}
|
||||
}
|
||||
|
||||
// Set sets the value using the specified selector and
|
||||
// returns the object on which Set was called.
|
||||
//
|
||||
// Set can only operate directly on map[string]interface{} and []interface
|
||||
//
|
||||
// Example
|
||||
//
|
||||
// To set the title of the third chapter of the second book, do:
|
||||
//
|
||||
// o.Set("books[1].chapters[2].title","Time to Go")
|
||||
func (m Map) Set(selector string, value interface{}) Map {
|
||||
access(m, selector, value, true)
|
||||
return m
|
||||
}
|
||||
|
||||
// access accesses the object using the selector and performs the
|
||||
// appropriate action.
|
||||
func access(current, selector, value interface{}, isSet bool) interface{} {
|
||||
switch selector.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
if array, ok := current.([]interface{}); ok {
|
||||
index := intFromInterface(selector)
|
||||
if index >= len(array) {
|
||||
return nil
|
||||
}
|
||||
return array[index]
|
||||
}
|
||||
return nil
|
||||
|
||||
case string:
|
||||
selStr := selector.(string)
|
||||
selSegs := strings.SplitN(selStr, PathSeparator, 2)
|
||||
thisSel := selSegs[0]
|
||||
index := -1
|
||||
var err error
|
||||
|
||||
if strings.Contains(thisSel, "[") {
|
||||
arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
|
||||
if len(arrayMatches) > 0 {
|
||||
// Get the key into the map
|
||||
thisSel = arrayMatches[1]
|
||||
|
||||
// Get the index into the array at the key
|
||||
index, err = strconv.Atoi(arrayMatches[2])
|
||||
|
||||
if err != nil {
|
||||
// This should never happen. If it does, something has gone
|
||||
// seriously wrong. Panic.
|
||||
panic("objx: Array index is not an integer. Must use array[int].")
|
||||
}
|
||||
}
|
||||
}
|
||||
if curMap, ok := current.(Map); ok {
|
||||
current = map[string]interface{}(curMap)
|
||||
}
|
||||
// get the object in question
|
||||
switch current.(type) {
|
||||
case map[string]interface{}:
|
||||
curMSI := current.(map[string]interface{})
|
||||
if len(selSegs) <= 1 && isSet {
|
||||
curMSI[thisSel] = value
|
||||
return nil
|
||||
}
|
||||
current = curMSI[thisSel]
|
||||
default:
|
||||
current = nil
|
||||
}
|
||||
// do we need to access the item of an array?
|
||||
if index > -1 {
|
||||
if array, ok := current.([]interface{}); ok {
|
||||
if index < len(array) {
|
||||
current = array[index]
|
||||
} else {
|
||||
current = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(selSegs) > 1 {
|
||||
current = access(current, selSegs[1], value, isSet)
|
||||
}
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
// intFromInterface converts an interface object to the largest
|
||||
// representation of an unsigned integer using a type switch and
|
||||
// assertions
|
||||
func intFromInterface(selector interface{}) int {
|
||||
var value int
|
||||
switch selector.(type) {
|
||||
case int:
|
||||
value = selector.(int)
|
||||
case int8:
|
||||
value = int(selector.(int8))
|
||||
case int16:
|
||||
value = int(selector.(int16))
|
||||
case int32:
|
||||
value = int(selector.(int32))
|
||||
case int64:
|
||||
value = int(selector.(int64))
|
||||
case uint:
|
||||
value = int(selector.(uint))
|
||||
case uint8:
|
||||
value = int(selector.(uint8))
|
||||
case uint16:
|
||||
value = int(selector.(uint16))
|
||||
case uint32:
|
||||
value = int(selector.(uint32))
|
||||
case uint64:
|
||||
value = int(selector.(uint64))
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
return value
|
||||
}
|
||||
13
vendor/github.com/stretchr/objx/constants.go
generated
vendored
Normal file
13
vendor/github.com/stretchr/objx/constants.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package objx
|
||||
|
||||
const (
|
||||
// PathSeparator is the character used to separate the elements
|
||||
// of the keypath.
|
||||
//
|
||||
// For example, `location.address.city`
|
||||
PathSeparator string = "."
|
||||
|
||||
// SignatureSeparator is the character that is used to
|
||||
// separate the Base64 string from the security signature.
|
||||
SignatureSeparator = "_"
|
||||
)
|
||||
108
vendor/github.com/stretchr/objx/conversions.go
generated
vendored
Normal file
108
vendor/github.com/stretchr/objx/conversions.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package objx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// JSON converts the contained object to a JSON string
|
||||
// representation
|
||||
func (m Map) JSON() (string, error) {
|
||||
result, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
err = errors.New("objx: JSON encode failed with: " + err.Error())
|
||||
}
|
||||
return string(result), err
|
||||
}
|
||||
|
||||
// MustJSON converts the contained object to a JSON string
|
||||
// representation and panics if there is an error
|
||||
func (m Map) MustJSON() string {
|
||||
result, err := m.JSON()
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Base64 converts the contained object to a Base64 string
|
||||
// representation of the JSON string representation
|
||||
func (m Map) Base64() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
jsonData, err := m.JSON()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
|
||||
_, err = encoder.Write([]byte(jsonData))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_ = encoder.Close()
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// MustBase64 converts the contained object to a Base64 string
|
||||
// representation of the JSON string representation and panics
|
||||
// if there is an error
|
||||
func (m Map) MustBase64() string {
|
||||
result, err := m.Base64()
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SignedBase64 converts the contained object to a Base64 string
|
||||
// representation of the JSON string representation and signs it
|
||||
// using the provided key.
|
||||
func (m Map) SignedBase64(key string) (string, error) {
|
||||
base64, err := m.Base64()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sig := HashWithKey(base64, key)
|
||||
return base64 + SignatureSeparator + sig, nil
|
||||
}
|
||||
|
||||
// MustSignedBase64 converts the contained object to a Base64 string
|
||||
// representation of the JSON string representation and signs it
|
||||
// using the provided key and panics if there is an error
|
||||
func (m Map) MustSignedBase64(key string) string {
|
||||
result, err := m.SignedBase64(key)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/*
|
||||
URL Query
|
||||
------------------------------------------------
|
||||
*/
|
||||
|
||||
// URLValues creates a url.Values object from an Obj. This
|
||||
// function requires that the wrapped object be a map[string]interface{}
|
||||
func (m Map) URLValues() url.Values {
|
||||
vals := make(url.Values)
|
||||
for k, v := range m {
|
||||
//TODO: can this be done without sprintf?
|
||||
vals.Set(k, fmt.Sprintf("%v", v))
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
// URLQuery gets an encoded URL query representing the given
|
||||
// Obj. This function requires that the wrapped object be a
|
||||
// map[string]interface{}
|
||||
func (m Map) URLQuery() (string, error) {
|
||||
return m.URLValues().Encode(), nil
|
||||
}
|
||||
66
vendor/github.com/stretchr/objx/doc.go
generated
vendored
Normal file
66
vendor/github.com/stretchr/objx/doc.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Objx - Go package for dealing with maps, slices, JSON and other data.
|
||||
|
||||
Overview
|
||||
|
||||
Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
|
||||
a powerful `Get` method (among others) that allows you to easily and quickly get
|
||||
access to data within the map, without having to worry too much about type assertions,
|
||||
missing data, default values etc.
|
||||
|
||||
Pattern
|
||||
|
||||
Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy.
|
||||
Call one of the `objx.` functions to create your `objx.Map` to get going:
|
||||
|
||||
m, err := objx.FromJSON(json)
|
||||
|
||||
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
|
||||
the rest will be optimistic and try to figure things out without panicking.
|
||||
|
||||
Use `Get` to access the value you're interested in. You can use dot and array
|
||||
notation too:
|
||||
|
||||
m.Get("places[0].latlng")
|
||||
|
||||
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
|
||||
|
||||
if m.Get("code").IsStr() { // Your code... }
|
||||
|
||||
Or you can just assume the type, and use one of the strong type methods to extract the real value:
|
||||
|
||||
m.Get("code").Int()
|
||||
|
||||
If there's no value there (or if it's the wrong type) then a default value will be returned,
|
||||
or you can be explicit about the default value.
|
||||
|
||||
Get("code").Int(-1)
|
||||
|
||||
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating,
|
||||
manipulating and selecting that data. You can find out more by exploring the index below.
|
||||
|
||||
Reading data
|
||||
|
||||
A simple example of how to use Objx:
|
||||
|
||||
// Use MustFromJSON to make an objx.Map from some JSON
|
||||
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
|
||||
|
||||
// Get the details
|
||||
name := m.Get("name").Str()
|
||||
age := m.Get("age").Int()
|
||||
|
||||
// Get their nickname (or use their name if they don't have one)
|
||||
nickname := m.Get("nickname").Str(name)
|
||||
|
||||
Ranging
|
||||
|
||||
Since `objx.Map` is a `map[string]interface{}` you can treat it as such.
|
||||
For example, to `range` the data, do what you would expect:
|
||||
|
||||
m := objx.MustFromJSON(json)
|
||||
for key, value := range m {
|
||||
// Your code...
|
||||
}
|
||||
*/
|
||||
package objx
|
||||
190
vendor/github.com/stretchr/objx/map.go
generated
vendored
Normal file
190
vendor/github.com/stretchr/objx/map.go
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
package objx
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MSIConvertable is an interface that defines methods for converting your
|
||||
// custom types to a map[string]interface{} representation.
|
||||
type MSIConvertable interface {
|
||||
// MSI gets a map[string]interface{} (msi) representing the
|
||||
// object.
|
||||
MSI() map[string]interface{}
|
||||
}
|
||||
|
||||
// Map provides extended functionality for working with
|
||||
// untyped data, in particular map[string]interface (msi).
|
||||
type Map map[string]interface{}
|
||||
|
||||
// Value returns the internal value instance
|
||||
func (m Map) Value() *Value {
|
||||
return &Value{data: m}
|
||||
}
|
||||
|
||||
// Nil represents a nil Map.
|
||||
var Nil = New(nil)
|
||||
|
||||
// New creates a new Map containing the map[string]interface{} in the data argument.
|
||||
// If the data argument is not a map[string]interface, New attempts to call the
|
||||
// MSI() method on the MSIConvertable interface to create one.
|
||||
func New(data interface{}) Map {
|
||||
if _, ok := data.(map[string]interface{}); !ok {
|
||||
if converter, ok := data.(MSIConvertable); ok {
|
||||
data = converter.MSI()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return Map(data.(map[string]interface{}))
|
||||
}
|
||||
|
||||
// MSI creates a map[string]interface{} and puts it inside a new Map.
|
||||
//
|
||||
// The arguments follow a key, value pattern.
|
||||
//
|
||||
//
|
||||
// Returns nil if any key argument is non-string or if there are an odd number of arguments.
|
||||
//
|
||||
// Example
|
||||
//
|
||||
// To easily create Maps:
|
||||
//
|
||||
// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
|
||||
//
|
||||
// // creates an Map equivalent to
|
||||
// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}}
|
||||
func MSI(keyAndValuePairs ...interface{}) Map {
|
||||
newMap := Map{}
|
||||
keyAndValuePairsLen := len(keyAndValuePairs)
|
||||
if keyAndValuePairsLen%2 != 0 {
|
||||
return nil
|
||||
}
|
||||
for i := 0; i < keyAndValuePairsLen; i = i + 2 {
|
||||
key := keyAndValuePairs[i]
|
||||
value := keyAndValuePairs[i+1]
|
||||
|
||||
// make sure the key is a string
|
||||
keyString, keyStringOK := key.(string)
|
||||
if !keyStringOK {
|
||||
return nil
|
||||
}
|
||||
newMap[keyString] = value
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// ****** Conversion Constructors
|
||||
|
||||
// MustFromJSON creates a new Map containing the data specified in the
|
||||
// jsonString.
|
||||
//
|
||||
// Panics if the JSON is invalid.
|
||||
func MustFromJSON(jsonString string) Map {
|
||||
o, err := FromJSON(jsonString)
|
||||
if err != nil {
|
||||
panic("objx: MustFromJSON failed with error: " + err.Error())
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// FromJSON creates a new Map containing the data specified in the
|
||||
// jsonString.
|
||||
//
|
||||
// Returns an error if the JSON is invalid.
|
||||
func FromJSON(jsonString string) (Map, error) {
|
||||
var data interface{}
|
||||
err := json.Unmarshal([]byte(jsonString), &data)
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
return New(data), nil
|
||||
}
|
||||
|
||||
// FromBase64 creates a new Obj containing the data specified
|
||||
// in the Base64 string.
|
||||
//
|
||||
// The string is an encoded JSON string returned by Base64
|
||||
func FromBase64(base64String string) (Map, error) {
|
||||
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
|
||||
decoded, err := ioutil.ReadAll(decoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FromJSON(string(decoded))
|
||||
}
|
||||
|
||||
// MustFromBase64 creates a new Obj containing the data specified
|
||||
// in the Base64 string and panics if there is an error.
|
||||
//
|
||||
// The string is an encoded JSON string returned by Base64
|
||||
func MustFromBase64(base64String string) Map {
|
||||
result, err := FromBase64(base64String)
|
||||
if err != nil {
|
||||
panic("objx: MustFromBase64 failed with error: " + err.Error())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FromSignedBase64 creates a new Obj containing the data specified
|
||||
// in the Base64 string.
|
||||
//
|
||||
// The string is an encoded JSON string returned by SignedBase64
|
||||
func FromSignedBase64(base64String, key string) (Map, error) {
|
||||
parts := strings.Split(base64String, SignatureSeparator)
|
||||
if len(parts) != 2 {
|
||||
return nil, errors.New("objx: Signed base64 string is malformed")
|
||||
}
|
||||
|
||||
sig := HashWithKey(parts[0], key)
|
||||
if parts[1] != sig {
|
||||
return nil, errors.New("objx: Signature for base64 data does not match")
|
||||
}
|
||||
return FromBase64(parts[0])
|
||||
}
|
||||
|
||||
// MustFromSignedBase64 creates a new Obj containing the data specified
|
||||
// in the Base64 string and panics if there is an error.
|
||||
//
|
||||
// The string is an encoded JSON string returned by Base64
|
||||
func MustFromSignedBase64(base64String, key string) Map {
|
||||
result, err := FromSignedBase64(base64String, key)
|
||||
if err != nil {
|
||||
panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FromURLQuery generates a new Obj by parsing the specified
|
||||
// query.
|
||||
//
|
||||
// For queries with multiple values, the first value is selected.
|
||||
func FromURLQuery(query string) (Map, error) {
|
||||
vals, err := url.ParseQuery(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := Map{}
|
||||
for k, vals := range vals {
|
||||
m[k] = vals[0]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MustFromURLQuery generates a new Obj by parsing the specified
|
||||
// query.
|
||||
//
|
||||
// For queries with multiple values, the first value is selected.
|
||||
//
|
||||
// Panics if it encounters an error
|
||||
func MustFromURLQuery(query string) Map {
|
||||
o, err := FromURLQuery(query)
|
||||
if err != nil {
|
||||
panic("objx: MustFromURLQuery failed with error: " + err.Error())
|
||||
}
|
||||
return o
|
||||
}
|
||||
77
vendor/github.com/stretchr/objx/mutations.go
generated
vendored
Normal file
77
vendor/github.com/stretchr/objx/mutations.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package objx
|
||||
|
||||
// Exclude returns a new Map with the keys in the specified []string
|
||||
// excluded.
|
||||
func (m Map) Exclude(exclude []string) Map {
|
||||
excluded := make(Map)
|
||||
for k, v := range m {
|
||||
if !contains(exclude, k) {
|
||||
excluded[k] = v
|
||||
}
|
||||
}
|
||||
return excluded
|
||||
}
|
||||
|
||||
// Copy creates a shallow copy of the Obj.
|
||||
func (m Map) Copy() Map {
|
||||
copied := Map{}
|
||||
for k, v := range m {
|
||||
copied[k] = v
|
||||
}
|
||||
return copied
|
||||
}
|
||||
|
||||
// Merge blends the specified map with a copy of this map and returns the result.
|
||||
//
|
||||
// Keys that appear in both will be selected from the specified map.
|
||||
// This method requires that the wrapped object be a map[string]interface{}
|
||||
func (m Map) Merge(merge Map) Map {
|
||||
return m.Copy().MergeHere(merge)
|
||||
}
|
||||
|
||||
// MergeHere blends the specified map with this map and returns the current map.
|
||||
//
|
||||
// Keys that appear in both will be selected from the specified map. The original map
|
||||
// will be modified. This method requires that
|
||||
// the wrapped object be a map[string]interface{}
|
||||
func (m Map) MergeHere(merge Map) Map {
|
||||
for k, v := range merge {
|
||||
m[k] = v
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Transform builds a new Obj giving the transformer a chance
|
||||
// to change the keys and values as it goes. This method requires that
|
||||
// the wrapped object be a map[string]interface{}
|
||||
func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
|
||||
newMap := Map{}
|
||||
for k, v := range m {
|
||||
modifiedKey, modifiedVal := transformer(k, v)
|
||||
newMap[modifiedKey] = modifiedVal
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// TransformKeys builds a new map using the specified key mapping.
|
||||
//
|
||||
// Unspecified keys will be unaltered.
|
||||
// This method requires that the wrapped object be a map[string]interface{}
|
||||
func (m Map) TransformKeys(mapping map[string]string) Map {
|
||||
return m.Transform(func(key string, value interface{}) (string, interface{}) {
|
||||
if newKey, ok := mapping[key]; ok {
|
||||
return newKey, value
|
||||
}
|
||||
return key, value
|
||||
})
|
||||
}
|
||||
|
||||
// Checks if a string slice contains a string
|
||||
func contains(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
12
vendor/github.com/stretchr/objx/security.go
generated
vendored
Normal file
12
vendor/github.com/stretchr/objx/security.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package objx
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// HashWithKey hashes the specified string using the security key
|
||||
func HashWithKey(data, key string) string {
|
||||
d := sha1.Sum([]byte(data + ":" + key))
|
||||
return hex.EncodeToString(d[:])
|
||||
}
|
||||
17
vendor/github.com/stretchr/objx/tests.go
generated
vendored
Normal file
17
vendor/github.com/stretchr/objx/tests.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package objx
|
||||
|
||||
// Has gets whether there is something at the specified selector
|
||||
// or not.
|
||||
//
|
||||
// If m is nil, Has will always return false.
|
||||
func (m Map) Has(selector string) bool {
|
||||
if m == nil {
|
||||
return false
|
||||
}
|
||||
return !m.Get(selector).IsNil()
|
||||
}
|
||||
|
||||
// IsNil gets whether the data is nil or not.
|
||||
func (v *Value) IsNil() bool {
|
||||
return v == nil || v.data == nil
|
||||
}
|
||||
2501
vendor/github.com/stretchr/objx/type_specific_codegen.go
generated
vendored
Normal file
2501
vendor/github.com/stretchr/objx/type_specific_codegen.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
vendor/github.com/stretchr/objx/value.go
generated
vendored
Normal file
53
vendor/github.com/stretchr/objx/value.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package objx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Value provides methods for extracting interface{} data in various
|
||||
// types.
|
||||
type Value struct {
|
||||
// data contains the raw data being managed by this Value
|
||||
data interface{}
|
||||
}
|
||||
|
||||
// Data returns the raw data contained by this Value
|
||||
func (v *Value) Data() interface{} {
|
||||
return v.data
|
||||
}
|
||||
|
||||
// String returns the value always as a string
|
||||
func (v *Value) String() string {
|
||||
switch {
|
||||
case v.IsStr():
|
||||
return v.Str()
|
||||
case v.IsBool():
|
||||
return strconv.FormatBool(v.Bool())
|
||||
case v.IsFloat32():
|
||||
return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32)
|
||||
case v.IsFloat64():
|
||||
return strconv.FormatFloat(v.Float64(), 'f', -1, 64)
|
||||
case v.IsInt():
|
||||
return strconv.FormatInt(int64(v.Int()), 10)
|
||||
case v.IsInt8():
|
||||
return strconv.FormatInt(int64(v.Int8()), 10)
|
||||
case v.IsInt16():
|
||||
return strconv.FormatInt(int64(v.Int16()), 10)
|
||||
case v.IsInt32():
|
||||
return strconv.FormatInt(int64(v.Int32()), 10)
|
||||
case v.IsInt64():
|
||||
return strconv.FormatInt(v.Int64(), 10)
|
||||
case v.IsUint():
|
||||
return strconv.FormatUint(uint64(v.Uint()), 10)
|
||||
case v.IsUint8():
|
||||
return strconv.FormatUint(uint64(v.Uint8()), 10)
|
||||
case v.IsUint16():
|
||||
return strconv.FormatUint(uint64(v.Uint16()), 10)
|
||||
case v.IsUint32():
|
||||
return strconv.FormatUint(uint64(v.Uint32()), 10)
|
||||
case v.IsUint64():
|
||||
return strconv.FormatUint(v.Uint64(), 10)
|
||||
}
|
||||
return fmt.Sprintf("%#v", v.Data())
|
||||
}
|
||||
44
vendor/github.com/stretchr/testify/mock/doc.go
generated
vendored
Normal file
44
vendor/github.com/stretchr/testify/mock/doc.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Package mock provides a system by which it is possible to mock your objects
|
||||
// and verify calls are happening as expected.
|
||||
//
|
||||
// Example Usage
|
||||
//
|
||||
// The mock package provides an object, Mock, that tracks activity on another object. It is usually
|
||||
// embedded into a test object as shown below:
|
||||
//
|
||||
// type MyTestObject struct {
|
||||
// // add a Mock object instance
|
||||
// mock.Mock
|
||||
//
|
||||
// // other fields go here as normal
|
||||
// }
|
||||
//
|
||||
// When implementing the methods of an interface, you wire your functions up
|
||||
// to call the Mock.Called(args...) method, and return the appropriate values.
|
||||
//
|
||||
// For example, to mock a method that saves the name and age of a person and returns
|
||||
// the year of their birth or an error, you might write this:
|
||||
//
|
||||
// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
|
||||
// args := o.Called(firstname, lastname, age)
|
||||
// return args.Int(0), args.Error(1)
|
||||
// }
|
||||
//
|
||||
// The Int, Error and Bool methods are examples of strongly typed getters that take the argument
|
||||
// index position. Given this argument list:
|
||||
//
|
||||
// (12, true, "Something")
|
||||
//
|
||||
// You could read them out strongly typed like this:
|
||||
//
|
||||
// args.Int(0)
|
||||
// args.Bool(1)
|
||||
// args.String(2)
|
||||
//
|
||||
// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
|
||||
//
|
||||
// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
|
||||
//
|
||||
// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
|
||||
// cases you should check for nil first.
|
||||
package mock
|
||||
917
vendor/github.com/stretchr/testify/mock/mock.go
generated
vendored
Normal file
917
vendor/github.com/stretchr/testify/mock/mock.go
generated
vendored
Normal file
@@ -0,0 +1,917 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/pmezard/go-difflib/difflib"
|
||||
"github.com/stretchr/objx"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestingT is an interface wrapper around *testing.T
|
||||
type TestingT interface {
|
||||
Logf(format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
FailNow()
|
||||
}
|
||||
|
||||
/*
|
||||
Call
|
||||
*/
|
||||
|
||||
// Call represents a method call and is used for setting expectations,
|
||||
// as well as recording activity.
|
||||
type Call struct {
|
||||
Parent *Mock
|
||||
|
||||
// The name of the method that was or will be called.
|
||||
Method string
|
||||
|
||||
// Holds the arguments of the method.
|
||||
Arguments Arguments
|
||||
|
||||
// Holds the arguments that should be returned when
|
||||
// this method is called.
|
||||
ReturnArguments Arguments
|
||||
|
||||
// Holds the caller info for the On() call
|
||||
callerInfo []string
|
||||
|
||||
// The number of times to return the return arguments when setting
|
||||
// expectations. 0 means to always return the value.
|
||||
Repeatability int
|
||||
|
||||
// Amount of times this call has been called
|
||||
totalCalls int
|
||||
|
||||
// Call to this method can be optional
|
||||
optional bool
|
||||
|
||||
// Holds a channel that will be used to block the Return until it either
|
||||
// receives a message or is closed. nil means it returns immediately.
|
||||
WaitFor <-chan time.Time
|
||||
|
||||
waitTime time.Duration
|
||||
|
||||
// Holds a handler used to manipulate arguments content that are passed by
|
||||
// reference. It's useful when mocking methods such as unmarshalers or
|
||||
// decoders.
|
||||
RunFn func(Arguments)
|
||||
}
|
||||
|
||||
func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call {
|
||||
return &Call{
|
||||
Parent: parent,
|
||||
Method: methodName,
|
||||
Arguments: methodArguments,
|
||||
ReturnArguments: make([]interface{}, 0),
|
||||
callerInfo: callerInfo,
|
||||
Repeatability: 0,
|
||||
WaitFor: nil,
|
||||
RunFn: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Call) lock() {
|
||||
c.Parent.mutex.Lock()
|
||||
}
|
||||
|
||||
func (c *Call) unlock() {
|
||||
c.Parent.mutex.Unlock()
|
||||
}
|
||||
|
||||
// Return specifies the return arguments for the expectation.
|
||||
//
|
||||
// Mock.On("DoSomething").Return(errors.New("failed"))
|
||||
func (c *Call) Return(returnArguments ...interface{}) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
|
||||
c.ReturnArguments = returnArguments
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Once indicates that that the mock should only return the value once.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
|
||||
func (c *Call) Once() *Call {
|
||||
return c.Times(1)
|
||||
}
|
||||
|
||||
// Twice indicates that that the mock should only return the value twice.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
|
||||
func (c *Call) Twice() *Call {
|
||||
return c.Times(2)
|
||||
}
|
||||
|
||||
// Times indicates that that the mock should only return the indicated number
|
||||
// of times.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
|
||||
func (c *Call) Times(i int) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.Repeatability = i
|
||||
return c
|
||||
}
|
||||
|
||||
// WaitUntil sets the channel that will block the mock's return until its closed
|
||||
// or a message is received.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
|
||||
func (c *Call) WaitUntil(w <-chan time.Time) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.WaitFor = w
|
||||
return c
|
||||
}
|
||||
|
||||
// After sets how long to block until the call returns
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2).After(time.Second)
|
||||
func (c *Call) After(d time.Duration) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.waitTime = d
|
||||
return c
|
||||
}
|
||||
|
||||
// Run sets a handler to be called before returning. It can be used when
|
||||
// mocking a method (such as an unmarshaler) that takes a pointer to a struct and
|
||||
// sets properties in such struct
|
||||
//
|
||||
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(func(args Arguments) {
|
||||
// arg := args.Get(0).(*map[string]interface{})
|
||||
// arg["foo"] = "bar"
|
||||
// })
|
||||
func (c *Call) Run(fn func(args Arguments)) *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.RunFn = fn
|
||||
return c
|
||||
}
|
||||
|
||||
// Maybe allows the method call to be optional. Not calling an optional method
|
||||
// will not cause an error while asserting expectations
|
||||
func (c *Call) Maybe() *Call {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
c.optional = true
|
||||
return c
|
||||
}
|
||||
|
||||
// On chains a new expectation description onto the mocked interface. This
|
||||
// allows syntax like.
|
||||
//
|
||||
// Mock.
|
||||
// On("MyMethod", 1).Return(nil).
|
||||
// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
|
||||
//go:noinline
|
||||
func (c *Call) On(methodName string, arguments ...interface{}) *Call {
|
||||
return c.Parent.On(methodName, arguments...)
|
||||
}
|
||||
|
||||
// Mock is the workhorse used to track activity on another object.
|
||||
// For an example of its usage, refer to the "Example Usage" section at the top
|
||||
// of this document.
|
||||
type Mock struct {
|
||||
// Represents the calls that are expected of
|
||||
// an object.
|
||||
ExpectedCalls []*Call
|
||||
|
||||
// Holds the calls that were made to this mocked object.
|
||||
Calls []Call
|
||||
|
||||
// test is An optional variable that holds the test struct, to be used when an
|
||||
// invalid mock call was made.
|
||||
test TestingT
|
||||
|
||||
// TestData holds any data that might be useful for testing. Testify ignores
|
||||
// this data completely allowing you to do whatever you like with it.
|
||||
testData objx.Map
|
||||
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// TestData holds any data that might be useful for testing. Testify ignores
|
||||
// this data completely allowing you to do whatever you like with it.
|
||||
func (m *Mock) TestData() objx.Map {
|
||||
|
||||
if m.testData == nil {
|
||||
m.testData = make(objx.Map)
|
||||
}
|
||||
|
||||
return m.testData
|
||||
}
|
||||
|
||||
/*
|
||||
Setting expectations
|
||||
*/
|
||||
|
||||
// Test sets the test struct variable of the mock object
|
||||
func (m *Mock) Test(t TestingT) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
m.test = t
|
||||
}
|
||||
|
||||
// fail fails the current test with the given formatted format and args.
|
||||
// In case that a test was defined, it uses the test APIs for failing a test,
|
||||
// otherwise it uses panic.
|
||||
func (m *Mock) fail(format string, args ...interface{}) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.test == nil {
|
||||
panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
m.test.Errorf(format, args...)
|
||||
m.test.FailNow()
|
||||
}
|
||||
|
||||
// On starts a description of an expectation of the specified method
|
||||
// being called.
|
||||
//
|
||||
// Mock.On("MyMethod", arg1, arg2)
|
||||
func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
|
||||
for _, arg := range arguments {
|
||||
if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
|
||||
panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg))
|
||||
}
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
c := newCall(m, methodName, assert.CallerInfo(), arguments...)
|
||||
m.ExpectedCalls = append(m.ExpectedCalls, c)
|
||||
return c
|
||||
}
|
||||
|
||||
// /*
|
||||
// Recording and responding to activity
|
||||
// */
|
||||
|
||||
func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
|
||||
var expectedCall *Call
|
||||
|
||||
for i, call := range m.ExpectedCalls {
|
||||
if call.Method == method {
|
||||
_, diffCount := call.Arguments.Diff(arguments)
|
||||
if diffCount == 0 {
|
||||
expectedCall = call
|
||||
if call.Repeatability > -1 {
|
||||
return i, call
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1, expectedCall
|
||||
}
|
||||
|
||||
func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) {
|
||||
var diffCount int
|
||||
var closestCall *Call
|
||||
var err string
|
||||
|
||||
for _, call := range m.expectedCalls() {
|
||||
if call.Method == method {
|
||||
|
||||
errInfo, tempDiffCount := call.Arguments.Diff(arguments)
|
||||
if tempDiffCount < diffCount || diffCount == 0 {
|
||||
diffCount = tempDiffCount
|
||||
closestCall = call
|
||||
err = errInfo
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return closestCall, err
|
||||
}
|
||||
|
||||
func callString(method string, arguments Arguments, includeArgumentValues bool) string {
|
||||
|
||||
var argValsString string
|
||||
if includeArgumentValues {
|
||||
var argVals []string
|
||||
for argIndex, arg := range arguments {
|
||||
argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg))
|
||||
}
|
||||
argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString)
|
||||
}
|
||||
|
||||
// Called tells the mock object that a method has been called, and gets an array
|
||||
// of arguments to return. Panics if the call is unexpected (i.e. not preceded by
|
||||
// appropriate .On .Return() calls)
|
||||
// If Call.WaitFor is set, blocks until the channel is closed or receives a message.
|
||||
func (m *Mock) Called(arguments ...interface{}) Arguments {
|
||||
// get the calling function's name
|
||||
pc, _, _, ok := runtime.Caller(1)
|
||||
if !ok {
|
||||
panic("Couldn't get the caller information")
|
||||
}
|
||||
functionPath := runtime.FuncForPC(pc).Name()
|
||||
//Next four lines are required to use GCCGO function naming conventions.
|
||||
//For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
|
||||
//uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
|
||||
//With GCCGO we need to remove interface information starting from pN<dd>.
|
||||
re := regexp.MustCompile("\\.pN\\d+_")
|
||||
if re.MatchString(functionPath) {
|
||||
functionPath = re.Split(functionPath, -1)[0]
|
||||
}
|
||||
parts := strings.Split(functionPath, ".")
|
||||
functionName := parts[len(parts)-1]
|
||||
return m.MethodCalled(functionName, arguments...)
|
||||
}
|
||||
|
||||
// MethodCalled tells the mock object that the given method has been called, and gets
|
||||
// an array of arguments to return. Panics if the call is unexpected (i.e. not preceded
|
||||
// by appropriate .On .Return() calls)
|
||||
// If Call.WaitFor is set, blocks until the channel is closed or receives a message.
|
||||
func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments {
|
||||
m.mutex.Lock()
|
||||
//TODO: could combine expected and closes in single loop
|
||||
found, call := m.findExpectedCall(methodName, arguments...)
|
||||
|
||||
if found < 0 {
|
||||
// expected call found but it has already been called with repeatable times
|
||||
if call != nil {
|
||||
m.mutex.Unlock()
|
||||
m.fail("\nassert: mock: The method has been called over %d times.\n\tEither do one more Mock.On(\"%s\").Return(...), or remove extra call.\n\tThis call was unexpected:\n\t\t%s\n\tat: %s", call.totalCalls, methodName, callString(methodName, arguments, true), assert.CallerInfo())
|
||||
}
|
||||
// we have to fail here - because we don't know what to do
|
||||
// as the return arguments. This is because:
|
||||
//
|
||||
// a) this is a totally unexpected call to this method,
|
||||
// b) the arguments are not what was expected, or
|
||||
// c) the developer has forgotten to add an accompanying On...Return pair.
|
||||
closestCall, mismatch := m.findClosestCall(methodName, arguments...)
|
||||
m.mutex.Unlock()
|
||||
|
||||
if closestCall != nil {
|
||||
m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s",
|
||||
callString(methodName, arguments, true),
|
||||
callString(methodName, closestCall.Arguments, true),
|
||||
diffArguments(closestCall.Arguments, arguments),
|
||||
strings.TrimSpace(mismatch),
|
||||
)
|
||||
} else {
|
||||
m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo())
|
||||
}
|
||||
}
|
||||
|
||||
if call.Repeatability == 1 {
|
||||
call.Repeatability = -1
|
||||
} else if call.Repeatability > 1 {
|
||||
call.Repeatability--
|
||||
}
|
||||
call.totalCalls++
|
||||
|
||||
// add the call
|
||||
m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...))
|
||||
m.mutex.Unlock()
|
||||
|
||||
// block if specified
|
||||
if call.WaitFor != nil {
|
||||
<-call.WaitFor
|
||||
} else {
|
||||
time.Sleep(call.waitTime)
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
runFn := call.RunFn
|
||||
m.mutex.Unlock()
|
||||
|
||||
if runFn != nil {
|
||||
runFn(arguments)
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
returnArgs := call.ReturnArguments
|
||||
m.mutex.Unlock()
|
||||
|
||||
return returnArgs
|
||||
}
|
||||
|
||||
/*
|
||||
Assertions
|
||||
*/
|
||||
|
||||
type assertExpectationser interface {
|
||||
AssertExpectations(TestingT) bool
|
||||
}
|
||||
|
||||
// AssertExpectationsForObjects asserts that everything specified with On and Return
|
||||
// of the specified objects was in fact called as expected.
|
||||
//
|
||||
// Calls may have occurred in any order.
|
||||
func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
for _, obj := range testObjects {
|
||||
if m, ok := obj.(Mock); ok {
|
||||
t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)")
|
||||
obj = &m
|
||||
}
|
||||
m := obj.(assertExpectationser)
|
||||
if !m.AssertExpectations(t) {
|
||||
t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m))
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AssertExpectations asserts that everything specified with On and Return was
|
||||
// in fact called as expected. Calls may have occurred in any order.
|
||||
func (m *Mock) AssertExpectations(t TestingT) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
var somethingMissing bool
|
||||
var failedExpectations int
|
||||
|
||||
// iterate through each expectation
|
||||
expectedCalls := m.expectedCalls()
|
||||
for _, expectedCall := range expectedCalls {
|
||||
if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {
|
||||
somethingMissing = true
|
||||
failedExpectations++
|
||||
t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo)
|
||||
} else {
|
||||
if expectedCall.Repeatability > 0 {
|
||||
somethingMissing = true
|
||||
failedExpectations++
|
||||
t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo)
|
||||
} else {
|
||||
t.Logf("PASS:\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if somethingMissing {
|
||||
t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo())
|
||||
}
|
||||
|
||||
return !somethingMissing
|
||||
}
|
||||
|
||||
// AssertNumberOfCalls asserts that the method was called expectedCalls times.
|
||||
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
var actualCalls int
|
||||
for _, call := range m.calls() {
|
||||
if call.Method == methodName {
|
||||
actualCalls++
|
||||
}
|
||||
}
|
||||
return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls))
|
||||
}
|
||||
|
||||
// AssertCalled asserts that the method was called.
|
||||
// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
|
||||
func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
if !m.methodWasCalled(methodName, arguments) {
|
||||
var calledWithArgs []string
|
||||
for _, call := range m.calls() {
|
||||
calledWithArgs = append(calledWithArgs, fmt.Sprintf("%v", call.Arguments))
|
||||
}
|
||||
if len(calledWithArgs) == 0 {
|
||||
return assert.Fail(t, "Should have called with given arguments",
|
||||
fmt.Sprintf("Expected %q to have been called with:\n%v\nbut no actual calls happened", methodName, arguments))
|
||||
}
|
||||
return assert.Fail(t, "Should have called with given arguments",
|
||||
fmt.Sprintf("Expected %q to have been called with:\n%v\nbut actual calls were:\n %v", methodName, arguments, strings.Join(calledWithArgs, "\n")))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AssertNotCalled asserts that the method was not called.
|
||||
// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
|
||||
func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
if m.methodWasCalled(methodName, arguments) {
|
||||
return assert.Fail(t, "Should not have called with given arguments",
|
||||
fmt.Sprintf("Expected %q to not have been called with:\n%v\nbut actually it was.", methodName, arguments))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
|
||||
for _, call := range m.calls() {
|
||||
if call.Method == methodName {
|
||||
|
||||
_, differences := Arguments(expected).Diff(call.Arguments)
|
||||
|
||||
if differences == 0 {
|
||||
// found the expected call
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// we didn't find the expected call
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Mock) expectedCalls() []*Call {
|
||||
return append([]*Call{}, m.ExpectedCalls...)
|
||||
}
|
||||
|
||||
func (m *Mock) calls() []Call {
|
||||
return append([]Call{}, m.Calls...)
|
||||
}
|
||||
|
||||
/*
|
||||
Arguments
|
||||
*/
|
||||
|
||||
// Arguments holds an array of method arguments or return values.
|
||||
type Arguments []interface{}
|
||||
|
||||
const (
|
||||
// Anything is used in Diff and Assert when the argument being tested
|
||||
// shouldn't be taken into consideration.
|
||||
Anything = "mock.Anything"
|
||||
)
|
||||
|
||||
// AnythingOfTypeArgument is a string that contains the type of an argument
|
||||
// for use when type checking. Used in Diff and Assert.
|
||||
type AnythingOfTypeArgument string
|
||||
|
||||
// AnythingOfType returns an AnythingOfTypeArgument object containing the
|
||||
// name of the type to check for. Used in Diff and Assert.
|
||||
//
|
||||
// For example:
|
||||
// Assert(t, AnythingOfType("string"), AnythingOfType("int"))
|
||||
func AnythingOfType(t string) AnythingOfTypeArgument {
|
||||
return AnythingOfTypeArgument(t)
|
||||
}
|
||||
|
||||
// IsTypeArgument is a struct that contains the type of an argument
|
||||
// for use when type checking. This is an alternative to AnythingOfType.
|
||||
// Used in Diff and Assert.
|
||||
type IsTypeArgument struct {
|
||||
t interface{}
|
||||
}
|
||||
|
||||
// IsType returns an IsTypeArgument object containing the type to check for.
|
||||
// You can provide a zero-value of the type to check. This is an
|
||||
// alternative to AnythingOfType. Used in Diff and Assert.
|
||||
//
|
||||
// For example:
|
||||
// Assert(t, IsType(""), IsType(0))
|
||||
func IsType(t interface{}) *IsTypeArgument {
|
||||
return &IsTypeArgument{t: t}
|
||||
}
|
||||
|
||||
// argumentMatcher performs custom argument matching, returning whether or
|
||||
// not the argument is matched by the expectation fixture function.
|
||||
type argumentMatcher struct {
|
||||
// fn is a function which accepts one argument, and returns a bool.
|
||||
fn reflect.Value
|
||||
}
|
||||
|
||||
func (f argumentMatcher) Matches(argument interface{}) bool {
|
||||
expectType := f.fn.Type().In(0)
|
||||
expectTypeNilSupported := false
|
||||
switch expectType.Kind() {
|
||||
case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Ptr:
|
||||
expectTypeNilSupported = true
|
||||
}
|
||||
|
||||
argType := reflect.TypeOf(argument)
|
||||
var arg reflect.Value
|
||||
if argType == nil {
|
||||
arg = reflect.New(expectType).Elem()
|
||||
} else {
|
||||
arg = reflect.ValueOf(argument)
|
||||
}
|
||||
|
||||
if argType == nil && !expectTypeNilSupported {
|
||||
panic(errors.New("attempting to call matcher with nil for non-nil expected type"))
|
||||
}
|
||||
if argType == nil || argType.AssignableTo(expectType) {
|
||||
result := f.fn.Call([]reflect.Value{arg})
|
||||
return result[0].Bool()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f argumentMatcher) String() string {
|
||||
return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name())
|
||||
}
|
||||
|
||||
// MatchedBy can be used to match a mock call based on only certain properties
|
||||
// from a complex struct or some calculation. It takes a function that will be
|
||||
// evaluated with the called argument and will return true when there's a match
|
||||
// and false otherwise.
|
||||
//
|
||||
// Example:
|
||||
// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" }))
|
||||
//
|
||||
// |fn|, must be a function accepting a single argument (of the expected type)
|
||||
// which returns a bool. If |fn| doesn't match the required signature,
|
||||
// MatchedBy() panics.
|
||||
func MatchedBy(fn interface{}) argumentMatcher {
|
||||
fnType := reflect.TypeOf(fn)
|
||||
|
||||
if fnType.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("assert: arguments: %s is not a func", fn))
|
||||
}
|
||||
if fnType.NumIn() != 1 {
|
||||
panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn))
|
||||
}
|
||||
if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool {
|
||||
panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn))
|
||||
}
|
||||
|
||||
return argumentMatcher{fn: reflect.ValueOf(fn)}
|
||||
}
|
||||
|
||||
// Get Returns the argument at the specified index.
|
||||
func (args Arguments) Get(index int) interface{} {
|
||||
if index+1 > len(args) {
|
||||
panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args)))
|
||||
}
|
||||
return args[index]
|
||||
}
|
||||
|
||||
// Is gets whether the objects match the arguments specified.
|
||||
func (args Arguments) Is(objects ...interface{}) bool {
|
||||
for i, obj := range args {
|
||||
if obj != objects[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff gets a string describing the differences between the arguments
|
||||
// and the specified objects.
|
||||
//
|
||||
// Returns the diff string and number of differences found.
|
||||
func (args Arguments) Diff(objects []interface{}) (string, int) {
|
||||
//TODO: could return string as error and nil for No difference
|
||||
|
||||
var output = "\n"
|
||||
var differences int
|
||||
|
||||
var maxArgCount = len(args)
|
||||
if len(objects) > maxArgCount {
|
||||
maxArgCount = len(objects)
|
||||
}
|
||||
|
||||
for i := 0; i < maxArgCount; i++ {
|
||||
var actual, expected interface{}
|
||||
var actualFmt, expectedFmt string
|
||||
|
||||
if len(objects) <= i {
|
||||
actual = "(Missing)"
|
||||
actualFmt = "(Missing)"
|
||||
} else {
|
||||
actual = objects[i]
|
||||
actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual)
|
||||
}
|
||||
|
||||
if len(args) <= i {
|
||||
expected = "(Missing)"
|
||||
expectedFmt = "(Missing)"
|
||||
} else {
|
||||
expected = args[i]
|
||||
expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected)
|
||||
}
|
||||
|
||||
if matcher, ok := expected.(argumentMatcher); ok {
|
||||
if matcher.Matches(actual) {
|
||||
output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher)
|
||||
} else {
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher)
|
||||
}
|
||||
} else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
|
||||
|
||||
// type checking
|
||||
if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
|
||||
// not match
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
|
||||
}
|
||||
|
||||
} else if reflect.TypeOf(expected) == reflect.TypeOf((*IsTypeArgument)(nil)) {
|
||||
t := expected.(*IsTypeArgument).t
|
||||
if reflect.TypeOf(t) != reflect.TypeOf(actual) {
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt)
|
||||
}
|
||||
} else {
|
||||
|
||||
// normal checking
|
||||
|
||||
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
|
||||
// match
|
||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt)
|
||||
} else {
|
||||
// not match
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if differences == 0 {
|
||||
return "No differences.", differences
|
||||
}
|
||||
|
||||
return output, differences
|
||||
|
||||
}
|
||||
|
||||
// Assert compares the arguments with the specified objects and fails if
|
||||
// they do not exactly match.
|
||||
func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
// get the differences
|
||||
diff, diffCount := args.Diff(objects)
|
||||
|
||||
if diffCount == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// there are differences... report them...
|
||||
t.Logf(diff)
|
||||
t.Errorf("%sArguments do not match.", assert.CallerInfo())
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
// String gets the argument at the specified index. Panics if there is no argument, or
|
||||
// if the argument is of the wrong type.
|
||||
//
|
||||
// If no index is provided, String() returns a complete string representation
|
||||
// of the arguments.
|
||||
func (args Arguments) String(indexOrNil ...int) string {
|
||||
|
||||
if len(indexOrNil) == 0 {
|
||||
// normal String() method - return a string representation of the args
|
||||
var argsStr []string
|
||||
for _, arg := range args {
|
||||
argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg)))
|
||||
}
|
||||
return strings.Join(argsStr, ",")
|
||||
} else if len(indexOrNil) == 1 {
|
||||
// Index has been specified - get the argument at that index
|
||||
var index = indexOrNil[0]
|
||||
var s string
|
||||
var ok bool
|
||||
if s, ok = args.Get(index).(string); !ok {
|
||||
panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index)))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil)))
|
||||
|
||||
}
|
||||
|
||||
// Int gets the argument at the specified index. Panics if there is no argument, or
|
||||
// if the argument is of the wrong type.
|
||||
func (args Arguments) Int(index int) int {
|
||||
var s int
|
||||
var ok bool
|
||||
if s, ok = args.Get(index).(int); !ok {
|
||||
panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Error gets the argument at the specified index. Panics if there is no argument, or
|
||||
// if the argument is of the wrong type.
|
||||
func (args Arguments) Error(index int) error {
|
||||
obj := args.Get(index)
|
||||
var s error
|
||||
var ok bool
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
if s, ok = obj.(error); !ok {
|
||||
panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Bool gets the argument at the specified index. Panics if there is no argument, or
|
||||
// if the argument is of the wrong type.
|
||||
func (args Arguments) Bool(index int) bool {
|
||||
var s bool
|
||||
var ok bool
|
||||
if s, ok = args.Get(index).(bool); !ok {
|
||||
panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
|
||||
t := reflect.TypeOf(v)
|
||||
k := t.Kind()
|
||||
|
||||
if k == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
k = t.Kind()
|
||||
}
|
||||
return t, k
|
||||
}
|
||||
|
||||
func diffArguments(expected Arguments, actual Arguments) string {
|
||||
if len(expected) != len(actual) {
|
||||
return fmt.Sprintf("Provided %v arguments, mocked for %v arguments", len(expected), len(actual))
|
||||
}
|
||||
|
||||
for x := range expected {
|
||||
if diffString := diff(expected[x], actual[x]); diffString != "" {
|
||||
return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// diff returns a diff of both values as long as both are of the same type and
|
||||
// are a struct, map, slice or array. Otherwise it returns an empty string.
|
||||
func diff(expected interface{}, actual interface{}) string {
|
||||
if expected == nil || actual == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
et, ek := typeAndKind(expected)
|
||||
at, _ := typeAndKind(actual)
|
||||
|
||||
if et != at {
|
||||
return ""
|
||||
}
|
||||
|
||||
if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {
|
||||
return ""
|
||||
}
|
||||
|
||||
e := spewConfig.Sdump(expected)
|
||||
a := spewConfig.Sdump(actual)
|
||||
|
||||
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
||||
A: difflib.SplitLines(e),
|
||||
B: difflib.SplitLines(a),
|
||||
FromFile: "Expected",
|
||||
FromDate: "",
|
||||
ToFile: "Actual",
|
||||
ToDate: "",
|
||||
Context: 1,
|
||||
})
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
var spewConfig = spew.ConfigState{
|
||||
Indent: " ",
|
||||
DisablePointerAddresses: true,
|
||||
DisableCapacities: true,
|
||||
SortKeys: true,
|
||||
}
|
||||
|
||||
type tHelper interface {
|
||||
Helper()
|
||||
}
|
||||
Reference in New Issue
Block a user