Merge pull request #611 from jzelinskie/drop-graceful

Remove dependency on graceful
This commit is contained in:
Jimmy Zelinskie 2018-09-06 17:10:01 -04:00 committed by GitHub
commit fffb67f137
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
133 changed files with 7826 additions and 4335 deletions

View File

@ -15,15 +15,14 @@
package api package api
import ( import (
"context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/tylerb/graceful"
"github.com/coreos/clair/api/v3" "github.com/coreos/clair/api/v3"
"github.com/coreos/clair/database" "github.com/coreos/clair/database"
@ -61,42 +60,22 @@ func RunHealth(cfg *Config, store database.Datastore, st *stopper.Stopper) {
} }
log.WithField("addr", cfg.HealthAddr).Info("starting health API") log.WithField("addr", cfg.HealthAddr).Info("starting health API")
srv := &graceful.Server{ srv := http.Server{
Timeout: 10 * time.Second, // Interrupt health checks when stopping Addr: cfg.HealthAddr,
NoSignalHandling: true, // We want to use our own Stopper Handler: http.TimeoutHandler(newHealthHandler(store), cfg.Timeout, timeoutResponse),
Server: &http.Server{
Addr: cfg.HealthAddr,
Handler: http.TimeoutHandler(newHealthHandler(store), cfg.Timeout, timeoutResponse),
},
} }
listenAndServeWithStopper(srv, st, "", "")
log.Info("health API stopped")
}
// listenAndServeWithStopper wraps graceful.Server's
// ListenAndServe/ListenAndServeTLS and adds the ability to interrupt them with
// the provided stopper.Stopper.
func listenAndServeWithStopper(srv *graceful.Server, st *stopper.Stopper, certFile, keyFile string) {
go func() { go func() {
<-st.Chan() <-st.Chan()
srv.Stop(0) srv.Shutdown(context.TODO())
}() }()
var err error err := srv.ListenAndServe()
if certFile != "" && keyFile != "" { if err != nil && err != http.ErrServerClosed {
log.Info("API: TLS Enabled") log.Fatal(err)
err = srv.ListenAndServeTLS(certFile, keyFile)
} else {
err = srv.ListenAndServe()
} }
if err != nil { log.Info("health API stopped")
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
log.Fatal(err)
}
}
} }
// tlsClientConfig initializes a *tls.Config using the given CA. The resulting // tlsClientConfig initializes a *tls.Config using the given CA. The resulting

View File

@ -1,132 +1,77 @@
[ [
{ {
"project": "github.com/beorn7/perks/quantile", "project": "github.com/coreos/clair",
"licenses": [ "license": "Apache License 2.0",
{ "confidence": 1
"type": "MIT License",
"confidence": 0.9891304347826086
}
]
}, },
{ {
"project": "github.com/coreos/clair", "project": "github.com/beorn7/perks/quantile",
"licenses": [ "license": "MIT License",
{ "confidence": 0.989
"type": "Apache License 2.0",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/coreos/pkg/timeutil", "project": "github.com/coreos/pkg/timeutil",
"licenses": [ "license": "Apache License 2.0",
{ "confidence": 1
"type": "Apache License 2.0",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/golang/protobuf/proto", "project": "github.com/golang/protobuf/proto",
"licenses": [ "license": "BSD 3-clause \"New\" or \"Revised\" License",
{ "confidence": 0.92
"type": "BSD 3-clause \"New\" or \"Revised\" License", },
"confidence": 0.92 {
} "project": "github.com/google/uuid",
] "license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.966
}, },
{ {
"project": "github.com/matttproud/golang_protobuf_extensions/pbutil", "project": "github.com/matttproud/golang_protobuf_extensions/pbutil",
"licenses": [ "license": "Apache License 2.0",
{ "confidence": 1
"type": "Apache License 2.0",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/pborman/uuid", "project": "github.com/pborman/uuid",
"licenses": [ "license": "BSD 3-clause \"New\" or \"Revised\" License",
{ "confidence": 0.966
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9663865546218487
}
]
}, },
{ {
"project": "github.com/prometheus/client_golang/prometheus", "project": "github.com/prometheus/client_golang/prometheus",
"licenses": [ "license": "Apache License 2.0",
{ "confidence": 1
"type": "Apache License 2.0",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/prometheus/client_model/go", "project": "github.com/prometheus/client_model/go",
"licenses": [ "license": "Apache License 2.0",
{ "confidence": 1
"type": "Apache License 2.0",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/prometheus/common", "project": "github.com/prometheus/common",
"licenses": [ "license": "Apache License 2.0",
{ "confidence": 1
"type": "Apache License 2.0",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/prometheus/procfs", "project": "github.com/prometheus/procfs/xfs",
"licenses": [ "license": "Apache License 2.0",
{ "confidence": 1
"type": "Apache License 2.0",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/sirupsen/logrus", "project": "github.com/sirupsen/logrus",
"licenses": [ "license": "MIT License",
{ "confidence": 1
"type": "MIT License",
"confidence": 1
}
]
}, },
{ {
"project": "github.com/stretchr/testify/assert", "project": "github.com/stretchr/testify/assert",
"licenses": [ "license": "MIT License",
{ "confidence": 0.943
"type": "MIT License",
"confidence": 0.9430051813471503
},
{
"type": "MIT License",
"confidence": 0.9430051813471503
}
]
}, },
{ {
"project": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew", "project": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew",
"licenses": [ "license": "ISC License",
{ "confidence": 0.985
"type": "ISC License",
"confidence": 0.9850746268656716
}
]
}, },
{ {
"project": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib", "project": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib",
"licenses": [ "license": "BSD 3-clause \"New\" or \"Revised\" License",
{ "confidence": 0.983
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9830508474576272
}
]
} }
] ]

18
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: b5b9ebebad30becd361736196a015af23b1d9a616a375c7fc13823121fd17226 hash: 9bf7ad53b92119a17068b8724d9b406a7ca84b5bfcd0baba44b08c696a538b14
updated: 2017-06-05T16:11:29.019891941-04:00 updated: 2018-09-06T15:58:19.234504-04:00
imports: imports:
- name: github.com/beorn7/perks - name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
@ -23,9 +23,13 @@ imports:
- jsonpb - jsonpb
- proto - proto
- protoc-gen-go/descriptor - protoc-gen-go/descriptor
- ptypes
- ptypes/any - ptypes/any
- ptypes/empty - ptypes/duration
- ptypes/struct - ptypes/struct
- ptypes/timestamp
- name: github.com/google/uuid
version: e704694aed0ea004bb7eb1fc2e911d048a54606a
- name: github.com/grpc-ecosystem/go-grpc-prometheus - name: github.com/grpc-ecosystem/go-grpc-prometheus
version: 2500245aa6110c562d17020fb31a2c133d737799 version: 2500245aa6110c562d17020fb31a2c133d737799
- name: github.com/grpc-ecosystem/grpc-gateway - name: github.com/grpc-ecosystem/grpc-gateway
@ -35,7 +39,7 @@ imports:
- runtime/internal - runtime/internal
- utilities - utilities
- name: github.com/guregu/null - name: github.com/guregu/null
version: 41961cea0328defc5f95c1c473f89ebf0d1813f6 version: 80515d440932108546bcade467bb7d6968e812e2
subpackages: subpackages:
- zero - zero
- name: github.com/hashicorp/golang-lru - name: github.com/hashicorp/golang-lru
@ -53,7 +57,7 @@ imports:
subpackages: subpackages:
- pbutil - pbutil
- name: github.com/pborman/uuid - name: github.com/pborman/uuid
version: a97ce2ca70fa5a848076093f05e639a89ca34d06 version: adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1
- name: github.com/pmezard/go-difflib - name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages: subpackages:
@ -81,11 +85,9 @@ imports:
- name: github.com/sirupsen/logrus - name: github.com/sirupsen/logrus
version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f
- name: github.com/stretchr/testify - name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 version: f35b8ab0b5a2cef36673838d662e249dd9c94686
subpackages: subpackages:
- assert - assert
- name: github.com/tylerb/graceful
version: 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb
- name: golang.org/x/net - name: golang.org/x/net
version: 59a0b19b5533c7977ddeb86b017bf507ed407b12 version: 59a0b19b5533c7977ddeb86b017bf507ed407b12
subpackages: subpackages:

View File

@ -26,7 +26,5 @@ import:
version: ^1.1.4 version: ^1.1.4
subpackages: subpackages:
- assert - assert
- package: github.com/tylerb/graceful
version: ^1.2.15
- package: gopkg.in/yaml.v2 - package: gopkg.in/yaml.v2
- package: github.com/cockroachdb/cmux - package: github.com/cockroachdb/cmux

9
vendor/github.com/google/uuid/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
go:
- 1.4.3
- 1.5.3
- tip
script:
- go test -v ./...

10
vendor/github.com/google/uuid/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,10 @@
# How to contribute
We definitely welcome patches and contribution to this project!
### Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
You may have already signed it for other Google projects.

9
vendor/github.com/google/uuid/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,9 @@
Paul Borman <borman@google.com>
bmatsuo
shawnps
theory
jboverfelt
dsymonds
cd1
wallclockbuilder
dansouza

27
vendor/github.com/google/uuid/LICENSE generated vendored Normal file
View File

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

19
vendor/github.com/google/uuid/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master)
The uuid package generates and inspects UUIDs based on
[RFC 4122](http://tools.ietf.org/html/rfc4122)
and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named
code.google.com/p/go-uuid). It differs from these earlier packages in that
a UUID is a 16 byte array rather than a byte slice. One loss due to this
change is the ability to represent an invalid UUID (vs a NIL UUID).
###### Install
`go get github.com/google/uuid`
###### Documentation
[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid)
Full `go doc` style documentation for the package can be viewed online without
installing this package by using the GoDoc site here:
http://godoc.org/github.com/google/uuid

80
vendor/github.com/google/uuid/dce.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"fmt"
"os"
)
// A Domain represents a Version 2 domain
type Domain byte
// Domain constants for DCE Security (Version 2) UUIDs.
const (
Person = Domain(0)
Group = Domain(1)
Org = Domain(2)
)
// NewDCESecurity returns a DCE Security (Version 2) UUID.
//
// The domain should be one of Person, Group or Org.
// On a POSIX system the id should be the users UID for the Person
// domain and the users GID for the Group. The meaning of id for
// the domain Org or on non-POSIX systems is site defined.
//
// For a given domain/id pair the same token may be returned for up to
// 7 minutes and 10 seconds.
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
uuid, err := NewUUID()
if err == nil {
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
uuid[9] = byte(domain)
binary.BigEndian.PutUint32(uuid[0:], id)
}
return uuid, err
}
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid.
//
// NewDCESecurity(Person, uint32(os.Getuid()))
func NewDCEPerson() (UUID, error) {
return NewDCESecurity(Person, uint32(os.Getuid()))
}
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid.
//
// NewDCESecurity(Group, uint32(os.Getgid()))
func NewDCEGroup() (UUID, error) {
return NewDCESecurity(Group, uint32(os.Getgid()))
}
// Domain returns the domain for a Version 2 UUID. Domains are only defined
// for Version 2 UUIDs.
func (uuid UUID) Domain() Domain {
return Domain(uuid[9])
}
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
// UUIDs.
func (uuid UUID) ID() uint32 {
return binary.BigEndian.Uint32(uuid[0:4])
}
func (d Domain) String() string {
switch d {
case Person:
return "Person"
case Group:
return "Group"
case Org:
return "Org"
}
return fmt.Sprintf("Domain%d", int(d))
}

12
vendor/github.com/google/uuid/doc.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package uuid generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
// maps or compared directly.
package uuid

53
vendor/github.com/google/uuid/hash.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
// Well known namespace IDs and UUIDs
var (
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
Nil UUID // empty UUID, all zeros
)
// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space[:])
h.Write(data)
s := h.Sum(nil)
var uuid UUID
copy(uuid[:], s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(md5.New(), space, data, 3)
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
}
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(sha1.New(), space, data, 5)
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved. // Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -10,7 +10,7 @@ import (
"testing" "testing"
) )
var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") var testUUID = Must(Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479"))
func TestJSON(t *testing.T) { func TestJSON(t *testing.T) {
type S struct { type S struct {
@ -35,9 +35,10 @@ func BenchmarkUUID_MarshalJSON(b *testing.B) {
x := &struct { x := &struct {
UUID UUID `json:"uuid"` UUID UUID `json:"uuid"`
}{} }{}
x.UUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") var err error
if x.UUID == nil { x.UUID, err = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
b.Fatal("invalid uuid") if err != nil {
b.Fatal(err)
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
js, err := json.Marshal(x) js, err := json.Marshal(x)

37
vendor/github.com/google/uuid/marshal.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "fmt"
// MarshalText implements encoding.TextMarshaler.
func (uuid UUID) MarshalText() ([]byte, error) {
var js [36]byte
encodeHex(js[:], uuid)
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (uuid *UUID) UnmarshalText(data []byte) error {
id, err := ParseBytes(data)
if err == nil {
*uuid = id
}
return err
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (uuid UUID) MarshalBinary() ([]byte, error) {
return uuid[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (uuid *UUID) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(uuid[:], data)
return nil
}

89
vendor/github.com/google/uuid/node.go generated vendored Normal file
View File

@ -0,0 +1,89 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"sync"
)
var (
nodeMu sync.Mutex
ifname string // name of interface being used
nodeID [6]byte // hardware for version 1 UUIDs
zeroID [6]byte // nodeID with only 0's
)
// NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
defer nodeMu.Unlock()
nodeMu.Lock()
return ifname
}
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
// If name is "" then the first usable interface found will be used or a random
// Node ID will be generated. If a named interface cannot be found then false
// is returned.
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
defer nodeMu.Unlock()
nodeMu.Lock()
return setNodeInterface(name)
}
func setNodeInterface(name string) bool {
iname, addr := getHardwareInterface(name) // null implementation for js
if iname != "" && addr != nil {
ifname = iname
copy(nodeID[:], addr)
return true
}
// We found no interfaces with a valid hardware address. If name
// does not specify a specific interface generate a random Node ID
// (section 4.1.6)
if name == "" {
randomBits(nodeID[:])
return true
}
return false
}
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
defer nodeMu.Unlock()
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nid := nodeID
return nid[:]
}
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
if len(id) < 6 {
return false
}
defer nodeMu.Unlock()
nodeMu.Lock()
copy(nodeID[:], id)
ifname = "user"
return true
}
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte {
var node [6]byte
copy(node[:], uuid[10:])
return node[:]
}

12
vendor/github.com/google/uuid/node_js.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js
package uuid
// getHardwareInterface returns nil values for the JS version of the code.
// This remvoves the "net" dependency, because it is not used in the browser.
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
func getHardwareInterface(name string) (string, []byte) { return "", nil }

33
vendor/github.com/google/uuid/node_net.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js
package uuid
import "net"
var interfaces []net.Interface // cached list of interfaces
// getHardwareInterface returns the name and hardware address of interface name.
// If name is "" then the name and hardware address of one of the system's
// interfaces is returned. If no interfaces are found (name does not exist or
// there are no interfaces) then "", nil is returned.
//
// Only addresses of at least 6 bytes are returned.
func getHardwareInterface(name string) (string, []byte) {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil {
return "", nil
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
return ifs.Name, ifs.HardwareAddr
}
}
return "", nil
}

66
vendor/github.com/google/uuid/seq_test.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"flag"
"runtime"
"testing"
"time"
)
// This test is only run when --regressions is passed on the go test line.
var regressions = flag.Bool("regressions", false, "run uuid regression tests")
// TestClockSeqRace tests for a particular race condition of returning two
// identical Version1 UUIDs. The duration of 1 minute was chosen as the race
// condition, before being fixed, nearly always occurred in under 30 seconds.
func TestClockSeqRace(t *testing.T) {
if !*regressions {
t.Skip("skipping regression tests")
}
duration := time.Minute
done := make(chan struct{})
defer close(done)
ch := make(chan UUID, 10000)
ncpu := runtime.NumCPU()
switch ncpu {
case 0, 1:
// We can't run the test effectively.
t.Skip("skipping race test, only one CPU detected")
return
default:
runtime.GOMAXPROCS(ncpu)
}
for i := 0; i < ncpu; i++ {
go func() {
for {
select {
case <-done:
return
case ch <- Must(NewUUID()):
}
}
}()
}
uuids := make(map[string]bool)
cnt := 0
start := time.Now()
for u := range ch {
s := u.String()
if uuids[s] {
t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
return
}
uuids[s] = true
if time.Since(start) > duration {
return
}
cnt++
}
}

59
vendor/github.com/google/uuid/sql.go generated vendored Normal file
View File

@ -0,0 +1,59 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"database/sql/driver"
"fmt"
)
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
switch src := src.(type) {
case nil:
return nil
case string:
// if an empty UUID comes from a table, we return a null UUID
if src == "" {
return nil
}
// see Parse for required string format
u, err := Parse(src)
if err != nil {
return fmt.Errorf("Scan: %v", err)
}
*uuid = u
case []byte:
// if an empty UUID comes from a table, we return a null UUID
if len(src) == 0 {
return nil
}
// assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse
if len(src) != 16 {
return uuid.Scan(string(src))
}
copy((*uuid)[:], src)
default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
}
return nil
}
// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
return uuid.String(), nil
}

113
vendor/github.com/google/uuid/sql_test.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"strings"
"testing"
)
func TestScan(t *testing.T) {
stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479"
badTypeTest := 6
invalidTest := "f47ac10b-58cc-0372-8567-0e02b2c3d4"
byteTest := make([]byte, 16)
byteTestUUID := Must(Parse(stringTest))
copy(byteTest, byteTestUUID[:])
// sunny day tests
var uuid UUID
err := (&uuid).Scan(stringTest)
if err != nil {
t.Fatal(err)
}
err = (&uuid).Scan([]byte(stringTest))
if err != nil {
t.Fatal(err)
}
err = (&uuid).Scan(byteTest)
if err != nil {
t.Fatal(err)
}
// bad type tests
err = (&uuid).Scan(badTypeTest)
if err == nil {
t.Error("int correctly parsed and shouldn't have")
}
if !strings.Contains(err.Error(), "unable to scan type") {
t.Error("attempting to parse an int returned an incorrect error message")
}
// invalid/incomplete uuids
err = (&uuid).Scan(invalidTest)
if err == nil {
t.Error("invalid uuid was parsed without error")
}
if !strings.Contains(err.Error(), "invalid UUID") {
t.Error("attempting to parse an invalid UUID returned an incorrect error message")
}
err = (&uuid).Scan(byteTest[:len(byteTest)-2])
if err == nil {
t.Error("invalid byte uuid was parsed without error")
}
if !strings.Contains(err.Error(), "invalid UUID") {
t.Error("attempting to parse an invalid byte UUID returned an incorrect error message")
}
// empty tests
uuid = UUID{}
var emptySlice []byte
err = (&uuid).Scan(emptySlice)
if err != nil {
t.Fatal(err)
}
for _, v := range uuid {
if v != 0 {
t.Error("UUID was not nil after scanning empty byte slice")
}
}
uuid = UUID{}
var emptyString string
err = (&uuid).Scan(emptyString)
if err != nil {
t.Fatal(err)
}
for _, v := range uuid {
if v != 0 {
t.Error("UUID was not nil after scanning empty byte slice")
}
}
uuid = UUID{}
err = (&uuid).Scan(nil)
if err != nil {
t.Fatal(err)
}
for _, v := range uuid {
if v != 0 {
t.Error("UUID was not nil after scanning nil")
}
}
}
func TestValue(t *testing.T) {
stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479"
uuid := Must(Parse(stringTest))
val, _ := uuid.Value()
if val != stringTest {
t.Error("Value() did not return expected string")
}
}

123
vendor/github.com/google/uuid/time.go generated vendored Normal file
View File

@ -0,0 +1,123 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"sync"
"time"
)
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582.
type Time int64
const (
lillian = 2299160 // Julian day of 15 Oct 1582
unix = 2440587 // Julian day of 1 Jan 1970
epoch = unix - lillian // Days between epochs
g1582 = epoch * 86400 // seconds between epochs
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
)
var (
timeMu sync.Mutex
lasttime uint64 // last time we returned
clockSeq uint16 // clock sequence for this run
timeNow = time.Now // for testing
)
// UnixTime converts t the number of seconds and nanoseconds using the Unix
// epoch of 1 Jan 1970.
func (t Time) UnixTime() (sec, nsec int64) {
sec = int64(t - g1582ns100)
nsec = (sec % 10000000) * 100
sec /= 10000000
return sec, nsec
}
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) {
defer timeMu.Unlock()
timeMu.Lock()
return getTime()
}
func getTime() (Time, uint16, error) {
t := timeNow()
// If we don't have a clock sequence already, set one.
if clockSeq == 0 {
setClockSequence(-1)
}
now := uint64(t.UnixNano()/100) + g1582ns100
// If time has gone backwards with this clock sequence then we
// increment the clock sequence
if now <= lasttime {
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
}
lasttime = now
return Time(now), clockSeq, nil
}
// ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs.
//
// The uuid package does not use global static storage for the clock sequence or
// the last time a UUID was generated. Unless SetClockSequence is used, a new
// random clock sequence is generated the first time a clock sequence is
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
func ClockSequence() int {
defer timeMu.Unlock()
timeMu.Lock()
return clockSequence()
}
func clockSequence() int {
if clockSeq == 0 {
setClockSequence(-1)
}
return int(clockSeq & 0x3fff)
}
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) {
defer timeMu.Unlock()
timeMu.Lock()
setClockSequence(seq)
}
func setClockSequence(seq int) {
if seq == -1 {
var b [2]byte
randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1])
}
oldSeq := clockSeq
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if oldSeq != clockSeq {
lasttime = 0
}
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. The time is only defined for version 1 and 2 UUIDs.
func (uuid UUID) Time() Time {
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
return Time(time)
}
// ClockSequence returns the clock sequence encoded in uuid.
// The clock sequence is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) ClockSequence() int {
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
}

43
vendor/github.com/google/uuid/util.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// randomBits completely fills slice b with random data.
func randomBits(b []byte) {
if _, err := io.ReadFull(rander, b); err != nil {
panic(err.Error()) // rand should never fail
}
}
// xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
}
// xtob converts hex characters x1 and x2 into a byte.
func xtob(x1, x2 byte) (byte, bool) {
b1 := xvalues[x1]
b2 := xvalues[x2]
return (b1 << 4) | b2, b1 != 255 && b2 != 255
}

208
vendor/github.com/google/uuid/uuid.go generated vendored Normal file
View File

@ -0,0 +1,208 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
)
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID [16]byte
// A Version represents a UUID's version.
type Version byte
// A Variant represents a UUID's variant.
type Variant byte
// Constants returned by Variant.
const (
Invalid = Variant(iota) // Invalid UUID
RFC4122 // The variant specified in RFC4122
Reserved // Reserved, NCS backward compatibility.
Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future // Reserved for future definition.
)
var rander = rand.Reader // random function
// Parse decodes s into a UUID or returns an error. Both the UUID form of
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
func Parse(s string) (UUID, error) {
var uuid UUID
if len(s) != 36 {
if len(s) != 36+9 {
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
}
if strings.ToLower(s[:9]) != "urn:uuid:" {
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
}
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
v, ok := xtob(s[x], s[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
var uuid UUID
if len(b) != 36 {
if len(b) != 36+9 {
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
}
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
}
b = b[9:]
}
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
v, ok := xtob(b[x], b[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// MustParse is like Parse but panics if the string cannot be parsed.
// It simplifies safe initialization of global variables holding compiled UUIDs.
func MustParse(s string) UUID {
uuid, err := Parse(s)
if err != nil {
panic(`uuid: Parse(` + s + `): ` + err.Error())
}
return uuid
}
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
// does not have a length of 16. The bytes are copied from the slice.
func FromBytes(b []byte) (uuid UUID, err error) {
err = uuid.UnmarshalBinary(b)
return uuid, err
}
// Must returns uuid if err is nil and panics otherwise.
func Must(uuid UUID, err error) UUID {
if err != nil {
panic(err)
}
return uuid
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
var buf [36]byte
encodeHex(buf[:], uuid)
return string(buf[:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
var buf [36 + 9]byte
copy(buf[:], "urn:uuid:")
encodeHex(buf[9:], uuid)
return string(buf[:])
}
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst, uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}
// Variant returns the variant encoded in uuid.
func (uuid UUID) Variant() Variant {
switch {
case (uuid[8] & 0xc0) == 0x80:
return RFC4122
case (uuid[8] & 0xe0) == 0xc0:
return Microsoft
case (uuid[8] & 0xe0) == 0xe0:
return Future
default:
return Reserved
}
}
// Version returns the version of uuid.
func (uuid UUID) Version() Version {
return Version(uuid[6] >> 4)
}
func (v Version) String() string {
if v > 15 {
return fmt.Sprintf("BAD_VERSION_%d", v)
}
return fmt.Sprintf("VERSION_%d", v)
}
func (v Variant) String() string {
switch v {
case RFC4122:
return "RFC4122"
case Reserved:
return "Reserved"
case Microsoft:
return "Microsoft"
case Future:
return "Future"
case Invalid:
return "Invalid"
}
return fmt.Sprintf("BadVariant%d", int(v))
}
// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
if r == nil {
rander = rand.Reader
return
}
rander = r
}

549
vendor/github.com/google/uuid/uuid_test.go generated vendored Normal file
View File

@ -0,0 +1,549 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"fmt"
"os"
"runtime"
"strings"
"testing"
"time"
"unsafe"
)
type test struct {
in string
version Version
variant Variant
isuuid bool
}
var tests = []test{
{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true},
{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true},
{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true},
{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true},
{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true},
{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true},
{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true},
{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true},
{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true},
{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true},
{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true},
{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true},
{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true},
{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true},
{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true},
{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true},
{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false},
{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false},
}
var constants = []struct {
c interface{}
name string
}{
{Person, "Person"},
{Group, "Group"},
{Org, "Org"},
{Invalid, "Invalid"},
{RFC4122, "RFC4122"},
{Reserved, "Reserved"},
{Microsoft, "Microsoft"},
{Future, "Future"},
{Domain(17), "Domain17"},
{Variant(42), "BadVariant42"},
}
func testTest(t *testing.T, in string, tt test) {
uuid, err := Parse(in)
if ok := (err == nil); ok != tt.isuuid {
t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid)
}
if err != nil {
return
}
if v := uuid.Variant(); v != tt.variant {
t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant)
}
if v := uuid.Version(); v != tt.version {
t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version)
}
}
func testBytes(t *testing.T, in []byte, tt test) {
uuid, err := ParseBytes(in)
if ok := (err == nil); ok != tt.isuuid {
t.Errorf("ParseBytes(%s) got %v expected %v\b", in, ok, tt.isuuid)
}
if err != nil {
return
}
suuid, _ := Parse(string(in))
if uuid != suuid {
t.Errorf("ParseBytes(%s) got %v expected %v\b", in, uuid, suuid)
}
}
func TestUUID(t *testing.T) {
for _, tt := range tests {
testTest(t, tt.in, tt)
testTest(t, strings.ToUpper(tt.in), tt)
testBytes(t, []byte(tt.in), tt)
}
}
func TestFromBytes(t *testing.T) {
b := []byte{
0x7d, 0x44, 0x48, 0x40,
0x9d, 0xc0,
0x11, 0xd1,
0xb2, 0x45,
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
}
uuid, err := FromBytes(b)
if err != nil {
t.Fatalf("%s", err)
}
for i := 0; i < len(uuid); i++ {
if b[i] != uuid[i] {
t.Fatalf("FromBytes() got %v expected %v\b", uuid[:], b)
}
}
}
func TestConstants(t *testing.T) {
for x, tt := range constants {
v, ok := tt.c.(fmt.Stringer)
if !ok {
t.Errorf("%x: %v: not a stringer", x, v)
} else if s := v.String(); s != tt.name {
v, _ := tt.c.(int)
t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name)
}
}
}
func TestRandomUUID(t *testing.T) {
m := make(map[string]bool)
for x := 1; x < 32; x++ {
uuid := New()
s := uuid.String()
if m[s] {
t.Errorf("NewRandom returned duplicated UUID %s", s)
}
m[s] = true
if v := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d", uuid.Variant())
}
}
}
func TestNew(t *testing.T) {
m := make(map[UUID]bool)
for x := 1; x < 32; x++ {
s := New()
if m[s] {
t.Errorf("New returned duplicated UUID %s", s)
}
m[s] = true
uuid, err := Parse(s.String())
if err != nil {
t.Errorf("New.String() returned %q which does not decode", s)
continue
}
if v := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d", uuid.Variant())
}
}
}
func TestClockSeq(t *testing.T) {
// Fake time.Now for this test to return a monotonically advancing time; restore it at end.
defer func(orig func() time.Time) { timeNow = orig }(timeNow)
monTime := time.Now()
timeNow = func() time.Time {
monTime = monTime.Add(1 * time.Second)
return monTime
}
SetClockSequence(-1)
uuid1, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
uuid2, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 != s2 {
t.Errorf("clock sequence %d != %d", s1, s2)
}
SetClockSequence(-1)
uuid2, err = NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
// Just on the very off chance we generated the same sequence
// two times we try again.
if uuid1.ClockSequence() == uuid2.ClockSequence() {
SetClockSequence(-1)
uuid2, err = NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
}
if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 == s2 {
t.Errorf("Duplicate clock sequence %d", s1)
}
SetClockSequence(0x1234)
uuid1, err = NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
if seq := uuid1.ClockSequence(); seq != 0x1234 {
t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq)
}
}
func TestCoding(t *testing.T) {
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
data := UUID{
0x7d, 0x44, 0x48, 0x40,
0x9d, 0xc0,
0x11, 0xd1,
0xb2, 0x45,
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
}
if v := data.String(); v != text {
t.Errorf("%x: encoded to %s, expected %s", data, v, text)
}
if v := data.URN(); v != urn {
t.Errorf("%x: urn is %s, expected %s", data, v, urn)
}
uuid, err := Parse(text)
if err != nil {
t.Errorf("Parse returned unexpected error %v", err)
}
if data != uuid {
t.Errorf("%s: decoded to %s, expected %s", text, uuid, data)
}
}
func TestVersion1(t *testing.T) {
uuid1, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
uuid2, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
if uuid1 == uuid2 {
t.Errorf("%s:duplicate uuid", uuid1)
}
if v := uuid1.Version(); v != 1 {
t.Errorf("%s: version %s expected 1", uuid1, v)
}
if v := uuid2.Version(); v != 1 {
t.Errorf("%s: version %s expected 1", uuid2, v)
}
n1 := uuid1.NodeID()
n2 := uuid2.NodeID()
if !bytes.Equal(n1, n2) {
t.Errorf("Different nodes %x != %x", n1, n2)
}
t1 := uuid1.Time()
t2 := uuid2.Time()
q1 := uuid1.ClockSequence()
q2 := uuid2.ClockSequence()
switch {
case t1 == t2 && q1 == q2:
t.Error("time stopped")
case t1 > t2 && q1 == q2:
t.Error("time reversed")
case t1 < t2 && q1 != q2:
t.Error("clock sequence changed unexpectedly")
}
}
func TestNode(t *testing.T) {
// This test is mostly to make sure we don't leave nodeMu locked.
ifname = ""
if ni := NodeInterface(); ni != "" {
t.Errorf("NodeInterface got %q, want %q", ni, "")
}
if SetNodeInterface("xyzzy") {
t.Error("SetNodeInterface succeeded on a bad interface name")
}
if !SetNodeInterface("") {
t.Error("SetNodeInterface failed")
}
if runtime.GOARCH != "js" {
if ni := NodeInterface(); ni == "" {
t.Error("NodeInterface returned an empty string")
}
}
ni := NodeID()
if len(ni) != 6 {
t.Errorf("ni got %d bytes, want 6", len(ni))
}
hasData := false
for _, b := range ni {
if b != 0 {
hasData = true
}
}
if !hasData {
t.Error("nodeid is all zeros")
}
id := []byte{1, 2, 3, 4, 5, 6, 7, 8}
SetNodeID(id)
ni = NodeID()
if !bytes.Equal(ni, id[:6]) {
t.Errorf("got nodeid %v, want %v", ni, id[:6])
}
if ni := NodeInterface(); ni != "user" {
t.Errorf("got interface %q, want %q", ni, "user")
}
}
func TestNodeAndTime(t *testing.T) {
// Time is February 5, 1998 12:30:23.136364800 AM GMT
uuid, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2")
if err != nil {
t.Fatalf("Parser returned unexpected error %v", err)
}
node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2}
ts := uuid.Time()
c := time.Unix(ts.UnixTime())
want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC)
if !c.Equal(want) {
t.Errorf("Got time %v, want %v", c, want)
}
if !bytes.Equal(node, uuid.NodeID()) {
t.Errorf("Expected node %v got %v", node, uuid.NodeID())
}
}
func TestMD5(t *testing.T) {
uuid := NewMD5(NameSpaceDNS, []byte("python.org")).String()
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
if uuid != want {
t.Errorf("MD5: got %q expected %q", uuid, want)
}
}
func TestSHA1(t *testing.T) {
uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String()
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
if uuid != want {
t.Errorf("SHA1: got %q expected %q", uuid, want)
}
}
func TestNodeID(t *testing.T) {
nid := []byte{1, 2, 3, 4, 5, 6}
SetNodeInterface("")
s := NodeInterface()
if runtime.GOARCH != "js" {
if s == "" || s == "user" {
t.Errorf("NodeInterface %q after SetInterface", s)
}
}
node1 := NodeID()
if node1 == nil {
t.Error("NodeID nil after SetNodeInterface", s)
}
SetNodeID(nid)
s = NodeInterface()
if s != "user" {
t.Errorf("Expected NodeInterface %q got %q", "user", s)
}
node2 := NodeID()
if node2 == nil {
t.Error("NodeID nil after SetNodeID", s)
}
if bytes.Equal(node1, node2) {
t.Error("NodeID not changed after SetNodeID", s)
} else if !bytes.Equal(nid, node2) {
t.Errorf("NodeID is %x, expected %x", node2, nid)
}
}
func testDCE(t *testing.T, name string, uuid UUID, err error, domain Domain, id uint32) {
if err != nil {
t.Errorf("%s failed: %v", name, err)
return
}
if v := uuid.Version(); v != 2 {
t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v)
return
}
if v := uuid.Domain(); v != domain {
t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v)
}
if v := uuid.ID(); v != id {
t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v)
}
}
func TestDCE(t *testing.T) {
uuid, err := NewDCESecurity(42, 12345678)
testDCE(t, "NewDCESecurity", uuid, err, 42, 12345678)
uuid, err = NewDCEPerson()
testDCE(t, "NewDCEPerson", uuid, err, Person, uint32(os.Getuid()))
uuid, err = NewDCEGroup()
testDCE(t, "NewDCEGroup", uuid, err, Group, uint32(os.Getgid()))
}
type badRand struct{}
func (r badRand) Read(buf []byte) (int, error) {
for i := range buf {
buf[i] = byte(i)
}
return len(buf), nil
}
func TestBadRand(t *testing.T) {
SetRand(badRand{})
uuid1 := New()
uuid2 := New()
if uuid1 != uuid2 {
t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2)
}
SetRand(nil)
uuid1 = New()
uuid2 = New()
if uuid1 == uuid2 {
t.Errorf("unexpected duplicates, got %q", uuid1)
}
}
var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
var asBytes = []byte(asString)
func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := Parse(asString)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkParseBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := ParseBytes(asBytes)
if err != nil {
b.Fatal(err)
}
}
}
// parseBytesUnsafe is to benchmark using unsafe.
func parseBytesUnsafe(b []byte) (UUID, error) {
return Parse(*(*string)(unsafe.Pointer(&b)))
}
func BenchmarkParseBytesUnsafe(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := parseBytesUnsafe(asBytes)
if err != nil {
b.Fatal(err)
}
}
}
// parseBytesCopy is to benchmark not using unsafe.
func parseBytesCopy(b []byte) (UUID, error) {
return Parse(string(b))
}
func BenchmarkParseBytesCopy(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := parseBytesCopy(asBytes)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkNew(b *testing.B) {
for i := 0; i < b.N; i++ {
New()
}
}
func BenchmarkUUID_String(b *testing.B) {
uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
if uuid.String() == "" {
b.Fatal("invalid uuid")
}
}
}
func BenchmarkUUID_URN(b *testing.B) {
uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
if uuid.URN() == "" {
b.Fatal("invalid uuid")
}
}
}

44
vendor/github.com/google/uuid/version1.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
)
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil and an error.
//
// In most cases, New should be used.
func NewUUID() (UUID, error) {
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nodeMu.Unlock()
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
timeLow := uint32(now & 0xffffffff)
timeMid := uint16((now >> 32) & 0xffff)
timeHi := uint16((now >> 48) & 0x0fff)
timeHi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], timeLow)
binary.BigEndian.PutUint16(uuid[4:], timeMid)
binary.BigEndian.PutUint16(uuid[6:], timeHi)
binary.BigEndian.PutUint16(uuid[8:], seq)
copy(uuid[10:], nodeID[:])
return uuid, nil
}

38
vendor/github.com/google/uuid/version4.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "io"
// New creates a new random UUID or panics. New is equivalent to
// the expression
//
// uuid.Must(uuid.NewRandom())
func New() UUID {
return Must(NewRandom())
}
// NewRandom returns a Random (Version 4) UUID.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() (UUID, error) {
var uuid UUID
_, err := io.ReadFull(rander, uuid[:])
if err != nil {
return Nil, err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}

View File

@ -1 +1,2 @@
coverage.out coverage.out
.idea/

View File

@ -1,4 +1,4 @@
## null [![GoDoc](https://godoc.org/github.com/guregu/null?status.svg)](https://godoc.org/github.com/guregu/null) [![Coverage](http://gocover.io/_badge/github.com/guregu/null)](http://gocover.io/github.com/guregu/null) ## null [![GoDoc](https://godoc.org/github.com/guregu/null?status.svg)](https://godoc.org/github.com/guregu/null) [![CircleCI](https://circleci.com/gh/guregu/null.svg?style=svg)](https://circleci.com/gh/guregu/null)
`import "gopkg.in/guregu/null.v3"` `import "gopkg.in/guregu/null.v3"`
null is a library with reasonable options for dealing with nullable SQL and JSON values null is a library with reasonable options for dealing with nullable SQL and JSON values
@ -69,7 +69,7 @@ Will marshal to the zero time if null. Uses `time.Time`'s marshaler. Can unmarsh
### Bugs ### Bugs
`json`'s `",omitempty"` struct tag does not work correctly right now. It will never omit a null or empty String. This might be [fixed eventually](https://github.com/golang/go/issues/4357). `json`'s `",omitempty"` struct tag does not work correctly right now. It will never omit a null or empty String. This might be [fixed eventually](https://github.com/golang/go/issues/11939).
### License ### License
BSD BSD

View File

@ -38,6 +38,11 @@ func BoolFromPtr(b *bool) Bool {
return NewBool(*b, true) return NewBool(*b, true)
} }
// ValueOrZero returns the inner value if valid, otherwise false.
func (b Bool) ValueOrZero() bool {
return b.Valid && b.Bool
}
// UnmarshalJSON implements json.Unmarshaler. // UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input. // It supports number and null input.
// 0 will not be considered a null Bool. // 0 will not be considered a null Bool.

View File

@ -176,6 +176,18 @@ func TestBoolScan(t *testing.T) {
assertNullBool(t, null, "scanned null") assertNullBool(t, null, "scanned null")
} }
func TestBoolValueOrZero(t *testing.T) {
valid := NewBool(true, true)
if valid.ValueOrZero() != true {
t.Error("unexpected ValueOrZero", valid.ValueOrZero())
}
invalid := NewBool(true, false)
if invalid.ValueOrZero() != false {
t.Error("unexpected ValueOrZero", invalid.ValueOrZero())
}
}
func assertBool(t *testing.T, b Bool, from string) { func assertBool(t *testing.T, b Bool, from string) {
if b.Bool != true { if b.Bool != true {
t.Errorf("bad %s bool: %v ≠ %v\n", from, b.Bool, true) t.Errorf("bad %s bool: %v ≠ %v\n", from, b.Bool, true)

View File

@ -4,6 +4,7 @@ import (
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math"
"reflect" "reflect"
"strconv" "strconv"
) )
@ -38,6 +39,14 @@ func FloatFromPtr(f *float64) Float {
return NewFloat(*f, true) return NewFloat(*f, true)
} }
// ValueOrZero returns the inner value if valid, otherwise zero.
func (f Float) ValueOrZero() float64 {
if !f.Valid {
return 0
}
return f.Float64
}
// UnmarshalJSON implements json.Unmarshaler. // UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input. // It supports number and null input.
// 0 will not be considered a null Float. // 0 will not be considered a null Float.
@ -51,6 +60,13 @@ func (f *Float) UnmarshalJSON(data []byte) error {
switch x := v.(type) { switch x := v.(type) {
case float64: case float64:
f.Float64 = float64(x) f.Float64 = float64(x)
case string:
str := string(x)
if len(str) == 0 {
f.Valid = false
return nil
}
f.Float64, err = strconv.ParseFloat(str, 64)
case map[string]interface{}: case map[string]interface{}:
err = json.Unmarshal(data, &f.NullFloat64) err = json.Unmarshal(data, &f.NullFloat64)
case nil: case nil:
@ -84,6 +100,12 @@ func (f Float) MarshalJSON() ([]byte, error) {
if !f.Valid { if !f.Valid {
return []byte("null"), nil return []byte("null"), nil
} }
if math.IsInf(f.Float64, 0) || math.IsNaN(f.Float64) {
return nil, &json.UnsupportedValueError{
Value: reflect.ValueOf(f.Float64),
Str: strconv.FormatFloat(f.Float64, 'g', -1, 64),
}
}
return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil
} }

View File

@ -2,12 +2,15 @@ package null
import ( import (
"encoding/json" "encoding/json"
"math"
"testing" "testing"
) )
var ( var (
floatJSON = []byte(`1.2345`) floatJSON = []byte(`1.2345`)
nullFloatJSON = []byte(`{"Float64":1.2345,"Valid":true}`) floatStringJSON = []byte(`"1.2345"`)
floatBlankJSON = []byte(`""`)
nullFloatJSON = []byte(`{"Float64":1.2345,"Valid":true}`)
) )
func TestFloatFrom(t *testing.T) { func TestFloatFrom(t *testing.T) {
@ -36,16 +39,26 @@ func TestUnmarshalFloat(t *testing.T) {
maybePanic(err) maybePanic(err)
assertFloat(t, f, "float json") assertFloat(t, f, "float json")
var sf Float
err = json.Unmarshal(floatStringJSON, &sf)
maybePanic(err)
assertFloat(t, sf, "string float json")
var nf Float var nf Float
err = json.Unmarshal(nullFloatJSON, &nf) err = json.Unmarshal(nullFloatJSON, &nf)
maybePanic(err) maybePanic(err)
assertFloat(t, nf, "sq.NullFloat64 json") assertFloat(t, nf, "sql.NullFloat64 json")
var null Float var null Float
err = json.Unmarshal(nullJSON, &null) err = json.Unmarshal(nullJSON, &null)
maybePanic(err) maybePanic(err)
assertNullFloat(t, null, "null json") assertNullFloat(t, null, "null json")
var blank Float
err = json.Unmarshal(floatBlankJSON, &blank)
maybePanic(err)
assertNullFloat(t, blank, "null blank string json")
var badType Float var badType Float
err = json.Unmarshal(boolJSON, &badType) err = json.Unmarshal(boolJSON, &badType)
if err == nil { if err == nil {
@ -147,12 +160,43 @@ func TestFloatScan(t *testing.T) {
maybePanic(err) maybePanic(err)
assertFloat(t, f, "scanned float") assertFloat(t, f, "scanned float")
var sf Float
err = sf.Scan("1.2345")
maybePanic(err)
assertFloat(t, sf, "scanned string float")
var null Float var null Float
err = null.Scan(nil) err = null.Scan(nil)
maybePanic(err) maybePanic(err)
assertNullFloat(t, null, "scanned null") assertNullFloat(t, null, "scanned null")
} }
func TestFloatInfNaN(t *testing.T) {
nan := NewFloat(math.NaN(), true)
_, err := nan.MarshalJSON()
if err == nil {
t.Error("expected error for NaN, got nil")
}
inf := NewFloat(math.Inf(1), true)
_, err = inf.MarshalJSON()
if err == nil {
t.Error("expected error for Inf, got nil")
}
}
func TestFloatValueOrZero(t *testing.T) {
valid := NewFloat(1.2345, true)
if valid.ValueOrZero() != 1.2345 {
t.Error("unexpected ValueOrZero", valid.ValueOrZero())
}
invalid := NewFloat(1.2345, false)
if invalid.ValueOrZero() != 0 {
t.Error("unexpected ValueOrZero", invalid.ValueOrZero())
}
}
func assertFloat(t *testing.T, f Float, from string) { func assertFloat(t *testing.T, f Float, from string) {
if f.Float64 != 1.2345 { if f.Float64 != 1.2345 {
t.Errorf("bad %s float: %f ≠ %f\n", from, f.Float64, 1.2345) t.Errorf("bad %s float: %f ≠ %f\n", from, f.Float64, 1.2345)

17
vendor/github.com/guregu/null/int.go generated vendored
View File

@ -38,6 +38,14 @@ func IntFromPtr(i *int64) Int {
return NewInt(*i, true) return NewInt(*i, true)
} }
// ValueOrZero returns the inner value if valid, otherwise zero.
func (i Int) ValueOrZero() int64 {
if !i.Valid {
return 0
}
return i.Int64
}
// UnmarshalJSON implements json.Unmarshaler. // UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input. // It supports number and null input.
// 0 will not be considered a null Int. // 0 will not be considered a null Int.
@ -48,10 +56,17 @@ func (i *Int) UnmarshalJSON(data []byte) error {
if err = json.Unmarshal(data, &v); err != nil { if err = json.Unmarshal(data, &v); err != nil {
return err return err
} }
switch v.(type) { switch x := v.(type) {
case float64: case float64:
// Unmarshal again, directly to int64, to avoid intermediate float64 // Unmarshal again, directly to int64, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int64) err = json.Unmarshal(data, &i.Int64)
case string:
str := string(x)
if len(str) == 0 {
i.Valid = false
return nil
}
i.Int64, err = strconv.ParseInt(str, 10, 64)
case map[string]interface{}: case map[string]interface{}:
err = json.Unmarshal(data, &i.NullInt64) err = json.Unmarshal(data, &i.NullInt64)
case nil: case nil:

View File

@ -8,8 +8,9 @@ import (
) )
var ( var (
intJSON = []byte(`12345`) intJSON = []byte(`12345`)
nullIntJSON = []byte(`{"Int64":12345,"Valid":true}`) intStringJSON = []byte(`"12345"`)
nullIntJSON = []byte(`{"Int64":12345,"Valid":true}`)
) )
func TestIntFrom(t *testing.T) { func TestIntFrom(t *testing.T) {
@ -38,10 +39,20 @@ func TestUnmarshalInt(t *testing.T) {
maybePanic(err) maybePanic(err)
assertInt(t, i, "int json") assertInt(t, i, "int json")
var si Int
err = json.Unmarshal(intStringJSON, &si)
maybePanic(err)
assertInt(t, si, "int string json")
var ni Int var ni Int
err = json.Unmarshal(nullIntJSON, &ni) err = json.Unmarshal(nullIntJSON, &ni)
maybePanic(err) maybePanic(err)
assertInt(t, ni, "sq.NullInt64 json") assertInt(t, ni, "sql.NullInt64 json")
var bi Int
err = json.Unmarshal(floatBlankJSON, &bi)
maybePanic(err)
assertNullInt(t, bi, "blank json string")
var null Int var null Int
err = json.Unmarshal(nullJSON, &null) err = json.Unmarshal(nullJSON, &null)
@ -180,6 +191,18 @@ func TestIntScan(t *testing.T) {
assertNullInt(t, null, "scanned null") assertNullInt(t, null, "scanned null")
} }
func TestIntValueOrZero(t *testing.T) {
valid := NewInt(12345, true)
if valid.ValueOrZero() != 12345 {
t.Error("unexpected ValueOrZero", valid.ValueOrZero())
}
invalid := NewInt(12345, false)
if invalid.ValueOrZero() != 0 {
t.Error("unexpected ValueOrZero", invalid.ValueOrZero())
}
}
func assertInt(t *testing.T, i Int, from string) { func assertInt(t *testing.T, i Int, from string) {
if i.Int64 != 12345 { if i.Int64 != 12345 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Int64, 12345) t.Errorf("bad %s int: %d ≠ %d\n", from, i.Int64, 12345)

View File

@ -30,6 +30,14 @@ func StringFromPtr(s *string) String {
return NewString(*s, true) return NewString(*s, true)
} }
// ValueOrZero returns the inner value if valid, otherwise zero.
func (s String) ValueOrZero() string {
if !s.Valid {
return ""
}
return s.String
}
// NewString creates a new String // NewString creates a new String
func NewString(s string, valid bool) String { func NewString(s string, valid bool) String {
return String{ return String{

View File

@ -178,6 +178,18 @@ func TestStringScan(t *testing.T) {
assertNullStr(t, null, "scanned null") assertNullStr(t, null, "scanned null")
} }
func TestStringValueOrZero(t *testing.T) {
valid := NewString("test", true)
if valid.ValueOrZero() != "test" {
t.Error("unexpected ValueOrZero", valid.ValueOrZero())
}
invalid := NewString("test", false)
if invalid.ValueOrZero() != "" {
t.Error("unexpected ValueOrZero", invalid.ValueOrZero())
}
}
func maybePanic(err error) { func maybePanic(err error) {
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -60,6 +60,14 @@ func TimeFromPtr(t *time.Time) Time {
return NewTime(*t, true) return NewTime(*t, true)
} }
// ValueOrZero returns the inner value if valid, otherwise zero.
func (t Time) ValueOrZero() time.Time {
if !t.Valid {
return time.Time{}
}
return t.Time
}
// MarshalJSON implements json.Marshaler. // MarshalJSON implements json.Marshaler.
// It will encode null if this time is null. // It will encode null if this time is null.
func (t Time) MarshalJSON() ([]byte, error) { func (t Time) MarshalJSON() ([]byte, error) {
@ -133,3 +141,9 @@ func (t Time) Ptr() *time.Time {
} }
return &t.Time return &t.Time
} }
// IsZero returns true for invalid Times, hopefully for future omitempty support.
// A non-null Time with a zero value will not be considered zero.
func (t Time) IsZero() bool {
return !t.Valid
}

View File

@ -159,6 +159,36 @@ func TestTimeScanValue(t *testing.T) {
assertNullTime(t, wrong, "scanned wrong") assertNullTime(t, wrong, "scanned wrong")
} }
func TestTimeValueOrZero(t *testing.T) {
valid := TimeFrom(timeValue)
if valid.ValueOrZero() != valid.Time || valid.ValueOrZero().IsZero() {
t.Error("unexpected ValueOrZero", valid.ValueOrZero())
}
invalid := valid
invalid.Valid = false
if !invalid.ValueOrZero().IsZero() {
t.Error("unexpected ValueOrZero", invalid.ValueOrZero())
}
}
func TestTimeIsZero(t *testing.T) {
str := TimeFrom(timeValue)
if str.IsZero() {
t.Errorf("IsZero() should be false")
}
zero := TimeFrom(time.Time{})
if zero.IsZero() {
t.Errorf("IsZero() should be false")
}
null := TimeFromPtr(nil)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func assertTime(t *testing.T, ti Time, from string) { func assertTime(t *testing.T, ti Time, from string) {
if ti.Time != timeValue { if ti.Time != timeValue {
t.Errorf("bad %v time: %v ≠ %v\n", from, ti.Time, timeValue) t.Errorf("bad %v time: %v ≠ %v\n", from, ti.Time, timeValue)

View File

@ -173,7 +173,7 @@ func TestBoolScan(t *testing.T) {
func assertBool(t *testing.T, b Bool, from string) { func assertBool(t *testing.T, b Bool, from string) {
if b.Bool != true { if b.Bool != true {
t.Errorf("bad %s bool: %d ≠ %v\n", from, b.Bool, true) t.Errorf("bad %s bool: %v ≠ %v\n", from, b.Bool, true)
} }
if !b.Valid { if !b.Valid {
t.Error(from, "is invalid, but should be valid") t.Error(from, "is invalid, but should be valid")

View File

@ -4,6 +4,7 @@ import (
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math"
"reflect" "reflect"
"strconv" "strconv"
) )
@ -51,6 +52,13 @@ func (f *Float) UnmarshalJSON(data []byte) error {
switch x := v.(type) { switch x := v.(type) {
case float64: case float64:
f.Float64 = x f.Float64 = x
case string:
str := string(x)
if len(str) == 0 {
f.Valid = false
return nil
}
f.Float64, err = strconv.ParseFloat(str, 64)
case map[string]interface{}: case map[string]interface{}:
err = json.Unmarshal(data, &f.NullFloat64) err = json.Unmarshal(data, &f.NullFloat64)
case nil: case nil:
@ -85,6 +93,12 @@ func (f Float) MarshalJSON() ([]byte, error) {
if !f.Valid { if !f.Valid {
n = 0 n = 0
} }
if math.IsInf(f.Float64, 0) || math.IsNaN(f.Float64) {
return nil, &json.UnsupportedValueError{
Value: reflect.ValueOf(f.Float64),
Str: strconv.FormatFloat(f.Float64, 'g', -1, 64),
}
}
return []byte(strconv.FormatFloat(n, 'f', -1, 64)), nil return []byte(strconv.FormatFloat(n, 'f', -1, 64)), nil
} }

View File

@ -2,12 +2,15 @@ package zero
import ( import (
"encoding/json" "encoding/json"
"math"
"testing" "testing"
) )
var ( var (
floatJSON = []byte(`1.2345`) floatJSON = []byte(`1.2345`)
nullFloatJSON = []byte(`{"Float64":1.2345,"Valid":true}`) floatStringJSON = []byte(`"1.2345"`)
floatBlankJSON = []byte(`""`)
nullFloatJSON = []byte(`{"Float64":1.2345,"Valid":true}`)
) )
func TestFloatFrom(t *testing.T) { func TestFloatFrom(t *testing.T) {
@ -36,11 +39,21 @@ func TestUnmarshalFloat(t *testing.T) {
maybePanic(err) maybePanic(err)
assertFloat(t, f, "float json") assertFloat(t, f, "float json")
var sf Float
err = json.Unmarshal(floatStringJSON, &sf)
maybePanic(err)
assertFloat(t, sf, "string float json")
var nf Float var nf Float
err = json.Unmarshal(nullFloatJSON, &nf) err = json.Unmarshal(nullFloatJSON, &nf)
maybePanic(err) maybePanic(err)
assertFloat(t, nf, "sql.NullFloat64 json") assertFloat(t, nf, "sql.NullFloat64 json")
var blank Float
err = json.Unmarshal(floatBlankJSON, &blank)
maybePanic(err)
assertNullFloat(t, blank, "null blank string json")
var zero Float var zero Float
err = json.Unmarshal(zeroJSON, &zero) err = json.Unmarshal(zeroJSON, &zero)
maybePanic(err) maybePanic(err)
@ -164,6 +177,20 @@ func TestFloatScan(t *testing.T) {
assertNullFloat(t, null, "scanned null") assertNullFloat(t, null, "scanned null")
} }
func TestFloatInfNaN(t *testing.T) {
nan := NewFloat(math.NaN(), true)
_, err := nan.MarshalJSON()
if err == nil {
t.Error("expected error for NaN, got nil")
}
inf := NewFloat(math.Inf(1), true)
_, err = inf.MarshalJSON()
if err == nil {
t.Error("expected error for Inf, got nil")
}
}
func assertFloat(t *testing.T, f Float, from string) { func assertFloat(t *testing.T, f Float, from string) {
if f.Float64 != 1.2345 { if f.Float64 != 1.2345 {
t.Errorf("bad %s float: %f ≠ %f\n", from, f.Float64, 1.2345) t.Errorf("bad %s float: %f ≠ %f\n", from, f.Float64, 1.2345)

View File

@ -49,10 +49,17 @@ func (i *Int) UnmarshalJSON(data []byte) error {
if err = json.Unmarshal(data, &v); err != nil { if err = json.Unmarshal(data, &v); err != nil {
return err return err
} }
switch v.(type) { switch x := v.(type) {
case float64: case float64:
// Unmarshal again, directly to int64, to avoid intermediate float64 // Unmarshal again, directly to int64, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int64) err = json.Unmarshal(data, &i.Int64)
case string:
str := string(x)
if len(str) == 0 {
i.Valid = false
return nil
}
i.Int64, err = strconv.ParseInt(str, 10, 64)
case map[string]interface{}: case map[string]interface{}:
err = json.Unmarshal(data, &i.NullInt64) err = json.Unmarshal(data, &i.NullInt64)
case nil: case nil:

View File

@ -8,9 +8,10 @@ import (
) )
var ( var (
intJSON = []byte(`12345`) intJSON = []byte(`12345`)
nullIntJSON = []byte(`{"Int64":12345,"Valid":true}`) intStringJSON = []byte(`"12345"`)
zeroJSON = []byte(`0`) nullIntJSON = []byte(`{"Int64":12345,"Valid":true}`)
zeroJSON = []byte(`0`)
) )
func TestIntFrom(t *testing.T) { func TestIntFrom(t *testing.T) {
@ -39,11 +40,21 @@ func TestUnmarshalInt(t *testing.T) {
maybePanic(err) maybePanic(err)
assertInt(t, i, "int json") assertInt(t, i, "int json")
var si Int
err = json.Unmarshal(intStringJSON, &si)
maybePanic(err)
assertInt(t, si, "int string json")
var ni Int var ni Int
err = json.Unmarshal(nullIntJSON, &ni) err = json.Unmarshal(nullIntJSON, &ni)
maybePanic(err) maybePanic(err)
assertInt(t, ni, "sql.NullInt64 json") assertInt(t, ni, "sql.NullInt64 json")
var bi Int
err = json.Unmarshal(floatBlankJSON, &bi)
maybePanic(err)
assertNullInt(t, bi, "blank json string")
var zero Int var zero Int
err = json.Unmarshal(zeroJSON, &zero) err = json.Unmarshal(zeroJSON, &zero)
maybePanic(err) maybePanic(err)

View File

@ -143,3 +143,8 @@ func (t Time) Ptr() *time.Time {
} }
return &t.Time return &t.Time
} }
// IsZero returns true for null or zero Times, for potential future omitempty support.
func (t Time) IsZero() bool {
return !t.Valid || t.Time.IsZero()
}

View File

@ -193,6 +193,23 @@ func TestTimeValue(t *testing.T) {
} }
} }
func TestTimeIsZero(t *testing.T) {
str := TimeFrom(timeValue)
if str.IsZero() {
t.Errorf("IsZero() should be false")
}
zero := TimeFrom(time.Time{})
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
null := TimeFromPtr(nil)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func assertTime(t *testing.T, ti Time, from string) { func assertTime(t *testing.T, ti Time, from string) {
if ti.Time != timeValue { if ti.Time != timeValue {
t.Errorf("bad %v time: %v ≠ %v\n", from, ti.Time, timeValue) t.Errorf("bad %v time: %v ≠ %v\n", from, ti.Time, timeValue)

View File

@ -1,9 +1,9 @@
language: go language: go
go: go:
- 1.4.3 - "1.9"
- 1.5.3 - "1.10"
- release - "1.11"
- tip - tip
script: script:

10
vendor/github.com/pborman/uuid/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,10 @@
# How to contribute
We definitely welcome patches and contribution to this project!
### Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
You may have already signed it for other Google projects.

View File

@ -1,7 +1,9 @@
This project was automatically exported from code.google.com/p/go-uuid This project was automatically exported from code.google.com/p/go-uuid
# uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master) # uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master)
The uuid package generates and inspects UUIDs based on [RFC 412](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services. The uuid package generates and inspects UUIDs based on [RFC 4122](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services.
This package now leverages the github.com/google/uuid package (which is based off an earlier version of this package).
###### Install ###### Install
`go get github.com/pborman/uuid` `go get github.com/pborman/uuid`

0
vendor/github.com/pborman/uuid/dce.go generated vendored Executable file → Normal file
View File

7
vendor/github.com/pborman/uuid/doc.go generated vendored Executable file → Normal file
View File

@ -4,5 +4,10 @@
// The uuid package generates and inspects UUIDs. // The uuid package generates and inspects UUIDs.
// //
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services. // UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// This package is a partial wrapper around the github.com/google/uuid package.
// This package represents a UUID as []byte while github.com/google/uuid
// represents a UUID as [16]byte.
package uuid package uuid

View File

@ -1,34 +0,0 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "errors"
func (u UUID) MarshalJSON() ([]byte, error) {
if len(u) != 16 {
return []byte(`""`), nil
}
var js [38]byte
js[0] = '"'
encodeHex(js[1:], u)
js[37] = '"'
return js[:], nil
}
func (u *UUID) UnmarshalJSON(data []byte) error {
if string(data) == `""` {
return nil
}
if data[0] != '"' {
return errors.New("invalid UUID format")
}
data = data[1 : len(data)-1]
uu := Parse(string(data))
if uu == nil {
return errors.New("invalid UUID format")
}
*u = uu
return nil
}

85
vendor/github.com/pborman/uuid/marshal.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"errors"
"fmt"
guuid "github.com/google/uuid"
)
// MarshalText implements encoding.TextMarshaler.
func (u UUID) MarshalText() ([]byte, error) {
if len(u) != 16 {
return nil, nil
}
var js [36]byte
encodeHex(js[:], u)
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (u *UUID) UnmarshalText(data []byte) error {
if len(data) == 0 {
return nil
}
id := Parse(string(data))
if id == nil {
return errors.New("invalid UUID")
}
*u = id
return nil
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (u UUID) MarshalBinary() ([]byte, error) {
return u[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (u *UUID) UnmarshalBinary(data []byte) error {
if len(data) == 0 {
return nil
}
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
var id [16]byte
copy(id[:], data)
*u = id[:]
return nil
}
// MarshalText implements encoding.TextMarshaler.
func (u Array) MarshalText() ([]byte, error) {
var js [36]byte
encodeHex(js[:], u[:])
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (u *Array) UnmarshalText(data []byte) error {
id, err := guuid.ParseBytes(data)
if err != nil {
return err
}
*u = Array(id)
return nil
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (u Array) MarshalBinary() ([]byte, error) {
return u[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (u *Array) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(u[:], data)
return nil
}

124
vendor/github.com/pborman/uuid/marshal_test.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"encoding/json"
"reflect"
"testing"
)
var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
var testArray = testUUID.Array()
func TestJSON(t *testing.T) {
type S struct {
ID1 UUID
ID2 UUID
}
s1 := S{ID1: testUUID}
data, err := json.Marshal(&s1)
if err != nil {
t.Fatal(err)
}
var s2 S
if err := json.Unmarshal(data, &s2); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&s1, &s2) {
t.Errorf("got %#v, want %#v", s2, s1)
}
}
func TestJSONArray(t *testing.T) {
type S struct {
ID1 Array
ID2 Array
}
s1 := S{ID1: testArray}
data, err := json.Marshal(&s1)
if err != nil {
t.Fatal(err)
}
var s2 S
if err := json.Unmarshal(data, &s2); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&s1, &s2) {
t.Errorf("got %#v, want %#v", s2, s1)
}
}
func TestMarshal(t *testing.T) {
data, err := testUUID.MarshalBinary()
if err != nil {
t.Fatalf("MarhsalBinary returned unexpected error %v", err)
}
if !bytes.Equal(data, testUUID) {
t.Fatalf("MarhsalBinary returns %x, want %x", data, testUUID)
}
var u UUID
u.UnmarshalBinary(data)
if !Equal(data, u) {
t.Fatalf("UnmarhsalBinary returns %v, want %v", u, testUUID)
}
}
func TestMarshalArray(t *testing.T) {
data, err := testArray.MarshalBinary()
if err != nil {
t.Fatalf("MarhsalBinary returned unexpected error %v", err)
}
if !bytes.Equal(data, testUUID) {
t.Fatalf("MarhsalBinary returns %x, want %x", data, testUUID)
}
var a Array
a.UnmarshalBinary(data)
if a != testArray {
t.Fatalf("UnmarhsalBinary returns %v, want %v", a, testArray)
}
}
func TestMarshalTextArray(t *testing.T) {
data, err := testArray.MarshalText()
if err != nil {
t.Fatalf("MarhsalText returned unexpected error %v", err)
}
var a Array
a.UnmarshalText(data)
if a != testArray {
t.Fatalf("UnmarhsalText returns %v, want %v", a, testArray)
}
}
func BenchmarkUUID_MarshalJSON(b *testing.B) {
x := &struct {
UUID UUID `json:"uuid"`
}{}
x.UUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if x.UUID == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
js, err := json.Marshal(x)
if err != nil {
b.Fatalf("marshal json: %#v (%v)", js, err)
}
}
}
func BenchmarkUUID_UnmarshalJSON(b *testing.B) {
js := []byte(`{"uuid":"f47ac10b-58cc-0372-8567-0e02b2c3d479"}`)
var x *struct {
UUID UUID `json:"uuid"`
}
for i := 0; i < b.N; i++ {
err := json.Unmarshal(js, &x)
if err != nil {
b.Fatalf("marshal json: %#v (%v)", js, err)
}
}
}

77
vendor/github.com/pborman/uuid/node.go generated vendored Executable file → Normal file
View File

@ -5,24 +5,14 @@
package uuid package uuid
import ( import (
"net" guuid "github.com/google/uuid"
"sync"
)
var (
nodeMu sync.Mutex
interfaces []net.Interface // cached list of interfaces
ifname string // name of interface being used
nodeID []byte // hardware for version 1 UUIDs
) )
// NodeInterface returns the name of the interface from which the NodeID was // NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by // derived. The interface "user" is returned if the NodeID was set by
// SetNodeID. // SetNodeID.
func NodeInterface() string { func NodeInterface() string {
defer nodeMu.Unlock() return guuid.NodeInterface()
nodeMu.Lock()
return ifname
} }
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. // SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
@ -32,77 +22,20 @@ func NodeInterface() string {
// //
// SetNodeInterface never fails when name is "". // SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool { func SetNodeInterface(name string) bool {
defer nodeMu.Unlock() return guuid.SetNodeInterface(name)
nodeMu.Lock()
return setNodeInterface(name)
}
func setNodeInterface(name string) bool {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil && name != "" {
return false
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
if setNodeID(ifs.HardwareAddr) {
ifname = ifs.Name
return true
}
}
}
// We found no interfaces with a valid hardware address. If name
// does not specify a specific interface generate a random Node ID
// (section 4.1.6)
if name == "" {
if nodeID == nil {
nodeID = make([]byte, 6)
}
randomBits(nodeID)
return true
}
return false
} }
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID // NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set. // if not already set.
func NodeID() []byte { func NodeID() []byte {
defer nodeMu.Unlock() return guuid.NodeID()
nodeMu.Lock()
if nodeID == nil {
setNodeInterface("")
}
nid := make([]byte, 6)
copy(nid, nodeID)
return nid
} }
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes // SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the // of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set. // Node ID is not set.
func SetNodeID(id []byte) bool { func SetNodeID(id []byte) bool {
defer nodeMu.Unlock() return guuid.SetNodeID(id)
nodeMu.Lock()
if setNodeID(id) {
ifname = "user"
return true
}
return false
}
func setNodeID(id []byte) bool {
if len(id) < 6 {
return false
}
if nodeID == nil {
nodeID = make([]byte, 6)
}
copy(nodeID, id)
return true
} }
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is // NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is

View File

@ -5,6 +5,7 @@
package uuid package uuid
import ( import (
"database/sql/driver"
"errors" "errors"
"fmt" "fmt"
) )
@ -39,7 +40,9 @@ func (uuid *UUID) Scan(src interface{}) error {
// assumes a simple slice of bytes if 16 bytes // assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse // otherwise attempts to parse
if len(b) == 16 { if len(b) == 16 {
*uuid = UUID(b) parsed := make([]byte, 16)
copy(parsed, b)
*uuid = UUID(parsed)
} else { } else {
u := Parse(string(b)) u := Parse(string(b))
@ -56,3 +59,10 @@ func (uuid *UUID) Scan(src interface{}) error {
return nil return nil
} }
// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
return uuid.String(), nil
}

View File

@ -85,3 +85,12 @@ func TestScan(t *testing.T) {
t.Error("UUID was not nil after scanning empty string") t.Error("UUID was not nil after scanning empty string")
} }
} }
func TestValue(t *testing.T) {
stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479"
uuid := Parse(stringTest)
val, _ := uuid.Value()
if val != stringTest {
t.Error("Value() did not return expected string")
}
}

87
vendor/github.com/pborman/uuid/time.go generated vendored Executable file → Normal file
View File

@ -6,65 +6,18 @@ package uuid
import ( import (
"encoding/binary" "encoding/binary"
"sync"
"time" guuid "github.com/google/uuid"
) )
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct // A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582. // 1582.
type Time int64 type Time = guuid.Time
const (
lillian = 2299160 // Julian day of 15 Oct 1582
unix = 2440587 // Julian day of 1 Jan 1970
epoch = unix - lillian // Days between epochs
g1582 = epoch * 86400 // seconds between epochs
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
)
var (
timeMu sync.Mutex
lasttime uint64 // last time we returned
clock_seq uint16 // clock sequence for this run
timeNow = time.Now // for testing
)
// UnixTime converts t the number of seconds and nanoseconds using the Unix
// epoch of 1 Jan 1970.
func (t Time) UnixTime() (sec, nsec int64) {
sec = int64(t - g1582ns100)
nsec = (sec % 10000000) * 100
sec /= 10000000
return sec, nsec
}
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and // GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error // clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined. // is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) { func GetTime() (Time, uint16, error) { return guuid.GetTime() }
defer timeMu.Unlock()
timeMu.Lock()
return getTime()
}
func getTime() (Time, uint16, error) {
t := timeNow()
// If we don't have a clock sequence already, set one.
if clock_seq == 0 {
setClockSequence(-1)
}
now := uint64(t.UnixNano()/100) + g1582ns100
// If time has gone backwards with this clock sequence then we
// increment the clock sequence
if now <= lasttime {
clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000
}
lasttime = now
return Time(now), clock_seq, nil
}
// ClockSequence returns the current clock sequence, generating one if not // ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs. // already set. The clock sequence is only used for Version 1 UUIDs.
@ -74,39 +27,11 @@ func getTime() (Time, uint16, error) {
// clock sequence is generated the first time a clock sequence is requested by // clock sequence is generated the first time a clock sequence is requested by
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated // ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
// for // for
func ClockSequence() int { func ClockSequence() int { return guuid.ClockSequence() }
defer timeMu.Unlock()
timeMu.Lock()
return clockSequence()
}
func clockSequence() int {
if clock_seq == 0 {
setClockSequence(-1)
}
return int(clock_seq & 0x3fff)
}
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to // SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated. // -1 causes a new sequence to be generated.
func SetClockSequence(seq int) { func SetClockSequence(seq int) { guuid.SetClockSequence(seq) }
defer timeMu.Unlock()
timeMu.Lock()
setClockSequence(seq)
}
func setClockSequence(seq int) {
if seq == -1 {
var b [2]byte
randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1])
}
old_seq := clock_seq
clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if old_seq != clock_seq {
lasttime = 0
}
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. It returns false if uuid is not valid. The time is only well defined // uuid. It returns false if uuid is not valid. The time is only well defined

View File

@ -4,17 +4,6 @@
package uuid package uuid
import (
"io"
)
// randomBits completely fills slice b with random data.
func randomBits(b []byte) {
if _, err := io.ReadFull(rander, b); err != nil {
panic(err.Error()) // rand should never fail
}
}
// xvalues returns the value of a byte as a hexadecimal digit or 255. // xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = [256]byte{ var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

View File

@ -8,28 +8,42 @@ import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"fmt"
"io" "io"
"strings"
guuid "github.com/google/uuid"
) )
// Array is a pass-by-value UUID that can be used as an effecient key in a map.
type Array [16]byte
// UUID converts uuid into a slice.
func (uuid Array) UUID() UUID {
return uuid[:]
}
// String returns the string representation of uuid,
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (uuid Array) String() string {
return guuid.UUID(uuid).String()
}
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122. // 4122.
type UUID []byte type UUID []byte
// A Version represents a UUIDs version. // A Version represents a UUIDs version.
type Version byte type Version = guuid.Version
// A Variant represents a UUIDs variant. // A Variant represents a UUIDs variant.
type Variant byte type Variant = guuid.Variant
// Constants returned by Variant. // Constants returned by Variant.
const ( const (
Invalid = Variant(iota) // Invalid UUID Invalid = guuid.Invalid // Invalid UUID
RFC4122 // The variant specified in RFC4122 RFC4122 = guuid.RFC4122 // The variant specified in RFC4122
Reserved // Reserved, NCS backward compatibility. Reserved = guuid.Reserved // Reserved, NCS backward compatibility.
Microsoft // Reserved, Microsoft Corporation backward compatibility. Microsoft = guuid.Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future // Reserved for future definition. Future = guuid.Future // Reserved for future definition.
) )
var rander = rand.Reader // random function var rander = rand.Reader // random function
@ -44,31 +58,20 @@ func New() string {
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
func Parse(s string) UUID { func Parse(s string) UUID {
if len(s) == 36+9 { gu, err := guuid.Parse(s)
if strings.ToLower(s[:9]) != "urn:uuid:" { if err == nil {
return nil return gu[:]
}
s = s[9:]
} else if len(s) != 36 {
return nil
} }
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { return nil
return nil }
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
gu, err := guuid.ParseBytes(b)
if err == nil {
return gu[:], nil
} }
var uuid [16]byte return nil, err
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
if v, ok := xtob(s[x:]); !ok {
return nil
} else {
uuid[i] = v
}
}
return uuid[:]
} }
// Equal returns true if uuid1 and uuid2 are equal. // Equal returns true if uuid1 and uuid2 are equal.
@ -76,6 +79,17 @@ func Equal(uuid1, uuid2 UUID) bool {
return bytes.Equal(uuid1, uuid2) return bytes.Equal(uuid1, uuid2)
} }
// Array returns an array representation of uuid that can be used as a map key.
// Array panics if uuid is not valid.
func (uuid UUID) Array() Array {
if len(uuid) != 16 {
panic("invalid uuid")
}
var a Array
copy(a[:], uuid)
return a
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid. // , or "" if uuid is invalid.
func (uuid UUID) String() string { func (uuid UUID) String() string {
@ -138,39 +152,12 @@ func (uuid UUID) Version() (Version, bool) {
return Version(uuid[6] >> 4), true return Version(uuid[6] >> 4), true
} }
func (v Version) String() string { // SetRand sets the random number generator to r, which implements io.Reader.
if v > 15 {
return fmt.Sprintf("BAD_VERSION_%d", v)
}
return fmt.Sprintf("VERSION_%d", v)
}
func (v Variant) String() string {
switch v {
case RFC4122:
return "RFC4122"
case Reserved:
return "Reserved"
case Microsoft:
return "Microsoft"
case Future:
return "Future"
case Invalid:
return "Invalid"
}
return fmt.Sprintf("BadVariant%d", int(v))
}
// SetRand sets the random number generator to r, which implents io.Reader.
// If r.Read returns an error when the package requests random data then // If r.Read returns an error when the package requests random data then
// a panic will be issued. // a panic will be issued.
// //
// Calling SetRand with nil sets the random number generator to the default // Calling SetRand with nil sets the random number generator to the default
// generator. // generator.
func SetRand(r io.Reader) { func SetRand(r io.Reader) {
if r == nil { guuid.SetRand(r)
rander = rand.Reader
return
}
rander = r
} }

View File

@ -4,13 +4,15 @@
package uuid package uuid
// Some of these tests can probably be removed as they are redundant with the
// tests in github.com/google/uuid.
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"os" "os"
"strings" "strings"
"testing" "testing"
"time"
) )
type test struct { type test struct {
@ -157,51 +159,6 @@ func TestNew(t *testing.T) {
} }
} }
func clockSeq(t *testing.T, uuid UUID) int {
seq, ok := uuid.ClockSequence()
if !ok {
t.Fatalf("%s: invalid clock sequence", uuid)
}
return seq
}
func TestClockSeq(t *testing.T) {
// Fake time.Now for this test to return a monotonically advancing time; restore it at end.
defer func(orig func() time.Time) { timeNow = orig }(timeNow)
monTime := time.Now()
timeNow = func() time.Time {
monTime = monTime.Add(1 * time.Second)
return monTime
}
SetClockSequence(-1)
uuid1 := NewUUID()
uuid2 := NewUUID()
if clockSeq(t, uuid1) != clockSeq(t, uuid2) {
t.Errorf("clock sequence %d != %d", clockSeq(t, uuid1), clockSeq(t, uuid2))
}
SetClockSequence(-1)
uuid2 = NewUUID()
// Just on the very off chance we generated the same sequence
// two times we try again.
if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
SetClockSequence(-1)
uuid2 = NewUUID()
}
if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
t.Errorf("Duplicate clock sequence %d", clockSeq(t, uuid1))
}
SetClockSequence(0x1234)
uuid1 = NewUUID()
if seq := clockSeq(t, uuid1); seq != 0x1234 {
t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq)
}
}
func TestCoding(t *testing.T) { func TestCoding(t *testing.T) {
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
@ -270,69 +227,6 @@ func TestVersion1(t *testing.T) {
} }
} }
func TestNode(t *testing.T) {
// This test is mostly to make sure we don't leave nodeMu locked.
ifname = ""
if ni := NodeInterface(); ni != "" {
t.Errorf("NodeInterface got %q, want %q", ni, "")
}
if SetNodeInterface("xyzzy") {
t.Error("SetNodeInterface succeeded on a bad interface name")
}
if !SetNodeInterface("") {
t.Error("SetNodeInterface failed")
}
if ni := NodeInterface(); ni == "" {
t.Error("NodeInterface returned an empty string")
}
ni := NodeID()
if len(ni) != 6 {
t.Errorf("ni got %d bytes, want 6", len(ni))
}
hasData := false
for _, b := range ni {
if b != 0 {
hasData = true
}
}
if !hasData {
t.Error("nodeid is all zeros")
}
id := []byte{1,2,3,4,5,6,7,8}
SetNodeID(id)
ni = NodeID()
if !bytes.Equal(ni, id[:6]) {
t.Errorf("got nodeid %v, want %v", ni, id[:6])
}
if ni := NodeInterface(); ni != "user" {
t.Errorf("got inteface %q, want %q", ni, "user")
}
}
func TestNodeAndTime(t *testing.T) {
// Time is February 5, 1998 12:30:23.136364800 AM GMT
uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2")
node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2}
ts, ok := uuid.Time()
if ok {
c := time.Unix(ts.UnixTime())
want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC)
if !c.Equal(want) {
t.Errorf("Got time %v, want %v", c, want)
}
} else {
t.Errorf("%s: bad time", uuid)
}
if !bytes.Equal(node, uuid.NodeID()) {
t.Errorf("Expected node %v got %v", node, uuid.NodeID())
}
}
func TestMD5(t *testing.T) { func TestMD5(t *testing.T) {
uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String() uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String()
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
@ -349,33 +243,6 @@ func TestSHA1(t *testing.T) {
} }
} }
func TestNodeID(t *testing.T) {
nid := []byte{1, 2, 3, 4, 5, 6}
SetNodeInterface("")
s := NodeInterface()
if s == "" || s == "user" {
t.Errorf("NodeInterface %q after SetInteface", s)
}
node1 := NodeID()
if node1 == nil {
t.Error("NodeID nil after SetNodeInterface", s)
}
SetNodeID(nid)
s = NodeInterface()
if s != "user" {
t.Errorf("Expected NodeInterface %q got %q", "user", s)
}
node2 := NodeID()
if node2 == nil {
t.Error("NodeID nil after SetNodeID", s)
}
if bytes.Equal(node1, node2) {
t.Error("NodeID not changed after SetNodeID", s)
} else if !bytes.Equal(nid, node2) {
t.Errorf("NodeID is %x, expected %x", node2, nid)
}
}
func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) { func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) {
if uuid == nil { if uuid == nil {
t.Errorf("%s failed", name) t.Errorf("%s failed", name)
@ -421,13 +288,47 @@ func TestBadRand(t *testing.T) {
uuid1 := New() uuid1 := New()
uuid2 := New() uuid2 := New()
if uuid1 != uuid2 { if uuid1 != uuid2 {
t.Errorf("execpted duplicates, got %q and %q", uuid1, uuid2) t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2)
} }
SetRand(nil) SetRand(nil)
uuid1 = New() uuid1 = New()
uuid2 = New() uuid2 = New()
if uuid1 == uuid2 { if uuid1 == uuid2 {
t.Errorf("unexecpted duplicates, got %q", uuid1) t.Errorf("unexpected duplicates, got %q", uuid1)
}
}
func TestUUID_Array(t *testing.T) {
expect := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if uuid == nil {
t.Fatal("invalid uuid")
}
if uuid.Array() != expect {
t.Fatal("invalid array")
}
}
func TestArray_UUID(t *testing.T) {
array := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
expect := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if expect == nil {
t.Fatal("invalid uuid")
}
if !bytes.Equal(array.UUID(), expect) {
t.Fatal("invalid uuid")
} }
} }
@ -469,3 +370,41 @@ func BenchmarkUUID_URN(b *testing.B) {
} }
} }
} }
func BenchmarkUUID_Array(b *testing.B) {
expect := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if uuid == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
if uuid.Array() != expect {
b.Fatal("invalid array")
}
}
}
func BenchmarkArray_UUID(b *testing.B) {
array := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
expect := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if expect == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
if !bytes.Equal(array.UUID(), expect) {
b.Fatal("invalid uuid")
}
}
}

View File

@ -5,7 +5,7 @@
package uuid package uuid
import ( import (
"encoding/binary" guuid "github.com/google/uuid"
) )
// NewUUID returns a Version 1 UUID based on the current NodeID and clock // NewUUID returns a Version 1 UUID based on the current NodeID and clock
@ -15,27 +15,9 @@ import (
// SetClockSequence then it will be set automatically. If GetTime fails to // SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil. // return the current NewUUID returns nil.
func NewUUID() UUID { func NewUUID() UUID {
if nodeID == nil { gu, err := guuid.NewUUID()
SetNodeInterface("") if err == nil {
return UUID(gu[:])
} }
return nil
now, seq, err := GetTime()
if err != nil {
return nil
}
uuid := make([]byte, 16)
time_low := uint32(now & 0xffffffff)
time_mid := uint16((now >> 32) & 0xffff)
time_hi := uint16((now >> 48) & 0x0fff)
time_hi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], time_low)
binary.BigEndian.PutUint16(uuid[4:], time_mid)
binary.BigEndian.PutUint16(uuid[6:], time_hi)
binary.BigEndian.PutUint16(uuid[8:], seq)
copy(uuid[10:], nodeID)
return uuid
} }

View File

@ -4,12 +4,14 @@
package uuid package uuid
import guuid "github.com/google/uuid"
// Random returns a Random (Version 4) UUID or panics. // Random returns a Random (Version 4) UUID or panics.
// //
// The strength of the UUIDs is based on the strength of the crypto/rand // The strength of the UUIDs is based on the strength of the crypto/rand
// package. // package.
// //
// A note about uniqueness derived from from the UUID Wikipedia entry: // A note about uniqueness derived from the UUID Wikipedia entry:
// //
// Randomly generated UUIDs have 122 random bits. One's annual risk of being // Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that // hit by a meteorite is estimated to be one chance in 17 billion, that
@ -17,9 +19,8 @@ package uuid
// equivalent to the odds of creating a few tens of trillions of UUIDs in a // equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate. // year and having one duplicate.
func NewRandom() UUID { func NewRandom() UUID {
uuid := make([]byte, 16) if gu, err := guuid.NewRandom(); err == nil {
randomBits([]byte(uuid)) return UUID(gu[:])
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 }
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 return nil
return uuid
} }

7
vendor/github.com/stretchr/testify/.travis.gofmt.sh generated vendored Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
if [ -n "$(gofmt -l .)" ]; then
echo "Go code is not formatted:"
gofmt -d .
exit 1
fi

13
vendor/github.com/stretchr/testify/.travis.gogenerate.sh generated vendored Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
if [[ "$TRAVIS_GO_VERSION" =~ ^1\.[45](\..*)?$ ]]; then
exit 0
fi
go get github.com/ernesto-jimenez/gogen/imports
go generate ./...
if [ -n "$(git diff)" ]; then
echo "Go generate had not been run"
git diff
exit 1
fi

10
vendor/github.com/stretchr/testify/.travis.govet.sh generated vendored Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
cd "$(dirname $0)"
DIRS=". assert require mock _codegen"
set -e
for subdir in $DIRS; do
pushd $subdir
go vet
popd
done

View File

@ -3,14 +3,13 @@ language: go
sudo: false sudo: false
go: go:
- 1.1 - "1.8"
- 1.2 - "1.9"
- 1.3 - "1.10"
- 1.4
- 1.5
- 1.6
- 1.7
- tip - tip
script: script:
- go test -v ./... - ./.travis.gogenerate.sh
- ./.travis.gofmt.sh
- ./.travis.govet.sh
- go test -v -race $(go list ./... | grep -v vendor)

View File

@ -1,23 +0,0 @@
{
"ImportPath": "github.com/stretchr/testify",
"GoVersion": "go1.5",
"GodepVersion": "v74",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "github.com/davecgh/go-spew/spew",
"Comment": "v1.0.0-3-g6d21280",
"Rev": "6d212800a42e8ab5c146b8ace3490ee17e5225f9"
},
{
"ImportPath": "github.com/pmezard/go-difflib/difflib",
"Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
},
{
"ImportPath": "github.com/stretchr/objx",
"Rev": "cbeaeb16a013161a98496fad62933b1d21786672"
}
]
}

View File

@ -1,5 +0,0 @@
This directory tree is generated automatically by godep.
Please do not edit.
See https://github.com/tools/godep for more information.

27
vendor/github.com/stretchr/testify/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,27 @@
# 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/objx"
packages = ["."]
revision = "facf9a85c22f48d2f52f2380e4efce1768749a89"
version = "v0.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "448ddae4702c6aded2555faafd390c537789bb1c483f70b0431e6634f73f2090"
solver-name = "gps-cdcl"
solver-version = 1

16
vendor/github.com/stretchr/testify/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,16 @@
[prune]
unused-packages = true
non-go = true
go-tests = true
[[constraint]]
name = "github.com/davecgh/go-spew"
version = "~1.1.0"
[[constraint]]
name = "github.com/pmezard/go-difflib"
version = "~1.0.0"
[[constraint]]
name = "github.com/stretchr/objx"
version = "~0.1.0"

View File

@ -1,22 +0,0 @@
Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
Please consider promoting this project if you find it useful.
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.

View File

@ -9,7 +9,6 @@ Features include:
* [Easy assertions](#assert-package) * [Easy assertions](#assert-package)
* [Mocking](#mock-package) * [Mocking](#mock-package)
* [HTTP response trapping](#http-package)
* [Testing suite interfaces and functions](#suite-package) * [Testing suite interfaces and functions](#suite-package)
Get started: Get started:
@ -106,14 +105,6 @@ The `require` package provides same global functions as the `assert` package, bu
See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details. See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details.
[`http`](http://godoc.org/github.com/stretchr/testify/http "API documentation") package
---------------------------------------------------------------------------------------
The `http` package contains test objects useful for testing code that relies on the `net/http` package. Check out the [(deprecated) API documentation for the `http` package](http://godoc.org/github.com/stretchr/testify/http).
We recommend you use [httptest](http://golang.org/pkg/net/http/httptest) instead.
[`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package [`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package
---------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------
@ -173,6 +164,29 @@ func TestSomething(t *testing.T) {
// assert that the expectations were met // assert that the expectations were met
testObj.AssertExpectations(t) testObj.AssertExpectations(t)
}
// TestSomethingElse is a second example of how to use our test object to
// make assertions about some target code we are testing.
// This time using a placeholder. Placeholders might be used when the
// data being passed in is normally dynamically generated and cannot be
// predicted beforehand (eg. containing hashes that are time sensitive)
func TestSomethingElse(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// setup expectations with a placeholder in the argument list
testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
} }
``` ```
@ -268,8 +282,7 @@ Installation
To install Testify, use `go get`: To install Testify, use `go get`:
* Latest version: go get github.com/stretchr/testify go get github.com/stretchr/testify
* Specific version: go get gopkg.in/stretchr/testify.v1
This will then make the following packages available to you: This will then make the following packages available to you:
@ -303,10 +316,10 @@ To update Testify to the latest version, use `go get -u github.com/stretchr/test
------ ------
Version History Supported go versions
=============== ==================
* 1.0 - New package versioning strategy adopted. We support the three major Go versions, which are 1.8, 1.9 and 1.10 at the moment.
------ ------
@ -316,17 +329,3 @@ Contributing
Please feel free to submit issues, fork the repository and send pull requests! Please feel free to submit issues, fork the repository and send pull requests!
When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it. When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it.
------
Licence
=======
Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
Please consider promoting this project if you find it useful.
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.

View File

@ -1,5 +1,5 @@
// This program reads all assertion functions from the assert package and // This program reads all assertion functions from the assert package and
// automatically generates the corersponding requires and forwarded assertions // automatically generates the corresponding requires and forwarded assertions
package main package main
@ -10,6 +10,7 @@ import (
"go/ast" "go/ast"
"go/build" "go/build"
"go/doc" "go/doc"
"go/format"
"go/importer" "go/importer"
"go/parser" "go/parser"
"go/token" "go/token"
@ -19,6 +20,7 @@ import (
"log" "log"
"os" "os"
"path" "path"
"regexp"
"strings" "strings"
"text/template" "text/template"
@ -27,6 +29,7 @@ import (
var ( var (
pkg = flag.String("assert-path", "github.com/stretchr/testify/assert", "Path to the assert package") pkg = flag.String("assert-path", "github.com/stretchr/testify/assert", "Path to the assert package")
includeF = flag.Bool("include-format-funcs", false, "include format functions such as Errorf and Equalf")
outputPkg = flag.String("output-package", "", "package for the resulting code") outputPkg = flag.String("output-package", "", "package for the resulting code")
tmplFile = flag.String("template", "", "What file to load the function template from") tmplFile = flag.String("template", "", "What file to load the function template from")
out = flag.String("out", "", "What file to write the source code to") out = flag.String("out", "", "What file to write the source code to")
@ -77,13 +80,18 @@ func generateCode(importer imports.Importer, funcs []testFunc) error {
} }
} }
code, err := format.Source(buff.Bytes())
if err != nil {
return err
}
// Write file // Write file
output, err := outputFile() output, err := outputFile()
if err != nil { if err != nil {
return err return err
} }
defer output.Close() defer output.Close()
_, err = io.Copy(output, buff) _, err = io.Copy(output, bytes.NewReader(code))
return err return err
} }
@ -133,7 +141,7 @@ func analyzeCode(scope *types.Scope, docs *doc.Package) (imports.Importer, []tes
if !ok { if !ok {
continue continue
} }
// Check function signatuer has at least two arguments // Check function signature has at least two arguments
sig := fn.Type().(*types.Signature) sig := fn.Type().(*types.Signature)
if sig.Params().Len() < 2 { if sig.Params().Len() < 2 {
continue continue
@ -151,13 +159,18 @@ func analyzeCode(scope *types.Scope, docs *doc.Package) (imports.Importer, []tes
continue continue
} }
// Skip functions ending with f
if strings.HasSuffix(fdocs.Name, "f") && !*includeF {
continue
}
funcs = append(funcs, testFunc{*outputPkg, fdocs, fn}) funcs = append(funcs, testFunc{*outputPkg, fdocs, fn})
importer.AddImportsFrom(sig.Params()) importer.AddImportsFrom(sig.Params())
} }
return importer, funcs, nil return importer, funcs, nil
} }
// parsePackageSource returns the types scope and the package documentation from the pa // parsePackageSource returns the types scope and the package documentation from the package
func parsePackageSource(pkg string) (*types.Scope, *doc.Package, error) { func parsePackageSource(pkg string) (*types.Scope, *doc.Package, error) {
pd, err := build.Import(pkg, ".", 0) pd, err := build.Import(pkg, ".", 0)
if err != nil { if err != nil {
@ -258,10 +271,26 @@ func (f *testFunc) ForwardedParams() string {
return p return p
} }
func (f *testFunc) ParamsFormat() string {
return strings.Replace(f.Params(), "msgAndArgs", "msg string, args", 1)
}
func (f *testFunc) ForwardedParamsFormat() string {
return strings.Replace(f.ForwardedParams(), "msgAndArgs", "append([]interface{}{msg}, args...)", 1)
}
func (f *testFunc) Comment() string { func (f *testFunc) Comment() string {
return "// " + strings.Replace(strings.TrimSpace(f.DocInfo.Doc), "\n", "\n// ", -1) return "// " + strings.Replace(strings.TrimSpace(f.DocInfo.Doc), "\n", "\n// ", -1)
} }
func (f *testFunc) CommentFormat() string {
search := fmt.Sprintf("%s", f.DocInfo.Name)
replace := fmt.Sprintf("%sf", f.DocInfo.Name)
comment := strings.Replace(f.Comment(), search, replace, -1)
exp := regexp.MustCompile(replace + `\(((\(\)|[^)])+)\)`)
return exp.ReplaceAllString(comment, replace+`($1, "error message %s", "formatted")`)
}
func (f *testFunc) CommentWithoutT(receiver string) string { func (f *testFunc) CommentWithoutT(receiver string) string {
search := fmt.Sprintf("assert.%s(t, ", f.DocInfo.Name) search := fmt.Sprintf("assert.%s(t, ", f.DocInfo.Name)
replace := fmt.Sprintf("%s.%s(", receiver, f.DocInfo.Name) replace := fmt.Sprintf("%s.%s(", receiver, f.DocInfo.Name)

View File

@ -0,0 +1,484 @@
/*
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
* THIS FILE MUST NOT BE EDITED BY HAND
*/
package assert
import (
http "net/http"
url "net/url"
time "time"
)
// Conditionf uses a Comparison to assert a complex condition.
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Condition(t, comp, append([]interface{}{msg}, args...)...)
}
// Containsf asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
}
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return DirExists(t, path, append([]interface{}{msg}, args...)...)
}
// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
}
// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// assert.Emptyf(t, obj, "error message %s", "formatted")
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Empty(t, object, append([]interface{}{msg}, args...)...)
}
// Equalf asserts that two objects are equal.
//
// assert.Equalf(t, 123, 123, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
}
// EqualValuesf asserts that two objects are equal or convertable to the same types
// and equal.
//
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if assert.Errorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err)
// }
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Error(t, err, append([]interface{}{msg}, args...)...)
}
// Exactlyf asserts that two objects are equal in value and type.
//
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Failf reports a failure through
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
}
// FailNowf fails test
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
}
// Falsef asserts that the specified value is false.
//
// assert.Falsef(t, myBool, "error message %s", "formatted")
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return False(t, value, append([]interface{}{msg}, args...)...)
}
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return FileExists(t, path, append([]interface{}{msg}, args...)...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string.
//
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
// HTTPErrorf asserts that a specified handler returns an error status code.
//
// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
//
// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
// HTTPSuccessf asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
// Implementsf asserts that an object is implemented by the specified interface.
//
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
}
// InDeltaf asserts that the two numerals are within delta of each other.
//
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
}
// IsTypef asserts that the specified objects are of the same type.
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
}
// JSONEqf asserts that two JSON strings are equivalent.
//
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Len(t, object, length, append([]interface{}{msg}, args...)...)
}
// Nilf asserts that the specified object is nil.
//
// assert.Nilf(t, err, "error message %s", "formatted")
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Nil(t, object, append([]interface{}{msg}, args...)...)
}
// NoErrorf asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if assert.NoErrorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj)
// }
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NoError(t, err, append([]interface{}{msg}, args...)...)
}
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
}
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1])
// }
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
}
// NotEqualf asserts that the specified values are NOT equal.
//
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotNilf asserts that the specified object is not nil.
//
// assert.NotNilf(t, err, "error message %s", "formatted")
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotNil(t, object, append([]interface{}{msg}, args...)...)
}
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotPanics(t, f, append([]interface{}{msg}, args...)...)
}
// NotRegexpf asserts that a specified regexp does not match a string.
//
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
// NotSubsetf asserts that the specified list(array, slice...) contains not all
// elements given in the specified subset(array, slice...).
//
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
}
// NotZerof asserts that i is not the zero value for its type.
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotZero(t, i, append([]interface{}{msg}, args...)...)
}
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
//
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Panics(t, f, append([]interface{}{msg}, args...)...)
}
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
}
// Regexpf asserts that a specified regexp matches a string.
//
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
// Subsetf asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...).
//
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
}
// Truef asserts that the specified value is true.
//
// assert.Truef(t, myBool, "error message %s", "formatted")
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return True(t, value, append([]interface{}{msg}, args...)...)
}
// WithinDurationf asserts that the two times are within duration delta of each other.
//
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// Zerof asserts that i is the zero value for its type.
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Zero(t, i, append([]interface{}{msg}, args...)...)
}

View File

@ -0,0 +1,5 @@
{{.CommentFormat}}
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
if h, ok := t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
{{.CommentWithoutT "a"}} {{.CommentWithoutT "a"}}
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
if h, ok := a.t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,17 @@
package assert package assert
import ( import (
"bytes"
"encoding/json"
"errors" "errors"
"fmt"
"io" "io"
"math" "math"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
"runtime"
"strings"
"testing" "testing"
"time" "time"
) )
@ -151,6 +156,9 @@ func TestImplements(t *testing.T) {
if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface") t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
} }
if Implements(mockT, (*AssertionTesterInterface)(nil), nil) {
t.Error("Implements method should return false: nil does not implement AssertionTesterInterface")
}
} }
@ -192,7 +200,86 @@ func TestEqual(t *testing.T) {
if !Equal(mockT, uint64(123), uint64(123)) { if !Equal(mockT, uint64(123), uint64(123)) {
t.Error("Equal should return true") t.Error("Equal should return true")
} }
if !Equal(mockT, &struct{}{}, &struct{}{}) {
t.Error("Equal should return true (pointer equality is based on equality of underlying value)")
}
var m map[string]interface{}
if Equal(mockT, m["bar"], "something") {
t.Error("Equal should return false")
}
}
// bufferT implements TestingT. Its implementation of Errorf writes the output that would be produced by
// testing.T.Errorf to an internal bytes.Buffer.
type bufferT struct {
buf bytes.Buffer
}
func (t *bufferT) Errorf(format string, args ...interface{}) {
// implementation of decorate is copied from testing.T
decorate := func(s string) string {
_, file, line, ok := runtime.Caller(3) // decorate + log + public function.
if ok {
// Truncate file name at last file name separator.
if index := strings.LastIndex(file, "/"); index >= 0 {
file = file[index+1:]
} else if index = strings.LastIndex(file, "\\"); index >= 0 {
file = file[index+1:]
}
} else {
file = "???"
line = 1
}
buf := new(bytes.Buffer)
// Every line is indented at least one tab.
buf.WriteByte('\t')
fmt.Fprintf(buf, "%s:%d: ", file, line)
lines := strings.Split(s, "\n")
if l := len(lines); l > 1 && lines[l-1] == "" {
lines = lines[:l-1]
}
for i, line := range lines {
if i > 0 {
// Second and subsequent lines are indented an extra tab.
buf.WriteString("\n\t\t")
}
buf.WriteString(line)
}
buf.WriteByte('\n')
return buf.String()
}
t.buf.WriteString(decorate(fmt.Sprintf(format, args...)))
}
func TestStringEqual(t *testing.T) {
for i, currCase := range []struct {
equalWant string
equalGot string
msgAndArgs []interface{}
want string
}{
{equalWant: "hi, \nmy name is", equalGot: "what,\nmy name is", want: "\tassertions.go:\\d+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"hi, \\\\nmy name is\"\n\\s+actual\\s+: \"what,\\\\nmy name is\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1,2 \\+1,2 @@\n\\s+-hi, \n\\s+\\+what,\n\\s+my name is"},
} {
mockT := &bufferT{}
Equal(mockT, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...)
Regexp(t, regexp.MustCompile(currCase.want), mockT.buf.String(), "Case %d", i)
}
}
func TestEqualFormatting(t *testing.T) {
for i, currCase := range []struct {
equalWant string
equalGot string
msgAndArgs []interface{}
want string
}{
{equalWant: "want", equalGot: "got", want: "\tassertions.go:\\d+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n"},
{equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{"hello, %v!", "world"}, want: "\tassertions.go:[0-9]+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n\\s+Messages:\\s+hello, world!\n"},
} {
mockT := &bufferT{}
Equal(mockT, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...)
Regexp(t, regexp.MustCompile(currCase.want), mockT.buf.String(), "Case %d", i)
}
} }
func TestFormatUnequalValues(t *testing.T) { func TestFormatUnequalValues(t *testing.T) {
@ -208,6 +295,10 @@ func TestFormatUnequalValues(t *testing.T) {
Equal(t, `int64(123)`, expected, "value should include type") Equal(t, `int64(123)`, expected, "value should include type")
Equal(t, `int32(123)`, actual, "value should include type") Equal(t, `int32(123)`, actual, "value should include type")
expected, actual = formatUnequalValues(int64(123), nil)
Equal(t, `int64(123)`, expected, "value should include type")
Equal(t, `<nil>(<nil>)`, actual, "value should include type")
type testStructType struct { type testStructType struct {
Val string Val string
} }
@ -324,8 +415,8 @@ func TestNotEqual(t *testing.T) {
} }
funcA := func() int { return 23 } funcA := func() int { return 23 }
funcB := func() int { return 42 } funcB := func() int { return 42 }
if !NotEqual(mockT, funcA, funcB) { if NotEqual(mockT, funcA, funcB) {
t.Error("NotEqual should return true") t.Error("NotEqual should return false")
} }
if NotEqual(mockT, "Hello World", "Hello World") { if NotEqual(mockT, "Hello World", "Hello World") {
@ -343,6 +434,9 @@ func TestNotEqual(t *testing.T) {
if NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { if NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
t.Error("NotEqual should return false") t.Error("NotEqual should return false")
} }
if NotEqual(mockT, &struct{}{}, &struct{}{}) {
t.Error("NotEqual should return false")
}
} }
type A struct { type A struct {
@ -418,6 +512,74 @@ func TestNotContains(t *testing.T) {
} }
} }
func TestSubset(t *testing.T) {
mockT := new(testing.T)
if !Subset(mockT, []int{1, 2, 3}, nil) {
t.Error("Subset should return true: given subset is nil")
}
if !Subset(mockT, []int{1, 2, 3}, []int{}) {
t.Error("Subset should return true: any set contains the nil set")
}
if !Subset(mockT, []int{1, 2, 3}, []int{1, 2}) {
t.Error("Subset should return true: [1, 2, 3] contains [1, 2]")
}
if !Subset(mockT, []int{1, 2, 3}, []int{1, 2, 3}) {
t.Error("Subset should return true: [1, 2, 3] contains [1, 2, 3]")
}
if !Subset(mockT, []string{"hello", "world"}, []string{"hello"}) {
t.Error("Subset should return true: [\"hello\", \"world\"] contains [\"hello\"]")
}
if Subset(mockT, []string{"hello", "world"}, []string{"hello", "testify"}) {
t.Error("Subset should return false: [\"hello\", \"world\"] does not contain [\"hello\", \"testify\"]")
}
if Subset(mockT, []int{1, 2, 3}, []int{4, 5}) {
t.Error("Subset should return false: [1, 2, 3] does not contain [4, 5]")
}
if Subset(mockT, []int{1, 2, 3}, []int{1, 5}) {
t.Error("Subset should return false: [1, 2, 3] does not contain [1, 5]")
}
}
func TestNotSubset(t *testing.T) {
mockT := new(testing.T)
if NotSubset(mockT, []int{1, 2, 3}, nil) {
t.Error("NotSubset should return false: given subset is nil")
}
if NotSubset(mockT, []int{1, 2, 3}, []int{}) {
t.Error("NotSubset should return false: any set contains the nil set")
}
if NotSubset(mockT, []int{1, 2, 3}, []int{1, 2}) {
t.Error("NotSubset should return false: [1, 2, 3] contains [1, 2]")
}
if NotSubset(mockT, []int{1, 2, 3}, []int{1, 2, 3}) {
t.Error("NotSubset should return false: [1, 2, 3] contains [1, 2, 3]")
}
if NotSubset(mockT, []string{"hello", "world"}, []string{"hello"}) {
t.Error("NotSubset should return false: [\"hello\", \"world\"] contains [\"hello\"]")
}
if !NotSubset(mockT, []string{"hello", "world"}, []string{"hello", "testify"}) {
t.Error("NotSubset should return true: [\"hello\", \"world\"] does not contain [\"hello\", \"testify\"]")
}
if !NotSubset(mockT, []int{1, 2, 3}, []int{4, 5}) {
t.Error("NotSubset should return true: [1, 2, 3] does not contain [4, 5]")
}
if !NotSubset(mockT, []int{1, 2, 3}, []int{1, 5}) {
t.Error("NotSubset should return true: [1, 2, 3] does not contain [1, 5]")
}
}
func TestNotSubsetNil(t *testing.T) {
mockT := new(testing.T)
NotSubset(mockT, []string{"foo"}, nil)
if !mockT.Failed() {
t.Error("NotSubset on nil set should have failed the test")
}
}
func Test_includeElement(t *testing.T) { func Test_includeElement(t *testing.T) {
list1 := []string{"Foo", "Bar"} list1 := []string{"Foo", "Bar"}
@ -469,6 +631,57 @@ func Test_includeElement(t *testing.T) {
False(t, found) False(t, found)
} }
func TestElementsMatch(t *testing.T) {
mockT := new(testing.T)
if !ElementsMatch(mockT, nil, nil) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []int{}, []int{}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []int{1}, []int{1}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []int{1, 1}, []int{1, 1}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []int{1, 2}, []int{1, 2}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []int{1, 2}, []int{2, 1}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, [2]int{1, 2}, [2]int{2, 1}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []string{"hello", "world"}, []string{"world", "hello"}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []string{"hello", "hello"}, []string{"hello", "hello"}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []string{"hello", "hello", "world"}, []string{"hello", "world", "hello"}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, [3]string{"hello", "hello", "world"}, [3]string{"hello", "world", "hello"}) {
t.Error("ElementsMatch should return true")
}
if !ElementsMatch(mockT, []int{}, nil) {
t.Error("ElementsMatch should return true")
}
if ElementsMatch(mockT, []int{1}, []int{1, 1}) {
t.Error("ElementsMatch should return false")
}
if ElementsMatch(mockT, []int{1, 2}, []int{2, 2}) {
t.Error("ElementsMatch should return false")
}
if ElementsMatch(mockT, []string{"hello", "hello"}, []string{"hello"}) {
t.Error("ElementsMatch should return false")
}
}
func TestCondition(t *testing.T) { func TestCondition(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
@ -514,6 +727,28 @@ func TestPanics(t *testing.T) {
} }
func TestPanicsWithValue(t *testing.T) {
mockT := new(testing.T)
if !PanicsWithValue(mockT, "Panic!", func() {
panic("Panic!")
}) {
t.Error("PanicsWithValue should return true")
}
if PanicsWithValue(mockT, "Panic!", func() {
}) {
t.Error("PanicsWithValue should return false")
}
if PanicsWithValue(mockT, "at the disco", func() {
panic("Panic!")
}) {
t.Error("PanicsWithValue should return false")
}
}
func TestNotPanics(t *testing.T) { func TestNotPanics(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
@ -555,7 +790,7 @@ func TestNoError(t *testing.T) {
}() }()
if err == nil { // err is not nil here! if err == nil { // err is not nil here!
t.Errorf("Error should be nil due to empty interface", err) t.Errorf("Error should be nil due to empty interface: %s", err)
} }
False(t, NoError(mockT, err), "NoError should fail with empty error interface") False(t, NoError(mockT, err), "NoError should fail with empty error interface")
@ -579,6 +814,9 @@ func TestError(t *testing.T) {
True(t, Error(mockT, err), "Error with error should return True") True(t, Error(mockT, err), "Error with error should return True")
// go vet check
True(t, Errorf(mockT, err, "example with %s", "formatted message"), "Errorf with error should rturn True")
// returning an empty error interface // returning an empty error interface
err = func() error { err = func() error {
var err *customError var err *customError
@ -589,7 +827,7 @@ func TestError(t *testing.T) {
}() }()
if err == nil { // err is not nil here! if err == nil { // err is not nil here!
t.Errorf("Error should be nil due to empty interface", err) t.Errorf("Error should be nil due to empty interface: %s", err)
} }
True(t, Error(mockT, err), "Error should pass with empty error interface") True(t, Error(mockT, err), "Error should pass with empty error interface")
@ -646,6 +884,15 @@ func TestEmpty(t *testing.T) {
var tiNP time.Time var tiNP time.Time
var s *string var s *string
var f *os.File var f *os.File
sP := &s
x := 1
xP := &x
type TString string
type TStruct struct {
x int
s []int
}
True(t, Empty(mockT, ""), "Empty string is empty") True(t, Empty(mockT, ""), "Empty string is empty")
True(t, Empty(mockT, nil), "Nil is empty") True(t, Empty(mockT, nil), "Nil is empty")
@ -657,6 +904,9 @@ func TestEmpty(t *testing.T) {
True(t, Empty(mockT, f), "Nil os.File pointer is empty") True(t, Empty(mockT, f), "Nil os.File pointer is empty")
True(t, Empty(mockT, tiP), "Nil time.Time pointer is empty") True(t, Empty(mockT, tiP), "Nil time.Time pointer is empty")
True(t, Empty(mockT, tiNP), "time.Time is empty") True(t, Empty(mockT, tiNP), "time.Time is empty")
True(t, Empty(mockT, TStruct{}), "struct with zero values is empty")
True(t, Empty(mockT, TString("")), "empty aliased string is empty")
True(t, Empty(mockT, sP), "ptr to nil value is empty")
False(t, Empty(mockT, "something"), "Non Empty string is not empty") False(t, Empty(mockT, "something"), "Non Empty string is not empty")
False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty") False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
@ -664,6 +914,9 @@ func TestEmpty(t *testing.T) {
False(t, Empty(mockT, 1), "Non-zero int value is not empty") False(t, Empty(mockT, 1), "Non-zero int value is not empty")
False(t, Empty(mockT, true), "True value is not empty") False(t, Empty(mockT, true), "True value is not empty")
False(t, Empty(mockT, chWithValue), "Channel with values is not empty") False(t, Empty(mockT, chWithValue), "Channel with values is not empty")
False(t, Empty(mockT, TStruct{x: 1}), "struct with initialized values is empty")
False(t, Empty(mockT, TString("abc")), "non-empty aliased string is empty")
False(t, Empty(mockT, xP), "ptr to non-nil value is not empty")
} }
func TestNotEmpty(t *testing.T) { func TestNotEmpty(t *testing.T) {
@ -870,6 +1123,82 @@ func TestInDeltaSlice(t *testing.T) {
False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
} }
func TestInDeltaMapValues(t *testing.T) {
mockT := new(testing.T)
for _, tc := range []struct {
title string
expect interface{}
actual interface{}
f func(TestingT, bool, ...interface{}) bool
delta float64
}{
{
title: "Within delta",
expect: map[string]float64{
"foo": 1.0,
"bar": 2.0,
},
actual: map[string]float64{
"foo": 1.01,
"bar": 1.99,
},
delta: 0.1,
f: True,
},
{
title: "Within delta",
expect: map[int]float64{
1: 1.0,
2: 2.0,
},
actual: map[int]float64{
1: 1.0,
2: 1.99,
},
delta: 0.1,
f: True,
},
{
title: "Different number of keys",
expect: map[int]float64{
1: 1.0,
2: 2.0,
},
actual: map[int]float64{
1: 1.0,
},
delta: 0.1,
f: False,
},
{
title: "Within delta with zero value",
expect: map[string]float64{
"zero": 0.0,
},
actual: map[string]float64{
"zero": 0.0,
},
delta: 0.1,
f: True,
},
{
title: "With missing key with zero value",
expect: map[string]float64{
"zero": 0.0,
"foo": 0.0,
},
actual: map[string]float64{
"zero": 0.0,
"bar": 0.0,
},
f: False,
},
} {
tc.f(t, InDeltaMapValues(mockT, tc.expect, tc.actual, tc.delta), tc.title+"\n"+diff(tc.expect, tc.actual))
}
}
func TestInEpsilon(t *testing.T) { func TestInEpsilon(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
@ -885,6 +1214,7 @@ func TestInEpsilon(t *testing.T) {
{uint64(100), uint8(101), 0.01}, {uint64(100), uint8(101), 0.01},
{0.1, -0.1, 2}, {0.1, -0.1, 2},
{0.1, 0, 2}, {0.1, 0, 2},
{time.Second, time.Second + time.Millisecond, 0.002},
} }
for _, tc := range cases { for _, tc := range cases {
@ -903,6 +1233,7 @@ func TestInEpsilon(t *testing.T) {
{2.1, "bla-bla", 0}, {2.1, "bla-bla", 0},
{0.1, -0.1, 1.99}, {0.1, -0.1, 1.99},
{0, 0.1, 2}, // expected must be different to zero {0, 0.1, 2}, // expected must be different to zero
{time.Second, time.Second + 10*time.Millisecond, 0.002},
} }
for _, tc := range cases { for _, tc := range cases {
@ -1006,6 +1337,28 @@ func TestNotZero(t *testing.T) {
} }
} }
func TestFileExists(t *testing.T) {
mockT := new(testing.T)
True(t, FileExists(mockT, "assertions.go"))
mockT = new(testing.T)
False(t, FileExists(mockT, "random_file"))
mockT = new(testing.T)
False(t, FileExists(mockT, "../_codegen"))
}
func TestDirExists(t *testing.T) {
mockT := new(testing.T)
False(t, DirExists(mockT, "assertions.go"))
mockT = new(testing.T)
False(t, DirExists(mockT, "random_dir"))
mockT = new(testing.T)
True(t, DirExists(mockT, "../_codegen"))
}
func TestJSONEq_EqualSONString(t *testing.T) { func TestJSONEq_EqualSONString(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)) True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`))
@ -1208,3 +1561,233 @@ func TestFailNowWithFullTestingT(t *testing.T) {
FailNow(mockT, "failed") FailNow(mockT, "failed")
}, "should call mockT.FailNow() rather than panicking") }, "should call mockT.FailNow() rather than panicking")
} }
func TestBytesEqual(t *testing.T) {
var cases = []struct {
a, b []byte
}{
{make([]byte, 2), make([]byte, 2)},
{make([]byte, 2), make([]byte, 2, 3)},
{nil, make([]byte, 0)},
}
for i, c := range cases {
Equal(t, reflect.DeepEqual(c.a, c.b), ObjectsAreEqual(c.a, c.b), "case %d failed", i+1)
}
}
func BenchmarkBytesEqual(b *testing.B) {
const size = 1024 * 8
s := make([]byte, size)
for i := range s {
s[i] = byte(i % 255)
}
s2 := make([]byte, size)
copy(s2, s)
mockT := &mockFailNowTestingT{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
Equal(mockT, s, s2)
}
}
func TestEqualArgsValidation(t *testing.T) {
err := validateEqualArgs(time.Now, time.Now)
EqualError(t, err, "cannot take func type as argument")
}
func ExampleComparisonAssertionFunc() {
t := &testing.T{} // provided by test
adder := func(x, y int) int {
return x + y
}
type args struct {
x int
y int
}
tests := []struct {
name string
args args
expect int
assertion ComparisonAssertionFunc
}{
{"2+2=4", args{2, 2}, 4, Equal},
{"2+2!=5", args{2, 2}, 5, NotEqual},
{"2+3==5", args{2, 3}, 5, Exactly},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, adder(tt.args.x, tt.args.y))
})
}
}
func TestComparisonAssertionFunc(t *testing.T) {
type iface interface {
Name() string
}
tests := []struct {
name string
expect interface{}
got interface{}
assertion ComparisonAssertionFunc
}{
{"implements", (*iface)(nil), t, Implements},
{"isType", (*testing.T)(nil), t, IsType},
{"equal", t, t, Equal},
{"equalValues", t, t, EqualValues},
{"exactly", t, t, Exactly},
{"notEqual", t, nil, NotEqual},
{"notContains", []int{1, 2, 3}, 4, NotContains},
{"subset", []int{1, 2, 3, 4}, []int{2, 3}, Subset},
{"notSubset", []int{1, 2, 3, 4}, []int{0, 3}, NotSubset},
{"elementsMatch", []byte("abc"), []byte("bac"), ElementsMatch},
{"regexp", "^t.*y$", "testify", Regexp},
{"notRegexp", "^t.*y$", "Testify", NotRegexp},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, tt.got)
})
}
}
func ExampleValueAssertionFunc() {
t := &testing.T{} // provided by test
dumbParse := func(input string) interface{} {
var x interface{}
json.Unmarshal([]byte(input), &x)
return x
}
tests := []struct {
name string
arg string
assertion ValueAssertionFunc
}{
{"true is not nil", "true", NotNil},
{"empty string is nil", "", Nil},
{"zero is not nil", "0", NotNil},
{"zero is zero", "0", Zero},
{"false is zero", "false", Zero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, dumbParse(tt.arg))
})
}
}
func TestValueAssertionFunc(t *testing.T) {
tests := []struct {
name string
value interface{}
assertion ValueAssertionFunc
}{
{"notNil", true, NotNil},
{"nil", nil, Nil},
{"empty", []int{}, Empty},
{"notEmpty", []int{1}, NotEmpty},
{"zero", false, Zero},
{"notZero", 42, NotZero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleBoolAssertionFunc() {
t := &testing.T{} // provided by test
isOkay := func(x int) bool {
return x >= 42
}
tests := []struct {
name string
arg int
assertion BoolAssertionFunc
}{
{"-1 is bad", -1, False},
{"42 is good", 42, True},
{"41 is bad", 41, False},
{"45 is cool", 45, True},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, isOkay(tt.arg))
})
}
}
func TestBoolAssertionFunc(t *testing.T) {
tests := []struct {
name string
value bool
assertion BoolAssertionFunc
}{
{"true", true, True},
{"false", false, False},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleErrorAssertionFunc() {
t := &testing.T{} // provided by test
dumbParseNum := func(input string, v interface{}) error {
return json.Unmarshal([]byte(input), v)
}
tests := []struct {
name string
arg string
assertion ErrorAssertionFunc
}{
{"1.2 is number", "1.2", NoError},
{"1.2.3 not number", "1.2.3", Error},
{"true is not number", "true", Error},
{"3 is number", "3", NoError},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var x float64
tt.assertion(t, dumbParseNum(tt.arg, &x))
})
}
}
func TestErrorAssertionFunc(t *testing.T) {
tests := []struct {
name string
err error
assertion ErrorAssertionFunc
}{
{"noError", nil, NoError},
{"error", errors.New("whoops"), Error},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.err)
})
}
}

View File

@ -13,4 +13,4 @@ func New(t TestingT) *Assertions {
} }
} }
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl //go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs

View File

@ -8,16 +8,17 @@ import (
"strings" "strings"
) )
// httpCode is a helper that returns HTTP code of the response. It returns -1 // httpCode is a helper that returns HTTP code of the response. It returns -1 and
// if building a new request fails. // an error if building a new request fails.
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) int { func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) req, err := http.NewRequest(method, url, nil)
if err != nil { if err != nil {
return -1 return -1, err
} }
req.URL.RawQuery = values.Encode()
handler(w, req) handler(w, req)
return w.Code return w.Code, nil
} }
// HTTPSuccess asserts that a specified handler returns a success status code. // HTTPSuccess asserts that a specified handler returns a success status code.
@ -25,12 +26,22 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) i
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
code := httpCode(handler, method, url, values) if h, ok := t.(tHelper); ok {
if code == -1 { h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
return false return false
} }
return code >= http.StatusOK && code <= http.StatusPartialContent
isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
if !isSuccessCode {
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code))
}
return isSuccessCode
} }
// HTTPRedirect asserts that a specified handler returns a redirect status code. // HTTPRedirect asserts that a specified handler returns a redirect status code.
@ -38,12 +49,22 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
code := httpCode(handler, method, url, values) if h, ok := t.(tHelper); ok {
if code == -1 { h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
return false return false
} }
return code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
if !isRedirectCode {
Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code))
}
return isRedirectCode
} }
// HTTPError asserts that a specified handler returns an error status code. // HTTPError asserts that a specified handler returns an error status code.
@ -51,12 +72,22 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
code := httpCode(handler, method, url, values) if h, ok := t.(tHelper); ok {
if code == -1 { h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
return false return false
} }
return code >= http.StatusBadRequest
isErrorCode := code >= http.StatusBadRequest
if !isErrorCode {
Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code))
}
return isErrorCode
} }
// HTTPBody is a helper that returns HTTP body of the response. It returns // HTTPBody is a helper that returns HTTP body of the response. It returns
@ -74,10 +105,13 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s
// HTTPBodyContains asserts that a specified handler returns a // HTTPBodyContains asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool { func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
body := HTTPBody(handler, method, url, values) body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))
@ -91,10 +125,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
// HTTPBodyNotContains asserts that a specified handler returns a // HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool { func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
body := HTTPBody(handler, method, url, values) body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))

View File

@ -19,21 +19,52 @@ func httpError(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
} }
func TestHTTPStatuses(t *testing.T) { func TestHTTPSuccess(t *testing.T) {
assert := New(t) assert := New(t)
mockT := new(testing.T)
assert.Equal(HTTPSuccess(mockT, httpOK, "GET", "/", nil), true) mockT1 := new(testing.T)
assert.Equal(HTTPSuccess(mockT, httpRedirect, "GET", "/", nil), false) assert.Equal(HTTPSuccess(mockT1, httpOK, "GET", "/", nil), true)
assert.Equal(HTTPSuccess(mockT, httpError, "GET", "/", nil), false) assert.False(mockT1.Failed())
assert.Equal(HTTPRedirect(mockT, httpOK, "GET", "/", nil), false) mockT2 := new(testing.T)
assert.Equal(HTTPRedirect(mockT, httpRedirect, "GET", "/", nil), true) assert.Equal(HTTPSuccess(mockT2, httpRedirect, "GET", "/", nil), false)
assert.Equal(HTTPRedirect(mockT, httpError, "GET", "/", nil), false) assert.True(mockT2.Failed())
assert.Equal(HTTPError(mockT, httpOK, "GET", "/", nil), false) mockT3 := new(testing.T)
assert.Equal(HTTPError(mockT, httpRedirect, "GET", "/", nil), false) assert.Equal(HTTPSuccess(mockT3, httpError, "GET", "/", nil), false)
assert.Equal(HTTPError(mockT, httpError, "GET", "/", nil), true) assert.True(mockT3.Failed())
}
func TestHTTPRedirect(t *testing.T) {
assert := New(t)
mockT1 := new(testing.T)
assert.Equal(HTTPRedirect(mockT1, httpOK, "GET", "/", nil), false)
assert.True(mockT1.Failed())
mockT2 := new(testing.T)
assert.Equal(HTTPRedirect(mockT2, httpRedirect, "GET", "/", nil), true)
assert.False(mockT2.Failed())
mockT3 := new(testing.T)
assert.Equal(HTTPRedirect(mockT3, httpError, "GET", "/", nil), false)
assert.True(mockT3.Failed())
}
func TestHTTPError(t *testing.T) {
assert := New(t)
mockT1 := new(testing.T)
assert.Equal(HTTPError(mockT1, httpOK, "GET", "/", nil), false)
assert.True(mockT1.Failed())
mockT2 := new(testing.T)
assert.Equal(HTTPError(mockT2, httpRedirect, "GET", "/", nil), false)
assert.True(mockT2.Failed())
mockT3 := new(testing.T)
assert.Equal(HTTPError(mockT3, httpError, "GET", "/", nil), true)
assert.False(mockT3.Failed())
} }
func TestHTTPStatusesWrapper(t *testing.T) { func TestHTTPStatusesWrapper(t *testing.T) {
@ -58,6 +89,35 @@ func httpHelloName(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf("Hello, %s!", name))) w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
} }
func TestHTTPRequestWithNoParams(t *testing.T) {
var got *http.Request
handler := func(w http.ResponseWriter, r *http.Request) {
got = r
w.WriteHeader(http.StatusOK)
}
True(t, HTTPSuccess(t, handler, "GET", "/url", nil))
Empty(t, got.URL.Query())
Equal(t, "/url", got.URL.RequestURI())
}
func TestHTTPRequestWithParams(t *testing.T) {
var got *http.Request
handler := func(w http.ResponseWriter, r *http.Request) {
got = r
w.WriteHeader(http.StatusOK)
}
params := url.Values{}
params.Add("id", "12345")
True(t, HTTPSuccess(t, handler, "GET", "/url", params))
Equal(t, url.Values{"id": []string{"12345"}}, got.URL.Query())
Equal(t, "/url?id=12345", got.URL.String())
Equal(t, "/url?id=12345", got.URL.RequestURI())
}
func TestHttpBody(t *testing.T) { func TestHttpBody(t *testing.T) {
assert := New(t) assert := New(t)
mockT := new(testing.T) mockT := new(testing.T)

View File

@ -1,6 +1,7 @@
package mock package mock
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
"regexp" "regexp"
@ -15,10 +16,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func inin() {
spew.Config.SortKeys = true
}
// TestingT is an interface wrapper around *testing.T // TestingT is an interface wrapper around *testing.T
type TestingT interface { type TestingT interface {
Logf(format string, args ...interface{}) Logf(format string, args ...interface{})
@ -45,6 +42,9 @@ type Call struct {
// this method is called. // this method is called.
ReturnArguments Arguments ReturnArguments Arguments
// Holds the caller info for the On() call
callerInfo []string
// The number of times to return the return arguments when setting // The number of times to return the return arguments when setting
// expectations. 0 means to always return the value. // expectations. 0 means to always return the value.
Repeatability int Repeatability int
@ -52,22 +52,28 @@ type Call struct {
// Amount of times this call has been called // Amount of times this call has been called
totalCalls int 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 // 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. // receives a message or is closed. nil means it returns immediately.
WaitFor <-chan time.Time WaitFor <-chan time.Time
waitTime time.Duration
// Holds a handler used to manipulate arguments content that are passed by // Holds a handler used to manipulate arguments content that are passed by
// reference. It's useful when mocking methods such as unmarshalers or // reference. It's useful when mocking methods such as unmarshalers or
// decoders. // decoders.
RunFn func(Arguments) RunFn func(Arguments)
} }
func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *Call { func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call {
return &Call{ return &Call{
Parent: parent, Parent: parent,
Method: methodName, Method: methodName,
Arguments: methodArguments, Arguments: methodArguments,
ReturnArguments: make([]interface{}, 0), ReturnArguments: make([]interface{}, 0),
callerInfo: callerInfo,
Repeatability: 0, Repeatability: 0,
WaitFor: nil, WaitFor: nil,
RunFn: nil, RunFn: nil,
@ -134,7 +140,10 @@ func (c *Call) WaitUntil(w <-chan time.Time) *Call {
// //
// Mock.On("MyMethod", arg1, arg2).After(time.Second) // Mock.On("MyMethod", arg1, arg2).After(time.Second)
func (c *Call) After(d time.Duration) *Call { func (c *Call) After(d time.Duration) *Call {
return c.WaitUntil(time.After(d)) c.lock()
defer c.unlock()
c.waitTime = d
return c
} }
// Run sets a handler to be called before returning. It can be used when // Run sets a handler to be called before returning. It can be used when
@ -145,13 +154,22 @@ func (c *Call) After(d time.Duration) *Call {
// arg := args.Get(0).(*map[string]interface{}) // arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar" // arg["foo"] = "bar"
// }) // })
func (c *Call) Run(fn func(Arguments)) *Call { func (c *Call) Run(fn func(args Arguments)) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
c.RunFn = fn c.RunFn = fn
return c 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 // On chains a new expectation description onto the mocked interface. This
// allows syntax like. // allows syntax like.
// //
@ -173,6 +191,10 @@ type Mock struct {
// Holds the calls that were made to this mocked object. // Holds the calls that were made to this mocked object.
Calls []Call 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 // TestData holds any data that might be useful for testing. Testify ignores
// this data completely allowing you to do whatever you like with it. // this data completely allowing you to do whatever you like with it.
testData objx.Map testData objx.Map
@ -195,6 +217,27 @@ func (m *Mock) TestData() objx.Map {
Setting expectations 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 // On starts a description of an expectation of the specified method
// being called. // being called.
// //
@ -208,7 +251,7 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
c := newCall(m, methodName, arguments...) c := newCall(m, methodName, assert.CallerInfo(), arguments...)
m.ExpectedCalls = append(m.ExpectedCalls, c) m.ExpectedCalls = append(m.ExpectedCalls, c)
return c return c
} }
@ -218,8 +261,6 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
// */ // */
func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
m.mutex.Lock()
defer m.mutex.Unlock()
for i, call := range m.ExpectedCalls { for i, call := range m.ExpectedCalls {
if call.Method == method && call.Repeatability > -1 { if call.Method == method && call.Repeatability > -1 {
@ -233,27 +274,25 @@ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *
return -1, nil return -1, nil
} }
func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) { func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) {
diffCount := 0 var diffCount int
var closestCall *Call var closestCall *Call
var err string
for _, call := range m.expectedCalls() { for _, call := range m.expectedCalls() {
if call.Method == method { if call.Method == method {
_, tempDiffCount := call.Arguments.Diff(arguments) errInfo, tempDiffCount := call.Arguments.Diff(arguments)
if tempDiffCount < diffCount || diffCount == 0 { if tempDiffCount < diffCount || diffCount == 0 {
diffCount = tempDiffCount diffCount = tempDiffCount
closestCall = call closestCall = call
err = errInfo
} }
} }
} }
if closestCall == nil { return closestCall, err
return false, nil
}
return true, closestCall
} }
func callString(method string, arguments Arguments, includeArgumentValues bool) string { func callString(method string, arguments Arguments, includeArgumentValues bool) string {
@ -283,7 +322,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
functionPath := runtime.FuncForPC(pc).Name() functionPath := runtime.FuncForPC(pc).Name()
//Next four lines are required to use GCCGO function naming conventions. //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 //For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
//uses inteface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree //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>. //With GCCGO we need to remove interface information starting from pN<dd>.
re := regexp.MustCompile("\\.pN\\d+_") re := regexp.MustCompile("\\.pN\\d+_")
if re.MatchString(functionPath) { if re.MatchString(functionPath) {
@ -291,8 +330,17 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
} }
parts := strings.Split(functionPath, ".") parts := strings.Split(functionPath, ".")
functionName := parts[len(parts)-1] functionName := parts[len(parts)-1]
return m.MethodCalled(functionName, arguments...)
}
found, call := m.findExpectedCall(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 { if found < 0 {
// we have to fail here - because we don't know what to do // we have to fail here - because we don't know what to do
@ -302,45 +350,52 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
// b) the arguments are not what was expected, or // b) the arguments are not what was expected, or
// c) the developer has forgotten to add an accompanying On...Return pair. // c) the developer has forgotten to add an accompanying On...Return pair.
closestFound, closestCall := m.findClosestCall(functionName, arguments...) closestCall, mismatch := m.findClosestCall(methodName, arguments...)
if closestFound {
panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\n", callString(functionName, arguments, true), callString(functionName, closestCall.Arguments, true), diffArguments(arguments, closestCall.Arguments)))
} else {
panic(fmt.Sprintf("\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", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo()))
}
} else {
m.mutex.Lock()
switch {
case call.Repeatability == 1:
call.Repeatability = -1
call.totalCalls++
case call.Repeatability > 1:
call.Repeatability--
call.totalCalls++
case call.Repeatability == 0:
call.totalCalls++
}
m.mutex.Unlock() 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 // add the call
m.mutex.Lock() m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...))
m.Calls = append(m.Calls, *newCall(m, functionName, arguments...))
m.mutex.Unlock() m.mutex.Unlock()
// block if specified // block if specified
if call.WaitFor != nil { if call.WaitFor != nil {
<-call.WaitFor <-call.WaitFor
} else {
time.Sleep(call.waitTime)
} }
if call.RunFn != nil { m.mutex.Lock()
call.RunFn(arguments) runFn := call.RunFn
m.mutex.Unlock()
if runFn != nil {
runFn(arguments)
} }
return call.ReturnArguments m.mutex.Lock()
returnArgs := call.ReturnArguments
m.mutex.Unlock()
return returnArgs
} }
/* /*
@ -356,6 +411,9 @@ type assertExpectationser interface {
// //
// Calls may have occurred in any order. // Calls may have occurred in any order.
func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
for _, obj := range testObjects { for _, obj := range testObjects {
if m, ok := obj.(Mock); ok { if m, ok := obj.(Mock); ok {
t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)")
@ -363,6 +421,7 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
} }
m := obj.(assertExpectationser) m := obj.(assertExpectationser)
if !m.AssertExpectations(t) { if !m.AssertExpectations(t) {
t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m))
return false return false
} }
} }
@ -372,25 +431,29 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
// AssertExpectations asserts that everything specified with On and Return was // AssertExpectations asserts that everything specified with On and Return was
// in fact called as expected. Calls may have occurred in any order. // in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertExpectations(t TestingT) bool { 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 somethingMissing bool
var failedExpectations int var failedExpectations int
// iterate through each expectation // iterate through each expectation
expectedCalls := m.expectedCalls() expectedCalls := m.expectedCalls()
for _, expectedCall := range expectedCalls { for _, expectedCall := range expectedCalls {
if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 { if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {
somethingMissing = true somethingMissing = true
failedExpectations++ failedExpectations++
t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo)
} else { } else {
m.mutex.Lock()
if expectedCall.Repeatability > 0 { if expectedCall.Repeatability > 0 {
somethingMissing = true somethingMissing = true
failedExpectations++ failedExpectations++
t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo)
} else { } else {
t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) t.Logf("PASS:\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
} }
m.mutex.Unlock()
} }
} }
@ -403,6 +466,11 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
// AssertNumberOfCalls asserts that the method was called expectedCalls times. // AssertNumberOfCalls asserts that the method was called expectedCalls times.
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { 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 var actualCalls int
for _, call := range m.calls() { for _, call := range m.calls() {
if call.Method == methodName { if call.Method == methodName {
@ -415,9 +483,22 @@ func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls
// AssertCalled asserts that the method was called. // 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. // 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 { func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) { if h, ok := t.(tHelper); ok {
t.Logf("%v", m.expectedCalls()) h.Helper()
return false }
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 return true
} }
@ -425,9 +506,14 @@ func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interfac
// AssertNotCalled asserts that the method was not called. // 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. // 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 { func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) { if h, ok := t.(tHelper); ok {
t.Logf("%v", m.expectedCalls()) h.Helper()
return false }
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 return true
} }
@ -450,14 +536,10 @@ func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
} }
func (m *Mock) expectedCalls() []*Call { func (m *Mock) expectedCalls() []*Call {
m.mutex.Lock()
defer m.mutex.Unlock()
return append([]*Call{}, m.ExpectedCalls...) return append([]*Call{}, m.ExpectedCalls...)
} }
func (m *Mock) calls() []Call { func (m *Mock) calls() []Call {
m.mutex.Lock()
defer m.mutex.Unlock()
return append([]Call{}, m.Calls...) return append([]Call{}, m.Calls...)
} }
@ -471,7 +553,7 @@ type Arguments []interface{}
const ( const (
// Anything is used in Diff and Assert when the argument being tested // Anything is used in Diff and Assert when the argument being tested
// shouldn't be taken into consideration. // shouldn't be taken into consideration.
Anything string = "mock.Anything" Anything = "mock.Anything"
) )
// AnythingOfTypeArgument is a string that contains the type of an argument // AnythingOfTypeArgument is a string that contains the type of an argument
@ -496,9 +578,25 @@ type argumentMatcher struct {
func (f argumentMatcher) Matches(argument interface{}) bool { func (f argumentMatcher) Matches(argument interface{}) bool {
expectType := f.fn.Type().In(0) 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
}
if reflect.TypeOf(argument).AssignableTo(expectType) { argType := reflect.TypeOf(argument)
result := f.fn.Call([]reflect.Value{reflect.ValueOf(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 result[0].Bool()
} }
return false return false
@ -518,7 +616,7 @@ func (f argumentMatcher) String() string {
// //
// |fn|, must be a function accepting a single argument (of the expected type) // |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, // which returns a bool. If |fn| doesn't match the required signature,
// MathedBy() panics. // MatchedBy() panics.
func MatchedBy(fn interface{}) argumentMatcher { func MatchedBy(fn interface{}) argumentMatcher {
fnType := reflect.TypeOf(fn) fnType := reflect.TypeOf(fn)
@ -558,6 +656,7 @@ func (args Arguments) Is(objects ...interface{}) bool {
// //
// Returns the diff string and number of differences found. // Returns the diff string and number of differences found.
func (args Arguments) Diff(objects []interface{}) (string, int) { func (args Arguments) Diff(objects []interface{}) (string, int) {
//TODO: could return string as error and nil for No difference
var output = "\n" var output = "\n"
var differences int var differences int
@ -569,25 +668,30 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
for i := 0; i < maxArgCount; i++ { for i := 0; i < maxArgCount; i++ {
var actual, expected interface{} var actual, expected interface{}
var actualFmt, expectedFmt string
if len(objects) <= i { if len(objects) <= i {
actual = "(Missing)" actual = "(Missing)"
actualFmt = "(Missing)"
} else { } else {
actual = objects[i] actual = objects[i]
actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual)
} }
if len(args) <= i { if len(args) <= i {
expected = "(Missing)" expected = "(Missing)"
expectedFmt = "(Missing)"
} else { } else {
expected = args[i] expected = args[i]
expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected)
} }
if matcher, ok := expected.(argumentMatcher); ok { if matcher, ok := expected.(argumentMatcher); ok {
if matcher.Matches(actual) { if matcher.Matches(actual) {
output = fmt.Sprintf("%s\t%d: \u2705 %s matched by %s\n", output, i, actual, matcher) output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher)
} else { } else {
differences++ differences++
output = fmt.Sprintf("%s\t%d: \u2705 %s not matched by %s\n", output, i, actual, matcher) output = fmt.Sprintf("%s\t%d: PASS: %s not matched by %s\n", output, i, actualFmt, matcher)
} }
} else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
@ -595,7 +699,7 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
// not match // not match
differences++ differences++
output = fmt.Sprintf("%s\t%d: \u274C type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual) output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
} }
} else { } else {
@ -604,11 +708,11 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
// match // match
output = fmt.Sprintf("%s\t%d: \u2705 %s == %s\n", output, i, actual, expected) output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt)
} else { } else {
// not match // not match
differences++ differences++
output = fmt.Sprintf("%s\t%d: \u274C %s != %s\n", output, i, actual, expected) output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
} }
} }
@ -625,6 +729,9 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
// Assert compares the arguments with the specified objects and fails if // Assert compares the arguments with the specified objects and fails if
// they do not exactly match. // they do not exactly match.
func (args Arguments) Assert(t TestingT, objects ...interface{}) bool { func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
// get the differences // get the differences
diff, diffCount := args.Diff(objects) diff, diffCount := args.Diff(objects)
@ -719,6 +826,10 @@ func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
} }
func diffArguments(expected Arguments, actual Arguments) string { 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 { for x := range expected {
if diffString := diff(expected[x], actual[x]); diffString != "" { if diffString := diff(expected[x], actual[x]); diffString != "" {
return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString) return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString)
@ -746,8 +857,8 @@ func diff(expected interface{}, actual interface{}) string {
return "" return ""
} }
e := spew.Sdump(expected) e := spewConfig.Sdump(expected)
a := spew.Sdump(actual) a := spewConfig.Sdump(actual)
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(e), A: difflib.SplitLines(e),
@ -761,3 +872,14 @@ func diff(expected interface{}, actual interface{}) string {
return diff return diff
} }
var spewConfig = spew.ConfigState{
Indent: " ",
DisablePointerAddresses: true,
DisableCapacities: true,
SortKeys: true,
}
type tHelper interface {
Helper()
}

View File

@ -2,10 +2,15 @@ package mock
import ( import (
"errors" "errors"
"github.com/stretchr/testify/assert" "fmt"
"github.com/stretchr/testify/require" "regexp"
"runtime"
"sync"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
/* /*
@ -40,6 +45,26 @@ func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error {
return args.Error(0) return args.Error(0)
} }
func (i *TestExampleImplementation) TheExampleMethod4(v ExampleInterface) error {
args := i.Called(v)
return args.Error(0)
}
func (i *TestExampleImplementation) TheExampleMethod5(ch chan struct{}) error {
args := i.Called(ch)
return args.Error(0)
}
func (i *TestExampleImplementation) TheExampleMethod6(m map[string]bool) error {
args := i.Called(m)
return args.Error(0)
}
func (i *TestExampleImplementation) TheExampleMethod7(slice []bool) error {
args := i.Called(slice)
return args.Error(0)
}
func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error { func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error {
args := i.Called(fn) args := i.Called(fn)
return args.Error(0) return args.Error(0)
@ -55,6 +80,11 @@ func (i *TestExampleImplementation) TheExampleMethodVariadicInterface(a ...inter
return args.Error(0) return args.Error(0)
} }
func (i *TestExampleImplementation) TheExampleMethodMixedVariadic(a int, b ...int) error {
args := i.Called(a, b)
return args.Error(0)
}
type ExampleFuncType func(string) error type ExampleFuncType func(string) error
func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error { func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error {
@ -62,6 +92,34 @@ func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType)
return args.Error(0) return args.Error(0)
} }
// MockTestingT mocks a test struct
type MockTestingT struct {
logfCount, errorfCount, failNowCount int
}
const mockTestingTFailNowCalled = "FailNow was called"
func (m *MockTestingT) Logf(string, ...interface{}) {
m.logfCount++
}
func (m *MockTestingT) Errorf(string, ...interface{}) {
m.errorfCount++
}
// FailNow mocks the FailNow call.
// It panics in order to mimic the FailNow behavior in the sense that
// the execution stops.
// When expecting this method, the call that invokes it should use the following code:
//
// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...})
func (m *MockTestingT) FailNow() {
m.failNowCount++
// this function should panic now to stop the execution as expected
panic(mockTestingTFailNowCalled)
}
/* /*
Mock Mock
*/ */
@ -91,6 +149,8 @@ func Test_Mock_Chained_On(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService = new(TestExampleImplementation) var mockedService = new(TestExampleImplementation)
// determine our current line number so we can assert the expected calls callerInfo properly
_, _, line, _ := runtime.Caller(0)
mockedService. mockedService.
On("TheExampleMethod", 1, 2, 3). On("TheExampleMethod", 1, 2, 3).
Return(0). Return(0).
@ -98,17 +158,19 @@ func Test_Mock_Chained_On(t *testing.T) {
Return(nil) Return(nil)
expectedCalls := []*Call{ expectedCalls := []*Call{
&Call{ {
Parent: &mockedService.Mock, Parent: &mockedService.Mock,
Method: "TheExampleMethod", Method: "TheExampleMethod",
Arguments: []interface{}{1, 2, 3}, Arguments: []interface{}{1, 2, 3},
ReturnArguments: []interface{}{0}, ReturnArguments: []interface{}{0},
callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+2)},
}, },
&Call{ {
Parent: &mockedService.Mock, Parent: &mockedService.Mock,
Method: "TheExampleMethod3", Method: "TheExampleMethod3",
Arguments: []interface{}{AnythingOfType("*mock.ExampleType")}, Arguments: []interface{}{AnythingOfType("*mock.ExampleType")},
ReturnArguments: []interface{}{nil}, ReturnArguments: []interface{}{nil},
callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+4)},
}, },
} }
assert.Equal(t, expectedCalls, mockedService.ExpectedCalls) assert.Equal(t, expectedCalls, mockedService.ExpectedCalls)
@ -170,19 +232,52 @@ func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
}) })
} }
func TestMock_WithTest(t *testing.T) {
var (
mockedService TestExampleImplementation
mockedTest MockTestingT
)
mockedService.Test(&mockedTest)
mockedService.On("TheExampleMethod", 1, 2, 3).Return(0, nil)
// Test that on an expected call, the test was not failed
mockedService.TheExampleMethod(1, 2, 3)
// Assert that Errorf and FailNow were not called
assert.Equal(t, 0, mockedTest.errorfCount)
assert.Equal(t, 0, mockedTest.failNowCount)
// Test that on unexpected call, the mocked test was called to fail the test
assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {
mockedService.TheExampleMethod(1, 1, 1)
})
// Assert that Errorf and FailNow were called once
assert.Equal(t, 1, mockedTest.errorfCount)
assert.Equal(t, 1, mockedTest.failNowCount)
}
func Test_Mock_On_WithPtrArgMatcher(t *testing.T) { func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod3", mockedService.On("TheExampleMethod3",
MatchedBy(func(a *ExampleType) bool { return a.ran == true }), MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == true }),
).Return(nil) ).Return(nil)
mockedService.On("TheExampleMethod3", mockedService.On("TheExampleMethod3",
MatchedBy(func(a *ExampleType) bool { return a.ran == false }), MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == false }),
).Return(errors.New("error")) ).Return(errors.New("error"))
mockedService.On("TheExampleMethod3",
MatchedBy(func(a *ExampleType) bool { return a == nil }),
).Return(errors.New("error2"))
assert.Equal(t, mockedService.TheExampleMethod3(&ExampleType{true}), nil) assert.Equal(t, mockedService.TheExampleMethod3(&ExampleType{true}), nil)
assert.EqualError(t, mockedService.TheExampleMethod3(&ExampleType{false}), "error") assert.EqualError(t, mockedService.TheExampleMethod3(&ExampleType{false}), "error")
assert.EqualError(t, mockedService.TheExampleMethod3(nil), "error2")
} }
func Test_Mock_On_WithFuncArgMatcher(t *testing.T) { func Test_Mock_On_WithFuncArgMatcher(t *testing.T) {
@ -191,17 +286,62 @@ func Test_Mock_On_WithFuncArgMatcher(t *testing.T) {
fixture1, fixture2 := errors.New("fixture1"), errors.New("fixture2") fixture1, fixture2 := errors.New("fixture1"), errors.New("fixture2")
mockedService.On("TheExampleMethodFunc", mockedService.On("TheExampleMethodFunc",
MatchedBy(func(a func(string) error) bool { return a("string") == fixture1 }), MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture1 }),
).Return(errors.New("fixture1")) ).Return(errors.New("fixture1"))
mockedService.On("TheExampleMethodFunc", mockedService.On("TheExampleMethodFunc",
MatchedBy(func(a func(string) error) bool { return a("string") == fixture2 }), MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture2 }),
).Return(errors.New("fixture2")) ).Return(errors.New("fixture2"))
mockedService.On("TheExampleMethodFunc",
MatchedBy(func(a func(string) error) bool { return a == nil }),
).Return(errors.New("fixture3"))
assert.EqualError(t, mockedService.TheExampleMethodFunc( assert.EqualError(t, mockedService.TheExampleMethodFunc(
func(string) error { return fixture1 }), "fixture1") func(string) error { return fixture1 }), "fixture1")
assert.EqualError(t, mockedService.TheExampleMethodFunc( assert.EqualError(t, mockedService.TheExampleMethodFunc(
func(string) error { return fixture2 }), "fixture2") func(string) error { return fixture2 }), "fixture2")
assert.EqualError(t, mockedService.TheExampleMethodFunc(nil), "fixture3")
}
func Test_Mock_On_WithInterfaceArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod4",
MatchedBy(func(a ExampleInterface) bool { return a == nil }),
).Return(errors.New("fixture1"))
assert.EqualError(t, mockedService.TheExampleMethod4(nil), "fixture1")
}
func Test_Mock_On_WithChannelArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod5",
MatchedBy(func(ch chan struct{}) bool { return ch == nil }),
).Return(errors.New("fixture1"))
assert.EqualError(t, mockedService.TheExampleMethod5(nil), "fixture1")
}
func Test_Mock_On_WithMapArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod6",
MatchedBy(func(m map[string]bool) bool { return m == nil }),
).Return(errors.New("fixture1"))
assert.EqualError(t, mockedService.TheExampleMethod6(nil), "fixture1")
}
func Test_Mock_On_WithSliceArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod7",
MatchedBy(func(slice []bool) bool { return slice == nil }),
).Return(errors.New("fixture1"))
assert.EqualError(t, mockedService.TheExampleMethod7(nil), "fixture1")
} }
func Test_Mock_On_WithVariadicFunc(t *testing.T) { func Test_Mock_On_WithVariadicFunc(t *testing.T) {
@ -226,6 +366,29 @@ func Test_Mock_On_WithVariadicFunc(t *testing.T) {
} }
func Test_Mock_On_WithMixedVariadicFunc(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
c := mockedService.
On("TheExampleMethodMixedVariadic", 1, []int{2, 3, 4}).
Return(nil)
assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
assert.Equal(t, 2, len(c.Arguments))
assert.Equal(t, 1, c.Arguments[0])
assert.Equal(t, []int{2, 3, 4}, c.Arguments[1])
assert.NotPanics(t, func() {
mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 4)
})
assert.Panics(t, func() {
mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 5)
})
}
func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) { func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) {
// make a test impl object // make a test impl object
@ -726,7 +889,7 @@ func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
mockedService2.Called(2) mockedService2.Called(2)
mockedService3.Called(3) mockedService3.Called(3)
assert.True(t, AssertExpectationsForObjects(t, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock)) assert.True(t, AssertExpectationsForObjects(t, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock))
assert.True(t, AssertExpectationsForObjects(t, mockedService1, mockedService2, mockedService3)) assert.True(t, AssertExpectationsForObjects(t, mockedService1, mockedService2, mockedService3))
} }
@ -745,7 +908,7 @@ func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
mockedService3.Called(3) mockedService3.Called(3)
tt := new(testing.T) tt := new(testing.T)
assert.False(t, AssertExpectationsForObjects(tt, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock)) assert.False(t, AssertExpectationsForObjects(tt, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock))
assert.False(t, AssertExpectationsForObjects(tt, mockedService1, mockedService2, mockedService3)) assert.False(t, AssertExpectationsForObjects(tt, mockedService1, mockedService2, mockedService3))
} }
@ -969,6 +1132,31 @@ func Test_Mock_AssertNotCalled(t *testing.T) {
} }
func Test_Mock_AssertOptional(t *testing.T) {
// Optional called
var ms1 = new(TestExampleImplementation)
ms1.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil)
ms1.TheExampleMethod(1, 2, 3)
tt1 := new(testing.T)
assert.Equal(t, true, ms1.AssertExpectations(tt1))
// Optional not called
var ms2 = new(TestExampleImplementation)
ms2.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil)
tt2 := new(testing.T)
assert.Equal(t, true, ms2.AssertExpectations(tt2))
// Non-optional called
var ms3 = new(TestExampleImplementation)
ms3.On("TheExampleMethod", 1, 2, 3).Return(4, nil)
ms3.TheExampleMethod(1, 2, 3)
tt3 := new(testing.T)
assert.Equal(t, true, ms3.AssertExpectations(tt3))
}
/* /*
Arguments helper methods Arguments helper methods
*/ */
@ -999,8 +1187,8 @@ func Test_Arguments_Diff(t *testing.T) {
diff, count = args.Diff([]interface{}{"Hello World", 456, "false"}) diff, count = args.Diff([]interface{}{"Hello World", 456, "false"})
assert.Equal(t, 2, count) assert.Equal(t, 2, count)
assert.Contains(t, diff, `%!s(int=456) != %!s(int=123)`) assert.Contains(t, diff, `(int=456) != (int=123)`)
assert.Contains(t, diff, `false != %!s(bool=true)`) assert.Contains(t, diff, `(string=false) != (bool=true)`)
} }
@ -1012,7 +1200,7 @@ func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"}) diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"})
assert.Equal(t, 3, count) assert.Equal(t, 3, count)
assert.Contains(t, diff, `extra != (Missing)`) assert.Contains(t, diff, `(string=extra) != (Missing)`)
} }
@ -1054,7 +1242,7 @@ func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
diff, count = args.Diff([]interface{}{"string", 123, true}) diff, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Contains(t, diff, `string != type int - %!s(int=123)`) assert.Contains(t, diff, `string != type int - (int=123)`)
} }
@ -1066,14 +1254,14 @@ func Test_Arguments_Diff_WithArgMatcher(t *testing.T) {
diff, count := args.Diff([]interface{}{"string", 124, true}) diff, count := args.Diff([]interface{}{"string", 124, true})
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Contains(t, diff, `%!s(int=124) not matched by func(int) bool`) assert.Contains(t, diff, `(int=124) not matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", false, true}) diff, count = args.Diff([]interface{}{"string", false, true})
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Contains(t, diff, `%!s(bool=false) not matched by func(int) bool`) assert.Contains(t, diff, `(bool=false) not matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", 123, false}) diff, count = args.Diff([]interface{}{"string", 123, false})
assert.Contains(t, diff, `%!s(int=123) matched by func(int) bool`) assert.Contains(t, diff, `(int=123) matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", 123, true}) diff, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 0, count) assert.Equal(t, 0, count)
@ -1130,3 +1318,180 @@ func Test_Arguments_Bool(t *testing.T) {
assert.Equal(t, true, args.Bool(2)) assert.Equal(t, true, args.Bool(2))
} }
func Test_WaitUntil_Parallel(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
ch1 := make(chan time.Time)
ch2 := make(chan time.Time)
mockedService.Mock.On("TheExampleMethod2", true).Return().WaitUntil(ch2).Run(func(args Arguments) {
ch1 <- time.Now()
})
mockedService.Mock.On("TheExampleMethod2", false).Return().WaitUntil(ch1)
// Lock both goroutines on the .WaitUntil method
go func() {
mockedService.TheExampleMethod2(false)
}()
go func() {
mockedService.TheExampleMethod2(true)
}()
// Allow the first call to execute, so the second one executes afterwards
ch2 <- time.Now()
}
func Test_MockMethodCalled(t *testing.T) {
m := new(Mock)
m.On("foo", "hello").Return("world")
retArgs := m.MethodCalled("foo", "hello")
require.True(t, len(retArgs) == 1)
require.Equal(t, "world", retArgs[0])
m.AssertExpectations(t)
}
// Test to validate fix for racy concurrent call access in MethodCalled()
func Test_MockReturnAndCalledConcurrent(t *testing.T) {
iterations := 1000
m := &Mock{}
call := m.On("ConcurrencyTestMethod")
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
for i := 0; i < iterations; i++ {
call.Return(10)
}
wg.Done()
}()
go func() {
for i := 0; i < iterations; i++ {
ConcurrencyTestMethod(m)
}
wg.Done()
}()
wg.Wait()
}
type timer struct{ Mock }
func (s *timer) GetTime(i int) string {
return s.Called(i).Get(0).(string)
}
type tCustomLogger struct {
*testing.T
logs []string
errs []string
}
func (tc *tCustomLogger) Logf(format string, args ...interface{}) {
tc.T.Logf(format, args...)
tc.logs = append(tc.logs, fmt.Sprintf(format, args...))
}
func (tc *tCustomLogger) Errorf(format string, args ...interface{}) {
tc.errs = append(tc.errs, fmt.Sprintf(format, args...))
}
func (tc *tCustomLogger) FailNow() {}
func TestLoggingAssertExpectations(t *testing.T) {
m := new(timer)
m.On("GetTime", 0).Return("")
tcl := &tCustomLogger{t, []string{}, []string{}}
AssertExpectationsForObjects(tcl, m, new(TestExampleImplementation))
require.Equal(t, 1, len(tcl.errs))
assert.Regexp(t, regexp.MustCompile("(?s)FAIL: 0 out of 1 expectation\\(s\\) were met.*The code you are testing needs to make 1 more call\\(s\\).*"), tcl.errs[0])
require.Equal(t, 2, len(tcl.logs))
assert.Regexp(t, regexp.MustCompile("(?s)FAIL:\tGetTime\\(int\\).*"), tcl.logs[0])
require.Equal(t, "Expectations didn't match for Mock: *mock.timer", tcl.logs[1])
}
func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
waitDuration := 1
total, waitMs := 5, time.Millisecond*time.Duration(waitDuration)
aTimer := new(timer)
for i := 0; i < total; i++ {
aTimer.On("GetTime", i).After(waitMs).Return(fmt.Sprintf("Time%d", i)).Once()
}
time.Sleep(waitMs)
start := time.Now()
var results []string
for i := 0; i < total; i++ {
results = append(results, aTimer.GetTime(i))
}
end := time.Now()
elapsedTime := end.Sub(start)
assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs))
assert.Equal(t, total, len(results))
for i := range results {
assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same")
}
}
func TestArgumentMatcherToPrintMismatch(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(
`\s+mock: Unexpected Method Call\s+-*\s+GetTime\(int\)\s+0: 1\s+The closest call I have is:\s+GetTime\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(int=1\) not matched by func\(int\) bool`)
assert.Regexp(t, matchingExp, r)
}
}()
m := new(timer)
m.On("GetTime", MatchedBy(func(i int) bool { return false })).Return("SomeTime").Once()
res := m.GetTime(1)
require.Equal(t, "SomeTime", res)
m.AssertExpectations(t)
}
func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod(int,int,int)`, `0: 1\s+1: 1\s+2: 2`, `0: 1\s+1: 1\s+2: 1`, `0: PASS: \(int=1\) == \(int=1\)\s+1: PASS: \(int=1\) == \(int=1\)\s+2: FAIL: \(int=2\) != \(int=1\)`))
assert.Regexp(t, matchingExp, r)
}
}()
m := new(TestExampleImplementation)
m.On("TheExampleMethod", 1, 1, 1).Return(1, nil).Once()
m.On("TheExampleMethod", 2, 2, 2).Return(2, nil).Once()
m.TheExampleMethod(1, 1, 2)
}
func TestClosestCallMismatchedArgumentValueInformation(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`GetTime(int)`, "0: 1", "0: 999", `0: FAIL: \(int=1\) != \(int=999\)`))
assert.Regexp(t, matchingExp, r)
}
}()
m := new(timer)
m.On("GetTime", 999).Return("SomeTime").Once()
_ = m.GetTime(1)
}
func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string {
rMethod := regexp.QuoteMeta(method)
return fmt.Sprintf(`\s+mock: Unexpected Method Call\s+-*\s+%s\s+%s\s+The closest call I have is:\s+%s\s+%s\s+Diff: %s`,
rMethod, calledArg, rMethod, expectedArg, diff)
}
func ConcurrencyTestMethod(m *Mock) {
m.Called()
}

View File

@ -13,4 +13,4 @@ func New(t TestingT) *Assertions {
} }
} }
//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl //go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{{.Comment}} {{.Comment}}
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
t.FailNow() if h, ok := t.(tHelper); ok { h.Helper() }
} t.FailNow()
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
{{.CommentWithoutT "a"}} {{.CommentWithoutT "a"}}
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
if h, ok := a.t.(tHelper); ok { h.Helper() }
{{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
} }

View File

@ -6,4 +6,24 @@ type TestingT interface {
FailNow() FailNow()
} }
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl type tHelper interface {
Helper()
}
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
// for table driven tests.
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
// for table driven tests.
type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
// for table driven tests.
type BoolAssertionFunc func(TestingT, bool, ...interface{})
// ValuesAssertionFunc is a common function prototype when validating an error value. Can be useful
// for table driven tests.
type ErrorAssertionFunc func(TestingT, error, ...interface{})
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs

View File

@ -1,6 +1,7 @@
package require package require
import ( import (
"encoding/json"
"errors" "errors"
"testing" "testing"
"time" "time"
@ -367,3 +368,199 @@ func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
t.Error("Check should fail") t.Error("Check should fail")
} }
} }
func ExampleComparisonAssertionFunc() {
t := &testing.T{} // provided by test
adder := func(x, y int) int {
return x + y
}
type args struct {
x int
y int
}
tests := []struct {
name string
args args
expect int
assertion ComparisonAssertionFunc
}{
{"2+2=4", args{2, 2}, 4, Equal},
{"2+2!=5", args{2, 2}, 5, NotEqual},
{"2+3==5", args{2, 3}, 5, Exactly},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, adder(tt.args.x, tt.args.y))
})
}
}
func TestComparisonAssertionFunc(t *testing.T) {
type iface interface {
Name() string
}
tests := []struct {
name string
expect interface{}
got interface{}
assertion ComparisonAssertionFunc
}{
{"implements", (*iface)(nil), t, Implements},
{"isType", (*testing.T)(nil), t, IsType},
{"equal", t, t, Equal},
{"equalValues", t, t, EqualValues},
{"exactly", t, t, Exactly},
{"notEqual", t, nil, NotEqual},
{"notContains", []int{1, 2, 3}, 4, NotContains},
{"subset", []int{1, 2, 3, 4}, []int{2, 3}, Subset},
{"notSubset", []int{1, 2, 3, 4}, []int{0, 3}, NotSubset},
{"elementsMatch", []byte("abc"), []byte("bac"), ElementsMatch},
{"regexp", "^t.*y$", "testify", Regexp},
{"notRegexp", "^t.*y$", "Testify", NotRegexp},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, tt.got)
})
}
}
func ExampleValueAssertionFunc() {
t := &testing.T{} // provided by test
dumbParse := func(input string) interface{} {
var x interface{}
json.Unmarshal([]byte(input), &x)
return x
}
tests := []struct {
name string
arg string
assertion ValueAssertionFunc
}{
{"true is not nil", "true", NotNil},
{"empty string is nil", "", Nil},
{"zero is not nil", "0", NotNil},
{"zero is zero", "0", Zero},
{"false is zero", "false", Zero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, dumbParse(tt.arg))
})
}
}
func TestValueAssertionFunc(t *testing.T) {
tests := []struct {
name string
value interface{}
assertion ValueAssertionFunc
}{
{"notNil", true, NotNil},
{"nil", nil, Nil},
{"empty", []int{}, Empty},
{"notEmpty", []int{1}, NotEmpty},
{"zero", false, Zero},
{"notZero", 42, NotZero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleBoolAssertionFunc() {
t := &testing.T{} // provided by test
isOkay := func(x int) bool {
return x >= 42
}
tests := []struct {
name string
arg int
assertion BoolAssertionFunc
}{
{"-1 is bad", -1, False},
{"42 is good", 42, True},
{"41 is bad", 41, False},
{"45 is cool", 45, True},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, isOkay(tt.arg))
})
}
}
func TestBoolAssertionFunc(t *testing.T) {
tests := []struct {
name string
value bool
assertion BoolAssertionFunc
}{
{"true", true, True},
{"false", false, False},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleErrorAssertionFunc() {
t := &testing.T{} // provided by test
dumbParseNum := func(input string, v interface{}) error {
return json.Unmarshal([]byte(input), v)
}
tests := []struct {
name string
arg string
assertion ErrorAssertionFunc
}{
{"1.2 is number", "1.2", NoError},
{"1.2.3 not number", "1.2.3", Error},
{"true is not number", "true", Error},
{"3 is number", "3", NoError},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var x float64
tt.assertion(t, dumbParseNum(tt.arg, &x))
})
}
}
func TestErrorAssertionFunc(t *testing.T) {
tests := []struct {
name string
err error
assertion ErrorAssertionFunc
}{
{"noError", nil, NoError},
{"error", errors.New("whoops"), Error},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.err)
})
}
}

View File

@ -32,3 +32,15 @@ type TearDownAllSuite interface {
type TearDownTestSuite interface { type TearDownTestSuite interface {
TearDownTest() TearDownTest()
} }
// BeforeTest has a function to be executed right before the test
// starts and receives the suite and test names as input
type BeforeTest interface {
BeforeTest(suiteName, testName string)
}
// AfterTest has a function to be executed right after the test
// finishes and receives the suite and test names as input
type AfterTest interface {
AfterTest(suiteName, testName string)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var allTestsFilter = func(_, _ string) (bool, error) { return true, nil }
var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run")
// Suite is a basic testing suite with methods for storing and // Suite is a basic testing suite with methods for storing and
@ -86,7 +87,13 @@ func Run(t *testing.T, suite TestingSuite) {
if setupTestSuite, ok := suite.(SetupTestSuite); ok { if setupTestSuite, ok := suite.(SetupTestSuite); ok {
setupTestSuite.SetupTest() setupTestSuite.SetupTest()
} }
if beforeTestSuite, ok := suite.(BeforeTest); ok {
beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name)
}
defer func() { defer func() {
if afterTestSuite, ok := suite.(AfterTest); ok {
afterTestSuite.AfterTest(methodFinder.Elem().Name(), method.Name)
}
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok { if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
tearDownTestSuite.TearDownTest() tearDownTestSuite.TearDownTest()
} }
@ -98,10 +105,20 @@ func Run(t *testing.T, suite TestingSuite) {
tests = append(tests, test) tests = append(tests, test)
} }
} }
runTests(t, tests)
}
if !testing.RunTests(func(_, _ string) (bool, error) { return true, nil }, func runTests(t testing.TB, tests []testing.InternalTest) {
tests) { r, ok := t.(runner)
t.Fail() if !ok { // backwards compatibility with Go 1.6 and below
if !testing.RunTests(allTestsFilter, tests) {
t.Fail()
}
return
}
for _, test := range tests {
r.Run(test.Name, test.F)
} }
} }
@ -113,3 +130,7 @@ func methodFilter(name string) (bool, error) {
} }
return regexp.MatchString(*matchMethod, name) return regexp.MatchString(*matchMethod, name)
} }
type runner interface {
Run(name string, f func(t *testing.T)) bool
}

View File

@ -5,8 +5,10 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
// SuiteRequireTwice is intended to test the usage of suite.Require in two // SuiteRequireTwice is intended to test the usage of suite.Require in two
@ -18,7 +20,7 @@ type SuiteRequireTwice struct{ Suite }
// A regression would result on these tests panicking rather than failing. // A regression would result on these tests panicking rather than failing.
func TestSuiteRequireTwice(t *testing.T) { func TestSuiteRequireTwice(t *testing.T) {
ok := testing.RunTests( ok := testing.RunTests(
func(_, _ string) (bool, error) { return true, nil }, allTestsFilter,
[]testing.InternalTest{{ []testing.InternalTest{{
Name: "TestSuiteRequireTwice", Name: "TestSuiteRequireTwice",
F: func(t *testing.T) { F: func(t *testing.T) {
@ -58,6 +60,15 @@ type SuiteTester struct {
TestOneRunCount int TestOneRunCount int
TestTwoRunCount int TestTwoRunCount int
NonTestMethodRunCount int NonTestMethodRunCount int
SuiteNameBefore []string
TestNameBefore []string
SuiteNameAfter []string
TestNameAfter []string
TimeBefore []time.Time
TimeAfter []time.Time
} }
type SuiteSkipTester struct { type SuiteSkipTester struct {
@ -75,6 +86,18 @@ func (suite *SuiteTester) SetupSuite() {
suite.SetupSuiteRunCount++ suite.SetupSuiteRunCount++
} }
func (suite *SuiteTester) BeforeTest(suiteName, testName string) {
suite.SuiteNameBefore = append(suite.SuiteNameBefore, suiteName)
suite.TestNameBefore = append(suite.TestNameBefore, testName)
suite.TimeBefore = append(suite.TimeBefore, time.Now())
}
func (suite *SuiteTester) AfterTest(suiteName, testName string) {
suite.SuiteNameAfter = append(suite.SuiteNameAfter, suiteName)
suite.TestNameAfter = append(suite.TestNameAfter, testName)
suite.TimeAfter = append(suite.TimeAfter, time.Now())
}
func (suite *SuiteSkipTester) SetupSuite() { func (suite *SuiteSkipTester) SetupSuite() {
suite.SetupSuiteRunCount++ suite.SetupSuiteRunCount++
suite.T().Skip() suite.T().Skip()
@ -145,6 +168,35 @@ func TestRunSuite(t *testing.T) {
assert.Equal(t, suiteTester.SetupSuiteRunCount, 1) assert.Equal(t, suiteTester.SetupSuiteRunCount, 1)
assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1) assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1)
assert.Equal(t, len(suiteTester.SuiteNameAfter), 3)
assert.Equal(t, len(suiteTester.SuiteNameBefore), 3)
assert.Equal(t, len(suiteTester.TestNameAfter), 3)
assert.Equal(t, len(suiteTester.TestNameBefore), 3)
assert.Contains(t, suiteTester.TestNameAfter, "TestOne")
assert.Contains(t, suiteTester.TestNameAfter, "TestTwo")
assert.Contains(t, suiteTester.TestNameAfter, "TestSkip")
assert.Contains(t, suiteTester.TestNameBefore, "TestOne")
assert.Contains(t, suiteTester.TestNameBefore, "TestTwo")
assert.Contains(t, suiteTester.TestNameBefore, "TestSkip")
for _, suiteName := range suiteTester.SuiteNameAfter {
assert.Equal(t, "SuiteTester", suiteName)
}
for _, suiteName := range suiteTester.SuiteNameBefore {
assert.Equal(t, "SuiteTester", suiteName)
}
for _, when := range suiteTester.TimeAfter {
assert.False(t, when.IsZero())
}
for _, when := range suiteTester.TimeBefore {
assert.False(t, when.IsZero())
}
// There are three test methods (TestOne, TestTwo, and TestSkip), so // There are three test methods (TestOne, TestTwo, and TestSkip), so
// the SetupTest and TearDownTest methods (which should be run once for // the SetupTest and TearDownTest methods (which should be run once for
// each test) should have been run three times. // each test) should have been run three times.
@ -216,16 +268,19 @@ func (sc *StdoutCapture) StopCapture() (string, error) {
} }
func TestSuiteLogging(t *testing.T) { func TestSuiteLogging(t *testing.T) {
testT := testing.T{}
suiteLoggingTester := new(SuiteLoggingTester) suiteLoggingTester := new(SuiteLoggingTester)
capture := StdoutCapture{} capture := StdoutCapture{}
internalTest := testing.InternalTest{
Name: "SomeTest",
F: func(subT *testing.T) {
Run(subT, suiteLoggingTester)
},
}
capture.StartCapture() capture.StartCapture()
Run(&testT, suiteLoggingTester) testing.RunTests(allTestsFilter, []testing.InternalTest{internalTest})
output, err := capture.StopCapture() output, err := capture.StopCapture()
require.NoError(t, err, "Got an error trying to capture stdout and stderr!")
assert.Nil(t, err, "Got an error trying to capture stdout!") require.NotEmpty(t, output, "output content must not be empty")
// Failed tests' output is always printed // Failed tests' output is always printed
assert.Contains(t, output, "TESTLOGFAIL") assert.Contains(t, output, "TESTLOGFAIL")

View File

@ -1,6 +1,6 @@
ISC License ISC License
Copyright (c) 2012-2013 Dave Collins <dave@davec.name> Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View File

@ -1,4 +1,4 @@
// Copyright (c) 2015 Dave Collins <dave@davec.name> // Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
// //
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above // purpose with or without fee is hereby granted, provided that the above

View File

@ -1,4 +1,4 @@
// Copyright (c) 2015 Dave Collins <dave@davec.name> // Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
// //
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above // purpose with or without fee is hereby granted, provided that the above

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013 Dave Collins <dave@davec.name> * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013 Dave Collins <dave@davec.name> * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -67,6 +67,15 @@ type ConfigState struct {
// Google App Engine or with the "safe" build tag specified. // Google App Engine or with the "safe" build tag specified.
DisablePointerMethods bool DisablePointerMethods bool
// DisablePointerAddresses specifies whether to disable the printing of
// pointer addresses. This is useful when diffing data structures in tests.
DisablePointerAddresses bool
// DisableCapacities specifies whether to disable the printing of capacities
// for arrays, slices, maps and channels. This is useful when diffing
// data structures in tests.
DisableCapacities bool
// ContinueOnMethod specifies whether or not recursion should continue once // ContinueOnMethod specifies whether or not recursion should continue once
// a custom error or Stringer interface is invoked. The default, false, // a custom error or Stringer interface is invoked. The default, false,
// means it will print the results of invoking the custom error or Stringer // means it will print the results of invoking the custom error or Stringer

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013 Dave Collins <dave@davec.name> * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -91,6 +91,15 @@ The following configuration options are available:
which only accept pointer receivers from non-pointer variables. which only accept pointer receivers from non-pointer variables.
Pointer method invocation is enabled by default. Pointer method invocation is enabled by default.
* DisablePointerAddresses
DisablePointerAddresses specifies whether to disable the printing of
pointer addresses. This is useful when diffing data structures in tests.
* DisableCapacities
DisableCapacities specifies whether to disable the printing of
capacities for arrays, slices, maps and channels. This is useful when
diffing data structures in tests.
* ContinueOnMethod * ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default. methods. Recursion after method invocation is disabled by default.

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