mirror of
https://github.com/beego/bee.git
synced 2024-11-22 10:10:53 +00:00
commit
c01a15197e
3
Beefile
3
Beefile
@ -1,7 +1,4 @@
|
||||
version: 0
|
||||
gopm:
|
||||
enable: false
|
||||
install: false
|
||||
go_install: false
|
||||
watch_ext: []
|
||||
dir_structure:
|
||||
|
4
bee.json
4
bee.json
@ -1,9 +1,5 @@
|
||||
{
|
||||
"version": 0,
|
||||
"gopm": {
|
||||
"enable": false,
|
||||
"install": false
|
||||
},
|
||||
"go_install": false,
|
||||
"watch_ext": [],
|
||||
"dir_structure": {
|
||||
|
@ -131,14 +131,10 @@ func AutoBuild(files []string, isgenerate bool) {
|
||||
os.Chdir(currpath)
|
||||
|
||||
cmdName := "go"
|
||||
if config.Conf.Gopm.Enable {
|
||||
cmdName = "gopm"
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
stderr bytes.Buffer
|
||||
stdout bytes.Buffer
|
||||
)
|
||||
// For applications use full import path like "github.com/.../.."
|
||||
// are able to use "go install" to reduce build time.
|
||||
@ -149,28 +145,6 @@ func AutoBuild(files []string, isgenerate bool) {
|
||||
icmd.Env = append(os.Environ(), "GOGC=off")
|
||||
icmd.Run()
|
||||
}
|
||||
if config.Conf.Gopm.Install {
|
||||
icmd := exec.Command("go", "list", "./...")
|
||||
icmd.Stdout = &stdout
|
||||
icmd.Env = append(os.Environ(), "GOGC=off")
|
||||
err = icmd.Run()
|
||||
if err == nil {
|
||||
list := strings.Split(stdout.String(), "\n")[1:]
|
||||
for _, pkg := range list {
|
||||
if len(pkg) == 0 {
|
||||
continue
|
||||
}
|
||||
icmd = exec.Command(cmdName, "install", pkg)
|
||||
icmd.Stdout = os.Stdout
|
||||
icmd.Stderr = os.Stderr
|
||||
icmd.Env = append(os.Environ(), "GOGC=off")
|
||||
err = icmd.Run()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isgenerate {
|
||||
beeLogger.Log.Info("Generating the docs...")
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
beeLogger "github.com/beego/bee/logger"
|
||||
@ -28,7 +27,6 @@ const confVer = 0
|
||||
|
||||
var Conf = struct {
|
||||
Version int
|
||||
Gopm gopm
|
||||
GoInstall bool `json:"go_install" yaml:"go_install"` // Indicates whether execute "go install" before "go build".
|
||||
DirStruct dirStruct `json:"dir_structure" yaml:"dir_structure"`
|
||||
CmdArgs []string `json:"cmd_args" yaml:"cmd_args"`
|
||||
@ -56,12 +54,6 @@ var Conf = struct {
|
||||
Scripts: map[string]string{},
|
||||
}
|
||||
|
||||
// gopm support
|
||||
type gopm struct {
|
||||
Enable bool
|
||||
Install bool
|
||||
}
|
||||
|
||||
// dirStruct describes the application's directory structure
|
||||
type dirStruct struct {
|
||||
WatchAll bool `json:"watch_all" yaml:"watch_all"`
|
||||
|
13
vendor/github.com/astaxie/beego/utils/safemap.go
generated
vendored
13
vendor/github.com/astaxie/beego/utils/safemap.go
generated
vendored
@ -61,10 +61,8 @@ func (m *BeeMap) Set(k interface{}, v interface{}) bool {
|
||||
func (m *BeeMap) Check(k interface{}) bool {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
if _, ok := m.bm[k]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
_, ok := m.bm[k]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Delete the given key and value.
|
||||
@ -84,3 +82,10 @@ func (m *BeeMap) Items() map[interface{}]interface{} {
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Count returns the number of items within the map.
|
||||
func (m *BeeMap) Count() int {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
return len(m.bm)
|
||||
}
|
||||
|
5
vendor/github.com/gorilla/websocket/README.md
generated
vendored
5
vendor/github.com/gorilla/websocket/README.md
generated
vendored
@ -3,6 +3,9 @@
|
||||
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
|
||||
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
|
||||
|
||||
[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket)
|
||||
[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
|
||||
|
||||
### Documentation
|
||||
|
||||
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
|
||||
@ -43,7 +46,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
|
||||
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>
|
||||
<tr><td>Get the <a href="https://tools.ietf.org/html/rfc6455#section-5.6">type</a> of a received data message</td><td>Yes</td><td>Yes, see note 2</td></tr>
|
||||
<tr><td colspan="3">Other Features</tr></td>
|
||||
<tr><td>Limit size of received message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.SetReadLimit">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=5082">No</a></td></tr>
|
||||
<tr><td><a href="https://tools.ietf.org/html/rfc7692">Compression Extensions</a></td><td>Experimental</td><td>No</td></tr>
|
||||
<tr><td>Read message using io.Reader</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextReader">Yes</a></td><td>No, see note 3</td></tr>
|
||||
<tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr>
|
||||
</table>
|
||||
|
81
vendor/github.com/gorilla/websocket/client.go
generated
vendored
81
vendor/github.com/gorilla/websocket/client.go
generated
vendored
@ -23,6 +23,8 @@ import (
|
||||
// invalid.
|
||||
var ErrBadHandshake = errors.New("websocket: bad handshake")
|
||||
|
||||
var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
|
||||
|
||||
// NewClient creates a new client connection using the given net connection.
|
||||
// The URL u specifies the host and request URI. Use requestHeader to specify
|
||||
// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
|
||||
@ -64,12 +66,24 @@ type Dialer struct {
|
||||
// HandshakeTimeout specifies the duration for the handshake to complete.
|
||||
HandshakeTimeout time.Duration
|
||||
|
||||
// Input and output buffer sizes. If the buffer size is zero, then a
|
||||
// default value of 4096 is used.
|
||||
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
|
||||
// size is zero, then a useful default size is used. The I/O buffer sizes
|
||||
// do not limit the size of the messages that can be sent or received.
|
||||
ReadBufferSize, WriteBufferSize int
|
||||
|
||||
// Subprotocols specifies the client's requested subprotocols.
|
||||
Subprotocols []string
|
||||
|
||||
// EnableCompression specifies if the client should attempt to negotiate
|
||||
// per message compression (RFC 7692). Setting this value to true does not
|
||||
// guarantee that compression will be supported. Currently only "no context
|
||||
// takeover" modes are supported.
|
||||
EnableCompression bool
|
||||
|
||||
// Jar specifies the cookie jar.
|
||||
// If Jar is nil, cookies are not sent in requests and ignored
|
||||
// in responses.
|
||||
Jar http.CookieJar
|
||||
}
|
||||
|
||||
var errMalformedURL = errors.New("malformed ws or wss URL")
|
||||
@ -83,7 +97,6 @@ func parseURL(s string) (*url.URL, error) {
|
||||
//
|
||||
// ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
|
||||
// wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
|
||||
|
||||
var u url.URL
|
||||
switch {
|
||||
case strings.HasPrefix(s, "ws://"):
|
||||
@ -193,6 +206,13 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
||||
Host: u.Host,
|
||||
}
|
||||
|
||||
// Set the cookies present in the cookie jar of the dialer
|
||||
if d.Jar != nil {
|
||||
for _, cookie := range d.Jar.Cookies(u) {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
// Set the request headers using the capitalization for names and values in
|
||||
// RFC examples. Although the capitalization shouldn't matter, there are
|
||||
// servers that depend on it. The Header.Set method is not used because the
|
||||
@ -214,6 +234,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
||||
k == "Connection" ||
|
||||
k == "Sec-Websocket-Key" ||
|
||||
k == "Sec-Websocket-Version" ||
|
||||
k == "Sec-Websocket-Extensions" ||
|
||||
(k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
|
||||
return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
|
||||
default:
|
||||
@ -221,6 +242,10 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
||||
}
|
||||
}
|
||||
|
||||
if d.EnableCompression {
|
||||
req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
|
||||
}
|
||||
|
||||
hostPort, hostNoPort := hostPortNoPort(u)
|
||||
|
||||
var proxyURL *url.URL
|
||||
@ -324,6 +349,13 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if d.Jar != nil {
|
||||
if rc := resp.Cookies(); len(rc) > 0 {
|
||||
d.Jar.SetCookies(u, rc)
|
||||
}
|
||||
}
|
||||
|
||||
if resp.StatusCode != 101 ||
|
||||
!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
|
||||
!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
|
||||
@ -337,6 +369,20 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
||||
return nil, resp, ErrBadHandshake
|
||||
}
|
||||
|
||||
for _, ext := range parseExtensions(req.Header) {
|
||||
if ext[""] != "permessage-deflate" {
|
||||
continue
|
||||
}
|
||||
_, snct := ext["server_no_context_takeover"]
|
||||
_, cnct := ext["client_no_context_takeover"]
|
||||
if !snct || !cnct {
|
||||
return nil, resp, errInvalidCompression
|
||||
}
|
||||
conn.newCompressionWriter = compressNoContextTakeover
|
||||
conn.newDecompressionReader = decompressNoContextTakeover
|
||||
break
|
||||
}
|
||||
|
||||
resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
|
||||
conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
|
||||
|
||||
@ -344,32 +390,3 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
||||
netConn = nil // to avoid close in defer.
|
||||
return conn, resp, nil
|
||||
}
|
||||
|
||||
// cloneTLSConfig clones all public fields except the fields
|
||||
// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
|
||||
// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
|
||||
// config in active use.
|
||||
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
|
||||
if cfg == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
return &tls.Config{
|
||||
Rand: cfg.Rand,
|
||||
Time: cfg.Time,
|
||||
Certificates: cfg.Certificates,
|
||||
NameToCertificate: cfg.NameToCertificate,
|
||||
GetCertificate: cfg.GetCertificate,
|
||||
RootCAs: cfg.RootCAs,
|
||||
NextProtos: cfg.NextProtos,
|
||||
ServerName: cfg.ServerName,
|
||||
ClientAuth: cfg.ClientAuth,
|
||||
ClientCAs: cfg.ClientCAs,
|
||||
InsecureSkipVerify: cfg.InsecureSkipVerify,
|
||||
CipherSuites: cfg.CipherSuites,
|
||||
PreferServerCipherSuites: cfg.PreferServerCipherSuites,
|
||||
ClientSessionCache: cfg.ClientSessionCache,
|
||||
MinVersion: cfg.MinVersion,
|
||||
MaxVersion: cfg.MaxVersion,
|
||||
CurvePreferences: cfg.CurvePreferences,
|
||||
}
|
||||
}
|
||||
|
16
vendor/github.com/gorilla/websocket/client_clone.go
generated
vendored
Normal file
16
vendor/github.com/gorilla/websocket/client_clone.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
|
||||
if cfg == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
return cfg.Clone()
|
||||
}
|
38
vendor/github.com/gorilla/websocket/client_clone_legacy.go
generated
vendored
Normal file
38
vendor/github.com/gorilla/websocket/client_clone_legacy.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
// cloneTLSConfig clones all public fields except the fields
|
||||
// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
|
||||
// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
|
||||
// config in active use.
|
||||
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
|
||||
if cfg == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
return &tls.Config{
|
||||
Rand: cfg.Rand,
|
||||
Time: cfg.Time,
|
||||
Certificates: cfg.Certificates,
|
||||
NameToCertificate: cfg.NameToCertificate,
|
||||
GetCertificate: cfg.GetCertificate,
|
||||
RootCAs: cfg.RootCAs,
|
||||
NextProtos: cfg.NextProtos,
|
||||
ServerName: cfg.ServerName,
|
||||
ClientAuth: cfg.ClientAuth,
|
||||
ClientCAs: cfg.ClientCAs,
|
||||
InsecureSkipVerify: cfg.InsecureSkipVerify,
|
||||
CipherSuites: cfg.CipherSuites,
|
||||
PreferServerCipherSuites: cfg.PreferServerCipherSuites,
|
||||
ClientSessionCache: cfg.ClientSessionCache,
|
||||
MinVersion: cfg.MinVersion,
|
||||
MaxVersion: cfg.MaxVersion,
|
||||
CurvePreferences: cfg.CurvePreferences,
|
||||
}
|
||||
}
|
148
vendor/github.com/gorilla/websocket/compression.go
generated
vendored
Normal file
148
vendor/github.com/gorilla/websocket/compression.go
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"compress/flate"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
|
||||
maxCompressionLevel = flate.BestCompression
|
||||
defaultCompressionLevel = 1
|
||||
)
|
||||
|
||||
var (
|
||||
flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
|
||||
flateReaderPool = sync.Pool{New: func() interface{} {
|
||||
return flate.NewReader(nil)
|
||||
}}
|
||||
)
|
||||
|
||||
func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
|
||||
const tail =
|
||||
// Add four bytes as specified in RFC
|
||||
"\x00\x00\xff\xff" +
|
||||
// Add final block to squelch unexpected EOF error from flate reader.
|
||||
"\x01\x00\x00\xff\xff"
|
||||
|
||||
fr, _ := flateReaderPool.Get().(io.ReadCloser)
|
||||
fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil)
|
||||
return &flateReadWrapper{fr}
|
||||
}
|
||||
|
||||
func isValidCompressionLevel(level int) bool {
|
||||
return minCompressionLevel <= level && level <= maxCompressionLevel
|
||||
}
|
||||
|
||||
func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
|
||||
p := &flateWriterPools[level-minCompressionLevel]
|
||||
tw := &truncWriter{w: w}
|
||||
fw, _ := p.Get().(*flate.Writer)
|
||||
if fw == nil {
|
||||
fw, _ = flate.NewWriter(tw, level)
|
||||
} else {
|
||||
fw.Reset(tw)
|
||||
}
|
||||
return &flateWriteWrapper{fw: fw, tw: tw, p: p}
|
||||
}
|
||||
|
||||
// truncWriter is an io.Writer that writes all but the last four bytes of the
|
||||
// stream to another io.Writer.
|
||||
type truncWriter struct {
|
||||
w io.WriteCloser
|
||||
n int
|
||||
p [4]byte
|
||||
}
|
||||
|
||||
func (w *truncWriter) Write(p []byte) (int, error) {
|
||||
n := 0
|
||||
|
||||
// fill buffer first for simplicity.
|
||||
if w.n < len(w.p) {
|
||||
n = copy(w.p[w.n:], p)
|
||||
p = p[n:]
|
||||
w.n += n
|
||||
if len(p) == 0 {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
||||
m := len(p)
|
||||
if m > len(w.p) {
|
||||
m = len(w.p)
|
||||
}
|
||||
|
||||
if nn, err := w.w.Write(w.p[:m]); err != nil {
|
||||
return n + nn, err
|
||||
}
|
||||
|
||||
copy(w.p[:], w.p[m:])
|
||||
copy(w.p[len(w.p)-m:], p[len(p)-m:])
|
||||
nn, err := w.w.Write(p[:len(p)-m])
|
||||
return n + nn, err
|
||||
}
|
||||
|
||||
type flateWriteWrapper struct {
|
||||
fw *flate.Writer
|
||||
tw *truncWriter
|
||||
p *sync.Pool
|
||||
}
|
||||
|
||||
func (w *flateWriteWrapper) Write(p []byte) (int, error) {
|
||||
if w.fw == nil {
|
||||
return 0, errWriteClosed
|
||||
}
|
||||
return w.fw.Write(p)
|
||||
}
|
||||
|
||||
func (w *flateWriteWrapper) Close() error {
|
||||
if w.fw == nil {
|
||||
return errWriteClosed
|
||||
}
|
||||
err1 := w.fw.Flush()
|
||||
w.p.Put(w.fw)
|
||||
w.fw = nil
|
||||
if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
|
||||
return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
|
||||
}
|
||||
err2 := w.tw.w.Close()
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
type flateReadWrapper struct {
|
||||
fr io.ReadCloser
|
||||
}
|
||||
|
||||
func (r *flateReadWrapper) Read(p []byte) (int, error) {
|
||||
if r.fr == nil {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
n, err := r.fr.Read(p)
|
||||
if err == io.EOF {
|
||||
// Preemptively place the reader back in the pool. This helps with
|
||||
// scenarios where the application does not call NextReader() soon after
|
||||
// this final read.
|
||||
r.Close()
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *flateReadWrapper) Close() error {
|
||||
if r.fr == nil {
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
err := r.fr.Close()
|
||||
flateReaderPool.Put(r.fr)
|
||||
r.fr = nil
|
||||
return err
|
||||
}
|
488
vendor/github.com/gorilla/websocket/conn.go
generated
vendored
488
vendor/github.com/gorilla/websocket/conn.go
generated
vendored
@ -13,16 +13,25 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
// Frame header byte 0 bits from Section 5.2 of RFC 6455
|
||||
finalBit = 1 << 7
|
||||
rsv1Bit = 1 << 6
|
||||
rsv2Bit = 1 << 5
|
||||
rsv3Bit = 1 << 4
|
||||
|
||||
// Frame header byte 1 bits from Section 5.2 of RFC 6455
|
||||
maskBit = 1 << 7
|
||||
|
||||
maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
|
||||
maxControlFramePayloadSize = 125
|
||||
finalBit = 1 << 7
|
||||
maskBit = 1 << 7
|
||||
writeWait = time.Second
|
||||
|
||||
writeWait = time.Second
|
||||
|
||||
defaultReadBufferSize = 4096
|
||||
defaultWriteBufferSize = 4096
|
||||
@ -172,6 +181,11 @@ var (
|
||||
errInvalidControlFrame = errors.New("websocket: invalid control frame")
|
||||
)
|
||||
|
||||
func newMaskKey() [4]byte {
|
||||
n := rand.Uint32()
|
||||
return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
|
||||
}
|
||||
|
||||
func hideTempErr(err error) error {
|
||||
if e, ok := err.(net.Error); ok && e.Temporary() {
|
||||
err = &netError{msg: e.Error(), timeout: e.Timeout()}
|
||||
@ -210,39 +224,28 @@ func isValidReceivedCloseCode(code int) bool {
|
||||
return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
|
||||
}
|
||||
|
||||
func maskBytes(key [4]byte, pos int, b []byte) int {
|
||||
for i := range b {
|
||||
b[i] ^= key[pos&3]
|
||||
pos++
|
||||
}
|
||||
return pos & 3
|
||||
}
|
||||
|
||||
func newMaskKey() [4]byte {
|
||||
n := rand.Uint32()
|
||||
return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
|
||||
}
|
||||
|
||||
// Conn represents a WebSocket connection.
|
||||
// The Conn type represents a WebSocket connection.
|
||||
type Conn struct {
|
||||
conn net.Conn
|
||||
isServer bool
|
||||
subprotocol string
|
||||
|
||||
// Write fields
|
||||
mu chan bool // used as mutex to protect write to conn and closeSent
|
||||
closeSent bool // true if close message was sent
|
||||
mu chan bool // used as mutex to protect write to conn
|
||||
writeBuf []byte // frame is constructed in this buffer.
|
||||
writeDeadline time.Time
|
||||
writer io.WriteCloser // the current writer returned to the application
|
||||
isWriting bool // for best-effort concurrent write detection
|
||||
|
||||
// Message writer fields.
|
||||
writeErr error
|
||||
writeBuf []byte // frame is constructed in this buffer.
|
||||
writePos int // end of data in writeBuf.
|
||||
writeFrameType int // type of the current frame.
|
||||
writeDeadline time.Time
|
||||
isWriting bool // for best-effort concurrent write detection
|
||||
messageWriter *messageWriter // the current writer
|
||||
writeErrMu sync.Mutex
|
||||
writeErr error
|
||||
|
||||
enableWriteCompression bool
|
||||
compressionLevel int
|
||||
newCompressionWriter func(io.WriteCloser, int) io.WriteCloser
|
||||
|
||||
// Read fields
|
||||
reader io.ReadCloser // the current reader returned to the application
|
||||
readErr error
|
||||
br *bufio.Reader
|
||||
readRemaining int64 // bytes remaining in current frame.
|
||||
@ -253,34 +256,83 @@ type Conn struct {
|
||||
readMaskKey [4]byte
|
||||
handlePong func(string) error
|
||||
handlePing func(string) error
|
||||
handleClose func(int, string) error
|
||||
readErrCount int
|
||||
messageReader *messageReader // the current reader
|
||||
messageReader *messageReader // the current low-level reader
|
||||
|
||||
readDecompress bool // whether last read frame had RSV1 set
|
||||
newDecompressionReader func(io.Reader) io.ReadCloser
|
||||
}
|
||||
|
||||
func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
|
||||
return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil)
|
||||
}
|
||||
|
||||
type writeHook struct {
|
||||
p []byte
|
||||
}
|
||||
|
||||
func (wh *writeHook) Write(p []byte) (int, error) {
|
||||
wh.p = p
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn {
|
||||
mu := make(chan bool, 1)
|
||||
mu <- true
|
||||
|
||||
if readBufferSize == 0 {
|
||||
readBufferSize = defaultReadBufferSize
|
||||
var br *bufio.Reader
|
||||
if readBufferSize == 0 && brw != nil && brw.Reader != nil {
|
||||
// Reuse the supplied bufio.Reader if the buffer has a useful size.
|
||||
// This code assumes that peek on a reader returns
|
||||
// bufio.Reader.buf[:0].
|
||||
brw.Reader.Reset(conn)
|
||||
if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 {
|
||||
br = brw.Reader
|
||||
}
|
||||
}
|
||||
if readBufferSize < maxControlFramePayloadSize {
|
||||
readBufferSize = maxControlFramePayloadSize
|
||||
if br == nil {
|
||||
if readBufferSize == 0 {
|
||||
readBufferSize = defaultReadBufferSize
|
||||
}
|
||||
if readBufferSize < maxControlFramePayloadSize {
|
||||
readBufferSize = maxControlFramePayloadSize
|
||||
}
|
||||
br = bufio.NewReaderSize(conn, readBufferSize)
|
||||
}
|
||||
if writeBufferSize == 0 {
|
||||
writeBufferSize = defaultWriteBufferSize
|
||||
|
||||
var writeBuf []byte
|
||||
if writeBufferSize == 0 && brw != nil && brw.Writer != nil {
|
||||
// Use the bufio.Writer's buffer if the buffer has a useful size. This
|
||||
// code assumes that bufio.Writer.buf[:1] is passed to the
|
||||
// bufio.Writer's underlying writer.
|
||||
var wh writeHook
|
||||
brw.Writer.Reset(&wh)
|
||||
brw.Writer.WriteByte(0)
|
||||
brw.Flush()
|
||||
if cap(wh.p) >= maxFrameHeaderSize+256 {
|
||||
writeBuf = wh.p[:cap(wh.p)]
|
||||
}
|
||||
}
|
||||
|
||||
if writeBuf == nil {
|
||||
if writeBufferSize == 0 {
|
||||
writeBufferSize = defaultWriteBufferSize
|
||||
}
|
||||
writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize)
|
||||
}
|
||||
|
||||
c := &Conn{
|
||||
isServer: isServer,
|
||||
br: bufio.NewReaderSize(conn, readBufferSize),
|
||||
conn: conn,
|
||||
mu: mu,
|
||||
readFinal: true,
|
||||
writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
|
||||
writeFrameType: noFrame,
|
||||
writePos: maxFrameHeaderSize,
|
||||
isServer: isServer,
|
||||
br: br,
|
||||
conn: conn,
|
||||
mu: mu,
|
||||
readFinal: true,
|
||||
writeBuf: writeBuf,
|
||||
enableWriteCompression: true,
|
||||
compressionLevel: defaultCompressionLevel,
|
||||
}
|
||||
c.SetCloseHandler(nil)
|
||||
c.SetPingHandler(nil)
|
||||
c.SetPongHandler(nil)
|
||||
return c
|
||||
@ -308,29 +360,40 @@ func (c *Conn) RemoteAddr() net.Addr {
|
||||
|
||||
// Write methods
|
||||
|
||||
func (c *Conn) writeFatal(err error) error {
|
||||
err = hideTempErr(err)
|
||||
c.writeErrMu.Lock()
|
||||
if c.writeErr == nil {
|
||||
c.writeErr = err
|
||||
}
|
||||
c.writeErrMu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error {
|
||||
<-c.mu
|
||||
defer func() { c.mu <- true }()
|
||||
|
||||
if c.closeSent {
|
||||
return ErrCloseSent
|
||||
} else if frameType == CloseMessage {
|
||||
c.closeSent = true
|
||||
c.writeErrMu.Lock()
|
||||
err := c.writeErr
|
||||
c.writeErrMu.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.conn.SetWriteDeadline(deadline)
|
||||
for _, buf := range bufs {
|
||||
if len(buf) > 0 {
|
||||
n, err := c.conn.Write(buf)
|
||||
if n != len(buf) {
|
||||
// Close on partial write.
|
||||
c.conn.Close()
|
||||
}
|
||||
_, err := c.conn.Write(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
return c.writeFatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if frameType == CloseMessage {
|
||||
c.writeFatal(ErrCloseSent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -379,18 +442,41 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
|
||||
}
|
||||
defer func() { c.mu <- true }()
|
||||
|
||||
if c.closeSent {
|
||||
return ErrCloseSent
|
||||
} else if messageType == CloseMessage {
|
||||
c.closeSent = true
|
||||
c.writeErrMu.Lock()
|
||||
err := c.writeErr
|
||||
c.writeErrMu.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.conn.SetWriteDeadline(deadline)
|
||||
n, err := c.conn.Write(buf)
|
||||
if n != 0 && n != len(buf) {
|
||||
c.conn.Close()
|
||||
_, err = c.conn.Write(buf)
|
||||
if err != nil {
|
||||
return c.writeFatal(err)
|
||||
}
|
||||
return hideTempErr(err)
|
||||
if messageType == CloseMessage {
|
||||
c.writeFatal(ErrCloseSent)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) prepWrite(messageType int) error {
|
||||
// Close previous writer if not already closed by the application. It's
|
||||
// probably better to return an error in this situation, but we cannot
|
||||
// change this without breaking existing applications.
|
||||
if c.writer != nil {
|
||||
c.writer.Close()
|
||||
c.writer = nil
|
||||
}
|
||||
|
||||
if !isControl(messageType) && !isData(messageType) {
|
||||
return errBadWriteOpCode
|
||||
}
|
||||
|
||||
c.writeErrMu.Lock()
|
||||
err := c.writeErr
|
||||
c.writeErrMu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// NextWriter returns a writer for the next message to send. The writer's Close
|
||||
@ -399,42 +485,61 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
|
||||
// There can be at most one open writer on a connection. NextWriter closes the
|
||||
// previous writer if the application has not already done so.
|
||||
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
|
||||
if c.writeErr != nil {
|
||||
return nil, c.writeErr
|
||||
if err := c.prepWrite(messageType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.writeFrameType != noFrame {
|
||||
if err := c.flushFrame(true, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mw := &messageWriter{
|
||||
c: c,
|
||||
frameType: messageType,
|
||||
pos: maxFrameHeaderSize,
|
||||
}
|
||||
|
||||
if !isControl(messageType) && !isData(messageType) {
|
||||
return nil, errBadWriteOpCode
|
||||
c.writer = mw
|
||||
if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
|
||||
w := c.newCompressionWriter(c.writer, c.compressionLevel)
|
||||
mw.compress = true
|
||||
c.writer = w
|
||||
}
|
||||
|
||||
c.writeFrameType = messageType
|
||||
w := &messageWriter{c}
|
||||
c.messageWriter = w
|
||||
return w, nil
|
||||
return c.writer, nil
|
||||
}
|
||||
|
||||
func (c *Conn) flushFrame(final bool, extra []byte) error {
|
||||
length := c.writePos - maxFrameHeaderSize + len(extra)
|
||||
type messageWriter struct {
|
||||
c *Conn
|
||||
compress bool // whether next call to flushFrame should set RSV1
|
||||
pos int // end of data in writeBuf.
|
||||
frameType int // type of the current frame.
|
||||
err error
|
||||
}
|
||||
|
||||
func (w *messageWriter) fatal(err error) error {
|
||||
if w.err != nil {
|
||||
w.err = err
|
||||
w.c.writer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// flushFrame writes buffered data and extra as a frame to the network. The
|
||||
// final argument indicates that this is the last frame in the message.
|
||||
func (w *messageWriter) flushFrame(final bool, extra []byte) error {
|
||||
c := w.c
|
||||
length := w.pos - maxFrameHeaderSize + len(extra)
|
||||
|
||||
// Check for invalid control frames.
|
||||
if isControl(c.writeFrameType) &&
|
||||
if isControl(w.frameType) &&
|
||||
(!final || length > maxControlFramePayloadSize) {
|
||||
c.messageWriter = nil
|
||||
c.writeFrameType = noFrame
|
||||
c.writePos = maxFrameHeaderSize
|
||||
return errInvalidControlFrame
|
||||
return w.fatal(errInvalidControlFrame)
|
||||
}
|
||||
|
||||
b0 := byte(c.writeFrameType)
|
||||
b0 := byte(w.frameType)
|
||||
if final {
|
||||
b0 |= finalBit
|
||||
}
|
||||
if w.compress {
|
||||
b0 |= rsv1Bit
|
||||
}
|
||||
w.compress = false
|
||||
|
||||
b1 := byte(0)
|
||||
if !c.isServer {
|
||||
b1 |= maskBit
|
||||
@ -466,10 +571,9 @@ func (c *Conn) flushFrame(final bool, extra []byte) error {
|
||||
if !c.isServer {
|
||||
key := newMaskKey()
|
||||
copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
|
||||
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:c.writePos])
|
||||
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
|
||||
if len(extra) > 0 {
|
||||
c.writeErr = errors.New("websocket: internal error, extra used in client mode")
|
||||
return c.writeErr
|
||||
return c.writeFatal(errors.New("websocket: internal error, extra used in client mode"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,43 +586,35 @@ func (c *Conn) flushFrame(final bool, extra []byte) error {
|
||||
}
|
||||
c.isWriting = true
|
||||
|
||||
c.writeErr = c.write(c.writeFrameType, c.writeDeadline, c.writeBuf[framePos:c.writePos], extra)
|
||||
err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra)
|
||||
|
||||
if !c.isWriting {
|
||||
panic("concurrent write to websocket connection")
|
||||
}
|
||||
c.isWriting = false
|
||||
|
||||
// Setup for next frame.
|
||||
c.writePos = maxFrameHeaderSize
|
||||
c.writeFrameType = continuationFrame
|
||||
if err != nil {
|
||||
return w.fatal(err)
|
||||
}
|
||||
|
||||
if final {
|
||||
c.messageWriter = nil
|
||||
c.writeFrameType = noFrame
|
||||
c.writer = nil
|
||||
return nil
|
||||
}
|
||||
return c.writeErr
|
||||
}
|
||||
|
||||
type messageWriter struct{ c *Conn }
|
||||
|
||||
func (w *messageWriter) err() error {
|
||||
c := w.c
|
||||
if c.messageWriter != w {
|
||||
return errWriteClosed
|
||||
}
|
||||
if c.writeErr != nil {
|
||||
return c.writeErr
|
||||
}
|
||||
// Setup for next frame.
|
||||
w.pos = maxFrameHeaderSize
|
||||
w.frameType = continuationFrame
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *messageWriter) ncopy(max int) (int, error) {
|
||||
n := len(w.c.writeBuf) - w.c.writePos
|
||||
n := len(w.c.writeBuf) - w.pos
|
||||
if n <= 0 {
|
||||
if err := w.c.flushFrame(false, nil); err != nil {
|
||||
if err := w.flushFrame(false, nil); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n = len(w.c.writeBuf) - w.c.writePos
|
||||
n = len(w.c.writeBuf) - w.pos
|
||||
}
|
||||
if n > max {
|
||||
n = max
|
||||
@ -526,14 +622,14 @@ func (w *messageWriter) ncopy(max int) (int, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (w *messageWriter) write(final bool, p []byte) (int, error) {
|
||||
if err := w.err(); err != nil {
|
||||
return 0, err
|
||||
func (w *messageWriter) Write(p []byte) (int, error) {
|
||||
if w.err != nil {
|
||||
return 0, w.err
|
||||
}
|
||||
|
||||
if len(p) > 2*len(w.c.writeBuf) && w.c.isServer {
|
||||
// Don't buffer large messages.
|
||||
err := w.c.flushFrame(final, p)
|
||||
err := w.flushFrame(false, p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -546,20 +642,16 @@ func (w *messageWriter) write(final bool, p []byte) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
copy(w.c.writeBuf[w.c.writePos:], p[:n])
|
||||
w.c.writePos += n
|
||||
copy(w.c.writeBuf[w.pos:], p[:n])
|
||||
w.pos += n
|
||||
p = p[n:]
|
||||
}
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (w *messageWriter) Write(p []byte) (int, error) {
|
||||
return w.write(false, p)
|
||||
}
|
||||
|
||||
func (w *messageWriter) WriteString(p string) (int, error) {
|
||||
if err := w.err(); err != nil {
|
||||
return 0, err
|
||||
if w.err != nil {
|
||||
return 0, w.err
|
||||
}
|
||||
|
||||
nn := len(p)
|
||||
@ -568,27 +660,27 @@ func (w *messageWriter) WriteString(p string) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
copy(w.c.writeBuf[w.c.writePos:], p[:n])
|
||||
w.c.writePos += n
|
||||
copy(w.c.writeBuf[w.pos:], p[:n])
|
||||
w.pos += n
|
||||
p = p[n:]
|
||||
}
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
|
||||
if err := w.err(); err != nil {
|
||||
return 0, err
|
||||
if w.err != nil {
|
||||
return 0, w.err
|
||||
}
|
||||
for {
|
||||
if w.c.writePos == len(w.c.writeBuf) {
|
||||
err = w.c.flushFrame(false, nil)
|
||||
if w.pos == len(w.c.writeBuf) {
|
||||
err = w.flushFrame(false, nil)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
var n int
|
||||
n, err = r.Read(w.c.writeBuf[w.c.writePos:])
|
||||
w.c.writePos += n
|
||||
n, err = r.Read(w.c.writeBuf[w.pos:])
|
||||
w.pos += n
|
||||
nn += int64(n)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
@ -601,27 +693,59 @@ func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
|
||||
}
|
||||
|
||||
func (w *messageWriter) Close() error {
|
||||
if err := w.err(); err != nil {
|
||||
if w.err != nil {
|
||||
return w.err
|
||||
}
|
||||
if err := w.flushFrame(true, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.c.flushFrame(true, nil)
|
||||
w.err = errWriteClosed
|
||||
return nil
|
||||
}
|
||||
|
||||
// WritePreparedMessage writes prepared message into connection.
|
||||
func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error {
|
||||
frameType, frameData, err := pm.frame(prepareKey{
|
||||
isServer: c.isServer,
|
||||
compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType),
|
||||
compressionLevel: c.compressionLevel,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.isWriting {
|
||||
panic("concurrent write to websocket connection")
|
||||
}
|
||||
c.isWriting = true
|
||||
err = c.write(frameType, c.writeDeadline, frameData, nil)
|
||||
if !c.isWriting {
|
||||
panic("concurrent write to websocket connection")
|
||||
}
|
||||
c.isWriting = false
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteMessage is a helper method for getting a writer using NextWriter,
|
||||
// writing the message and closing the writer.
|
||||
func (c *Conn) WriteMessage(messageType int, data []byte) error {
|
||||
|
||||
if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) {
|
||||
// Fast path with no allocations and single frame.
|
||||
|
||||
if err := c.prepWrite(messageType); err != nil {
|
||||
return err
|
||||
}
|
||||
mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize}
|
||||
n := copy(c.writeBuf[mw.pos:], data)
|
||||
mw.pos += n
|
||||
data = data[n:]
|
||||
return mw.flushFrame(true, data)
|
||||
}
|
||||
|
||||
w, err := c.NextWriter(messageType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := w.(*messageWriter); ok && c.isServer {
|
||||
// Optimize write as a single frame.
|
||||
n := copy(c.writeBuf[c.writePos:], data)
|
||||
c.writePos += n
|
||||
data = data[n:]
|
||||
err = c.flushFrame(true, data)
|
||||
return err
|
||||
}
|
||||
if _, err = w.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -658,12 +782,17 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||
|
||||
final := p[0]&finalBit != 0
|
||||
frameType := int(p[0] & 0xf)
|
||||
reserved := int((p[0] >> 4) & 0x7)
|
||||
mask := p[1]&maskBit != 0
|
||||
c.readRemaining = int64(p[1] & 0x7f)
|
||||
|
||||
if reserved != 0 {
|
||||
return noFrame, c.handleProtocolError("unexpected reserved bits " + strconv.Itoa(reserved))
|
||||
c.readDecompress = false
|
||||
if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
|
||||
c.readDecompress = true
|
||||
p[0] &^= rsv1Bit
|
||||
}
|
||||
|
||||
if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 {
|
||||
return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16))
|
||||
}
|
||||
|
||||
switch frameType {
|
||||
@ -759,11 +888,9 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||
return noFrame, err
|
||||
}
|
||||
case CloseMessage:
|
||||
echoMessage := []byte{}
|
||||
closeCode := CloseNoStatusReceived
|
||||
closeText := ""
|
||||
if len(payload) >= 2 {
|
||||
echoMessage = payload[:2]
|
||||
closeCode = int(binary.BigEndian.Uint16(payload))
|
||||
if !isValidReceivedCloseCode(closeCode) {
|
||||
return noFrame, c.handleProtocolError("invalid close code")
|
||||
@ -773,7 +900,9 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||
return noFrame, c.handleProtocolError("invalid utf8 payload in close frame")
|
||||
}
|
||||
}
|
||||
c.WriteControl(CloseMessage, echoMessage, time.Now().Add(writeWait))
|
||||
if err := c.handleClose(closeCode, closeText); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
return noFrame, &CloseError{Code: closeCode, Text: closeText}
|
||||
}
|
||||
|
||||
@ -796,6 +925,11 @@ func (c *Conn) handleProtocolError(message string) error {
|
||||
// permanent. Once this method returns a non-nil error, all subsequent calls to
|
||||
// this method return the same error.
|
||||
func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
|
||||
// Close previous reader, only relevant for decompression.
|
||||
if c.reader != nil {
|
||||
c.reader.Close()
|
||||
c.reader = nil
|
||||
}
|
||||
|
||||
c.messageReader = nil
|
||||
c.readLength = 0
|
||||
@ -807,9 +941,12 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
|
||||
break
|
||||
}
|
||||
if frameType == TextMessage || frameType == BinaryMessage {
|
||||
r := &messageReader{c}
|
||||
c.messageReader = r
|
||||
return frameType, r, nil
|
||||
c.messageReader = &messageReader{c}
|
||||
c.reader = c.messageReader
|
||||
if c.readDecompress {
|
||||
c.reader = c.newDecompressionReader(c.reader)
|
||||
}
|
||||
return frameType, c.reader, nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -871,6 +1008,10 @@ func (r *messageReader) Read(b []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func (r *messageReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadMessage is a helper method for getting a reader using NextReader and
|
||||
// reading from that reader to a buffer.
|
||||
func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
|
||||
@ -898,6 +1039,38 @@ func (c *Conn) SetReadLimit(limit int64) {
|
||||
c.readLimit = limit
|
||||
}
|
||||
|
||||
// CloseHandler returns the current close handler
|
||||
func (c *Conn) CloseHandler() func(code int, text string) error {
|
||||
return c.handleClose
|
||||
}
|
||||
|
||||
// SetCloseHandler sets the handler for close messages received from the peer.
|
||||
// The code argument to h is the received close code or CloseNoStatusReceived
|
||||
// if the close message is empty. The default close handler sends a close frame
|
||||
// back to the peer.
|
||||
//
|
||||
// The application must read the connection to process close messages as
|
||||
// described in the section on Control Frames above.
|
||||
//
|
||||
// The connection read methods return a CloseError when a close frame is
|
||||
// received. Most applications should handle close messages as part of their
|
||||
// normal error handling. Applications should only set a close handler when the
|
||||
// application must perform some action before sending a close frame back to
|
||||
// the peer.
|
||||
func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
|
||||
if h == nil {
|
||||
h = func(code int, text string) error {
|
||||
message := []byte{}
|
||||
if code != CloseNoStatusReceived {
|
||||
message = FormatCloseMessage(code, "")
|
||||
}
|
||||
c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
c.handleClose = h
|
||||
}
|
||||
|
||||
// PingHandler returns the current ping handler
|
||||
func (c *Conn) PingHandler() func(appData string) error {
|
||||
return c.handlePing
|
||||
@ -906,6 +1079,9 @@ func (c *Conn) PingHandler() func(appData string) error {
|
||||
// SetPingHandler sets the handler for ping messages received from the peer.
|
||||
// The appData argument to h is the PING frame application data. The default
|
||||
// ping handler sends a pong to the peer.
|
||||
//
|
||||
// The application must read the connection to process ping messages as
|
||||
// described in the section on Control Frames above.
|
||||
func (c *Conn) SetPingHandler(h func(appData string) error) {
|
||||
if h == nil {
|
||||
h = func(message string) error {
|
||||
@ -929,6 +1105,9 @@ func (c *Conn) PongHandler() func(appData string) error {
|
||||
// SetPongHandler sets the handler for pong messages received from the peer.
|
||||
// The appData argument to h is the PONG frame application data. The default
|
||||
// pong handler does nothing.
|
||||
//
|
||||
// The application must read the connection to process ping messages as
|
||||
// described in the section on Control Frames above.
|
||||
func (c *Conn) SetPongHandler(h func(appData string) error) {
|
||||
if h == nil {
|
||||
h = func(string) error { return nil }
|
||||
@ -942,6 +1121,25 @@ func (c *Conn) UnderlyingConn() net.Conn {
|
||||
return c.conn
|
||||
}
|
||||
|
||||
// EnableWriteCompression enables and disables write compression of
|
||||
// subsequent text and binary messages. This function is a noop if
|
||||
// compression was not negotiated with the peer.
|
||||
func (c *Conn) EnableWriteCompression(enable bool) {
|
||||
c.enableWriteCompression = enable
|
||||
}
|
||||
|
||||
// SetCompressionLevel sets the flate compression level for subsequent text and
|
||||
// binary messages. This function is a noop if compression was not negotiated
|
||||
// with the peer. See the compress/flate package for a description of
|
||||
// compression levels.
|
||||
func (c *Conn) SetCompressionLevel(level int) error {
|
||||
if !isValidCompressionLevel(level) {
|
||||
return errors.New("websocket: invalid compression level")
|
||||
}
|
||||
c.compressionLevel = level
|
||||
return nil
|
||||
}
|
||||
|
||||
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
|
||||
func FormatCloseMessage(closeCode int, text string) []byte {
|
||||
buf := make([]byte, 2+len(text))
|
||||
|
34
vendor/github.com/gorilla/websocket/doc.go
generated
vendored
34
vendor/github.com/gorilla/websocket/doc.go
generated
vendored
@ -118,9 +118,10 @@
|
||||
//
|
||||
// Applications are responsible for ensuring that no more than one goroutine
|
||||
// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
|
||||
// WriteJSON) concurrently and that no more than one goroutine calls the read
|
||||
// methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler,
|
||||
// SetPingHandler) concurrently.
|
||||
// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and
|
||||
// that no more than one goroutine calls the read methods (NextReader,
|
||||
// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler)
|
||||
// concurrently.
|
||||
//
|
||||
// The Close and WriteControl methods can be called concurrently with all other
|
||||
// methods.
|
||||
@ -149,4 +150,31 @@
|
||||
// The deprecated Upgrade function does not enforce an origin policy. It's the
|
||||
// application's responsibility to check the Origin header before calling
|
||||
// Upgrade.
|
||||
//
|
||||
// Compression EXPERIMENTAL
|
||||
//
|
||||
// Per message compression extensions (RFC 7692) are experimentally supported
|
||||
// by this package in a limited capacity. Setting the EnableCompression option
|
||||
// to true in Dialer or Upgrader will attempt to negotiate per message deflate
|
||||
// support.
|
||||
//
|
||||
// var upgrader = websocket.Upgrader{
|
||||
// EnableCompression: true,
|
||||
// }
|
||||
//
|
||||
// If compression was successfully negotiated with the connection's peer, any
|
||||
// message received in compressed form will be automatically decompressed.
|
||||
// All Read methods will return uncompressed bytes.
|
||||
//
|
||||
// Per message compression of messages written to a connection can be enabled
|
||||
// or disabled by calling the corresponding Conn method:
|
||||
//
|
||||
// conn.EnableWriteCompression(false)
|
||||
//
|
||||
// Currently this package does not support compression with "context takeover".
|
||||
// This means that messages must be compressed and decompressed in isolation,
|
||||
// without retaining sliding window or dictionary state across messages. For
|
||||
// more details refer to RFC 7692.
|
||||
//
|
||||
// Use of compression is experimental and may result in decreased performance.
|
||||
package websocket
|
||||
|
55
vendor/github.com/gorilla/websocket/mask.go
generated
vendored
Normal file
55
vendor/github.com/gorilla/websocket/mask.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
|
||||
// this source code is governed by a BSD-style license that can be found in the
|
||||
// LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
|
||||
package websocket
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const wordSize = int(unsafe.Sizeof(uintptr(0)))
|
||||
|
||||
func maskBytes(key [4]byte, pos int, b []byte) int {
|
||||
|
||||
// Mask one byte at a time for small buffers.
|
||||
if len(b) < 2*wordSize {
|
||||
for i := range b {
|
||||
b[i] ^= key[pos&3]
|
||||
pos++
|
||||
}
|
||||
return pos & 3
|
||||
}
|
||||
|
||||
// Mask one byte at a time to word boundary.
|
||||
if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 {
|
||||
n = wordSize - n
|
||||
for i := range b[:n] {
|
||||
b[i] ^= key[pos&3]
|
||||
pos++
|
||||
}
|
||||
b = b[n:]
|
||||
}
|
||||
|
||||
// Create aligned word size key.
|
||||
var k [wordSize]byte
|
||||
for i := range k {
|
||||
k[i] = key[(pos+i)&3]
|
||||
}
|
||||
kw := *(*uintptr)(unsafe.Pointer(&k))
|
||||
|
||||
// Mask one word at a time.
|
||||
n := (len(b) / wordSize) * wordSize
|
||||
for i := 0; i < n; i += wordSize {
|
||||
*(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw
|
||||
}
|
||||
|
||||
// Mask one byte at a time for remaining bytes.
|
||||
b = b[n:]
|
||||
for i := range b {
|
||||
b[i] ^= key[pos&3]
|
||||
pos++
|
||||
}
|
||||
|
||||
return pos & 3
|
||||
}
|
15
vendor/github.com/gorilla/websocket/mask_safe.go
generated
vendored
Normal file
15
vendor/github.com/gorilla/websocket/mask_safe.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
|
||||
// this source code is governed by a BSD-style license that can be found in the
|
||||
// LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package websocket
|
||||
|
||||
func maskBytes(key [4]byte, pos int, b []byte) int {
|
||||
for i := range b {
|
||||
b[i] ^= key[pos&3]
|
||||
pos++
|
||||
}
|
||||
return pos & 3
|
||||
}
|
103
vendor/github.com/gorilla/websocket/prepared.go
generated
vendored
Normal file
103
vendor/github.com/gorilla/websocket/prepared.go
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PreparedMessage caches on the wire representations of a message payload.
|
||||
// Use PreparedMessage to efficiently send a message payload to multiple
|
||||
// connections. PreparedMessage is especially useful when compression is used
|
||||
// because the CPU and memory expensive compression operation can be executed
|
||||
// once for a given set of compression options.
|
||||
type PreparedMessage struct {
|
||||
messageType int
|
||||
data []byte
|
||||
err error
|
||||
mu sync.Mutex
|
||||
frames map[prepareKey]*preparedFrame
|
||||
}
|
||||
|
||||
// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage.
|
||||
type prepareKey struct {
|
||||
isServer bool
|
||||
compress bool
|
||||
compressionLevel int
|
||||
}
|
||||
|
||||
// preparedFrame contains data in wire representation.
|
||||
type preparedFrame struct {
|
||||
once sync.Once
|
||||
data []byte
|
||||
}
|
||||
|
||||
// NewPreparedMessage returns an initialized PreparedMessage. You can then send
|
||||
// it to connection using WritePreparedMessage method. Valid wire
|
||||
// representation will be calculated lazily only once for a set of current
|
||||
// connection options.
|
||||
func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) {
|
||||
pm := &PreparedMessage{
|
||||
messageType: messageType,
|
||||
frames: make(map[prepareKey]*preparedFrame),
|
||||
data: data,
|
||||
}
|
||||
|
||||
// Prepare a plain server frame.
|
||||
_, frameData, err := pm.frame(prepareKey{isServer: true, compress: false})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// To protect against caller modifying the data argument, remember the data
|
||||
// copied to the plain server frame.
|
||||
pm.data = frameData[len(frameData)-len(data):]
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
|
||||
pm.mu.Lock()
|
||||
frame, ok := pm.frames[key]
|
||||
if !ok {
|
||||
frame = &preparedFrame{}
|
||||
pm.frames[key] = frame
|
||||
}
|
||||
pm.mu.Unlock()
|
||||
|
||||
var err error
|
||||
frame.once.Do(func() {
|
||||
// Prepare a frame using a 'fake' connection.
|
||||
// TODO: Refactor code in conn.go to allow more direct construction of
|
||||
// the frame.
|
||||
mu := make(chan bool, 1)
|
||||
mu <- true
|
||||
var nc prepareConn
|
||||
c := &Conn{
|
||||
conn: &nc,
|
||||
mu: mu,
|
||||
isServer: key.isServer,
|
||||
compressionLevel: key.compressionLevel,
|
||||
enableWriteCompression: true,
|
||||
writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize),
|
||||
}
|
||||
if key.compress {
|
||||
c.newCompressionWriter = compressNoContextTakeover
|
||||
}
|
||||
err = c.WriteMessage(pm.messageType, pm.data)
|
||||
frame.data = nc.buf.Bytes()
|
||||
})
|
||||
return pm.messageType, frame.data, err
|
||||
}
|
||||
|
||||
type prepareConn struct {
|
||||
buf bytes.Buffer
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) }
|
||||
func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }
|
61
vendor/github.com/gorilla/websocket/server.go
generated
vendored
61
vendor/github.com/gorilla/websocket/server.go
generated
vendored
@ -28,8 +28,9 @@ type Upgrader struct {
|
||||
HandshakeTimeout time.Duration
|
||||
|
||||
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
|
||||
// size is zero, then a default value of 4096 is used. The I/O buffer sizes
|
||||
// do not limit the size of the messages that can be sent or received.
|
||||
// size is zero, then buffers allocated by the HTTP server are used. The
|
||||
// I/O buffer sizes do not limit the size of the messages that can be sent
|
||||
// or received.
|
||||
ReadBufferSize, WriteBufferSize int
|
||||
|
||||
// Subprotocols specifies the server's supported protocols in order of
|
||||
@ -46,6 +47,12 @@ type Upgrader struct {
|
||||
// CheckOrigin is nil, the host in the Origin header must not be set or
|
||||
// must match the host of the request.
|
||||
CheckOrigin func(r *http.Request) bool
|
||||
|
||||
// EnableCompression specify if the server should attempt to negotiate per
|
||||
// message compression (RFC 7692). Setting this value to true does not
|
||||
// guarantee that compression will be supported. Currently only "no context
|
||||
// takeover" modes are supported.
|
||||
EnableCompression bool
|
||||
}
|
||||
|
||||
func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
|
||||
@ -53,6 +60,7 @@ func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status in
|
||||
if u.Error != nil {
|
||||
u.Error(w, r, status, err)
|
||||
} else {
|
||||
w.Header().Set("Sec-Websocket-Version", "13")
|
||||
http.Error(w, http.StatusText(status), status)
|
||||
}
|
||||
return nil, err
|
||||
@ -97,18 +105,23 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header
|
||||
// response.
|
||||
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
|
||||
if r.Method != "GET" {
|
||||
return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET")
|
||||
return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET")
|
||||
}
|
||||
if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
|
||||
|
||||
if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
|
||||
return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported")
|
||||
}
|
||||
|
||||
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'")
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header")
|
||||
}
|
||||
|
||||
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'")
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header")
|
||||
}
|
||||
|
||||
if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
|
||||
}
|
||||
|
||||
checkOrigin := u.CheckOrigin
|
||||
@ -116,19 +129,30 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
||||
checkOrigin = checkSameOrigin
|
||||
}
|
||||
if !checkOrigin(r) {
|
||||
return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
|
||||
return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed")
|
||||
}
|
||||
|
||||
challengeKey := r.Header.Get("Sec-Websocket-Key")
|
||||
if challengeKey == "" {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-Websocket-Key' header is missing or blank")
|
||||
}
|
||||
|
||||
subprotocol := u.selectSubprotocol(r, responseHeader)
|
||||
|
||||
// Negotiate PMCE
|
||||
var compress bool
|
||||
if u.EnableCompression {
|
||||
for _, ext := range parseExtensions(r.Header) {
|
||||
if ext[""] != "permessage-deflate" {
|
||||
continue
|
||||
}
|
||||
compress = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
netConn net.Conn
|
||||
br *bufio.Reader
|
||||
err error
|
||||
)
|
||||
|
||||
@ -136,21 +160,25 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
||||
if !ok {
|
||||
return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
|
||||
}
|
||||
var rw *bufio.ReadWriter
|
||||
netConn, rw, err = h.Hijack()
|
||||
var brw *bufio.ReadWriter
|
||||
netConn, brw, err = h.Hijack()
|
||||
if err != nil {
|
||||
return u.returnError(w, r, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
br = rw.Reader
|
||||
|
||||
if br.Buffered() > 0 {
|
||||
if brw.Reader.Buffered() > 0 {
|
||||
netConn.Close()
|
||||
return nil, errors.New("websocket: client sent data before handshake is complete")
|
||||
}
|
||||
|
||||
c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
|
||||
c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw)
|
||||
c.subprotocol = subprotocol
|
||||
|
||||
if compress {
|
||||
c.newCompressionWriter = compressNoContextTakeover
|
||||
c.newDecompressionReader = decompressNoContextTakeover
|
||||
}
|
||||
|
||||
p := c.writeBuf[:0]
|
||||
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
|
||||
p = append(p, computeAcceptKey(challengeKey)...)
|
||||
@ -160,6 +188,9 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
||||
p = append(p, c.subprotocol...)
|
||||
p = append(p, "\r\n"...)
|
||||
}
|
||||
if compress {
|
||||
p = append(p, "Sec-Websocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
|
||||
}
|
||||
for k, vs := range responseHeader {
|
||||
if k == "Sec-Websocket-Protocol" {
|
||||
continue
|
||||
|
28
vendor/github.com/howeyc/fsnotify/AUTHORS
generated
vendored
28
vendor/github.com/howeyc/fsnotify/AUTHORS
generated
vendored
@ -1,28 +0,0 @@
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# You can update this list using the following command:
|
||||
#
|
||||
# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Adrien Bustany <adrien@bustany.org>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Case Nelson <case@teammating.com>
|
||||
Chris Howey <howeyc@gmail.com> <chris@howey.me>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
Dave Cheney <dave@cheney.net>
|
||||
Francisco Souza <f@souza.cc>
|
||||
John C Barstow
|
||||
Kelvin Fo <vmirage@gmail.com>
|
||||
Nathan Youngman <git@nathany.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Pursuit92 <JoshChase@techpursuit.net>
|
||||
Rob Figueiredo <robfig@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
bronze1man <bronze1man@gmail.com>
|
||||
debrando <denis.brandolini@gmail.com>
|
||||
henrikedwards <henrik.edwards@gmail.com>
|
160
vendor/github.com/howeyc/fsnotify/CHANGELOG.md
generated
vendored
160
vendor/github.com/howeyc/fsnotify/CHANGELOG.md
generated
vendored
@ -1,160 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## v0.9.0 / 2014-01-17
|
||||
|
||||
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
|
||||
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
|
||||
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
|
||||
|
||||
## v0.8.12 / 2013-11-13
|
||||
|
||||
* [API] Remove FD_SET and friends from Linux adapter
|
||||
|
||||
## v0.8.11 / 2013-11-02
|
||||
|
||||
* [Doc] Add Changelog [#72][] (thanks @nathany)
|
||||
* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond)
|
||||
|
||||
## v0.8.10 / 2013-10-19
|
||||
|
||||
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
|
||||
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
|
||||
* [Doc] specify OS-specific limits in README (thanks @debrando)
|
||||
|
||||
## v0.8.9 / 2013-09-08
|
||||
|
||||
* [Doc] Contributing (thanks @nathany)
|
||||
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
|
||||
* [Doc] GoCI badge in README (Linux only) [#60][]
|
||||
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
|
||||
|
||||
## v0.8.8 / 2013-06-17
|
||||
|
||||
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
|
||||
|
||||
## v0.8.7 / 2013-06-03
|
||||
|
||||
* [API] Make syscall flags internal
|
||||
* [Fix] inotify: ignore event changes
|
||||
* [Fix] race in symlink test [#45][] (reported by @srid)
|
||||
* [Fix] tests on Windows
|
||||
* lower case error messages
|
||||
|
||||
## v0.8.6 / 2013-05-23
|
||||
|
||||
* kqueue: Use EVT_ONLY flag on Darwin
|
||||
* [Doc] Update README with full example
|
||||
|
||||
## v0.8.5 / 2013-05-09
|
||||
|
||||
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
|
||||
|
||||
## v0.8.4 / 2013-04-07
|
||||
|
||||
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
|
||||
|
||||
## v0.8.3 / 2013-03-13
|
||||
|
||||
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
|
||||
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
|
||||
|
||||
## v0.8.2 / 2013-02-07
|
||||
|
||||
* [Doc] add Authors
|
||||
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
|
||||
|
||||
## v0.8.1 / 2013-01-09
|
||||
|
||||
* [Fix] Windows path separators
|
||||
* [Doc] BSD License
|
||||
|
||||
## v0.8.0 / 2012-11-09
|
||||
|
||||
* kqueue: directory watching improvements (thanks @vmirage)
|
||||
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
|
||||
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
|
||||
|
||||
## v0.7.4 / 2012-10-09
|
||||
|
||||
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
|
||||
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
|
||||
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
|
||||
* [Fix] kqueue: modify after recreation of file
|
||||
|
||||
## v0.7.3 / 2012-09-27
|
||||
|
||||
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
|
||||
* [Fix] kqueue: no longer get duplicate CREATE events
|
||||
|
||||
## v0.7.2 / 2012-09-01
|
||||
|
||||
* kqueue: events for created directories
|
||||
|
||||
## v0.7.1 / 2012-07-14
|
||||
|
||||
* [Fix] for renaming files
|
||||
|
||||
## v0.7.0 / 2012-07-02
|
||||
|
||||
* [Feature] FSNotify flags
|
||||
* [Fix] inotify: Added file name back to event path
|
||||
|
||||
## v0.6.0 / 2012-06-06
|
||||
|
||||
* kqueue: watch files after directory created (thanks @tmc)
|
||||
|
||||
## v0.5.1 / 2012-05-22
|
||||
|
||||
* [Fix] inotify: remove all watches before Close()
|
||||
|
||||
## v0.5.0 / 2012-05-03
|
||||
|
||||
* [API] kqueue: return errors during watch instead of sending over channel
|
||||
* kqueue: match symlink behavior on Linux
|
||||
* inotify: add `DELETE_SELF` (requested by @taralx)
|
||||
* [Fix] kqueue: handle EINTR (reported by @robfig)
|
||||
* [Doc] Godoc example [#1][] (thanks @davecheney)
|
||||
|
||||
## v0.4.0 / 2012-03-30
|
||||
|
||||
* Go 1 released: build with go tool
|
||||
* [Feature] Windows support using winfsnotify
|
||||
* Windows does not have attribute change notifications
|
||||
* Roll attribute notifications into IsModify
|
||||
|
||||
## v0.3.0 / 2012-02-19
|
||||
|
||||
* kqueue: add files when watch directory
|
||||
|
||||
## v0.2.0 / 2011-12-30
|
||||
|
||||
* update to latest Go weekly code
|
||||
|
||||
## v0.1.0 / 2011-10-19
|
||||
|
||||
* kqueue: add watch on file creation to match inotify
|
||||
* kqueue: create file event
|
||||
* inotify: ignore `IN_IGNORED` events
|
||||
* event String()
|
||||
* linux: common FileEvent functions
|
||||
* initial commit
|
||||
|
||||
[#79]: https://github.com/howeyc/fsnotify/pull/79
|
||||
[#77]: https://github.com/howeyc/fsnotify/pull/77
|
||||
[#72]: https://github.com/howeyc/fsnotify/issues/72
|
||||
[#71]: https://github.com/howeyc/fsnotify/issues/71
|
||||
[#70]: https://github.com/howeyc/fsnotify/issues/70
|
||||
[#63]: https://github.com/howeyc/fsnotify/issues/63
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#60]: https://github.com/howeyc/fsnotify/issues/60
|
||||
[#59]: https://github.com/howeyc/fsnotify/issues/59
|
||||
[#49]: https://github.com/howeyc/fsnotify/issues/49
|
||||
[#45]: https://github.com/howeyc/fsnotify/issues/45
|
||||
[#40]: https://github.com/howeyc/fsnotify/issues/40
|
||||
[#36]: https://github.com/howeyc/fsnotify/issues/36
|
||||
[#33]: https://github.com/howeyc/fsnotify/issues/33
|
||||
[#29]: https://github.com/howeyc/fsnotify/issues/29
|
||||
[#25]: https://github.com/howeyc/fsnotify/issues/25
|
||||
[#24]: https://github.com/howeyc/fsnotify/issues/24
|
||||
[#21]: https://github.com/howeyc/fsnotify/issues/21
|
||||
[#1]: https://github.com/howeyc/fsnotify/issues/1
|
7
vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md
generated
vendored
7
vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md
generated
vendored
@ -1,7 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
## Moving Notice
|
||||
|
||||
There is a fork being actively developed with a new API in preparation for the Go Standard Library:
|
||||
[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify)
|
||||
|
28
vendor/github.com/howeyc/fsnotify/LICENSE
generated
vendored
28
vendor/github.com/howeyc/fsnotify/LICENSE
generated
vendored
@ -1,28 +0,0 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2012 fsnotify Authors. 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.
|
93
vendor/github.com/howeyc/fsnotify/README.md
generated
vendored
93
vendor/github.com/howeyc/fsnotify/README.md
generated
vendored
@ -1,93 +0,0 @@
|
||||
# File system notifications for Go
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/howeyc/fsnotify?status.png)](http://godoc.org/github.com/howeyc/fsnotify)
|
||||
|
||||
Cross platform: Windows, Linux, BSD and OS X.
|
||||
|
||||
## Moving Notice
|
||||
|
||||
There is a fork being actively developed with a new API in preparation for the Go Standard Library:
|
||||
[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify)
|
||||
|
||||
## Example:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/howeyc/fsnotify"
|
||||
)
|
||||
|
||||
func main() {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
|
||||
// Process events
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case ev := <-watcher.Event:
|
||||
log.Println("event:", ev)
|
||||
case err := <-watcher.Error:
|
||||
log.Println("error:", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = watcher.Watch("testDir")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Hang so program doesn't exit
|
||||
<-done
|
||||
|
||||
/* ... do stuff ... */
|
||||
watcher.Close()
|
||||
}
|
||||
```
|
||||
|
||||
For each event:
|
||||
* Name
|
||||
* IsCreate()
|
||||
* IsDelete()
|
||||
* IsModify()
|
||||
* IsRename()
|
||||
|
||||
## FAQ
|
||||
|
||||
**When a file is moved to another directory is it still being watched?**
|
||||
|
||||
No (it shouldn't be, unless you are watching where it was moved to).
|
||||
|
||||
**When I watch a directory, are all subdirectories watched as well?**
|
||||
|
||||
No, you must add watches for any directory you want to watch (a recursive watcher is in the works [#56][]).
|
||||
|
||||
**Do I have to watch the Error and Event channels in a separate goroutine?**
|
||||
|
||||
As of now, yes. Looking into making this single-thread friendly (see [#7][])
|
||||
|
||||
**Why am I receiving multiple events for the same file on OS X?**
|
||||
|
||||
Spotlight indexing on OS X can result in multiple events (see [#62][]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#54][]).
|
||||
|
||||
**How many files can be watched at once?**
|
||||
|
||||
There are OS-specific limits as to how many watches can be created:
|
||||
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit,
|
||||
reaching this limit results in a "no space left on device" error.
|
||||
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
||||
|
||||
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#56]: https://github.com/howeyc/fsnotify/issues/56
|
||||
[#54]: https://github.com/howeyc/fsnotify/issues/54
|
||||
[#7]: https://github.com/howeyc/fsnotify/issues/7
|
||||
|
111
vendor/github.com/howeyc/fsnotify/fsnotify.go
generated
vendored
111
vendor/github.com/howeyc/fsnotify/fsnotify.go
generated
vendored
@ -1,111 +0,0 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package fsnotify implements file system notification.
|
||||
package fsnotify
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
FSN_CREATE = 1
|
||||
FSN_MODIFY = 2
|
||||
FSN_DELETE = 4
|
||||
FSN_RENAME = 8
|
||||
|
||||
FSN_ALL = FSN_MODIFY | FSN_DELETE | FSN_RENAME | FSN_CREATE
|
||||
)
|
||||
|
||||
// Purge events from interal chan to external chan if passes filter
|
||||
func (w *Watcher) purgeEvents() {
|
||||
for ev := range w.internalEvent {
|
||||
sendEvent := false
|
||||
w.fsnmut.Lock()
|
||||
fsnFlags := w.fsnFlags[ev.Name]
|
||||
w.fsnmut.Unlock()
|
||||
|
||||
if (fsnFlags&FSN_CREATE == FSN_CREATE) && ev.IsCreate() {
|
||||
sendEvent = true
|
||||
}
|
||||
|
||||
if (fsnFlags&FSN_MODIFY == FSN_MODIFY) && ev.IsModify() {
|
||||
sendEvent = true
|
||||
}
|
||||
|
||||
if (fsnFlags&FSN_DELETE == FSN_DELETE) && ev.IsDelete() {
|
||||
sendEvent = true
|
||||
}
|
||||
|
||||
if (fsnFlags&FSN_RENAME == FSN_RENAME) && ev.IsRename() {
|
||||
sendEvent = true
|
||||
}
|
||||
|
||||
if sendEvent {
|
||||
w.Event <- ev
|
||||
}
|
||||
|
||||
// If there's no file, then no more events for user
|
||||
// BSD must keep watch for internal use (watches DELETEs to keep track
|
||||
// what files exist for create events)
|
||||
if ev.IsDelete() {
|
||||
w.fsnmut.Lock()
|
||||
delete(w.fsnFlags, ev.Name)
|
||||
w.fsnmut.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
close(w.Event)
|
||||
}
|
||||
|
||||
// Watch a given file path
|
||||
func (w *Watcher) Watch(path string) error {
|
||||
return w.WatchFlags(path, FSN_ALL)
|
||||
}
|
||||
|
||||
// Watch a given file path for a particular set of notifications (FSN_MODIFY etc.)
|
||||
func (w *Watcher) WatchFlags(path string, flags uint32) error {
|
||||
w.fsnmut.Lock()
|
||||
w.fsnFlags[path] = flags
|
||||
w.fsnmut.Unlock()
|
||||
return w.watch(path)
|
||||
}
|
||||
|
||||
// Remove a watch on a file
|
||||
func (w *Watcher) RemoveWatch(path string) error {
|
||||
w.fsnmut.Lock()
|
||||
delete(w.fsnFlags, path)
|
||||
w.fsnmut.Unlock()
|
||||
return w.removeWatch(path)
|
||||
}
|
||||
|
||||
// String formats the event e in the form
|
||||
// "filename: DELETE|MODIFY|..."
|
||||
func (e *FileEvent) String() string {
|
||||
var events string = ""
|
||||
|
||||
if e.IsCreate() {
|
||||
events += "|" + "CREATE"
|
||||
}
|
||||
|
||||
if e.IsDelete() {
|
||||
events += "|" + "DELETE"
|
||||
}
|
||||
|
||||
if e.IsModify() {
|
||||
events += "|" + "MODIFY"
|
||||
}
|
||||
|
||||
if e.IsRename() {
|
||||
events += "|" + "RENAME"
|
||||
}
|
||||
|
||||
if e.IsAttrib() {
|
||||
events += "|" + "ATTRIB"
|
||||
}
|
||||
|
||||
if len(events) > 0 {
|
||||
events = events[1:]
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%q: %s", e.Name, events)
|
||||
}
|
496
vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go
generated
vendored
496
vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go
generated
vendored
@ -1,496 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build freebsd openbsd netbsd dragonfly darwin
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
// Flags (from <sys/event.h>)
|
||||
sys_NOTE_DELETE = 0x0001 /* vnode was removed */
|
||||
sys_NOTE_WRITE = 0x0002 /* data contents changed */
|
||||
sys_NOTE_EXTEND = 0x0004 /* size increased */
|
||||
sys_NOTE_ATTRIB = 0x0008 /* attributes changed */
|
||||
sys_NOTE_LINK = 0x0010 /* link count changed */
|
||||
sys_NOTE_RENAME = 0x0020 /* vnode was renamed */
|
||||
sys_NOTE_REVOKE = 0x0040 /* vnode access was revoked */
|
||||
|
||||
// Watch all events
|
||||
sys_NOTE_ALLEVENTS = sys_NOTE_DELETE | sys_NOTE_WRITE | sys_NOTE_ATTRIB | sys_NOTE_RENAME
|
||||
|
||||
// Block for 100 ms on each call to kevent
|
||||
keventWaitTime = 100e6
|
||||
)
|
||||
|
||||
type FileEvent struct {
|
||||
mask uint32 // Mask of events
|
||||
Name string // File name (optional)
|
||||
create bool // set by fsnotify package if found new file
|
||||
}
|
||||
|
||||
// IsCreate reports whether the FileEvent was triggered by a creation
|
||||
func (e *FileEvent) IsCreate() bool { return e.create }
|
||||
|
||||
// IsDelete reports whether the FileEvent was triggered by a delete
|
||||
func (e *FileEvent) IsDelete() bool { return (e.mask & sys_NOTE_DELETE) == sys_NOTE_DELETE }
|
||||
|
||||
// IsModify reports whether the FileEvent was triggered by a file modification
|
||||
func (e *FileEvent) IsModify() bool {
|
||||
return ((e.mask&sys_NOTE_WRITE) == sys_NOTE_WRITE || (e.mask&sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB)
|
||||
}
|
||||
|
||||
// IsRename reports whether the FileEvent was triggered by a change name
|
||||
func (e *FileEvent) IsRename() bool { return (e.mask & sys_NOTE_RENAME) == sys_NOTE_RENAME }
|
||||
|
||||
// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata.
|
||||
func (e *FileEvent) IsAttrib() bool {
|
||||
return (e.mask & sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB
|
||||
}
|
||||
|
||||
type Watcher struct {
|
||||
mu sync.Mutex // Mutex for the Watcher itself.
|
||||
kq int // File descriptor (as returned by the kqueue() syscall)
|
||||
watches map[string]int // Map of watched file descriptors (key: path)
|
||||
wmut sync.Mutex // Protects access to watches.
|
||||
fsnFlags map[string]uint32 // Map of watched files to flags used for filter
|
||||
fsnmut sync.Mutex // Protects access to fsnFlags.
|
||||
enFlags map[string]uint32 // Map of watched files to evfilt note flags used in kqueue
|
||||
enmut sync.Mutex // Protects access to enFlags.
|
||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||
finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor)
|
||||
pmut sync.Mutex // Protects access to paths and finfo.
|
||||
fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events)
|
||||
femut sync.Mutex // Protects access to fileExists.
|
||||
externalWatches map[string]bool // Map of watches added by user of the library.
|
||||
ewmut sync.Mutex // Protects access to externalWatches.
|
||||
Error chan error // Errors are sent on this channel
|
||||
internalEvent chan *FileEvent // Events are queued on this channel
|
||||
Event chan *FileEvent // Events are returned on this channel
|
||||
done chan bool // Channel for sending a "quit message" to the reader goroutine
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
}
|
||||
|
||||
// NewWatcher creates and returns a new kevent instance using kqueue(2)
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
fd, errno := syscall.Kqueue()
|
||||
if fd == -1 {
|
||||
return nil, os.NewSyscallError("kqueue", errno)
|
||||
}
|
||||
w := &Watcher{
|
||||
kq: fd,
|
||||
watches: make(map[string]int),
|
||||
fsnFlags: make(map[string]uint32),
|
||||
enFlags: make(map[string]uint32),
|
||||
paths: make(map[int]string),
|
||||
finfo: make(map[int]os.FileInfo),
|
||||
fileExists: make(map[string]bool),
|
||||
externalWatches: make(map[string]bool),
|
||||
internalEvent: make(chan *FileEvent),
|
||||
Event: make(chan *FileEvent),
|
||||
Error: make(chan error),
|
||||
done: make(chan bool, 1),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
go w.purgeEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close closes a kevent watcher instance
|
||||
// It sends a message to the reader goroutine to quit and removes all watches
|
||||
// associated with the kevent instance
|
||||
func (w *Watcher) Close() error {
|
||||
w.mu.Lock()
|
||||
if w.isClosed {
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
w.mu.Unlock()
|
||||
|
||||
// Send "quit" message to the reader goroutine
|
||||
w.done <- true
|
||||
w.wmut.Lock()
|
||||
ws := w.watches
|
||||
w.wmut.Unlock()
|
||||
for path := range ws {
|
||||
w.removeWatch(path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddWatch adds path to the watched file set.
|
||||
// The flags are interpreted as described in kevent(2).
|
||||
func (w *Watcher) addWatch(path string, flags uint32) error {
|
||||
w.mu.Lock()
|
||||
if w.isClosed {
|
||||
w.mu.Unlock()
|
||||
return errors.New("kevent instance already closed")
|
||||
}
|
||||
w.mu.Unlock()
|
||||
|
||||
watchDir := false
|
||||
|
||||
w.wmut.Lock()
|
||||
watchfd, found := w.watches[path]
|
||||
w.wmut.Unlock()
|
||||
if !found {
|
||||
fi, errstat := os.Lstat(path)
|
||||
if errstat != nil {
|
||||
return errstat
|
||||
}
|
||||
|
||||
// don't watch socket
|
||||
if fi.Mode()&os.ModeSocket == os.ModeSocket {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Follow Symlinks
|
||||
// Unfortunately, Linux can add bogus symlinks to watch list without
|
||||
// issue, and Windows can't do symlinks period (AFAIK). To maintain
|
||||
// consistency, we will act like everything is fine. There will simply
|
||||
// be no file events for broken symlinks.
|
||||
// Hence the returns of nil on errors.
|
||||
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
path, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fi, errstat = os.Lstat(path)
|
||||
if errstat != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
fd, errno := syscall.Open(path, open_FLAGS, 0700)
|
||||
if fd == -1 {
|
||||
return errno
|
||||
}
|
||||
watchfd = fd
|
||||
|
||||
w.wmut.Lock()
|
||||
w.watches[path] = watchfd
|
||||
w.wmut.Unlock()
|
||||
|
||||
w.pmut.Lock()
|
||||
w.paths[watchfd] = path
|
||||
w.finfo[watchfd] = fi
|
||||
w.pmut.Unlock()
|
||||
}
|
||||
// Watch the directory if it has not been watched before.
|
||||
w.pmut.Lock()
|
||||
w.enmut.Lock()
|
||||
if w.finfo[watchfd].IsDir() &&
|
||||
(flags&sys_NOTE_WRITE) == sys_NOTE_WRITE &&
|
||||
(!found || (w.enFlags[path]&sys_NOTE_WRITE) != sys_NOTE_WRITE) {
|
||||
watchDir = true
|
||||
}
|
||||
w.enmut.Unlock()
|
||||
w.pmut.Unlock()
|
||||
|
||||
w.enmut.Lock()
|
||||
w.enFlags[path] = flags
|
||||
w.enmut.Unlock()
|
||||
|
||||
var kbuf [1]syscall.Kevent_t
|
||||
watchEntry := &kbuf[0]
|
||||
watchEntry.Fflags = flags
|
||||
syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)
|
||||
entryFlags := watchEntry.Flags
|
||||
success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil)
|
||||
if success == -1 {
|
||||
return errno
|
||||
} else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
|
||||
return errors.New("kevent add error")
|
||||
}
|
||||
|
||||
if watchDir {
|
||||
errdir := w.watchDirectoryFiles(path)
|
||||
if errdir != nil {
|
||||
return errdir
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Watch adds path to the watched file set, watching all events.
|
||||
func (w *Watcher) watch(path string) error {
|
||||
w.ewmut.Lock()
|
||||
w.externalWatches[path] = true
|
||||
w.ewmut.Unlock()
|
||||
return w.addWatch(path, sys_NOTE_ALLEVENTS)
|
||||
}
|
||||
|
||||
// RemoveWatch removes path from the watched file set.
|
||||
func (w *Watcher) removeWatch(path string) error {
|
||||
w.wmut.Lock()
|
||||
watchfd, ok := w.watches[path]
|
||||
w.wmut.Unlock()
|
||||
if !ok {
|
||||
return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
|
||||
}
|
||||
var kbuf [1]syscall.Kevent_t
|
||||
watchEntry := &kbuf[0]
|
||||
syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
|
||||
entryFlags := watchEntry.Flags
|
||||
success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil)
|
||||
if success == -1 {
|
||||
return os.NewSyscallError("kevent_rm_watch", errno)
|
||||
} else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
|
||||
return errors.New("kevent rm error")
|
||||
}
|
||||
syscall.Close(watchfd)
|
||||
w.wmut.Lock()
|
||||
delete(w.watches, path)
|
||||
w.wmut.Unlock()
|
||||
w.enmut.Lock()
|
||||
delete(w.enFlags, path)
|
||||
w.enmut.Unlock()
|
||||
w.pmut.Lock()
|
||||
delete(w.paths, watchfd)
|
||||
fInfo := w.finfo[watchfd]
|
||||
delete(w.finfo, watchfd)
|
||||
w.pmut.Unlock()
|
||||
|
||||
// Find all watched paths that are in this directory that are not external.
|
||||
if fInfo.IsDir() {
|
||||
var pathsToRemove []string
|
||||
w.pmut.Lock()
|
||||
for _, wpath := range w.paths {
|
||||
wdir, _ := filepath.Split(wpath)
|
||||
if filepath.Clean(wdir) == filepath.Clean(path) {
|
||||
w.ewmut.Lock()
|
||||
if !w.externalWatches[wpath] {
|
||||
pathsToRemove = append(pathsToRemove, wpath)
|
||||
}
|
||||
w.ewmut.Unlock()
|
||||
}
|
||||
}
|
||||
w.pmut.Unlock()
|
||||
for _, p := range pathsToRemove {
|
||||
// Since these are internal, not much sense in propagating error
|
||||
// to the user, as that will just confuse them with an error about
|
||||
// a path they did not explicitly watch themselves.
|
||||
w.removeWatch(p)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// readEvents reads from the kqueue file descriptor, converts the
|
||||
// received events into Event objects and sends them via the Event channel
|
||||
func (w *Watcher) readEvents() {
|
||||
var (
|
||||
eventbuf [10]syscall.Kevent_t // Event buffer
|
||||
events []syscall.Kevent_t // Received events
|
||||
twait *syscall.Timespec // Time to block waiting for events
|
||||
n int // Number of events returned from kevent
|
||||
errno error // Syscall errno
|
||||
)
|
||||
events = eventbuf[0:0]
|
||||
twait = new(syscall.Timespec)
|
||||
*twait = syscall.NsecToTimespec(keventWaitTime)
|
||||
|
||||
for {
|
||||
// See if there is a message on the "done" channel
|
||||
var done bool
|
||||
select {
|
||||
case done = <-w.done:
|
||||
default:
|
||||
}
|
||||
|
||||
// If "done" message is received
|
||||
if done {
|
||||
errno := syscall.Close(w.kq)
|
||||
if errno != nil {
|
||||
w.Error <- os.NewSyscallError("close", errno)
|
||||
}
|
||||
close(w.internalEvent)
|
||||
close(w.Error)
|
||||
return
|
||||
}
|
||||
|
||||
// Get new events
|
||||
if len(events) == 0 {
|
||||
n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait)
|
||||
|
||||
// EINTR is okay, basically the syscall was interrupted before
|
||||
// timeout expired.
|
||||
if errno != nil && errno != syscall.EINTR {
|
||||
w.Error <- os.NewSyscallError("kevent", errno)
|
||||
continue
|
||||
}
|
||||
|
||||
// Received some events
|
||||
if n > 0 {
|
||||
events = eventbuf[0:n]
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the events we received to the events channel
|
||||
for len(events) > 0 {
|
||||
fileEvent := new(FileEvent)
|
||||
watchEvent := &events[0]
|
||||
fileEvent.mask = uint32(watchEvent.Fflags)
|
||||
w.pmut.Lock()
|
||||
fileEvent.Name = w.paths[int(watchEvent.Ident)]
|
||||
fileInfo := w.finfo[int(watchEvent.Ident)]
|
||||
w.pmut.Unlock()
|
||||
if fileInfo != nil && fileInfo.IsDir() && !fileEvent.IsDelete() {
|
||||
// Double check to make sure the directory exist. This can happen when
|
||||
// we do a rm -fr on a recursively watched folders and we receive a
|
||||
// modification event first but the folder has been deleted and later
|
||||
// receive the delete event
|
||||
if _, err := os.Lstat(fileEvent.Name); os.IsNotExist(err) {
|
||||
// mark is as delete event
|
||||
fileEvent.mask |= sys_NOTE_DELETE
|
||||
}
|
||||
}
|
||||
|
||||
if fileInfo != nil && fileInfo.IsDir() && fileEvent.IsModify() && !fileEvent.IsDelete() {
|
||||
w.sendDirectoryChangeEvents(fileEvent.Name)
|
||||
} else {
|
||||
// Send the event on the events channel
|
||||
w.internalEvent <- fileEvent
|
||||
}
|
||||
|
||||
// Move to next event
|
||||
events = events[1:]
|
||||
|
||||
if fileEvent.IsRename() {
|
||||
w.removeWatch(fileEvent.Name)
|
||||
w.femut.Lock()
|
||||
delete(w.fileExists, fileEvent.Name)
|
||||
w.femut.Unlock()
|
||||
}
|
||||
if fileEvent.IsDelete() {
|
||||
w.removeWatch(fileEvent.Name)
|
||||
w.femut.Lock()
|
||||
delete(w.fileExists, fileEvent.Name)
|
||||
w.femut.Unlock()
|
||||
|
||||
// Look for a file that may have overwritten this
|
||||
// (ie mv f1 f2 will delete f2 then create f2)
|
||||
fileDir, _ := filepath.Split(fileEvent.Name)
|
||||
fileDir = filepath.Clean(fileDir)
|
||||
w.wmut.Lock()
|
||||
_, found := w.watches[fileDir]
|
||||
w.wmut.Unlock()
|
||||
if found {
|
||||
// make sure the directory exist before we watch for changes. When we
|
||||
// do a recursive watch and perform rm -fr, the parent directory might
|
||||
// have gone missing, ignore the missing directory and let the
|
||||
// upcoming delete event remove the watch form the parent folder
|
||||
if _, err := os.Lstat(fileDir); !os.IsNotExist(err) {
|
||||
w.sendDirectoryChangeEvents(fileDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) watchDirectoryFiles(dirPath string) error {
|
||||
// Get all files
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Search for new files
|
||||
for _, fileInfo := range files {
|
||||
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||
|
||||
// Inherit fsnFlags from parent directory
|
||||
w.fsnmut.Lock()
|
||||
if flags, found := w.fsnFlags[dirPath]; found {
|
||||
w.fsnFlags[filePath] = flags
|
||||
} else {
|
||||
w.fsnFlags[filePath] = FSN_ALL
|
||||
}
|
||||
w.fsnmut.Unlock()
|
||||
|
||||
if fileInfo.IsDir() == false {
|
||||
// Watch file to mimic linux fsnotify
|
||||
e := w.addWatch(filePath, sys_NOTE_ALLEVENTS)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
} else {
|
||||
// If the user is currently watching directory
|
||||
// we want to preserve the flags used
|
||||
w.enmut.Lock()
|
||||
currFlags, found := w.enFlags[filePath]
|
||||
w.enmut.Unlock()
|
||||
var newFlags uint32 = sys_NOTE_DELETE
|
||||
if found {
|
||||
newFlags |= currFlags
|
||||
}
|
||||
|
||||
// Linux gives deletes if not explicitly watching
|
||||
e := w.addWatch(filePath, newFlags)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
w.femut.Lock()
|
||||
w.fileExists[filePath] = true
|
||||
w.femut.Unlock()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendDirectoryEvents searches the directory for newly created files
|
||||
// and sends them over the event channel. This functionality is to have
|
||||
// the BSD version of fsnotify match linux fsnotify which provides a
|
||||
// create event for files created in a watched directory.
|
||||
func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
|
||||
// Get all files
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
w.Error <- err
|
||||
}
|
||||
|
||||
// Search for new files
|
||||
for _, fileInfo := range files {
|
||||
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||
w.femut.Lock()
|
||||
_, doesExist := w.fileExists[filePath]
|
||||
w.femut.Unlock()
|
||||
if !doesExist {
|
||||
// Inherit fsnFlags from parent directory
|
||||
w.fsnmut.Lock()
|
||||
if flags, found := w.fsnFlags[dirPath]; found {
|
||||
w.fsnFlags[filePath] = flags
|
||||
} else {
|
||||
w.fsnFlags[filePath] = FSN_ALL
|
||||
}
|
||||
w.fsnmut.Unlock()
|
||||
|
||||
// Send create event
|
||||
fileEvent := new(FileEvent)
|
||||
fileEvent.Name = filePath
|
||||
fileEvent.create = true
|
||||
w.internalEvent <- fileEvent
|
||||
}
|
||||
w.femut.Lock()
|
||||
w.fileExists[filePath] = true
|
||||
w.femut.Unlock()
|
||||
}
|
||||
w.watchDirectoryFiles(dirPath)
|
||||
}
|
304
vendor/github.com/howeyc/fsnotify/fsnotify_linux.go
generated
vendored
304
vendor/github.com/howeyc/fsnotify/fsnotify_linux.go
generated
vendored
@ -1,304 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Options for inotify_init() are not exported
|
||||
// sys_IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
|
||||
// sys_IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
|
||||
|
||||
// Options for AddWatch
|
||||
sys_IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
|
||||
sys_IN_ONESHOT uint32 = syscall.IN_ONESHOT
|
||||
sys_IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
|
||||
|
||||
// The "sys_IN_MASK_ADD" option is not exported, as AddWatch
|
||||
// adds it automatically, if there is already a watch for the given path
|
||||
// sys_IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
|
||||
|
||||
// Events
|
||||
sys_IN_ACCESS uint32 = syscall.IN_ACCESS
|
||||
sys_IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
|
||||
sys_IN_ATTRIB uint32 = syscall.IN_ATTRIB
|
||||
sys_IN_CLOSE uint32 = syscall.IN_CLOSE
|
||||
sys_IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
|
||||
sys_IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
|
||||
sys_IN_CREATE uint32 = syscall.IN_CREATE
|
||||
sys_IN_DELETE uint32 = syscall.IN_DELETE
|
||||
sys_IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
|
||||
sys_IN_MODIFY uint32 = syscall.IN_MODIFY
|
||||
sys_IN_MOVE uint32 = syscall.IN_MOVE
|
||||
sys_IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
|
||||
sys_IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
|
||||
sys_IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
|
||||
sys_IN_OPEN uint32 = syscall.IN_OPEN
|
||||
|
||||
sys_AGNOSTIC_EVENTS = sys_IN_MOVED_TO | sys_IN_MOVED_FROM | sys_IN_CREATE | sys_IN_ATTRIB | sys_IN_MODIFY | sys_IN_MOVE_SELF | sys_IN_DELETE | sys_IN_DELETE_SELF
|
||||
|
||||
// Special events
|
||||
sys_IN_ISDIR uint32 = syscall.IN_ISDIR
|
||||
sys_IN_IGNORED uint32 = syscall.IN_IGNORED
|
||||
sys_IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
|
||||
sys_IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
|
||||
)
|
||||
|
||||
type FileEvent struct {
|
||||
mask uint32 // Mask of events
|
||||
cookie uint32 // Unique cookie associating related events (for rename(2))
|
||||
Name string // File name (optional)
|
||||
}
|
||||
|
||||
// IsCreate reports whether the FileEvent was triggered by a creation
|
||||
func (e *FileEvent) IsCreate() bool {
|
||||
return (e.mask&sys_IN_CREATE) == sys_IN_CREATE || (e.mask&sys_IN_MOVED_TO) == sys_IN_MOVED_TO
|
||||
}
|
||||
|
||||
// IsDelete reports whether the FileEvent was triggered by a delete
|
||||
func (e *FileEvent) IsDelete() bool {
|
||||
return (e.mask&sys_IN_DELETE_SELF) == sys_IN_DELETE_SELF || (e.mask&sys_IN_DELETE) == sys_IN_DELETE
|
||||
}
|
||||
|
||||
// IsModify reports whether the FileEvent was triggered by a file modification or attribute change
|
||||
func (e *FileEvent) IsModify() bool {
|
||||
return ((e.mask&sys_IN_MODIFY) == sys_IN_MODIFY || (e.mask&sys_IN_ATTRIB) == sys_IN_ATTRIB)
|
||||
}
|
||||
|
||||
// IsRename reports whether the FileEvent was triggered by a change name
|
||||
func (e *FileEvent) IsRename() bool {
|
||||
return ((e.mask&sys_IN_MOVE_SELF) == sys_IN_MOVE_SELF || (e.mask&sys_IN_MOVED_FROM) == sys_IN_MOVED_FROM)
|
||||
}
|
||||
|
||||
// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata.
|
||||
func (e *FileEvent) IsAttrib() bool {
|
||||
return (e.mask & sys_IN_ATTRIB) == sys_IN_ATTRIB
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
}
|
||||
|
||||
type Watcher struct {
|
||||
mu sync.Mutex // Map access
|
||||
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||
watches map[string]*watch // Map of inotify watches (key: path)
|
||||
fsnFlags map[string]uint32 // Map of watched files to flags used for filter
|
||||
fsnmut sync.Mutex // Protects access to fsnFlags.
|
||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||
Error chan error // Errors are sent on this channel
|
||||
internalEvent chan *FileEvent // Events are queued on this channel
|
||||
Event chan *FileEvent // Events are returned on this channel
|
||||
done chan bool // Channel for sending a "quit message" to the reader goroutine
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
}
|
||||
|
||||
// NewWatcher creates and returns a new inotify instance using inotify_init(2)
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
fd, errno := syscall.InotifyInit()
|
||||
if fd == -1 {
|
||||
return nil, os.NewSyscallError("inotify_init", errno)
|
||||
}
|
||||
w := &Watcher{
|
||||
fd: fd,
|
||||
watches: make(map[string]*watch),
|
||||
fsnFlags: make(map[string]uint32),
|
||||
paths: make(map[int]string),
|
||||
internalEvent: make(chan *FileEvent),
|
||||
Event: make(chan *FileEvent),
|
||||
Error: make(chan error),
|
||||
done: make(chan bool, 1),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
go w.purgeEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close closes an inotify watcher instance
|
||||
// It sends a message to the reader goroutine to quit and removes all watches
|
||||
// associated with the inotify instance
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed {
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
// Remove all watches
|
||||
for path := range w.watches {
|
||||
w.RemoveWatch(path)
|
||||
}
|
||||
|
||||
// Send "quit" message to the reader goroutine
|
||||
w.done <- true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddWatch adds path to the watched file set.
|
||||
// The flags are interpreted as described in inotify_add_watch(2).
|
||||
func (w *Watcher) addWatch(path string, flags uint32) error {
|
||||
if w.isClosed {
|
||||
return errors.New("inotify instance already closed")
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
watchEntry, found := w.watches[path]
|
||||
w.mu.Unlock()
|
||||
if found {
|
||||
watchEntry.flags |= flags
|
||||
flags |= syscall.IN_MASK_ADD
|
||||
}
|
||||
wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
|
||||
if wd == -1 {
|
||||
return errno
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
w.watches[path] = &watch{wd: uint32(wd), flags: flags}
|
||||
w.paths[wd] = path
|
||||
w.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Watch adds path to the watched file set, watching all events.
|
||||
func (w *Watcher) watch(path string) error {
|
||||
return w.addWatch(path, sys_AGNOSTIC_EVENTS)
|
||||
}
|
||||
|
||||
// RemoveWatch removes path from the watched file set.
|
||||
func (w *Watcher) removeWatch(path string) error {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
watch, ok := w.watches[path]
|
||||
if !ok {
|
||||
return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
|
||||
}
|
||||
success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
|
||||
if success == -1 {
|
||||
return os.NewSyscallError("inotify_rm_watch", errno)
|
||||
}
|
||||
delete(w.watches, path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// readEvents reads from the inotify file descriptor, converts the
|
||||
// received events into Event objects and sends them via the Event channel
|
||||
func (w *Watcher) readEvents() {
|
||||
var (
|
||||
buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
||||
n int // Number of bytes read with read()
|
||||
errno error // Syscall errno
|
||||
)
|
||||
|
||||
for {
|
||||
// See if there is a message on the "done" channel
|
||||
select {
|
||||
case <-w.done:
|
||||
syscall.Close(w.fd)
|
||||
close(w.internalEvent)
|
||||
close(w.Error)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
n, errno = syscall.Read(w.fd, buf[:])
|
||||
|
||||
// If EOF is received
|
||||
if n == 0 {
|
||||
syscall.Close(w.fd)
|
||||
close(w.internalEvent)
|
||||
close(w.Error)
|
||||
return
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
w.Error <- os.NewSyscallError("read", errno)
|
||||
continue
|
||||
}
|
||||
if n < syscall.SizeofInotifyEvent {
|
||||
w.Error <- errors.New("inotify: short read in readEvents()")
|
||||
continue
|
||||
}
|
||||
|
||||
var offset uint32 = 0
|
||||
// We don't know how many events we just read into the buffer
|
||||
// While the offset points to at least one whole event...
|
||||
for offset <= uint32(n-syscall.SizeofInotifyEvent) {
|
||||
// Point "raw" to the event in the buffer
|
||||
raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
||||
event := new(FileEvent)
|
||||
event.mask = uint32(raw.Mask)
|
||||
event.cookie = uint32(raw.Cookie)
|
||||
nameLen := uint32(raw.Len)
|
||||
// If the event happened to the watched directory or the watched file, the kernel
|
||||
// doesn't append the filename to the event, but we would like to always fill the
|
||||
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
||||
// the "paths" map.
|
||||
w.mu.Lock()
|
||||
event.Name = w.paths[int(raw.Wd)]
|
||||
w.mu.Unlock()
|
||||
watchedName := event.Name
|
||||
if nameLen > 0 {
|
||||
// Point "bytes" at the first byte of the filename
|
||||
bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
|
||||
// The filename is padded with NUL bytes. TrimRight() gets rid of those.
|
||||
event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
||||
}
|
||||
|
||||
// Send the events that are not ignored on the events channel
|
||||
if !event.ignoreLinux() {
|
||||
// Setup FSNotify flags (inherit from directory watch)
|
||||
w.fsnmut.Lock()
|
||||
if _, fsnFound := w.fsnFlags[event.Name]; !fsnFound {
|
||||
if fsnFlags, watchFound := w.fsnFlags[watchedName]; watchFound {
|
||||
w.fsnFlags[event.Name] = fsnFlags
|
||||
} else {
|
||||
w.fsnFlags[event.Name] = FSN_ALL
|
||||
}
|
||||
}
|
||||
w.fsnmut.Unlock()
|
||||
|
||||
w.internalEvent <- event
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
offset += syscall.SizeofInotifyEvent + nameLen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Certain types of events can be "ignored" and not sent over the Event
|
||||
// channel. Such as events marked ignore by the kernel, or MODIFY events
|
||||
// against files that do not exist.
|
||||
func (e *FileEvent) ignoreLinux() bool {
|
||||
// Ignore anything the inotify API says to ignore
|
||||
if e.mask&sys_IN_IGNORED == sys_IN_IGNORED {
|
||||
return true
|
||||
}
|
||||
|
||||
// If the event is not a DELETE or RENAME, the file must exist.
|
||||
// Otherwise the event is ignored.
|
||||
// *Note*: this was put in place because it was seen that a MODIFY
|
||||
// event was sent after the DELETE. This ignores that MODIFY and
|
||||
// assumes a DELETE will come or has come if the file doesn't exist.
|
||||
if !(e.IsDelete() || e.IsRename()) {
|
||||
_, statErr := os.Lstat(e.Name)
|
||||
return os.IsNotExist(statErr)
|
||||
}
|
||||
return false
|
||||
}
|
11
vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go
generated
vendored
11
vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build freebsd openbsd netbsd dragonfly
|
||||
|
||||
package fsnotify
|
||||
|
||||
import "syscall"
|
||||
|
||||
const open_FLAGS = syscall.O_NONBLOCK | syscall.O_RDONLY
|
11
vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go
generated
vendored
11
vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package fsnotify
|
||||
|
||||
import "syscall"
|
||||
|
||||
const open_FLAGS = syscall.O_EVTONLY
|
598
vendor/github.com/howeyc/fsnotify/fsnotify_windows.go
generated
vendored
598
vendor/github.com/howeyc/fsnotify/fsnotify_windows.go
generated
vendored
@ -1,598 +0,0 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Options for AddWatch
|
||||
sys_FS_ONESHOT = 0x80000000
|
||||
sys_FS_ONLYDIR = 0x1000000
|
||||
|
||||
// Events
|
||||
sys_FS_ACCESS = 0x1
|
||||
sys_FS_ALL_EVENTS = 0xfff
|
||||
sys_FS_ATTRIB = 0x4
|
||||
sys_FS_CLOSE = 0x18
|
||||
sys_FS_CREATE = 0x100
|
||||
sys_FS_DELETE = 0x200
|
||||
sys_FS_DELETE_SELF = 0x400
|
||||
sys_FS_MODIFY = 0x2
|
||||
sys_FS_MOVE = 0xc0
|
||||
sys_FS_MOVED_FROM = 0x40
|
||||
sys_FS_MOVED_TO = 0x80
|
||||
sys_FS_MOVE_SELF = 0x800
|
||||
|
||||
// Special events
|
||||
sys_FS_IGNORED = 0x8000
|
||||
sys_FS_Q_OVERFLOW = 0x4000
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO(nj): Use syscall.ERROR_MORE_DATA from ztypes_windows in Go 1.3+
|
||||
sys_ERROR_MORE_DATA syscall.Errno = 234
|
||||
)
|
||||
|
||||
// Event is the type of the notification messages
|
||||
// received on the watcher's Event channel.
|
||||
type FileEvent struct {
|
||||
mask uint32 // Mask of events
|
||||
cookie uint32 // Unique cookie associating related events (for rename)
|
||||
Name string // File name (optional)
|
||||
}
|
||||
|
||||
// IsCreate reports whether the FileEvent was triggered by a creation
|
||||
func (e *FileEvent) IsCreate() bool { return (e.mask & sys_FS_CREATE) == sys_FS_CREATE }
|
||||
|
||||
// IsDelete reports whether the FileEvent was triggered by a delete
|
||||
func (e *FileEvent) IsDelete() bool {
|
||||
return ((e.mask&sys_FS_DELETE) == sys_FS_DELETE || (e.mask&sys_FS_DELETE_SELF) == sys_FS_DELETE_SELF)
|
||||
}
|
||||
|
||||
// IsModify reports whether the FileEvent was triggered by a file modification or attribute change
|
||||
func (e *FileEvent) IsModify() bool {
|
||||
return ((e.mask&sys_FS_MODIFY) == sys_FS_MODIFY || (e.mask&sys_FS_ATTRIB) == sys_FS_ATTRIB)
|
||||
}
|
||||
|
||||
// IsRename reports whether the FileEvent was triggered by a change name
|
||||
func (e *FileEvent) IsRename() bool {
|
||||
return ((e.mask&sys_FS_MOVE) == sys_FS_MOVE || (e.mask&sys_FS_MOVE_SELF) == sys_FS_MOVE_SELF || (e.mask&sys_FS_MOVED_FROM) == sys_FS_MOVED_FROM || (e.mask&sys_FS_MOVED_TO) == sys_FS_MOVED_TO)
|
||||
}
|
||||
|
||||
// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata.
|
||||
func (e *FileEvent) IsAttrib() bool {
|
||||
return (e.mask & sys_FS_ATTRIB) == sys_FS_ATTRIB
|
||||
}
|
||||
|
||||
const (
|
||||
opAddWatch = iota
|
||||
opRemoveWatch
|
||||
)
|
||||
|
||||
const (
|
||||
provisional uint64 = 1 << (32 + iota)
|
||||
)
|
||||
|
||||
type input struct {
|
||||
op int
|
||||
path string
|
||||
flags uint32
|
||||
reply chan error
|
||||
}
|
||||
|
||||
type inode struct {
|
||||
handle syscall.Handle
|
||||
volume uint32
|
||||
index uint64
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
ov syscall.Overlapped
|
||||
ino *inode // i-number
|
||||
path string // Directory path
|
||||
mask uint64 // Directory itself is being watched with these notify flags
|
||||
names map[string]uint64 // Map of names being watched and their notify flags
|
||||
rename string // Remembers the old name while renaming a file
|
||||
buf [4096]byte
|
||||
}
|
||||
|
||||
type indexMap map[uint64]*watch
|
||||
type watchMap map[uint32]indexMap
|
||||
|
||||
// A Watcher waits for and receives event notifications
|
||||
// for a specific set of files and directories.
|
||||
type Watcher struct {
|
||||
mu sync.Mutex // Map access
|
||||
port syscall.Handle // Handle to completion port
|
||||
watches watchMap // Map of watches (key: i-number)
|
||||
fsnFlags map[string]uint32 // Map of watched files to flags used for filter
|
||||
fsnmut sync.Mutex // Protects access to fsnFlags.
|
||||
input chan *input // Inputs to the reader are sent on this channel
|
||||
internalEvent chan *FileEvent // Events are queued on this channel
|
||||
Event chan *FileEvent // Events are returned on this channel
|
||||
Error chan error // Errors are sent on this channel
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
quit chan chan<- error
|
||||
cookie uint32
|
||||
}
|
||||
|
||||
// NewWatcher creates and returns a Watcher.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
|
||||
if e != nil {
|
||||
return nil, os.NewSyscallError("CreateIoCompletionPort", e)
|
||||
}
|
||||
w := &Watcher{
|
||||
port: port,
|
||||
watches: make(watchMap),
|
||||
fsnFlags: make(map[string]uint32),
|
||||
input: make(chan *input, 1),
|
||||
Event: make(chan *FileEvent, 50),
|
||||
internalEvent: make(chan *FileEvent),
|
||||
Error: make(chan error),
|
||||
quit: make(chan chan<- error, 1),
|
||||
}
|
||||
go w.readEvents()
|
||||
go w.purgeEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close closes a Watcher.
|
||||
// It sends a message to the reader goroutine to quit and removes all watches
|
||||
// associated with the watcher.
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed {
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
// Send "quit" message to the reader goroutine
|
||||
ch := make(chan error)
|
||||
w.quit <- ch
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-ch
|
||||
}
|
||||
|
||||
// AddWatch adds path to the watched file set.
|
||||
func (w *Watcher) AddWatch(path string, flags uint32) error {
|
||||
if w.isClosed {
|
||||
return errors.New("watcher already closed")
|
||||
}
|
||||
in := &input{
|
||||
op: opAddWatch,
|
||||
path: filepath.Clean(path),
|
||||
flags: flags,
|
||||
reply: make(chan error),
|
||||
}
|
||||
w.input <- in
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-in.reply
|
||||
}
|
||||
|
||||
// Watch adds path to the watched file set, watching all events.
|
||||
func (w *Watcher) watch(path string) error {
|
||||
return w.AddWatch(path, sys_FS_ALL_EVENTS)
|
||||
}
|
||||
|
||||
// RemoveWatch removes path from the watched file set.
|
||||
func (w *Watcher) removeWatch(path string) error {
|
||||
in := &input{
|
||||
op: opRemoveWatch,
|
||||
path: filepath.Clean(path),
|
||||
reply: make(chan error),
|
||||
}
|
||||
w.input <- in
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-in.reply
|
||||
}
|
||||
|
||||
func (w *Watcher) wakeupReader() error {
|
||||
e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
||||
if e != nil {
|
||||
return os.NewSyscallError("PostQueuedCompletionStatus", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDir(pathname string) (dir string, err error) {
|
||||
attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
|
||||
if e != nil {
|
||||
return "", os.NewSyscallError("GetFileAttributes", e)
|
||||
}
|
||||
if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
dir = pathname
|
||||
} else {
|
||||
dir, _ = filepath.Split(pathname)
|
||||
dir = filepath.Clean(dir)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getIno(path string) (ino *inode, err error) {
|
||||
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
|
||||
syscall.FILE_LIST_DIRECTORY,
|
||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||
nil, syscall.OPEN_EXISTING,
|
||||
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
|
||||
if e != nil {
|
||||
return nil, os.NewSyscallError("CreateFile", e)
|
||||
}
|
||||
var fi syscall.ByHandleFileInformation
|
||||
if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
|
||||
syscall.CloseHandle(h)
|
||||
return nil, os.NewSyscallError("GetFileInformationByHandle", e)
|
||||
}
|
||||
ino = &inode{
|
||||
handle: h,
|
||||
volume: fi.VolumeSerialNumber,
|
||||
index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
|
||||
}
|
||||
return ino, nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (m watchMap) get(ino *inode) *watch {
|
||||
if i := m[ino.volume]; i != nil {
|
||||
return i[ino.index]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (m watchMap) set(ino *inode, watch *watch) {
|
||||
i := m[ino.volume]
|
||||
if i == nil {
|
||||
i = make(indexMap)
|
||||
m[ino.volume] = i
|
||||
}
|
||||
i[ino.index] = watch
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) addWatch(pathname string, flags uint64) error {
|
||||
dir, err := getDir(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if flags&sys_FS_ONLYDIR != 0 && pathname != dir {
|
||||
return nil
|
||||
}
|
||||
ino, err := getIno(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.mu.Lock()
|
||||
watchEntry := w.watches.get(ino)
|
||||
w.mu.Unlock()
|
||||
if watchEntry == nil {
|
||||
if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
|
||||
syscall.CloseHandle(ino.handle)
|
||||
return os.NewSyscallError("CreateIoCompletionPort", e)
|
||||
}
|
||||
watchEntry = &watch{
|
||||
ino: ino,
|
||||
path: dir,
|
||||
names: make(map[string]uint64),
|
||||
}
|
||||
w.mu.Lock()
|
||||
w.watches.set(ino, watchEntry)
|
||||
w.mu.Unlock()
|
||||
flags |= provisional
|
||||
} else {
|
||||
syscall.CloseHandle(ino.handle)
|
||||
}
|
||||
if pathname == dir {
|
||||
watchEntry.mask |= flags
|
||||
} else {
|
||||
watchEntry.names[filepath.Base(pathname)] |= flags
|
||||
}
|
||||
if err = w.startRead(watchEntry); err != nil {
|
||||
return err
|
||||
}
|
||||
if pathname == dir {
|
||||
watchEntry.mask &= ^provisional
|
||||
} else {
|
||||
watchEntry.names[filepath.Base(pathname)] &= ^provisional
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) remWatch(pathname string) error {
|
||||
dir, err := getDir(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ino, err := getIno(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.mu.Lock()
|
||||
watch := w.watches.get(ino)
|
||||
w.mu.Unlock()
|
||||
if watch == nil {
|
||||
return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
|
||||
}
|
||||
if pathname == dir {
|
||||
w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED)
|
||||
watch.mask = 0
|
||||
} else {
|
||||
name := filepath.Base(pathname)
|
||||
w.sendEvent(watch.path+"\\"+name, watch.names[name]&sys_FS_IGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
return w.startRead(watch)
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) deleteWatch(watch *watch) {
|
||||
for name, mask := range watch.names {
|
||||
if mask&provisional == 0 {
|
||||
w.sendEvent(watch.path+"\\"+name, mask&sys_FS_IGNORED)
|
||||
}
|
||||
delete(watch.names, name)
|
||||
}
|
||||
if watch.mask != 0 {
|
||||
if watch.mask&provisional == 0 {
|
||||
w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED)
|
||||
}
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) startRead(watch *watch) error {
|
||||
if e := syscall.CancelIo(watch.ino.handle); e != nil {
|
||||
w.Error <- os.NewSyscallError("CancelIo", e)
|
||||
w.deleteWatch(watch)
|
||||
}
|
||||
mask := toWindowsFlags(watch.mask)
|
||||
for _, m := range watch.names {
|
||||
mask |= toWindowsFlags(m)
|
||||
}
|
||||
if mask == 0 {
|
||||
if e := syscall.CloseHandle(watch.ino.handle); e != nil {
|
||||
w.Error <- os.NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
w.mu.Lock()
|
||||
delete(w.watches[watch.ino.volume], watch.ino.index)
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
|
||||
uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
|
||||
if e != nil {
|
||||
err := os.NewSyscallError("ReadDirectoryChanges", e)
|
||||
if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
||||
// Watched directory was probably removed
|
||||
if w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF) {
|
||||
if watch.mask&sys_FS_ONESHOT != 0 {
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readEvents reads from the I/O completion port, converts the
|
||||
// received events into Event objects and sends them via the Event channel.
|
||||
// Entry point to the I/O thread.
|
||||
func (w *Watcher) readEvents() {
|
||||
var (
|
||||
n, key uint32
|
||||
ov *syscall.Overlapped
|
||||
)
|
||||
runtime.LockOSThread()
|
||||
|
||||
for {
|
||||
e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
|
||||
watch := (*watch)(unsafe.Pointer(ov))
|
||||
|
||||
if watch == nil {
|
||||
select {
|
||||
case ch := <-w.quit:
|
||||
w.mu.Lock()
|
||||
var indexes []indexMap
|
||||
for _, index := range w.watches {
|
||||
indexes = append(indexes, index)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
for _, index := range indexes {
|
||||
for _, watch := range index {
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if e := syscall.CloseHandle(w.port); e != nil {
|
||||
err = os.NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
close(w.internalEvent)
|
||||
close(w.Error)
|
||||
ch <- err
|
||||
return
|
||||
case in := <-w.input:
|
||||
switch in.op {
|
||||
case opAddWatch:
|
||||
in.reply <- w.addWatch(in.path, uint64(in.flags))
|
||||
case opRemoveWatch:
|
||||
in.reply <- w.remWatch(in.path)
|
||||
}
|
||||
default:
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch e {
|
||||
case sys_ERROR_MORE_DATA:
|
||||
if watch == nil {
|
||||
w.Error <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
|
||||
} else {
|
||||
// The i/o succeeded but the buffer is full.
|
||||
// In theory we should be building up a full packet.
|
||||
// In practice we can get away with just carrying on.
|
||||
n = uint32(unsafe.Sizeof(watch.buf))
|
||||
}
|
||||
case syscall.ERROR_ACCESS_DENIED:
|
||||
// Watched directory was probably removed
|
||||
w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF)
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
continue
|
||||
case syscall.ERROR_OPERATION_ABORTED:
|
||||
// CancelIo was called on this handle
|
||||
continue
|
||||
default:
|
||||
w.Error <- os.NewSyscallError("GetQueuedCompletionPort", e)
|
||||
continue
|
||||
case nil:
|
||||
}
|
||||
|
||||
var offset uint32
|
||||
for {
|
||||
if n == 0 {
|
||||
w.internalEvent <- &FileEvent{mask: sys_FS_Q_OVERFLOW}
|
||||
w.Error <- errors.New("short read in readEvents()")
|
||||
break
|
||||
}
|
||||
|
||||
// Point "raw" to the event in the buffer
|
||||
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
|
||||
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
|
||||
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
|
||||
fullname := watch.path + "\\" + name
|
||||
|
||||
var mask uint64
|
||||
switch raw.Action {
|
||||
case syscall.FILE_ACTION_REMOVED:
|
||||
mask = sys_FS_DELETE_SELF
|
||||
case syscall.FILE_ACTION_MODIFIED:
|
||||
mask = sys_FS_MODIFY
|
||||
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||
watch.rename = name
|
||||
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||
if watch.names[watch.rename] != 0 {
|
||||
watch.names[name] |= watch.names[watch.rename]
|
||||
delete(watch.names, watch.rename)
|
||||
mask = sys_FS_MOVE_SELF
|
||||
}
|
||||
}
|
||||
|
||||
sendNameEvent := func() {
|
||||
if w.sendEvent(fullname, watch.names[name]&mask) {
|
||||
if watch.names[name]&sys_FS_ONESHOT != 0 {
|
||||
delete(watch.names, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
sendNameEvent()
|
||||
}
|
||||
if raw.Action == syscall.FILE_ACTION_REMOVED {
|
||||
w.sendEvent(fullname, watch.names[name]&sys_FS_IGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
|
||||
if watch.mask&sys_FS_ONESHOT != 0 {
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
fullname = watch.path + "\\" + watch.rename
|
||||
sendNameEvent()
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
if raw.NextEntryOffset == 0 {
|
||||
break
|
||||
}
|
||||
offset += raw.NextEntryOffset
|
||||
|
||||
// Error!
|
||||
if offset >= n {
|
||||
w.Error <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := w.startRead(watch); err != nil {
|
||||
w.Error <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
||||
if mask == 0 {
|
||||
return false
|
||||
}
|
||||
event := &FileEvent{mask: uint32(mask), Name: name}
|
||||
if mask&sys_FS_MOVE != 0 {
|
||||
if mask&sys_FS_MOVED_FROM != 0 {
|
||||
w.cookie++
|
||||
}
|
||||
event.cookie = w.cookie
|
||||
}
|
||||
select {
|
||||
case ch := <-w.quit:
|
||||
w.quit <- ch
|
||||
case w.Event <- event:
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func toWindowsFlags(mask uint64) uint32 {
|
||||
var m uint32
|
||||
if mask&sys_FS_ACCESS != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
|
||||
}
|
||||
if mask&sys_FS_MODIFY != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||
}
|
||||
if mask&sys_FS_ATTRIB != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||||
}
|
||||
if mask&(sys_FS_MOVE|sys_FS_CREATE|sys_FS_DELETE) != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func toFSnotifyFlags(action uint32) uint64 {
|
||||
switch action {
|
||||
case syscall.FILE_ACTION_ADDED:
|
||||
return sys_FS_CREATE
|
||||
case syscall.FILE_ACTION_REMOVED:
|
||||
return sys_FS_DELETE
|
||||
case syscall.FILE_ACTION_MODIFIED:
|
||||
return sys_FS_MODIFY
|
||||
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||
return sys_FS_MOVED_FROM
|
||||
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||
return sys_FS_MOVED_TO
|
||||
}
|
||||
return 0
|
||||
}
|
18
vendor/github.com/jtolds/gls/LICENSE
generated
vendored
18
vendor/github.com/jtolds/gls/LICENSE
generated
vendored
@ -1,18 +0,0 @@
|
||||
Copyright (c) 2013, Space Monkey, Inc.
|
||||
|
||||
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.
|
89
vendor/github.com/jtolds/gls/README.md
generated
vendored
89
vendor/github.com/jtolds/gls/README.md
generated
vendored
@ -1,89 +0,0 @@
|
||||
gls
|
||||
===
|
||||
|
||||
Goroutine local storage
|
||||
|
||||
### IMPORTANT NOTE ###
|
||||
|
||||
It is my duty to point you to https://blog.golang.org/context, which is how
|
||||
Google solves all of the problems you'd perhaps consider using this package
|
||||
for at scale.
|
||||
|
||||
One downside to Google's approach is that *all* of your functions must have
|
||||
a new first argument, but after clearing that hurdle everything else is much
|
||||
better.
|
||||
|
||||
If you aren't interested in this warning, read on.
|
||||
|
||||
### Huhwaht? Why? ###
|
||||
|
||||
Every so often, a thread shows up on the
|
||||
[golang-nuts](https://groups.google.com/d/forum/golang-nuts) asking for some
|
||||
form of goroutine-local-storage, or some kind of goroutine id, or some kind of
|
||||
context. There are a few valid use cases for goroutine-local-storage, one of
|
||||
the most prominent being log line context. One poster was interested in being
|
||||
able to log an HTTP request context id in every log line in the same goroutine
|
||||
as the incoming HTTP request, without having to change every library and
|
||||
function call he was interested in logging.
|
||||
|
||||
This would be pretty useful. Provided that you could get some kind of
|
||||
goroutine-local-storage, you could call
|
||||
[log.SetOutput](http://golang.org/pkg/log/#SetOutput) with your own logging
|
||||
writer that checks goroutine-local-storage for some context information and
|
||||
adds that context to your log lines.
|
||||
|
||||
But alas, Andrew Gerrand's typically diplomatic answer to the question of
|
||||
goroutine-local variables was:
|
||||
|
||||
> We wouldn't even be having this discussion if thread local storage wasn't
|
||||
> useful. But every feature comes at a cost, and in my opinion the cost of
|
||||
> threadlocals far outweighs their benefits. They're just not a good fit for
|
||||
> Go.
|
||||
|
||||
So, yeah, that makes sense. That's a pretty good reason for why the language
|
||||
won't support a specific and (relatively) unuseful feature that requires some
|
||||
runtime changes, just for the sake of a little bit of log improvement.
|
||||
|
||||
But does Go require runtime changes?
|
||||
|
||||
### How it works ###
|
||||
|
||||
Go has pretty fantastic introspective and reflective features, but one thing Go
|
||||
doesn't give you is any kind of access to the stack pointer, or frame pointer,
|
||||
or goroutine id, or anything contextual about your current stack. It gives you
|
||||
access to your list of callers, but only along with program counters, which are
|
||||
fixed at compile time.
|
||||
|
||||
But it does give you the stack.
|
||||
|
||||
So, we define 16 special functions and embed base-16 tags into the stack using
|
||||
the call order of those 16 functions. Then, we can read our tags back out of
|
||||
the stack looking at the callers list.
|
||||
|
||||
We then use these tags as an index into a traditional map for implementing
|
||||
this library.
|
||||
|
||||
### What are people saying? ###
|
||||
|
||||
"Wow, that's horrifying."
|
||||
|
||||
"This is the most terrible thing I have seen in a very long time."
|
||||
|
||||
"Where is it getting a context from? Is this serializing all the requests?
|
||||
What the heck is the client being bound to? What are these tags? Why does he
|
||||
need callers? Oh god no. No no no."
|
||||
|
||||
### Docs ###
|
||||
|
||||
Please see the docs at http://godoc.org/github.com/jtolds/gls
|
||||
|
||||
### Related ###
|
||||
|
||||
If you're okay relying on the string format of the current runtime stacktrace
|
||||
including a unique goroutine id (not guaranteed by the spec or anything, but
|
||||
very unlikely to change within a Go release), you might be able to squeeze
|
||||
out a bit more performance by using this similar library, inspired by some
|
||||
code Brad Fitzpatrick wrote for debugging his HTTP/2 library:
|
||||
https://github.com/tylerb/gls (in contrast, jtolds/gls doesn't require
|
||||
any knowledge of the string format of the runtime stacktrace, which
|
||||
probably adds unnecessary overhead).
|
144
vendor/github.com/jtolds/gls/context.go
generated
vendored
144
vendor/github.com/jtolds/gls/context.go
generated
vendored
@ -1,144 +0,0 @@
|
||||
// Package gls implements goroutine-local storage.
|
||||
package gls
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
maxCallers = 64
|
||||
)
|
||||
|
||||
var (
|
||||
stackTagPool = &idPool{}
|
||||
mgrRegistry = make(map[*ContextManager]bool)
|
||||
mgrRegistryMtx sync.RWMutex
|
||||
)
|
||||
|
||||
// Values is simply a map of key types to value types. Used by SetValues to
|
||||
// set multiple values at once.
|
||||
type Values map[interface{}]interface{}
|
||||
|
||||
// ContextManager is the main entrypoint for interacting with
|
||||
// Goroutine-local-storage. You can have multiple independent ContextManagers
|
||||
// at any given time. ContextManagers are usually declared globally for a given
|
||||
// class of context variables. You should use NewContextManager for
|
||||
// construction.
|
||||
type ContextManager struct {
|
||||
mtx sync.RWMutex
|
||||
values map[uint]Values
|
||||
}
|
||||
|
||||
// NewContextManager returns a brand new ContextManager. It also registers the
|
||||
// new ContextManager in the ContextManager registry which is used by the Go
|
||||
// method. ContextManagers are typically defined globally at package scope.
|
||||
func NewContextManager() *ContextManager {
|
||||
mgr := &ContextManager{values: make(map[uint]Values)}
|
||||
mgrRegistryMtx.Lock()
|
||||
defer mgrRegistryMtx.Unlock()
|
||||
mgrRegistry[mgr] = true
|
||||
return mgr
|
||||
}
|
||||
|
||||
// Unregister removes a ContextManager from the global registry, used by the
|
||||
// Go method. Only intended for use when you're completely done with a
|
||||
// ContextManager. Use of Unregister at all is rare.
|
||||
func (m *ContextManager) Unregister() {
|
||||
mgrRegistryMtx.Lock()
|
||||
defer mgrRegistryMtx.Unlock()
|
||||
delete(mgrRegistry, m)
|
||||
}
|
||||
|
||||
// SetValues takes a collection of values and a function to call for those
|
||||
// values to be set in. Anything further down the stack will have the set
|
||||
// values available through GetValue. SetValues will add new values or replace
|
||||
// existing values of the same key and will not mutate or change values for
|
||||
// previous stack frames.
|
||||
// SetValues is slow (makes a copy of all current and new values for the new
|
||||
// gls-context) in order to reduce the amount of lookups GetValue requires.
|
||||
func (m *ContextManager) SetValues(new_values Values, context_call func()) {
|
||||
if len(new_values) == 0 {
|
||||
context_call()
|
||||
return
|
||||
}
|
||||
|
||||
tags := readStackTags(1)
|
||||
|
||||
m.mtx.Lock()
|
||||
values := new_values
|
||||
for _, tag := range tags {
|
||||
if existing_values, ok := m.values[tag]; ok {
|
||||
// oh, we found existing values, let's make a copy
|
||||
values = make(Values, len(existing_values)+len(new_values))
|
||||
for key, val := range existing_values {
|
||||
values[key] = val
|
||||
}
|
||||
for key, val := range new_values {
|
||||
values[key] = val
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
new_tag := stackTagPool.Acquire()
|
||||
m.values[new_tag] = values
|
||||
m.mtx.Unlock()
|
||||
defer func() {
|
||||
m.mtx.Lock()
|
||||
delete(m.values, new_tag)
|
||||
m.mtx.Unlock()
|
||||
stackTagPool.Release(new_tag)
|
||||
}()
|
||||
|
||||
addStackTag(new_tag, context_call)
|
||||
}
|
||||
|
||||
// GetValue will return a previously set value, provided that the value was set
|
||||
// by SetValues somewhere higher up the stack. If the value is not found, ok
|
||||
// will be false.
|
||||
func (m *ContextManager) GetValue(key interface{}) (value interface{}, ok bool) {
|
||||
|
||||
tags := readStackTags(1)
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
for _, tag := range tags {
|
||||
if values, ok := m.values[tag]; ok {
|
||||
value, ok := values[key]
|
||||
return value, ok
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (m *ContextManager) getValues() Values {
|
||||
tags := readStackTags(2)
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
for _, tag := range tags {
|
||||
if values, ok := m.values[tag]; ok {
|
||||
return values
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Go preserves ContextManager values and Goroutine-local-storage across new
|
||||
// goroutine invocations. The Go method makes a copy of all existing values on
|
||||
// all registered context managers and makes sure they are still set after
|
||||
// kicking off the provided function in a new goroutine. If you don't use this
|
||||
// Go method instead of the standard 'go' keyword, you will lose values in
|
||||
// ContextManagers, as goroutines have brand new stacks.
|
||||
func Go(cb func()) {
|
||||
mgrRegistryMtx.RLock()
|
||||
defer mgrRegistryMtx.RUnlock()
|
||||
|
||||
for mgr, _ := range mgrRegistry {
|
||||
values := mgr.getValues()
|
||||
if len(values) > 0 {
|
||||
mgr_copy := mgr
|
||||
cb_copy := cb
|
||||
cb = func() { mgr_copy.SetValues(values, cb_copy) }
|
||||
}
|
||||
}
|
||||
|
||||
go cb()
|
||||
}
|
13
vendor/github.com/jtolds/gls/gen_sym.go
generated
vendored
13
vendor/github.com/jtolds/gls/gen_sym.go
generated
vendored
@ -1,13 +0,0 @@
|
||||
package gls
|
||||
|
||||
var (
|
||||
symPool = &idPool{}
|
||||
)
|
||||
|
||||
// ContextKey is a throwaway value you can use as a key to a ContextManager
|
||||
type ContextKey struct{ id uint }
|
||||
|
||||
// GenSym will return a brand new, never-before-used ContextKey
|
||||
func GenSym() ContextKey {
|
||||
return ContextKey{id: symPool.Acquire()}
|
||||
}
|
34
vendor/github.com/jtolds/gls/id_pool.go
generated
vendored
34
vendor/github.com/jtolds/gls/id_pool.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package gls
|
||||
|
||||
// though this could probably be better at keeping ids smaller, the goal of
|
||||
// this class is to keep a registry of the smallest unique integer ids
|
||||
// per-process possible
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type idPool struct {
|
||||
mtx sync.Mutex
|
||||
released []uint
|
||||
max_id uint
|
||||
}
|
||||
|
||||
func (p *idPool) Acquire() (id uint) {
|
||||
p.mtx.Lock()
|
||||
defer p.mtx.Unlock()
|
||||
if len(p.released) > 0 {
|
||||
id = p.released[len(p.released)-1]
|
||||
p.released = p.released[:len(p.released)-1]
|
||||
return id
|
||||
}
|
||||
id = p.max_id
|
||||
p.max_id++
|
||||
return id
|
||||
}
|
||||
|
||||
func (p *idPool) Release(id uint) {
|
||||
p.mtx.Lock()
|
||||
defer p.mtx.Unlock()
|
||||
p.released = append(p.released, id)
|
||||
}
|
43
vendor/github.com/jtolds/gls/stack_tags.go
generated
vendored
43
vendor/github.com/jtolds/gls/stack_tags.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
package gls
|
||||
|
||||
// so, basically, we're going to encode integer tags in base-16 on the stack
|
||||
|
||||
const (
|
||||
bitWidth = 4
|
||||
)
|
||||
|
||||
func addStackTag(tag uint, context_call func()) {
|
||||
if context_call == nil {
|
||||
return
|
||||
}
|
||||
markS(tag, context_call)
|
||||
}
|
||||
|
||||
func markS(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark0(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark1(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark2(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark3(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark4(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark5(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark6(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark7(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark8(tag uint, cb func()) { _m(tag, cb) }
|
||||
func mark9(tag uint, cb func()) { _m(tag, cb) }
|
||||
func markA(tag uint, cb func()) { _m(tag, cb) }
|
||||
func markB(tag uint, cb func()) { _m(tag, cb) }
|
||||
func markC(tag uint, cb func()) { _m(tag, cb) }
|
||||
func markD(tag uint, cb func()) { _m(tag, cb) }
|
||||
func markE(tag uint, cb func()) { _m(tag, cb) }
|
||||
func markF(tag uint, cb func()) { _m(tag, cb) }
|
||||
|
||||
var pc_lookup = make(map[uintptr]int8, 17)
|
||||
var mark_lookup [16]func(uint, func())
|
||||
|
||||
func _m(tag_remainder uint, cb func()) {
|
||||
if tag_remainder == 0 {
|
||||
cb()
|
||||
} else {
|
||||
mark_lookup[tag_remainder&0xf](tag_remainder>>bitWidth, cb)
|
||||
}
|
||||
}
|
101
vendor/github.com/jtolds/gls/stack_tags_js.go
generated
vendored
101
vendor/github.com/jtolds/gls/stack_tags_js.go
generated
vendored
@ -1,101 +0,0 @@
|
||||
// +build js
|
||||
|
||||
package gls
|
||||
|
||||
// This file is used for GopherJS builds, which don't have normal runtime support
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
)
|
||||
|
||||
var stackRE = regexp.MustCompile("\\s+at (\\S*) \\([^:]+:(\\d+):(\\d+)")
|
||||
|
||||
func findPtr() uintptr {
|
||||
jsStack := js.Global.Get("Error").New().Get("stack").Call("split", "\n")
|
||||
for i := 1; i < jsStack.Get("length").Int(); i++ {
|
||||
item := jsStack.Index(i).String()
|
||||
matches := stackRE.FindAllStringSubmatch(item, -1)
|
||||
if matches == nil {
|
||||
return 0
|
||||
}
|
||||
pkgPath := matches[0][1]
|
||||
if strings.HasPrefix(pkgPath, "$packages.github.com/jtolds/gls.mark") {
|
||||
line, _ := strconv.Atoi(matches[0][2])
|
||||
char, _ := strconv.Atoi(matches[0][3])
|
||||
x := (uintptr(line) << 16) | uintptr(char)
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
setEntries := func(f func(uint, func()), v int8) {
|
||||
var ptr uintptr
|
||||
f(0, func() {
|
||||
ptr = findPtr()
|
||||
})
|
||||
pc_lookup[ptr] = v
|
||||
if v >= 0 {
|
||||
mark_lookup[v] = f
|
||||
}
|
||||
}
|
||||
setEntries(markS, -0x1)
|
||||
setEntries(mark0, 0x0)
|
||||
setEntries(mark1, 0x1)
|
||||
setEntries(mark2, 0x2)
|
||||
setEntries(mark3, 0x3)
|
||||
setEntries(mark4, 0x4)
|
||||
setEntries(mark5, 0x5)
|
||||
setEntries(mark6, 0x6)
|
||||
setEntries(mark7, 0x7)
|
||||
setEntries(mark8, 0x8)
|
||||
setEntries(mark9, 0x9)
|
||||
setEntries(markA, 0xa)
|
||||
setEntries(markB, 0xb)
|
||||
setEntries(markC, 0xc)
|
||||
setEntries(markD, 0xd)
|
||||
setEntries(markE, 0xe)
|
||||
setEntries(markF, 0xf)
|
||||
}
|
||||
|
||||
func currentStack(skip int) (stack []uintptr) {
|
||||
jsStack := js.Global.Get("Error").New().Get("stack").Call("split", "\n")
|
||||
for i := skip + 2; i < jsStack.Get("length").Int(); i++ {
|
||||
item := jsStack.Index(i).String()
|
||||
matches := stackRE.FindAllStringSubmatch(item, -1)
|
||||
if matches == nil {
|
||||
return stack
|
||||
}
|
||||
line, _ := strconv.Atoi(matches[0][2])
|
||||
char, _ := strconv.Atoi(matches[0][3])
|
||||
x := (uintptr(line) << 16) | uintptr(char)&0xffff
|
||||
stack = append(stack, x)
|
||||
}
|
||||
|
||||
return stack
|
||||
}
|
||||
|
||||
func readStackTags(skip int) (tags []uint) {
|
||||
stack := currentStack(skip)
|
||||
var current_tag uint
|
||||
for _, pc := range stack {
|
||||
val, ok := pc_lookup[pc]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if val < 0 {
|
||||
tags = append(tags, current_tag)
|
||||
current_tag = 0
|
||||
continue
|
||||
}
|
||||
current_tag <<= bitWidth
|
||||
current_tag += uint(val)
|
||||
}
|
||||
return
|
||||
}
|
61
vendor/github.com/jtolds/gls/stack_tags_main.go
generated
vendored
61
vendor/github.com/jtolds/gls/stack_tags_main.go
generated
vendored
@ -1,61 +0,0 @@
|
||||
// +build !js
|
||||
|
||||
package gls
|
||||
|
||||
// This file is used for standard Go builds, which have the expected runtime support
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func init() {
|
||||
setEntries := func(f func(uint, func()), v int8) {
|
||||
pc_lookup[reflect.ValueOf(f).Pointer()] = v
|
||||
if v >= 0 {
|
||||
mark_lookup[v] = f
|
||||
}
|
||||
}
|
||||
setEntries(markS, -0x1)
|
||||
setEntries(mark0, 0x0)
|
||||
setEntries(mark1, 0x1)
|
||||
setEntries(mark2, 0x2)
|
||||
setEntries(mark3, 0x3)
|
||||
setEntries(mark4, 0x4)
|
||||
setEntries(mark5, 0x5)
|
||||
setEntries(mark6, 0x6)
|
||||
setEntries(mark7, 0x7)
|
||||
setEntries(mark8, 0x8)
|
||||
setEntries(mark9, 0x9)
|
||||
setEntries(markA, 0xa)
|
||||
setEntries(markB, 0xb)
|
||||
setEntries(markC, 0xc)
|
||||
setEntries(markD, 0xd)
|
||||
setEntries(markE, 0xe)
|
||||
setEntries(markF, 0xf)
|
||||
}
|
||||
|
||||
func currentStack(skip int) []uintptr {
|
||||
stack := make([]uintptr, maxCallers)
|
||||
return stack[:runtime.Callers(3+skip, stack)]
|
||||
}
|
||||
|
||||
func readStackTags(skip int) (tags []uint) {
|
||||
stack := currentStack(skip)
|
||||
var current_tag uint
|
||||
for _, pc := range stack {
|
||||
pc = runtime.FuncForPC(pc).Entry()
|
||||
val, ok := pc_lookup[pc]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if val < 0 {
|
||||
tags = append(tags, current_tag)
|
||||
current_tag = 0
|
||||
continue
|
||||
}
|
||||
current_tag <<= bitWidth
|
||||
current_tag += uint(val)
|
||||
}
|
||||
return
|
||||
}
|
23
vendor/github.com/smartystreets/assertions/LICENSE.md
generated
vendored
23
vendor/github.com/smartystreets/assertions/LICENSE.md
generated
vendored
@ -1,23 +0,0 @@
|
||||
Copyright (c) 2015 SmartyStreets, LLC
|
||||
|
||||
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.
|
||||
|
||||
NOTE: Various optional and subordinate components carry their own licensing
|
||||
requirements and restrictions. Use of those components is subject to the terms
|
||||
and conditions outlined the respective license of each component.
|
554
vendor/github.com/smartystreets/assertions/README.md
generated
vendored
554
vendor/github.com/smartystreets/assertions/README.md
generated
vendored
@ -1,554 +0,0 @@
|
||||
# assertions
|
||||
--
|
||||
import "github.com/smartystreets/assertions"
|
||||
|
||||
Package assertions contains the implementations for all assertions which are
|
||||
referenced in goconvey's `convey` package
|
||||
(github.com/smartystreets/goconvey/convey) for use with the So(...) method. They
|
||||
can also be used in traditional Go test functions and even in applicaitons.
|
||||
|
||||
## Usage
|
||||
|
||||
#### func GoConveyMode
|
||||
|
||||
```go
|
||||
func GoConveyMode(yes bool)
|
||||
```
|
||||
GoConveyMode provides control over JSON serialization of failures. When using
|
||||
the assertions in this package from the convey package JSON results are very
|
||||
helpful and can be rendered in a DIFF view. In that case, this function will be
|
||||
called with a true value to enable the JSON serialization. By default, the
|
||||
assertions in this package will not serializer a JSON result, making standalone
|
||||
ussage more convenient.
|
||||
|
||||
#### func ShouldAlmostEqual
|
||||
|
||||
```go
|
||||
func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldAlmostEqual makes sure that two parameters are close enough to being
|
||||
equal. The acceptable delta may be specified with a third argument, or a very
|
||||
small default delta will be used.
|
||||
|
||||
#### func ShouldBeBetween
|
||||
|
||||
```go
|
||||
func ShouldBeBetween(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeBetween receives exactly three parameters: an actual value, a lower
|
||||
bound, and an upper bound. It ensures that the actual value is between both
|
||||
bounds (but not equal to either of them).
|
||||
|
||||
#### func ShouldBeBetweenOrEqual
|
||||
|
||||
```go
|
||||
func ShouldBeBetweenOrEqual(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeBetweenOrEqual receives exactly three parameters: an actual value, a
|
||||
lower bound, and an upper bound. It ensures that the actual value is between
|
||||
both bounds or equal to one of them.
|
||||
|
||||
#### func ShouldBeBlank
|
||||
|
||||
```go
|
||||
func ShouldBeBlank(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeBlank receives exactly 1 string parameter and ensures that it is equal
|
||||
to "".
|
||||
|
||||
#### func ShouldBeChronological
|
||||
|
||||
```go
|
||||
func ShouldBeChronological(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeChronological receives a []time.Time slice and asserts that the are in
|
||||
chronological order starting with the first time.Time as the earliest.
|
||||
|
||||
#### func ShouldBeEmpty
|
||||
|
||||
```go
|
||||
func ShouldBeEmpty(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeEmpty receives a single parameter (actual) and determines whether or not
|
||||
calling len(actual) would return `0`. It obeys the rules specified by the len
|
||||
function for determining length: http://golang.org/pkg/builtin/#len
|
||||
|
||||
#### func ShouldBeFalse
|
||||
|
||||
```go
|
||||
func ShouldBeFalse(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeFalse receives a single parameter and ensures that it is false.
|
||||
|
||||
#### func ShouldBeGreaterThan
|
||||
|
||||
```go
|
||||
func ShouldBeGreaterThan(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeGreaterThan receives exactly two parameters and ensures that the first
|
||||
is greater than the second.
|
||||
|
||||
#### func ShouldBeGreaterThanOrEqualTo
|
||||
|
||||
```go
|
||||
func ShouldBeGreaterThanOrEqualTo(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeGreaterThanOrEqualTo receives exactly two parameters and ensures that
|
||||
the first is greater than or equal to the second.
|
||||
|
||||
#### func ShouldBeIn
|
||||
|
||||
```go
|
||||
func ShouldBeIn(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeIn receives at least 2 parameters. The first is a proposed member of the
|
||||
collection that is passed in either as the second parameter, or of the
|
||||
collection that is comprised of all the remaining parameters. This assertion
|
||||
ensures that the proposed member is in the collection (using ShouldEqual).
|
||||
|
||||
#### func ShouldBeLessThan
|
||||
|
||||
```go
|
||||
func ShouldBeLessThan(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeLessThan receives exactly two parameters and ensures that the first is
|
||||
less than the second.
|
||||
|
||||
#### func ShouldBeLessThanOrEqualTo
|
||||
|
||||
```go
|
||||
func ShouldBeLessThanOrEqualTo(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeLessThan receives exactly two parameters and ensures that the first is
|
||||
less than or equal to the second.
|
||||
|
||||
#### func ShouldBeNil
|
||||
|
||||
```go
|
||||
func ShouldBeNil(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeNil receives a single parameter and ensures that it is nil.
|
||||
|
||||
#### func ShouldBeTrue
|
||||
|
||||
```go
|
||||
func ShouldBeTrue(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeTrue receives a single parameter and ensures that it is true.
|
||||
|
||||
#### func ShouldBeZeroValue
|
||||
|
||||
```go
|
||||
func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldBeZeroValue receives a single parameter and ensures that it is the Go
|
||||
equivalent of the default value, or "zero" value.
|
||||
|
||||
#### func ShouldContain
|
||||
|
||||
```go
|
||||
func ShouldContain(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldContain receives exactly two parameters. The first is a slice and the
|
||||
second is a proposed member. Membership is determined using ShouldEqual.
|
||||
|
||||
#### func ShouldContainKey
|
||||
|
||||
```go
|
||||
func ShouldContainKey(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldContainKey receives exactly two parameters. The first is a map and the
|
||||
second is a proposed key. Keys are compared with a simple '=='.
|
||||
|
||||
#### func ShouldContainSubstring
|
||||
|
||||
```go
|
||||
func ShouldContainSubstring(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldContainSubstring receives exactly 2 string parameters and ensures that the
|
||||
first contains the second as a substring.
|
||||
|
||||
#### func ShouldEndWith
|
||||
|
||||
```go
|
||||
func ShouldEndWith(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldEndWith receives exactly 2 string parameters and ensures that the first
|
||||
ends with the second.
|
||||
|
||||
#### func ShouldEqual
|
||||
|
||||
```go
|
||||
func ShouldEqual(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldEqual receives exactly two parameters and does an equality check.
|
||||
|
||||
#### func ShouldEqualTrimSpace
|
||||
|
||||
```go
|
||||
func ShouldEqualTrimSpace(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldEqualTrimSpace receives exactly 2 string parameters and ensures that the
|
||||
first is equal to the second after removing all leading and trailing whitespace
|
||||
using strings.TrimSpace(first).
|
||||
|
||||
#### func ShouldEqualWithout
|
||||
|
||||
```go
|
||||
func ShouldEqualWithout(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldEqualWithout receives exactly 3 string parameters and ensures that the
|
||||
first is equal to the second after removing all instances of the third from the
|
||||
first using strings.Replace(first, third, "", -1).
|
||||
|
||||
#### func ShouldHappenAfter
|
||||
|
||||
```go
|
||||
func ShouldHappenAfter(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHappenAfter receives exactly 2 time.Time arguments and asserts that the
|
||||
first happens after the second.
|
||||
|
||||
#### func ShouldHappenBefore
|
||||
|
||||
```go
|
||||
func ShouldHappenBefore(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHappenBefore receives exactly 2 time.Time arguments and asserts that the
|
||||
first happens before the second.
|
||||
|
||||
#### func ShouldHappenBetween
|
||||
|
||||
```go
|
||||
func ShouldHappenBetween(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHappenBetween receives exactly 3 time.Time arguments and asserts that the
|
||||
first happens between (not on) the second and third.
|
||||
|
||||
#### func ShouldHappenOnOrAfter
|
||||
|
||||
```go
|
||||
func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHappenOnOrAfter receives exactly 2 time.Time arguments and asserts that
|
||||
the first happens on or after the second.
|
||||
|
||||
#### func ShouldHappenOnOrBefore
|
||||
|
||||
```go
|
||||
func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHappenOnOrBefore receives exactly 2 time.Time arguments and asserts that
|
||||
the first happens on or before the second.
|
||||
|
||||
#### func ShouldHappenOnOrBetween
|
||||
|
||||
```go
|
||||
func ShouldHappenOnOrBetween(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that
|
||||
the first happens between or on the second and third.
|
||||
|
||||
#### func ShouldHappenWithin
|
||||
|
||||
```go
|
||||
func ShouldHappenWithin(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHappenWithin receives a time.Time, a time.Duration, and a time.Time (3
|
||||
arguments) and asserts that the first time.Time happens within or on the
|
||||
duration specified relative to the other time.Time.
|
||||
|
||||
#### func ShouldHaveLength
|
||||
|
||||
```go
|
||||
func ShouldHaveLength(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHaveLength receives a collection and a positive integer and asserts that
|
||||
the length of the collection is equal to the integer provided.
|
||||
|
||||
#### func ShouldHaveSameTypeAs
|
||||
|
||||
```go
|
||||
func ShouldHaveSameTypeAs(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldHaveSameTypeAs receives exactly two parameters and compares their
|
||||
underlying types for equality.
|
||||
|
||||
#### func ShouldImplement
|
||||
|
||||
```go
|
||||
func ShouldImplement(actual interface{}, expectedList ...interface{}) string
|
||||
```
|
||||
ShouldImplement receives exactly two parameters and ensures that the first
|
||||
implements the interface type of the second.
|
||||
|
||||
#### func ShouldNotAlmostEqual
|
||||
|
||||
```go
|
||||
func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual
|
||||
|
||||
#### func ShouldNotBeBetween
|
||||
|
||||
```go
|
||||
func ShouldNotBeBetween(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotBeBetween receives exactly three parameters: an actual value, a lower
|
||||
bound, and an upper bound. It ensures that the actual value is NOT between both
|
||||
bounds.
|
||||
|
||||
#### func ShouldNotBeBetweenOrEqual
|
||||
|
||||
```go
|
||||
func ShouldNotBeBetweenOrEqual(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotBeBetweenOrEqual receives exactly three parameters: an actual value, a
|
||||
lower bound, and an upper bound. It ensures that the actual value is nopt
|
||||
between the bounds nor equal to either of them.
|
||||
|
||||
#### func ShouldNotBeBlank
|
||||
|
||||
```go
|
||||
func ShouldNotBeBlank(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotBeBlank receives exactly 1 string parameter and ensures that it is
|
||||
equal to "".
|
||||
|
||||
#### func ShouldNotBeEmpty
|
||||
|
||||
```go
|
||||
func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotBeEmpty receives a single parameter (actual) and determines whether or
|
||||
not calling len(actual) would return a value greater than zero. It obeys the
|
||||
rules specified by the `len` function for determining length:
|
||||
http://golang.org/pkg/builtin/#len
|
||||
|
||||
#### func ShouldNotBeIn
|
||||
|
||||
```go
|
||||
func ShouldNotBeIn(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of
|
||||
the collection that is passed in either as the second parameter, or of the
|
||||
collection that is comprised of all the remaining parameters. This assertion
|
||||
ensures that the proposed member is NOT in the collection (using ShouldEqual).
|
||||
|
||||
#### func ShouldNotBeNil
|
||||
|
||||
```go
|
||||
func ShouldNotBeNil(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotBeNil receives a single parameter and ensures that it is not nil.
|
||||
|
||||
#### func ShouldNotContain
|
||||
|
||||
```go
|
||||
func ShouldNotContain(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotContain receives exactly two parameters. The first is a slice and the
|
||||
second is a proposed member. Membership is determinied using ShouldEqual.
|
||||
|
||||
#### func ShouldNotContainKey
|
||||
|
||||
```go
|
||||
func ShouldNotContainKey(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotContainKey receives exactly two parameters. The first is a map and the
|
||||
second is a proposed absent key. Keys are compared with a simple '=='.
|
||||
|
||||
#### func ShouldNotContainSubstring
|
||||
|
||||
```go
|
||||
func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotContainSubstring receives exactly 2 string parameters and ensures that
|
||||
the first does NOT contain the second as a substring.
|
||||
|
||||
#### func ShouldNotEndWith
|
||||
|
||||
```go
|
||||
func ShouldNotEndWith(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldEndWith receives exactly 2 string parameters and ensures that the first
|
||||
does not end with the second.
|
||||
|
||||
#### func ShouldNotEqual
|
||||
|
||||
```go
|
||||
func ShouldNotEqual(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotEqual receives exactly two parameters and does an inequality check.
|
||||
|
||||
#### func ShouldNotHappenOnOrBetween
|
||||
|
||||
```go
|
||||
func ShouldNotHappenOnOrBetween(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotHappenOnOrBetween receives exactly 3 time.Time arguments and asserts
|
||||
that the first does NOT happen between or on the second or third.
|
||||
|
||||
#### func ShouldNotHappenWithin
|
||||
|
||||
```go
|
||||
func ShouldNotHappenWithin(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotHappenWithin receives a time.Time, a time.Duration, and a time.Time (3
|
||||
arguments) and asserts that the first time.Time does NOT happen within or on the
|
||||
duration specified relative to the other time.Time.
|
||||
|
||||
#### func ShouldNotHaveSameTypeAs
|
||||
|
||||
```go
|
||||
func ShouldNotHaveSameTypeAs(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotHaveSameTypeAs receives exactly two parameters and compares their
|
||||
underlying types for inequality.
|
||||
|
||||
#### func ShouldNotImplement
|
||||
|
||||
```go
|
||||
func ShouldNotImplement(actual interface{}, expectedList ...interface{}) string
|
||||
```
|
||||
ShouldNotImplement receives exactly two parameters and ensures that the first
|
||||
does NOT implement the interface type of the second.
|
||||
|
||||
#### func ShouldNotPanic
|
||||
|
||||
```go
|
||||
func ShouldNotPanic(actual interface{}, expected ...interface{}) (message string)
|
||||
```
|
||||
ShouldNotPanic receives a void, niladic function and expects to execute the
|
||||
function without any panic.
|
||||
|
||||
#### func ShouldNotPanicWith
|
||||
|
||||
```go
|
||||
func ShouldNotPanicWith(actual interface{}, expected ...interface{}) (message string)
|
||||
```
|
||||
ShouldNotPanicWith receives a void, niladic function and expects to recover a
|
||||
panic whose content differs from the second argument.
|
||||
|
||||
#### func ShouldNotPointTo
|
||||
|
||||
```go
|
||||
func ShouldNotPointTo(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotPointTo receives exactly two parameters and checks to see that they
|
||||
point to different addresess.
|
||||
|
||||
#### func ShouldNotResemble
|
||||
|
||||
```go
|
||||
func ShouldNotResemble(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotResemble receives exactly two parameters and does an inverse deep equal
|
||||
check (see reflect.DeepEqual)
|
||||
|
||||
#### func ShouldNotStartWith
|
||||
|
||||
```go
|
||||
func ShouldNotStartWith(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldNotStartWith receives exactly 2 string parameters and ensures that the
|
||||
first does not start with the second.
|
||||
|
||||
#### func ShouldPanic
|
||||
|
||||
```go
|
||||
func ShouldPanic(actual interface{}, expected ...interface{}) (message string)
|
||||
```
|
||||
ShouldPanic receives a void, niladic function and expects to recover a panic.
|
||||
|
||||
#### func ShouldPanicWith
|
||||
|
||||
```go
|
||||
func ShouldPanicWith(actual interface{}, expected ...interface{}) (message string)
|
||||
```
|
||||
ShouldPanicWith receives a void, niladic function and expects to recover a panic
|
||||
with the second argument as the content.
|
||||
|
||||
#### func ShouldPointTo
|
||||
|
||||
```go
|
||||
func ShouldPointTo(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldPointTo receives exactly two parameters and checks to see that they point
|
||||
to the same address.
|
||||
|
||||
#### func ShouldResemble
|
||||
|
||||
```go
|
||||
func ShouldResemble(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldResemble receives exactly two parameters and does a deep equal check (see
|
||||
reflect.DeepEqual)
|
||||
|
||||
#### func ShouldStartWith
|
||||
|
||||
```go
|
||||
func ShouldStartWith(actual interface{}, expected ...interface{}) string
|
||||
```
|
||||
ShouldStartWith receives exactly 2 string parameters and ensures that the first
|
||||
starts with the second.
|
||||
|
||||
#### func So
|
||||
|
||||
```go
|
||||
func So(actual interface{}, assert assertion, expected ...interface{}) (bool, string)
|
||||
```
|
||||
So is a convenience function (as opposed to an inconvenience function?) for
|
||||
running assertions on arbitrary arguments in any context, be it for testing or
|
||||
even application logging. It allows you to perform assertion-like behavior (and
|
||||
get nicely formatted messages detailing discrepancies) but without the program
|
||||
blowing up or panicking. All that is required is to import this package and call
|
||||
`So` with one of the assertions exported by this package as the second
|
||||
parameter. The first return parameter is a boolean indicating if the assertion
|
||||
was true. The second return parameter is the well-formatted message showing why
|
||||
an assertion was incorrect, or blank if the assertion was correct.
|
||||
|
||||
Example:
|
||||
|
||||
if ok, message := So(x, ShouldBeGreaterThan, y); !ok {
|
||||
log.Println(message)
|
||||
}
|
||||
|
||||
#### type Assertion
|
||||
|
||||
```go
|
||||
type Assertion struct {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### func New
|
||||
|
||||
```go
|
||||
func New(t testingT) *Assertion
|
||||
```
|
||||
New swallows the *testing.T struct and prints failed assertions using t.Error.
|
||||
Example: assertions.New(t).So(1, should.Equal, 1)
|
||||
|
||||
#### func (*Assertion) Failed
|
||||
|
||||
```go
|
||||
func (this *Assertion) Failed() bool
|
||||
```
|
||||
Failed reports whether any calls to So (on this Assertion instance) have failed.
|
||||
|
||||
#### func (*Assertion) So
|
||||
|
||||
```go
|
||||
func (this *Assertion) So(actual interface{}, assert assertion, expected ...interface{}) bool
|
||||
```
|
||||
So calls the standalone So function and additionally, calls t.Error in failure
|
||||
scenarios.
|
||||
|
||||
#### type Serializer
|
||||
|
||||
```go
|
||||
type Serializer interface {
|
||||
// contains filtered or unexported methods
|
||||
}
|
||||
```
|
3
vendor/github.com/smartystreets/assertions/assertions.goconvey
generated
vendored
3
vendor/github.com/smartystreets/assertions/assertions.goconvey
generated
vendored
@ -1,3 +0,0 @@
|
||||
#ignore
|
||||
-timeout=1s
|
||||
-coverpkg=github.com/smartystreets/assertions,github.com/smartystreets/assertions/internal/oglematchers
|
250
vendor/github.com/smartystreets/assertions/collections.go
generated
vendored
250
vendor/github.com/smartystreets/assertions/collections.go
generated
vendored
@ -1,250 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/smartystreets/assertions/internal/oglematchers"
|
||||
)
|
||||
|
||||
// ShouldContain receives exactly two parameters. The first is a slice and the
|
||||
// second is a proposed member. Membership is determined using ShouldEqual.
|
||||
func ShouldContain(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil {
|
||||
typeName := reflect.TypeOf(actual)
|
||||
|
||||
if fmt.Sprintf("%v", matchError) == "which is not a slice or array" {
|
||||
return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName)
|
||||
}
|
||||
return fmt.Sprintf(shouldHaveContained, typeName, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotContain receives exactly two parameters. The first is a slice and the
|
||||
// second is a proposed member. Membership is determinied using ShouldEqual.
|
||||
func ShouldNotContain(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
typeName := reflect.TypeOf(actual)
|
||||
|
||||
if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil {
|
||||
if fmt.Sprintf("%v", matchError) == "which is not a slice or array" {
|
||||
return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName)
|
||||
}
|
||||
return success
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveContained, typeName, expected[0])
|
||||
}
|
||||
|
||||
// ShouldContainKey receives exactly two parameters. The first is a map and the
|
||||
// second is a proposed key. Keys are compared with a simple '=='.
|
||||
func ShouldContainKey(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
keys, isMap := mapKeys(actual)
|
||||
if !isMap {
|
||||
return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual))
|
||||
}
|
||||
|
||||
if !keyFound(keys, expected[0]) {
|
||||
return fmt.Sprintf(shouldHaveContainedKey, reflect.TypeOf(actual), expected)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// ShouldNotContainKey receives exactly two parameters. The first is a map and the
|
||||
// second is a proposed absent key. Keys are compared with a simple '=='.
|
||||
func ShouldNotContainKey(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
keys, isMap := mapKeys(actual)
|
||||
if !isMap {
|
||||
return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual))
|
||||
}
|
||||
|
||||
if keyFound(keys, expected[0]) {
|
||||
return fmt.Sprintf(shouldNotHaveContainedKey, reflect.TypeOf(actual), expected)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func mapKeys(m interface{}) ([]reflect.Value, bool) {
|
||||
value := reflect.ValueOf(m)
|
||||
if value.Kind() != reflect.Map {
|
||||
return nil, false
|
||||
}
|
||||
return value.MapKeys(), true
|
||||
}
|
||||
func keyFound(keys []reflect.Value, expectedKey interface{}) bool {
|
||||
found := false
|
||||
for _, key := range keys {
|
||||
if key.Interface() == expectedKey {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
// ShouldBeIn receives at least 2 parameters. The first is a proposed member of the collection
|
||||
// that is passed in either as the second parameter, or of the collection that is comprised
|
||||
// of all the remaining parameters. This assertion ensures that the proposed member is in
|
||||
// the collection (using ShouldEqual).
|
||||
func ShouldBeIn(actual interface{}, expected ...interface{}) string {
|
||||
if fail := atLeast(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if len(expected) == 1 {
|
||||
return shouldBeIn(actual, expected[0])
|
||||
}
|
||||
return shouldBeIn(actual, expected)
|
||||
}
|
||||
func shouldBeIn(actual interface{}, expected interface{}) string {
|
||||
if matchError := oglematchers.Contains(actual).Matches(expected); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenIn, actual, reflect.TypeOf(expected))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of the collection
|
||||
// that is passed in either as the second parameter, or of the collection that is comprised
|
||||
// of all the remaining parameters. This assertion ensures that the proposed member is NOT in
|
||||
// the collection (using ShouldEqual).
|
||||
func ShouldNotBeIn(actual interface{}, expected ...interface{}) string {
|
||||
if fail := atLeast(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if len(expected) == 1 {
|
||||
return shouldNotBeIn(actual, expected[0])
|
||||
}
|
||||
return shouldNotBeIn(actual, expected)
|
||||
}
|
||||
func shouldNotBeIn(actual interface{}, expected interface{}) string {
|
||||
if matchError := oglematchers.Contains(actual).Matches(expected); matchError == nil {
|
||||
return fmt.Sprintf(shouldNotHaveBeenIn, actual, reflect.TypeOf(expected))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeEmpty receives a single parameter (actual) and determines whether or not
|
||||
// calling len(actual) would return `0`. It obeys the rules specified by the len
|
||||
// function for determining length: http://golang.org/pkg/builtin/#len
|
||||
func ShouldBeEmpty(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if actual == nil {
|
||||
return success
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(actual)
|
||||
switch value.Kind() {
|
||||
case reflect.Slice:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.Chan:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.Map:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.String:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.Ptr:
|
||||
elem := value.Elem()
|
||||
kind := elem.Kind()
|
||||
if (kind == reflect.Slice || kind == reflect.Array) && elem.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(shouldHaveBeenEmpty, actual)
|
||||
}
|
||||
|
||||
// ShouldNotBeEmpty receives a single parameter (actual) and determines whether or not
|
||||
// calling len(actual) would return a value greater than zero. It obeys the rules
|
||||
// specified by the `len` function for determining length: http://golang.org/pkg/builtin/#len
|
||||
func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if empty := ShouldBeEmpty(actual, expected...); empty != success {
|
||||
return success
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveBeenEmpty, actual)
|
||||
}
|
||||
|
||||
// ShouldHaveLength receives 2 parameters. The first is a collection to check
|
||||
// the length of, the second being the expected length. It obeys the rules
|
||||
// specified by the len function for determining length:
|
||||
// http://golang.org/pkg/builtin/#len
|
||||
func ShouldHaveLength(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
var expectedLen int64
|
||||
lenValue := reflect.ValueOf(expected[0])
|
||||
switch lenValue.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
expectedLen = lenValue.Int()
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
expectedLen = int64(lenValue.Uint())
|
||||
default:
|
||||
return fmt.Sprintf(shouldHaveBeenAValidInteger, reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
if expectedLen < 0 {
|
||||
return fmt.Sprintf(shouldHaveBeenAValidLength, expected[0])
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(actual)
|
||||
switch value.Kind() {
|
||||
case reflect.Slice:
|
||||
if int64(value.Len()) == expectedLen {
|
||||
return success
|
||||
}
|
||||
case reflect.Chan:
|
||||
if int64(value.Len()) == expectedLen {
|
||||
return success
|
||||
}
|
||||
case reflect.Map:
|
||||
if int64(value.Len()) == expectedLen {
|
||||
return success
|
||||
}
|
||||
case reflect.String:
|
||||
if int64(value.Len()) == expectedLen {
|
||||
return success
|
||||
}
|
||||
case reflect.Ptr:
|
||||
elem := value.Elem()
|
||||
kind := elem.Kind()
|
||||
if (kind == reflect.Slice || kind == reflect.Array) && int64(elem.Len()) == expectedLen {
|
||||
return success
|
||||
}
|
||||
default:
|
||||
return fmt.Sprintf(shouldHaveBeenAValidCollection, reflect.TypeOf(actual))
|
||||
}
|
||||
|
||||
return fmt.Sprintf(shouldHaveHadLength, actual, expectedLen)
|
||||
}
|
99
vendor/github.com/smartystreets/assertions/doc.go
generated
vendored
99
vendor/github.com/smartystreets/assertions/doc.go
generated
vendored
@ -1,99 +0,0 @@
|
||||
// Package assertions contains the implementations for all assertions which
|
||||
// are referenced in goconvey's `convey` package
|
||||
// (github.com/smartystreets/goconvey/convey) for use with the So(...) method.
|
||||
// They can also be used in traditional Go test functions and even in
|
||||
// applicaitons.
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// By default we use a no-op serializer. The actual Serializer provides a JSON
|
||||
// representation of failure results on selected assertions so the goconvey
|
||||
// web UI can display a convenient diff.
|
||||
var serializer Serializer = new(noopSerializer)
|
||||
|
||||
// GoConveyMode provides control over JSON serialization of failures. When
|
||||
// using the assertions in this package from the convey package JSON results
|
||||
// are very helpful and can be rendered in a DIFF view. In that case, this function
|
||||
// will be called with a true value to enable the JSON serialization. By default,
|
||||
// the assertions in this package will not serializer a JSON result, making
|
||||
// standalone ussage more convenient.
|
||||
func GoConveyMode(yes bool) {
|
||||
if yes {
|
||||
serializer = newSerializer()
|
||||
} else {
|
||||
serializer = new(noopSerializer)
|
||||
}
|
||||
}
|
||||
|
||||
type testingT interface {
|
||||
Error(args ...interface{})
|
||||
}
|
||||
|
||||
type Assertion struct {
|
||||
t testingT
|
||||
failed bool
|
||||
}
|
||||
|
||||
// New swallows the *testing.T struct and prints failed assertions using t.Error.
|
||||
// Example: assertions.New(t).So(1, should.Equal, 1)
|
||||
func New(t testingT) *Assertion {
|
||||
return &Assertion{t: t}
|
||||
}
|
||||
|
||||
// Failed reports whether any calls to So (on this Assertion instance) have failed.
|
||||
func (this *Assertion) Failed() bool {
|
||||
return this.failed
|
||||
}
|
||||
|
||||
// So calls the standalone So function and additionally, calls t.Error in failure scenarios.
|
||||
func (this *Assertion) So(actual interface{}, assert assertion, expected ...interface{}) bool {
|
||||
ok, result := So(actual, assert, expected...)
|
||||
if !ok {
|
||||
this.failed = true
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
this.t.Error(fmt.Sprintf("\n%s:%d\n%s", file, line, result))
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// So is a convenience function (as opposed to an inconvenience function?)
|
||||
// for running assertions on arbitrary arguments in any context, be it for testing or even
|
||||
// application logging. It allows you to perform assertion-like behavior (and get nicely
|
||||
// formatted messages detailing discrepancies) but without the program blowing up or panicking.
|
||||
// All that is required is to import this package and call `So` with one of the assertions
|
||||
// exported by this package as the second parameter.
|
||||
// The first return parameter is a boolean indicating if the assertion was true. The second
|
||||
// return parameter is the well-formatted message showing why an assertion was incorrect, or
|
||||
// blank if the assertion was correct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// if ok, message := So(x, ShouldBeGreaterThan, y); !ok {
|
||||
// log.Println(message)
|
||||
// }
|
||||
//
|
||||
func So(actual interface{}, assert assertion, expected ...interface{}) (bool, string) {
|
||||
if result := so(actual, assert, expected...); len(result) == 0 {
|
||||
return true, result
|
||||
} else {
|
||||
return false, result
|
||||
}
|
||||
}
|
||||
|
||||
// so is like So, except that it only returns the string message, which is blank if the
|
||||
// assertion passed. Used to facilitate testing.
|
||||
func so(actual interface{}, assert func(interface{}, ...interface{}) string, expected ...interface{}) string {
|
||||
return assert(actual, expected...)
|
||||
}
|
||||
|
||||
// assertion is an alias for a function with a signature that the So()
|
||||
// function can handle. Any future or custom assertions should conform to this
|
||||
// method signature. The return value should be an empty string if the assertion
|
||||
// passes and a well-formed failure message if not.
|
||||
type assertion func(actual interface{}, expected ...interface{}) string
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
286
vendor/github.com/smartystreets/assertions/equality.go
generated
vendored
286
vendor/github.com/smartystreets/assertions/equality.go
generated
vendored
@ -1,286 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/smartystreets/assertions/internal/oglematchers"
|
||||
)
|
||||
|
||||
// default acceptable delta for ShouldAlmostEqual
|
||||
const defaultDelta = 0.0000000001
|
||||
|
||||
// ShouldEqual receives exactly two parameters and does an equality check.
|
||||
func ShouldEqual(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
return shouldEqual(actual, expected[0])
|
||||
}
|
||||
func shouldEqual(actual, expected interface{}) (message string) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
message = serializer.serialize(expected, actual, fmt.Sprintf(shouldHaveBeenEqual, expected, actual))
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
if matchError := oglematchers.Equals(expected).Matches(actual); matchError != nil {
|
||||
expectedSyntax := fmt.Sprintf("%v", expected)
|
||||
actualSyntax := fmt.Sprintf("%v", actual)
|
||||
if expectedSyntax == actualSyntax && reflect.TypeOf(expected) != reflect.TypeOf(actual) {
|
||||
message = fmt.Sprintf(shouldHaveBeenEqualTypeMismatch, expected, expected, actual, actual)
|
||||
} else {
|
||||
message = fmt.Sprintf(shouldHaveBeenEqual, expected, actual)
|
||||
}
|
||||
message = serializer.serialize(expected, actual, message)
|
||||
return
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotEqual receives exactly two parameters and does an inequality check.
|
||||
func ShouldNotEqual(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if ShouldEqual(actual, expected[0]) == success {
|
||||
return fmt.Sprintf(shouldNotHaveBeenEqual, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldAlmostEqual makes sure that two parameters are close enough to being equal.
|
||||
// The acceptable delta may be specified with a third argument,
|
||||
// or a very small default delta will be used.
|
||||
func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string {
|
||||
actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...)
|
||||
|
||||
if err != "" {
|
||||
return err
|
||||
}
|
||||
|
||||
if math.Abs(actualFloat-expectedFloat) <= deltaFloat {
|
||||
return success
|
||||
} else {
|
||||
return fmt.Sprintf(shouldHaveBeenAlmostEqual, actualFloat, expectedFloat)
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual
|
||||
func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string {
|
||||
actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...)
|
||||
|
||||
if err != "" {
|
||||
return err
|
||||
}
|
||||
|
||||
if math.Abs(actualFloat-expectedFloat) > deltaFloat {
|
||||
return success
|
||||
} else {
|
||||
return fmt.Sprintf(shouldHaveNotBeenAlmostEqual, actualFloat, expectedFloat)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanAlmostEqualInput(actual interface{}, expected ...interface{}) (float64, float64, float64, string) {
|
||||
deltaFloat := 0.0000000001
|
||||
|
||||
if len(expected) == 0 {
|
||||
return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided neither)"
|
||||
} else if len(expected) == 2 {
|
||||
delta, err := getFloat(expected[1])
|
||||
|
||||
if err != nil {
|
||||
return 0.0, 0.0, 0.0, "delta must be a numerical type"
|
||||
}
|
||||
|
||||
deltaFloat = delta
|
||||
} else if len(expected) > 2 {
|
||||
return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided more values)"
|
||||
}
|
||||
|
||||
actualFloat, err := getFloat(actual)
|
||||
|
||||
if err != nil {
|
||||
return 0.0, 0.0, 0.0, err.Error()
|
||||
}
|
||||
|
||||
expectedFloat, err := getFloat(expected[0])
|
||||
|
||||
if err != nil {
|
||||
return 0.0, 0.0, 0.0, err.Error()
|
||||
}
|
||||
|
||||
return actualFloat, expectedFloat, deltaFloat, ""
|
||||
}
|
||||
|
||||
// returns the float value of any real number, or error if it is not a numerical type
|
||||
func getFloat(num interface{}) (float64, error) {
|
||||
numValue := reflect.ValueOf(num)
|
||||
numKind := numValue.Kind()
|
||||
|
||||
if numKind == reflect.Int ||
|
||||
numKind == reflect.Int8 ||
|
||||
numKind == reflect.Int16 ||
|
||||
numKind == reflect.Int32 ||
|
||||
numKind == reflect.Int64 {
|
||||
return float64(numValue.Int()), nil
|
||||
} else if numKind == reflect.Uint ||
|
||||
numKind == reflect.Uint8 ||
|
||||
numKind == reflect.Uint16 ||
|
||||
numKind == reflect.Uint32 ||
|
||||
numKind == reflect.Uint64 {
|
||||
return float64(numValue.Uint()), nil
|
||||
} else if numKind == reflect.Float32 ||
|
||||
numKind == reflect.Float64 {
|
||||
return numValue.Float(), nil
|
||||
} else {
|
||||
return 0.0, errors.New("must be a numerical type, but was " + numKind.String())
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldResemble receives exactly two parameters and does a deep equal check (see reflect.DeepEqual)
|
||||
func ShouldResemble(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
|
||||
if matchError := oglematchers.DeepEquals(expected[0]).Matches(actual); matchError != nil {
|
||||
expectedSyntax := fmt.Sprintf("%#v", expected[0])
|
||||
actualSyntax := fmt.Sprintf("%#v", actual)
|
||||
var message string
|
||||
if expectedSyntax == actualSyntax {
|
||||
message = fmt.Sprintf(shouldHaveResembledTypeMismatch, expected[0], expected[0], actual, actual)
|
||||
} else {
|
||||
message = fmt.Sprintf(shouldHaveResembled, expected[0], actual)
|
||||
}
|
||||
return serializer.serializeDetailed(expected[0], actual, message)
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotResemble receives exactly two parameters and does an inverse deep equal check (see reflect.DeepEqual)
|
||||
func ShouldNotResemble(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
} else if ShouldResemble(actual, expected[0]) == success {
|
||||
return fmt.Sprintf(shouldNotHaveResembled, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldPointTo receives exactly two parameters and checks to see that they point to the same address.
|
||||
func ShouldPointTo(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
return shouldPointTo(actual, expected[0])
|
||||
|
||||
}
|
||||
func shouldPointTo(actual, expected interface{}) string {
|
||||
actualValue := reflect.ValueOf(actual)
|
||||
expectedValue := reflect.ValueOf(expected)
|
||||
|
||||
if ShouldNotBeNil(actual) != success {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "nil")
|
||||
} else if ShouldNotBeNil(expected) != success {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "nil")
|
||||
} else if actualValue.Kind() != reflect.Ptr {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "not")
|
||||
} else if expectedValue.Kind() != reflect.Ptr {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "not")
|
||||
} else if ShouldEqual(actualValue.Pointer(), expectedValue.Pointer()) != success {
|
||||
actualAddress := reflect.ValueOf(actual).Pointer()
|
||||
expectedAddress := reflect.ValueOf(expected).Pointer()
|
||||
return serializer.serialize(expectedAddress, actualAddress, fmt.Sprintf(shouldHavePointedTo,
|
||||
actual, actualAddress,
|
||||
expected, expectedAddress))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotPointTo receives exactly two parameters and checks to see that they point to different addresess.
|
||||
func ShouldNotPointTo(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
compare := ShouldPointTo(actual, expected[0])
|
||||
if strings.HasPrefix(compare, shouldBePointers) {
|
||||
return compare
|
||||
} else if compare == success {
|
||||
return fmt.Sprintf(shouldNotHavePointedTo, actual, expected[0], reflect.ValueOf(actual).Pointer())
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeNil receives a single parameter and ensures that it is nil.
|
||||
func ShouldBeNil(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if actual == nil {
|
||||
return success
|
||||
} else if interfaceHasNilValue(actual) {
|
||||
return success
|
||||
}
|
||||
return fmt.Sprintf(shouldHaveBeenNil, actual)
|
||||
}
|
||||
func interfaceHasNilValue(actual interface{}) bool {
|
||||
value := reflect.ValueOf(actual)
|
||||
kind := value.Kind()
|
||||
nilable := kind == reflect.Slice ||
|
||||
kind == reflect.Chan ||
|
||||
kind == reflect.Func ||
|
||||
kind == reflect.Ptr ||
|
||||
kind == reflect.Map
|
||||
|
||||
// Careful: reflect.Value.IsNil() will panic unless it's an interface, chan, map, func, slice, or ptr
|
||||
// Reference: http://golang.org/pkg/reflect/#Value.IsNil
|
||||
return nilable && value.IsNil()
|
||||
}
|
||||
|
||||
// ShouldNotBeNil receives a single parameter and ensures that it is not nil.
|
||||
func ShouldNotBeNil(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if ShouldBeNil(actual) == success {
|
||||
return fmt.Sprintf(shouldNotHaveBeenNil, actual)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeTrue receives a single parameter and ensures that it is true.
|
||||
func ShouldBeTrue(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if actual != true {
|
||||
return fmt.Sprintf(shouldHaveBeenTrue, actual)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeFalse receives a single parameter and ensures that it is false.
|
||||
func ShouldBeFalse(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if actual != false {
|
||||
return fmt.Sprintf(shouldHaveBeenFalse, actual)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeZeroValue receives a single parameter and ensures that it is
|
||||
// the Go equivalent of the default value, or "zero" value.
|
||||
func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
zeroVal := reflect.Zero(reflect.TypeOf(actual)).Interface()
|
||||
if !reflect.DeepEqual(zeroVal, actual) {
|
||||
return serializer.serialize(zeroVal, actual, fmt.Sprintf(shouldHaveBeenZeroValue, actual))
|
||||
}
|
||||
return success
|
||||
}
|
23
vendor/github.com/smartystreets/assertions/filter.go
generated
vendored
23
vendor/github.com/smartystreets/assertions/filter.go
generated
vendored
@ -1,23 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
success = ""
|
||||
needExactValues = "This assertion requires exactly %d comparison values (you provided %d)."
|
||||
needNonEmptyCollection = "This assertion requires at least 1 comparison value (you provided 0)."
|
||||
)
|
||||
|
||||
func need(needed int, expected []interface{}) string {
|
||||
if len(expected) != needed {
|
||||
return fmt.Sprintf(needExactValues, needed, len(expected))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func atLeast(minimum int, expected []interface{}) string {
|
||||
if len(expected) < 1 {
|
||||
return needNonEmptyCollection
|
||||
}
|
||||
return success
|
||||
}
|
202
vendor/github.com/smartystreets/assertions/internal/oglematchers/LICENSE
generated
vendored
202
vendor/github.com/smartystreets/assertions/internal/oglematchers/LICENSE
generated
vendored
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
58
vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md
generated
vendored
58
vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md
generated
vendored
@ -1,58 +0,0 @@
|
||||
[![GoDoc](https://godoc.org/github.com/smartystreets/assertions/internal/oglematchers?status.svg)](https://godoc.org/github.com/smartystreets/assertions/internal/oglematchers)
|
||||
|
||||
`oglematchers` is a package for the Go programming language containing a set of
|
||||
matchers, useful in a testing or mocking framework, inspired by and mostly
|
||||
compatible with [Google Test][googletest] for C++ and
|
||||
[Google JS Test][google-js-test]. The package is used by the
|
||||
[ogletest][ogletest] testing framework and [oglemock][oglemock] mocking
|
||||
framework, which may be more directly useful to you, but can be generically used
|
||||
elsewhere as well.
|
||||
|
||||
A "matcher" is simply an object with a `Matches` method defining a set of golang
|
||||
values matched by the matcher, and a `Description` method describing that set.
|
||||
For example, here are some matchers:
|
||||
|
||||
```go
|
||||
// Numbers
|
||||
Equals(17.13)
|
||||
LessThan(19)
|
||||
|
||||
// Strings
|
||||
Equals("taco")
|
||||
HasSubstr("burrito")
|
||||
MatchesRegex("t.*o")
|
||||
|
||||
// Combining matchers
|
||||
AnyOf(LessThan(17), GreaterThan(19))
|
||||
```
|
||||
|
||||
There are lots more; see [here][reference] for a reference. You can also add
|
||||
your own simply by implementing the `oglematchers.Matcher` interface.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
First, make sure you have installed Go 1.0.2 or newer. See
|
||||
[here][golang-install] for instructions.
|
||||
|
||||
Use the following command to install `oglematchers` and keep it up to date:
|
||||
|
||||
go get -u github.com/smartystreets/assertions/internal/oglematchers
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
See [here][reference] for documentation. Alternatively, you can install the
|
||||
package and then use `godoc`:
|
||||
|
||||
godoc github.com/smartystreets/assertions/internal/oglematchers
|
||||
|
||||
|
||||
[reference]: http://godoc.org/github.com/smartystreets/assertions/internal/oglematchers
|
||||
[golang-install]: http://golang.org/doc/install.html
|
||||
[googletest]: http://code.google.com/p/googletest/
|
||||
[google-js-test]: http://code.google.com/p/google-js-test/
|
||||
[ogletest]: http://github.com/smartystreets/assertions/internal/ogletest
|
||||
[oglemock]: http://github.com/smartystreets/assertions/internal/oglemock
|
70
vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go
generated
vendored
70
vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go
generated
vendored
@ -1,70 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AllOf accepts a set of matchers S and returns a matcher that follows the
|
||||
// algorithm below when considering a candidate c:
|
||||
//
|
||||
// 1. Return true if for every Matcher m in S, m matches c.
|
||||
//
|
||||
// 2. Otherwise, if there is a matcher m in S such that m returns a fatal
|
||||
// error for c, return that matcher's error message.
|
||||
//
|
||||
// 3. Otherwise, return false with the error from some wrapped matcher.
|
||||
//
|
||||
// This is akin to a logical AND operation for matchers.
|
||||
func AllOf(matchers ...Matcher) Matcher {
|
||||
return &allOfMatcher{matchers}
|
||||
}
|
||||
|
||||
type allOfMatcher struct {
|
||||
wrappedMatchers []Matcher
|
||||
}
|
||||
|
||||
func (m *allOfMatcher) Description() string {
|
||||
// Special case: the empty set.
|
||||
if len(m.wrappedMatchers) == 0 {
|
||||
return "is anything"
|
||||
}
|
||||
|
||||
// Join the descriptions for the wrapped matchers.
|
||||
wrappedDescs := make([]string, len(m.wrappedMatchers))
|
||||
for i, wrappedMatcher := range m.wrappedMatchers {
|
||||
wrappedDescs[i] = wrappedMatcher.Description()
|
||||
}
|
||||
|
||||
return strings.Join(wrappedDescs, ", and ")
|
||||
}
|
||||
|
||||
func (m *allOfMatcher) Matches(c interface{}) (err error) {
|
||||
for _, wrappedMatcher := range m.wrappedMatchers {
|
||||
if wrappedErr := wrappedMatcher.Matches(c); wrappedErr != nil {
|
||||
err = wrappedErr
|
||||
|
||||
// If the error is fatal, return immediately with this error.
|
||||
_, ok := wrappedErr.(*FatalError)
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
32
vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go
generated
vendored
32
vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go
generated
vendored
@ -1,32 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
// Any returns a matcher that matches any value.
|
||||
func Any() Matcher {
|
||||
return &anyMatcher{}
|
||||
}
|
||||
|
||||
type anyMatcher struct {
|
||||
}
|
||||
|
||||
func (m *anyMatcher) Description() string {
|
||||
return "is anything"
|
||||
}
|
||||
|
||||
func (m *anyMatcher) Matches(c interface{}) error {
|
||||
return nil
|
||||
}
|
94
vendor/github.com/smartystreets/assertions/internal/oglematchers/any_of.go
generated
vendored
94
vendor/github.com/smartystreets/assertions/internal/oglematchers/any_of.go
generated
vendored
@ -1,94 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AnyOf accepts a set of values S and returns a matcher that follows the
|
||||
// algorithm below when considering a candidate c:
|
||||
//
|
||||
// 1. If there exists a value m in S such that m implements the Matcher
|
||||
// interface and m matches c, return true.
|
||||
//
|
||||
// 2. Otherwise, if there exists a value v in S such that v does not implement
|
||||
// the Matcher interface and the matcher Equals(v) matches c, return true.
|
||||
//
|
||||
// 3. Otherwise, if there is a value m in S such that m implements the Matcher
|
||||
// interface and m returns a fatal error for c, return that fatal error.
|
||||
//
|
||||
// 4. Otherwise, return false.
|
||||
//
|
||||
// This is akin to a logical OR operation for matchers, with non-matchers x
|
||||
// being treated as Equals(x).
|
||||
func AnyOf(vals ...interface{}) Matcher {
|
||||
// Get ahold of a type variable for the Matcher interface.
|
||||
var dummy *Matcher
|
||||
matcherType := reflect.TypeOf(dummy).Elem()
|
||||
|
||||
// Create a matcher for each value, or use the value itself if it's already a
|
||||
// matcher.
|
||||
wrapped := make([]Matcher, len(vals))
|
||||
for i, v := range vals {
|
||||
t := reflect.TypeOf(v)
|
||||
if t != nil && t.Implements(matcherType) {
|
||||
wrapped[i] = v.(Matcher)
|
||||
} else {
|
||||
wrapped[i] = Equals(v)
|
||||
}
|
||||
}
|
||||
|
||||
return &anyOfMatcher{wrapped}
|
||||
}
|
||||
|
||||
type anyOfMatcher struct {
|
||||
wrapped []Matcher
|
||||
}
|
||||
|
||||
func (m *anyOfMatcher) Description() string {
|
||||
wrappedDescs := make([]string, len(m.wrapped))
|
||||
for i, matcher := range m.wrapped {
|
||||
wrappedDescs[i] = matcher.Description()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("or(%s)", strings.Join(wrappedDescs, ", "))
|
||||
}
|
||||
|
||||
func (m *anyOfMatcher) Matches(c interface{}) (err error) {
|
||||
err = errors.New("")
|
||||
|
||||
// Try each matcher in turn.
|
||||
for _, matcher := range m.wrapped {
|
||||
wrappedErr := matcher.Matches(c)
|
||||
|
||||
// Return immediately if there's a match.
|
||||
if wrappedErr == nil {
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
// Note the fatal error, if any.
|
||||
if _, isFatal := wrappedErr.(*FatalError); isFatal {
|
||||
err = wrappedErr
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
61
vendor/github.com/smartystreets/assertions/internal/oglematchers/contains.go
generated
vendored
61
vendor/github.com/smartystreets/assertions/internal/oglematchers/contains.go
generated
vendored
@ -1,61 +0,0 @@
|
||||
// Copyright 2012 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Return a matcher that matches arrays slices with at least one element that
|
||||
// matches the supplied argument. If the argument x is not itself a Matcher,
|
||||
// this is equivalent to Contains(Equals(x)).
|
||||
func Contains(x interface{}) Matcher {
|
||||
var result containsMatcher
|
||||
var ok bool
|
||||
|
||||
if result.elementMatcher, ok = x.(Matcher); !ok {
|
||||
result.elementMatcher = Equals(x)
|
||||
}
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
type containsMatcher struct {
|
||||
elementMatcher Matcher
|
||||
}
|
||||
|
||||
func (m *containsMatcher) Description() string {
|
||||
return fmt.Sprintf("contains: %s", m.elementMatcher.Description())
|
||||
}
|
||||
|
||||
func (m *containsMatcher) Matches(candidate interface{}) error {
|
||||
// The candidate must be a slice or an array.
|
||||
v := reflect.ValueOf(candidate)
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return NewFatalError("which is not a slice or array")
|
||||
}
|
||||
|
||||
// Check each element.
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
elem := v.Index(i)
|
||||
if matchErr := m.elementMatcher.Matches(elem.Interface()); matchErr == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("")
|
||||
}
|
88
vendor/github.com/smartystreets/assertions/internal/oglematchers/deep_equals.go
generated
vendored
88
vendor/github.com/smartystreets/assertions/internal/oglematchers/deep_equals.go
generated
vendored
@ -1,88 +0,0 @@
|
||||
// Copyright 2012 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var byteSliceType reflect.Type = reflect.TypeOf([]byte{})
|
||||
|
||||
// DeepEquals returns a matcher that matches based on 'deep equality', as
|
||||
// defined by the reflect package. This matcher requires that values have
|
||||
// identical types to x.
|
||||
func DeepEquals(x interface{}) Matcher {
|
||||
return &deepEqualsMatcher{x}
|
||||
}
|
||||
|
||||
type deepEqualsMatcher struct {
|
||||
x interface{}
|
||||
}
|
||||
|
||||
func (m *deepEqualsMatcher) Description() string {
|
||||
xDesc := fmt.Sprintf("%v", m.x)
|
||||
xValue := reflect.ValueOf(m.x)
|
||||
|
||||
// Special case: fmt.Sprintf presents nil slices as "[]", but
|
||||
// reflect.DeepEqual makes a distinction between nil and empty slices. Make
|
||||
// this less confusing.
|
||||
if xValue.Kind() == reflect.Slice && xValue.IsNil() {
|
||||
xDesc = "<nil slice>"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("deep equals: %s", xDesc)
|
||||
}
|
||||
|
||||
func (m *deepEqualsMatcher) Matches(c interface{}) error {
|
||||
// Make sure the types match.
|
||||
ct := reflect.TypeOf(c)
|
||||
xt := reflect.TypeOf(m.x)
|
||||
|
||||
if ct != xt {
|
||||
return NewFatalError(fmt.Sprintf("which is of type %v", ct))
|
||||
}
|
||||
|
||||
// Special case: handle byte slices more efficiently.
|
||||
cValue := reflect.ValueOf(c)
|
||||
xValue := reflect.ValueOf(m.x)
|
||||
|
||||
if ct == byteSliceType && !cValue.IsNil() && !xValue.IsNil() {
|
||||
xBytes := m.x.([]byte)
|
||||
cBytes := c.([]byte)
|
||||
|
||||
if bytes.Equal(cBytes, xBytes) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("")
|
||||
}
|
||||
|
||||
// Defer to the reflect package.
|
||||
if reflect.DeepEqual(m.x, c) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special case: if the comparison failed because c is the nil slice, given
|
||||
// an indication of this (since its value is printed as "[]").
|
||||
if cValue.Kind() == reflect.Slice && cValue.IsNil() {
|
||||
return errors.New("which is nil")
|
||||
}
|
||||
|
||||
return errors.New("")
|
||||
}
|
91
vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go
generated
vendored
91
vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go
generated
vendored
@ -1,91 +0,0 @@
|
||||
// Copyright 2012 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Given a list of arguments M, ElementsAre returns a matcher that matches
|
||||
// arrays and slices A where all of the following hold:
|
||||
//
|
||||
// * A is the same length as M.
|
||||
//
|
||||
// * For each i < len(A) where M[i] is a matcher, A[i] matches M[i].
|
||||
//
|
||||
// * For each i < len(A) where M[i] is not a matcher, A[i] matches
|
||||
// Equals(M[i]).
|
||||
//
|
||||
func ElementsAre(M ...interface{}) Matcher {
|
||||
// Copy over matchers, or convert to Equals(x) for non-matcher x.
|
||||
subMatchers := make([]Matcher, len(M))
|
||||
for i, x := range M {
|
||||
if matcher, ok := x.(Matcher); ok {
|
||||
subMatchers[i] = matcher
|
||||
continue
|
||||
}
|
||||
|
||||
subMatchers[i] = Equals(x)
|
||||
}
|
||||
|
||||
return &elementsAreMatcher{subMatchers}
|
||||
}
|
||||
|
||||
type elementsAreMatcher struct {
|
||||
subMatchers []Matcher
|
||||
}
|
||||
|
||||
func (m *elementsAreMatcher) Description() string {
|
||||
subDescs := make([]string, len(m.subMatchers))
|
||||
for i, sm := range m.subMatchers {
|
||||
subDescs[i] = sm.Description()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("elements are: [%s]", strings.Join(subDescs, ", "))
|
||||
}
|
||||
|
||||
func (m *elementsAreMatcher) Matches(candidates interface{}) error {
|
||||
// The candidate must be a slice or an array.
|
||||
v := reflect.ValueOf(candidates)
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return NewFatalError("which is not a slice or array")
|
||||
}
|
||||
|
||||
// The length must be correct.
|
||||
if v.Len() != len(m.subMatchers) {
|
||||
return errors.New(fmt.Sprintf("which is of length %d", v.Len()))
|
||||
}
|
||||
|
||||
// Check each element.
|
||||
for i, subMatcher := range m.subMatchers {
|
||||
c := v.Index(i)
|
||||
if matchErr := subMatcher.Matches(c.Interface()); matchErr != nil {
|
||||
// Return an errors indicating which element doesn't match. If the
|
||||
// matcher error was fatal, make this one fatal too.
|
||||
err := errors.New(fmt.Sprintf("whose element %d doesn't match", i))
|
||||
if _, isFatal := matchErr.(*FatalError); isFatal {
|
||||
err = NewFatalError(err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
541
vendor/github.com/smartystreets/assertions/internal/oglematchers/equals.go
generated
vendored
541
vendor/github.com/smartystreets/assertions/internal/oglematchers/equals.go
generated
vendored
@ -1,541 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Equals(x) returns a matcher that matches values v such that v and x are
|
||||
// equivalent. This includes the case when the comparison v == x using Go's
|
||||
// built-in comparison operator is legal (except for structs, which this
|
||||
// matcher does not support), but for convenience the following rules also
|
||||
// apply:
|
||||
//
|
||||
// * Type checking is done based on underlying types rather than actual
|
||||
// types, so that e.g. two aliases for string can be compared:
|
||||
//
|
||||
// type stringAlias1 string
|
||||
// type stringAlias2 string
|
||||
//
|
||||
// a := "taco"
|
||||
// b := stringAlias1("taco")
|
||||
// c := stringAlias2("taco")
|
||||
//
|
||||
// ExpectTrue(a == b) // Legal, passes
|
||||
// ExpectTrue(b == c) // Illegal, doesn't compile
|
||||
//
|
||||
// ExpectThat(a, Equals(b)) // Passes
|
||||
// ExpectThat(b, Equals(c)) // Passes
|
||||
//
|
||||
// * Values of numeric type are treated as if they were abstract numbers, and
|
||||
// compared accordingly. Therefore Equals(17) will match int(17),
|
||||
// int16(17), uint(17), float32(17), complex64(17), and so on.
|
||||
//
|
||||
// If you want a stricter matcher that contains no such cleverness, see
|
||||
// IdenticalTo instead.
|
||||
//
|
||||
// Arrays are supported by this matcher, but do not participate in the
|
||||
// exceptions above. Two arrays compared with this matcher must have identical
|
||||
// types, and their element type must itself be comparable according to Go's ==
|
||||
// operator.
|
||||
func Equals(x interface{}) Matcher {
|
||||
v := reflect.ValueOf(x)
|
||||
|
||||
// This matcher doesn't support structs.
|
||||
if v.Kind() == reflect.Struct {
|
||||
panic(fmt.Sprintf("oglematchers.Equals: unsupported kind %v", v.Kind()))
|
||||
}
|
||||
|
||||
// The == operator is not defined for non-nil slices.
|
||||
if v.Kind() == reflect.Slice && v.Pointer() != uintptr(0) {
|
||||
panic(fmt.Sprintf("oglematchers.Equals: non-nil slice"))
|
||||
}
|
||||
|
||||
return &equalsMatcher{v}
|
||||
}
|
||||
|
||||
type equalsMatcher struct {
|
||||
expectedValue reflect.Value
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Numeric types
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func isSignedInteger(v reflect.Value) bool {
|
||||
k := v.Kind()
|
||||
return k >= reflect.Int && k <= reflect.Int64
|
||||
}
|
||||
|
||||
func isUnsignedInteger(v reflect.Value) bool {
|
||||
k := v.Kind()
|
||||
return k >= reflect.Uint && k <= reflect.Uintptr
|
||||
}
|
||||
|
||||
func isInteger(v reflect.Value) bool {
|
||||
return isSignedInteger(v) || isUnsignedInteger(v)
|
||||
}
|
||||
|
||||
func isFloat(v reflect.Value) bool {
|
||||
k := v.Kind()
|
||||
return k == reflect.Float32 || k == reflect.Float64
|
||||
}
|
||||
|
||||
func isComplex(v reflect.Value) bool {
|
||||
k := v.Kind()
|
||||
return k == reflect.Complex64 || k == reflect.Complex128
|
||||
}
|
||||
|
||||
func checkAgainstInt64(e int64, c reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
|
||||
switch {
|
||||
case isSignedInteger(c):
|
||||
if c.Int() == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isUnsignedInteger(c):
|
||||
u := c.Uint()
|
||||
if u <= math.MaxInt64 && int64(u) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
// Turn around the various floating point types so that the checkAgainst*
|
||||
// functions for them can deal with precision issues.
|
||||
case isFloat(c), isComplex(c):
|
||||
return Equals(c.Interface()).Matches(e)
|
||||
|
||||
default:
|
||||
err = NewFatalError("which is not numeric")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstUint64(e uint64, c reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
|
||||
switch {
|
||||
case isSignedInteger(c):
|
||||
i := c.Int()
|
||||
if i >= 0 && uint64(i) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isUnsignedInteger(c):
|
||||
if c.Uint() == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
// Turn around the various floating point types so that the checkAgainst*
|
||||
// functions for them can deal with precision issues.
|
||||
case isFloat(c), isComplex(c):
|
||||
return Equals(c.Interface()).Matches(e)
|
||||
|
||||
default:
|
||||
err = NewFatalError("which is not numeric")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstFloat32(e float32, c reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
|
||||
switch {
|
||||
case isSignedInteger(c):
|
||||
if float32(c.Int()) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isUnsignedInteger(c):
|
||||
if float32(c.Uint()) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isFloat(c):
|
||||
// Compare using float32 to avoid a false sense of precision; otherwise
|
||||
// e.g. Equals(float32(0.1)) won't match float32(0.1).
|
||||
if float32(c.Float()) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isComplex(c):
|
||||
comp := c.Complex()
|
||||
rl := real(comp)
|
||||
im := imag(comp)
|
||||
|
||||
// Compare using float32 to avoid a false sense of precision; otherwise
|
||||
// e.g. Equals(float32(0.1)) won't match (0.1 + 0i).
|
||||
if im == 0 && float32(rl) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
default:
|
||||
err = NewFatalError("which is not numeric")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstFloat64(e float64, c reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
|
||||
ck := c.Kind()
|
||||
|
||||
switch {
|
||||
case isSignedInteger(c):
|
||||
if float64(c.Int()) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isUnsignedInteger(c):
|
||||
if float64(c.Uint()) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
// If the actual value is lower precision, turn the comparison around so we
|
||||
// apply the low-precision rules. Otherwise, e.g. Equals(0.1) may not match
|
||||
// float32(0.1).
|
||||
case ck == reflect.Float32 || ck == reflect.Complex64:
|
||||
return Equals(c.Interface()).Matches(e)
|
||||
|
||||
// Otherwise, compare with double precision.
|
||||
case isFloat(c):
|
||||
if c.Float() == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isComplex(c):
|
||||
comp := c.Complex()
|
||||
rl := real(comp)
|
||||
im := imag(comp)
|
||||
|
||||
if im == 0 && rl == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
default:
|
||||
err = NewFatalError("which is not numeric")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstComplex64(e complex64, c reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
realPart := real(e)
|
||||
imaginaryPart := imag(e)
|
||||
|
||||
switch {
|
||||
case isInteger(c) || isFloat(c):
|
||||
// If we have no imaginary part, then we should just compare against the
|
||||
// real part. Otherwise, we can't be equal.
|
||||
if imaginaryPart != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
return checkAgainstFloat32(realPart, c)
|
||||
|
||||
case isComplex(c):
|
||||
// Compare using complex64 to avoid a false sense of precision; otherwise
|
||||
// e.g. Equals(0.1 + 0i) won't match float32(0.1).
|
||||
if complex64(c.Complex()) == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
default:
|
||||
err = NewFatalError("which is not numeric")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstComplex128(e complex128, c reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
realPart := real(e)
|
||||
imaginaryPart := imag(e)
|
||||
|
||||
switch {
|
||||
case isInteger(c) || isFloat(c):
|
||||
// If we have no imaginary part, then we should just compare against the
|
||||
// real part. Otherwise, we can't be equal.
|
||||
if imaginaryPart != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
return checkAgainstFloat64(realPart, c)
|
||||
|
||||
case isComplex(c):
|
||||
if c.Complex() == e {
|
||||
err = nil
|
||||
}
|
||||
|
||||
default:
|
||||
err = NewFatalError("which is not numeric")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Other types
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func checkAgainstBool(e bool, c reflect.Value) (err error) {
|
||||
if c.Kind() != reflect.Bool {
|
||||
err = NewFatalError("which is not a bool")
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.Bool() == e {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstChan(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Create a description of e's type, e.g. "chan int".
|
||||
typeStr := fmt.Sprintf("%s %s", e.Type().ChanDir(), e.Type().Elem())
|
||||
|
||||
// Make sure c is a chan of the correct type.
|
||||
if c.Kind() != reflect.Chan ||
|
||||
c.Type().ChanDir() != e.Type().ChanDir() ||
|
||||
c.Type().Elem() != e.Type().Elem() {
|
||||
err = NewFatalError(fmt.Sprintf("which is not a %s", typeStr))
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.Pointer() == e.Pointer() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstFunc(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Make sure c is a function.
|
||||
if c.Kind() != reflect.Func {
|
||||
err = NewFatalError("which is not a function")
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.Pointer() == e.Pointer() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstMap(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Make sure c is a map.
|
||||
if c.Kind() != reflect.Map {
|
||||
err = NewFatalError("which is not a map")
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.Pointer() == e.Pointer() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstPtr(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Create a description of e's type, e.g. "*int".
|
||||
typeStr := fmt.Sprintf("*%v", e.Type().Elem())
|
||||
|
||||
// Make sure c is a pointer of the correct type.
|
||||
if c.Kind() != reflect.Ptr ||
|
||||
c.Type().Elem() != e.Type().Elem() {
|
||||
err = NewFatalError(fmt.Sprintf("which is not a %s", typeStr))
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.Pointer() == e.Pointer() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstSlice(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Create a description of e's type, e.g. "[]int".
|
||||
typeStr := fmt.Sprintf("[]%v", e.Type().Elem())
|
||||
|
||||
// Make sure c is a slice of the correct type.
|
||||
if c.Kind() != reflect.Slice ||
|
||||
c.Type().Elem() != e.Type().Elem() {
|
||||
err = NewFatalError(fmt.Sprintf("which is not a %s", typeStr))
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.Pointer() == e.Pointer() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstString(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Make sure c is a string.
|
||||
if c.Kind() != reflect.String {
|
||||
err = NewFatalError("which is not a string")
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.String() == e.String() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstArray(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Create a description of e's type, e.g. "[2]int".
|
||||
typeStr := fmt.Sprintf("%v", e.Type())
|
||||
|
||||
// Make sure c is the correct type.
|
||||
if c.Type() != e.Type() {
|
||||
err = NewFatalError(fmt.Sprintf("which is not %s", typeStr))
|
||||
return
|
||||
}
|
||||
|
||||
// Check for equality.
|
||||
if e.Interface() != c.Interface() {
|
||||
err = errors.New("")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkAgainstUnsafePointer(e reflect.Value, c reflect.Value) (err error) {
|
||||
// Make sure c is a pointer.
|
||||
if c.Kind() != reflect.UnsafePointer {
|
||||
err = NewFatalError("which is not a unsafe.Pointer")
|
||||
return
|
||||
}
|
||||
|
||||
err = errors.New("")
|
||||
if c.Pointer() == e.Pointer() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkForNil(c reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
|
||||
// Make sure it is legal to call IsNil.
|
||||
switch c.Kind() {
|
||||
case reflect.Invalid:
|
||||
case reflect.Chan:
|
||||
case reflect.Func:
|
||||
case reflect.Interface:
|
||||
case reflect.Map:
|
||||
case reflect.Ptr:
|
||||
case reflect.Slice:
|
||||
|
||||
default:
|
||||
err = NewFatalError("which cannot be compared to nil")
|
||||
return
|
||||
}
|
||||
|
||||
// Ask whether the value is nil. Handle a nil literal (kind Invalid)
|
||||
// specially, since it's not legal to call IsNil there.
|
||||
if c.Kind() == reflect.Invalid || c.IsNil() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Public implementation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (m *equalsMatcher) Matches(candidate interface{}) error {
|
||||
e := m.expectedValue
|
||||
c := reflect.ValueOf(candidate)
|
||||
ek := e.Kind()
|
||||
|
||||
switch {
|
||||
case ek == reflect.Bool:
|
||||
return checkAgainstBool(e.Bool(), c)
|
||||
|
||||
case isSignedInteger(e):
|
||||
return checkAgainstInt64(e.Int(), c)
|
||||
|
||||
case isUnsignedInteger(e):
|
||||
return checkAgainstUint64(e.Uint(), c)
|
||||
|
||||
case ek == reflect.Float32:
|
||||
return checkAgainstFloat32(float32(e.Float()), c)
|
||||
|
||||
case ek == reflect.Float64:
|
||||
return checkAgainstFloat64(e.Float(), c)
|
||||
|
||||
case ek == reflect.Complex64:
|
||||
return checkAgainstComplex64(complex64(e.Complex()), c)
|
||||
|
||||
case ek == reflect.Complex128:
|
||||
return checkAgainstComplex128(complex128(e.Complex()), c)
|
||||
|
||||
case ek == reflect.Chan:
|
||||
return checkAgainstChan(e, c)
|
||||
|
||||
case ek == reflect.Func:
|
||||
return checkAgainstFunc(e, c)
|
||||
|
||||
case ek == reflect.Map:
|
||||
return checkAgainstMap(e, c)
|
||||
|
||||
case ek == reflect.Ptr:
|
||||
return checkAgainstPtr(e, c)
|
||||
|
||||
case ek == reflect.Slice:
|
||||
return checkAgainstSlice(e, c)
|
||||
|
||||
case ek == reflect.String:
|
||||
return checkAgainstString(e, c)
|
||||
|
||||
case ek == reflect.Array:
|
||||
return checkAgainstArray(e, c)
|
||||
|
||||
case ek == reflect.UnsafePointer:
|
||||
return checkAgainstUnsafePointer(e, c)
|
||||
|
||||
case ek == reflect.Invalid:
|
||||
return checkForNil(c)
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("equalsMatcher.Matches: unexpected kind: %v", ek))
|
||||
}
|
||||
|
||||
func (m *equalsMatcher) Description() string {
|
||||
// Special case: handle nil.
|
||||
if !m.expectedValue.IsValid() {
|
||||
return "is nil"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", m.expectedValue.Interface())
|
||||
}
|
51
vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go
generated
vendored
51
vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
// Error returns a matcher that matches non-nil values implementing the
|
||||
// built-in error interface for whom the return value of Error() matches the
|
||||
// supplied matcher.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// err := errors.New("taco burrito")
|
||||
//
|
||||
// Error(Equals("taco burrito")) // matches err
|
||||
// Error(HasSubstr("taco")) // matches err
|
||||
// Error(HasSubstr("enchilada")) // doesn't match err
|
||||
//
|
||||
func Error(m Matcher) Matcher {
|
||||
return &errorMatcher{m}
|
||||
}
|
||||
|
||||
type errorMatcher struct {
|
||||
wrappedMatcher Matcher
|
||||
}
|
||||
|
||||
func (m *errorMatcher) Description() string {
|
||||
return "error " + m.wrappedMatcher.Description()
|
||||
}
|
||||
|
||||
func (m *errorMatcher) Matches(c interface{}) error {
|
||||
// Make sure that c is an error.
|
||||
e, ok := c.(error)
|
||||
if !ok {
|
||||
return NewFatalError("which is not an error")
|
||||
}
|
||||
|
||||
// Pass on the error text to the wrapped matcher.
|
||||
return m.wrappedMatcher.Matches(e.Error())
|
||||
}
|
39
vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_or_equal.go
generated
vendored
39
vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_or_equal.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// GreaterOrEqual returns a matcher that matches integer, floating point, or
|
||||
// strings values v such that v >= x. Comparison is not defined between numeric
|
||||
// and string types, but is defined between all integer and floating point
|
||||
// types.
|
||||
//
|
||||
// x must itself be an integer, floating point, or string type; otherwise,
|
||||
// GreaterOrEqual will panic.
|
||||
func GreaterOrEqual(x interface{}) Matcher {
|
||||
desc := fmt.Sprintf("greater than or equal to %v", x)
|
||||
|
||||
// Special case: make it clear that strings are strings.
|
||||
if reflect.TypeOf(x).Kind() == reflect.String {
|
||||
desc = fmt.Sprintf("greater than or equal to \"%s\"", x)
|
||||
}
|
||||
|
||||
return transformDescription(Not(LessThan(x)), desc)
|
||||
}
|
39
vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_than.go
generated
vendored
39
vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_than.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// GreaterThan returns a matcher that matches integer, floating point, or
|
||||
// strings values v such that v > x. Comparison is not defined between numeric
|
||||
// and string types, but is defined between all integer and floating point
|
||||
// types.
|
||||
//
|
||||
// x must itself be an integer, floating point, or string type; otherwise,
|
||||
// GreaterThan will panic.
|
||||
func GreaterThan(x interface{}) Matcher {
|
||||
desc := fmt.Sprintf("greater than %v", x)
|
||||
|
||||
// Special case: make it clear that strings are strings.
|
||||
if reflect.TypeOf(x).Kind() == reflect.String {
|
||||
desc = fmt.Sprintf("greater than \"%s\"", x)
|
||||
}
|
||||
|
||||
return transformDescription(Not(LessOrEqual(x)), desc)
|
||||
}
|
37
vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go
generated
vendored
37
vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
// Copyright 2015 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// HasSameTypeAs returns a matcher that matches values with exactly the same
|
||||
// type as the supplied prototype.
|
||||
func HasSameTypeAs(p interface{}) Matcher {
|
||||
expected := reflect.TypeOf(p)
|
||||
pred := func(c interface{}) error {
|
||||
actual := reflect.TypeOf(c)
|
||||
if actual != expected {
|
||||
return fmt.Errorf("which has type %v", actual)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return NewMatcher(pred, fmt.Sprintf("has type %v", expected))
|
||||
}
|
46
vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go
generated
vendored
46
vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go
generated
vendored
@ -1,46 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HasSubstr returns a matcher that matches strings containing s as a
|
||||
// substring.
|
||||
func HasSubstr(s string) Matcher {
|
||||
return NewMatcher(
|
||||
func(c interface{}) error { return hasSubstr(s, c) },
|
||||
fmt.Sprintf("has substring \"%s\"", s))
|
||||
}
|
||||
|
||||
func hasSubstr(needle string, c interface{}) error {
|
||||
v := reflect.ValueOf(c)
|
||||
if v.Kind() != reflect.String {
|
||||
return NewFatalError("which is not a string")
|
||||
}
|
||||
|
||||
// Perform the substring search.
|
||||
haystack := v.String()
|
||||
if strings.Contains(haystack, needle) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("")
|
||||
}
|
134
vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go
generated
vendored
134
vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go
generated
vendored
@ -1,134 +0,0 @@
|
||||
// Copyright 2012 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Is the type comparable according to the definition here?
|
||||
//
|
||||
// http://weekly.golang.org/doc/go_spec.html#Comparison_operators
|
||||
//
|
||||
func isComparable(t reflect.Type) bool {
|
||||
switch t.Kind() {
|
||||
case reflect.Array:
|
||||
return isComparable(t.Elem())
|
||||
|
||||
case reflect.Struct:
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
if !isComparable(t.Field(i).Type) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case reflect.Slice, reflect.Map, reflect.Func:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Should the supplied type be allowed as an argument to IdenticalTo?
|
||||
func isLegalForIdenticalTo(t reflect.Type) (bool, error) {
|
||||
// Allow the zero type.
|
||||
if t == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Reference types are always okay; we compare pointers.
|
||||
switch t.Kind() {
|
||||
case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan:
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Reject other non-comparable types.
|
||||
if !isComparable(t) {
|
||||
return false, errors.New(fmt.Sprintf("%v is not comparable", t))
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// IdenticalTo(x) returns a matcher that matches values v with type identical
|
||||
// to x such that:
|
||||
//
|
||||
// 1. If v and x are of a reference type (slice, map, function, channel), then
|
||||
// they are either both nil or are references to the same object.
|
||||
//
|
||||
// 2. Otherwise, if v and x are not of a reference type but have a valid type,
|
||||
// then v == x.
|
||||
//
|
||||
// If v and x are both the invalid type (which results from the predeclared nil
|
||||
// value, or from nil interface variables), then the matcher is satisfied.
|
||||
//
|
||||
// This function will panic if x is of a value type that is not comparable. For
|
||||
// example, x cannot be an array of functions.
|
||||
func IdenticalTo(x interface{}) Matcher {
|
||||
t := reflect.TypeOf(x)
|
||||
|
||||
// Reject illegal arguments.
|
||||
if ok, err := isLegalForIdenticalTo(t); !ok {
|
||||
panic("IdenticalTo: " + err.Error())
|
||||
}
|
||||
|
||||
return &identicalToMatcher{x}
|
||||
}
|
||||
|
||||
type identicalToMatcher struct {
|
||||
x interface{}
|
||||
}
|
||||
|
||||
func (m *identicalToMatcher) Description() string {
|
||||
t := reflect.TypeOf(m.x)
|
||||
return fmt.Sprintf("identical to <%v> %v", t, m.x)
|
||||
}
|
||||
|
||||
func (m *identicalToMatcher) Matches(c interface{}) error {
|
||||
// Make sure the candidate's type is correct.
|
||||
t := reflect.TypeOf(m.x)
|
||||
if ct := reflect.TypeOf(c); t != ct {
|
||||
return NewFatalError(fmt.Sprintf("which is of type %v", ct))
|
||||
}
|
||||
|
||||
// Special case: two values of the invalid type are always identical.
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle reference types.
|
||||
switch t.Kind() {
|
||||
case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan:
|
||||
xv := reflect.ValueOf(m.x)
|
||||
cv := reflect.ValueOf(c)
|
||||
if xv.Pointer() == cv.Pointer() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("which is not an identical reference")
|
||||
}
|
||||
|
||||
// Are the values equal?
|
||||
if m.x == c {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("")
|
||||
}
|
41
vendor/github.com/smartystreets/assertions/internal/oglematchers/less_or_equal.go
generated
vendored
41
vendor/github.com/smartystreets/assertions/internal/oglematchers/less_or_equal.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// LessOrEqual returns a matcher that matches integer, floating point, or
|
||||
// strings values v such that v <= x. Comparison is not defined between numeric
|
||||
// and string types, but is defined between all integer and floating point
|
||||
// types.
|
||||
//
|
||||
// x must itself be an integer, floating point, or string type; otherwise,
|
||||
// LessOrEqual will panic.
|
||||
func LessOrEqual(x interface{}) Matcher {
|
||||
desc := fmt.Sprintf("less than or equal to %v", x)
|
||||
|
||||
// Special case: make it clear that strings are strings.
|
||||
if reflect.TypeOf(x).Kind() == reflect.String {
|
||||
desc = fmt.Sprintf("less than or equal to \"%s\"", x)
|
||||
}
|
||||
|
||||
// Put LessThan last so that its error messages will be used in the event of
|
||||
// failure.
|
||||
return transformDescription(AnyOf(Equals(x), LessThan(x)), desc)
|
||||
}
|
152
vendor/github.com/smartystreets/assertions/internal/oglematchers/less_than.go
generated
vendored
152
vendor/github.com/smartystreets/assertions/internal/oglematchers/less_than.go
generated
vendored
@ -1,152 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// LessThan returns a matcher that matches integer, floating point, or strings
|
||||
// values v such that v < x. Comparison is not defined between numeric and
|
||||
// string types, but is defined between all integer and floating point types.
|
||||
//
|
||||
// x must itself be an integer, floating point, or string type; otherwise,
|
||||
// LessThan will panic.
|
||||
func LessThan(x interface{}) Matcher {
|
||||
v := reflect.ValueOf(x)
|
||||
kind := v.Kind()
|
||||
|
||||
switch {
|
||||
case isInteger(v):
|
||||
case isFloat(v):
|
||||
case kind == reflect.String:
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("LessThan: unexpected kind %v", kind))
|
||||
}
|
||||
|
||||
return &lessThanMatcher{v}
|
||||
}
|
||||
|
||||
type lessThanMatcher struct {
|
||||
limit reflect.Value
|
||||
}
|
||||
|
||||
func (m *lessThanMatcher) Description() string {
|
||||
// Special case: make it clear that strings are strings.
|
||||
if m.limit.Kind() == reflect.String {
|
||||
return fmt.Sprintf("less than \"%s\"", m.limit.String())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("less than %v", m.limit.Interface())
|
||||
}
|
||||
|
||||
func compareIntegers(v1, v2 reflect.Value) (err error) {
|
||||
err = errors.New("")
|
||||
|
||||
switch {
|
||||
case isSignedInteger(v1) && isSignedInteger(v2):
|
||||
if v1.Int() < v2.Int() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
|
||||
case isSignedInteger(v1) && isUnsignedInteger(v2):
|
||||
if v1.Int() < 0 || uint64(v1.Int()) < v2.Uint() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
|
||||
case isUnsignedInteger(v1) && isSignedInteger(v2):
|
||||
if v1.Uint() <= math.MaxInt64 && int64(v1.Uint()) < v2.Int() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
|
||||
case isUnsignedInteger(v1) && isUnsignedInteger(v2):
|
||||
if v1.Uint() < v2.Uint() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("compareIntegers: %v %v", v1, v2))
|
||||
}
|
||||
|
||||
func getFloat(v reflect.Value) float64 {
|
||||
switch {
|
||||
case isSignedInteger(v):
|
||||
return float64(v.Int())
|
||||
|
||||
case isUnsignedInteger(v):
|
||||
return float64(v.Uint())
|
||||
|
||||
case isFloat(v):
|
||||
return v.Float()
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("getFloat: %v", v))
|
||||
}
|
||||
|
||||
func (m *lessThanMatcher) Matches(c interface{}) (err error) {
|
||||
v1 := reflect.ValueOf(c)
|
||||
v2 := m.limit
|
||||
|
||||
err = errors.New("")
|
||||
|
||||
// Handle strings as a special case.
|
||||
if v1.Kind() == reflect.String && v2.Kind() == reflect.String {
|
||||
if v1.String() < v2.String() {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If we get here, we require that we are dealing with integers or floats.
|
||||
v1Legal := isInteger(v1) || isFloat(v1)
|
||||
v2Legal := isInteger(v2) || isFloat(v2)
|
||||
if !v1Legal || !v2Legal {
|
||||
err = NewFatalError("which is not comparable")
|
||||
return
|
||||
}
|
||||
|
||||
// Handle the various comparison cases.
|
||||
switch {
|
||||
// Both integers
|
||||
case isInteger(v1) && isInteger(v2):
|
||||
return compareIntegers(v1, v2)
|
||||
|
||||
// At least one float32
|
||||
case v1.Kind() == reflect.Float32 || v2.Kind() == reflect.Float32:
|
||||
if float32(getFloat(v1)) < float32(getFloat(v2)) {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
|
||||
// At least one float64
|
||||
case v1.Kind() == reflect.Float64 || v2.Kind() == reflect.Float64:
|
||||
if getFloat(v1) < getFloat(v2) {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// We shouldn't get here.
|
||||
panic(fmt.Sprintf("lessThanMatcher.Matches: Shouldn't get here: %v %v", v1, v2))
|
||||
}
|
86
vendor/github.com/smartystreets/assertions/internal/oglematchers/matcher.go
generated
vendored
86
vendor/github.com/smartystreets/assertions/internal/oglematchers/matcher.go
generated
vendored
@ -1,86 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package oglematchers provides a set of matchers useful in a testing or
|
||||
// mocking framework. These matchers are inspired by and mostly compatible with
|
||||
// Google Test for C++ and Google JS Test.
|
||||
//
|
||||
// This package is used by github.com/smartystreets/assertions/internal/ogletest and
|
||||
// github.com/smartystreets/assertions/internal/oglemock, which may be more directly useful if you're not
|
||||
// writing your own testing package or defining your own matchers.
|
||||
package oglematchers
|
||||
|
||||
// A Matcher is some predicate implicitly defining a set of values that it
|
||||
// matches. For example, GreaterThan(17) matches all numeric values greater
|
||||
// than 17, and HasSubstr("taco") matches all strings with the substring
|
||||
// "taco".
|
||||
//
|
||||
// Matchers are typically exposed to tests via constructor functions like
|
||||
// HasSubstr. In order to implement such a function you can either define your
|
||||
// own matcher type or use NewMatcher.
|
||||
type Matcher interface {
|
||||
// Check whether the supplied value belongs to the the set defined by the
|
||||
// matcher. Return a non-nil error if and only if it does not.
|
||||
//
|
||||
// The error describes why the value doesn't match. The error text is a
|
||||
// relative clause that is suitable for being placed after the value. For
|
||||
// example, a predicate that matches strings with a particular substring may,
|
||||
// when presented with a numerical value, return the following error text:
|
||||
//
|
||||
// "which is not a string"
|
||||
//
|
||||
// Then the failure message may look like:
|
||||
//
|
||||
// Expected: has substring "taco"
|
||||
// Actual: 17, which is not a string
|
||||
//
|
||||
// If the error is self-apparent based on the description of the matcher, the
|
||||
// error text may be empty (but the error still non-nil). For example:
|
||||
//
|
||||
// Expected: 17
|
||||
// Actual: 19
|
||||
//
|
||||
// If you are implementing a new matcher, see also the documentation on
|
||||
// FatalError.
|
||||
Matches(candidate interface{}) error
|
||||
|
||||
// Description returns a string describing the property that values matching
|
||||
// this matcher have, as a verb phrase where the subject is the value. For
|
||||
// example, "is greather than 17" or "has substring "taco"".
|
||||
Description() string
|
||||
}
|
||||
|
||||
// FatalError is an implementation of the error interface that may be returned
|
||||
// from matchers, indicating the error should be propagated. Returning a
|
||||
// *FatalError indicates that the matcher doesn't process values of the
|
||||
// supplied type, or otherwise doesn't know how to handle the value.
|
||||
//
|
||||
// For example, if GreaterThan(17) returned false for the value "taco" without
|
||||
// a fatal error, then Not(GreaterThan(17)) would return true. This is
|
||||
// technically correct, but is surprising and may mask failures where the wrong
|
||||
// sort of matcher is accidentally used. Instead, GreaterThan(17) can return a
|
||||
// fatal error, which will be propagated by Not().
|
||||
type FatalError struct {
|
||||
errorText string
|
||||
}
|
||||
|
||||
// NewFatalError creates a FatalError struct with the supplied error text.
|
||||
func NewFatalError(s string) *FatalError {
|
||||
return &FatalError{s}
|
||||
}
|
||||
|
||||
func (e *FatalError) Error() string {
|
||||
return e.errorText
|
||||
}
|
69
vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go
generated
vendored
69
vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go
generated
vendored
@ -1,69 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// MatchesRegexp returns a matcher that matches strings and byte slices whose
|
||||
// contents match the supplied regular expression. The semantics are those of
|
||||
// regexp.Match. In particular, that means the match is not implicitly anchored
|
||||
// to the ends of the string: MatchesRegexp("bar") will match "foo bar baz".
|
||||
func MatchesRegexp(pattern string) Matcher {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
panic("MatchesRegexp: " + err.Error())
|
||||
}
|
||||
|
||||
return &matchesRegexpMatcher{re}
|
||||
}
|
||||
|
||||
type matchesRegexpMatcher struct {
|
||||
re *regexp.Regexp
|
||||
}
|
||||
|
||||
func (m *matchesRegexpMatcher) Description() string {
|
||||
return fmt.Sprintf("matches regexp \"%s\"", m.re.String())
|
||||
}
|
||||
|
||||
func (m *matchesRegexpMatcher) Matches(c interface{}) (err error) {
|
||||
v := reflect.ValueOf(c)
|
||||
isString := v.Kind() == reflect.String
|
||||
isByteSlice := v.Kind() == reflect.Slice && v.Elem().Kind() == reflect.Uint8
|
||||
|
||||
err = errors.New("")
|
||||
|
||||
switch {
|
||||
case isString:
|
||||
if m.re.MatchString(v.String()) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
case isByteSlice:
|
||||
if m.re.Match(v.Bytes()) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
default:
|
||||
err = NewFatalError("which is not a string or []byte")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
43
vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go
generated
vendored
43
vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
// Copyright 2015 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
// Create a matcher with the given description and predicate function, which
|
||||
// will be invoked to handle calls to Matchers.
|
||||
//
|
||||
// Using this constructor may be a convenience over defining your own type that
|
||||
// implements Matcher if you do not need any logic in your Description method.
|
||||
func NewMatcher(
|
||||
predicate func(interface{}) error,
|
||||
description string) Matcher {
|
||||
return &predicateMatcher{
|
||||
predicate: predicate,
|
||||
description: description,
|
||||
}
|
||||
}
|
||||
|
||||
type predicateMatcher struct {
|
||||
predicate func(interface{}) error
|
||||
description string
|
||||
}
|
||||
|
||||
func (pm *predicateMatcher) Matches(c interface{}) error {
|
||||
return pm.predicate(c)
|
||||
}
|
||||
|
||||
func (pm *predicateMatcher) Description() string {
|
||||
return pm.description
|
||||
}
|
53
vendor/github.com/smartystreets/assertions/internal/oglematchers/not.go
generated
vendored
53
vendor/github.com/smartystreets/assertions/internal/oglematchers/not.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Not returns a matcher that inverts the set of values matched by the wrapped
|
||||
// matcher. It does not transform the result for values for which the wrapped
|
||||
// matcher returns a fatal error.
|
||||
func Not(m Matcher) Matcher {
|
||||
return ¬Matcher{m}
|
||||
}
|
||||
|
||||
type notMatcher struct {
|
||||
wrapped Matcher
|
||||
}
|
||||
|
||||
func (m *notMatcher) Matches(c interface{}) (err error) {
|
||||
err = m.wrapped.Matches(c)
|
||||
|
||||
// Did the wrapped matcher say yes?
|
||||
if err == nil {
|
||||
return errors.New("")
|
||||
}
|
||||
|
||||
// Did the wrapped matcher return a fatal error?
|
||||
if _, isFatal := err.(*FatalError); isFatal {
|
||||
return err
|
||||
}
|
||||
|
||||
// The wrapped matcher returned a non-fatal error.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *notMatcher) Description() string {
|
||||
return fmt.Sprintf("not(%s)", m.wrapped.Description())
|
||||
}
|
74
vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go
generated
vendored
74
vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go
generated
vendored
@ -1,74 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Panics matches zero-arg functions which, when invoked, panic with an error
|
||||
// that matches the supplied matcher.
|
||||
//
|
||||
// NOTE(jacobsa): This matcher cannot detect the case where the function panics
|
||||
// using panic(nil), by design of the language. See here for more info:
|
||||
//
|
||||
// http://goo.gl/9aIQL
|
||||
//
|
||||
func Panics(m Matcher) Matcher {
|
||||
return &panicsMatcher{m}
|
||||
}
|
||||
|
||||
type panicsMatcher struct {
|
||||
wrappedMatcher Matcher
|
||||
}
|
||||
|
||||
func (m *panicsMatcher) Description() string {
|
||||
return "panics with: " + m.wrappedMatcher.Description()
|
||||
}
|
||||
|
||||
func (m *panicsMatcher) Matches(c interface{}) (err error) {
|
||||
// Make sure c is a zero-arg function.
|
||||
v := reflect.ValueOf(c)
|
||||
if v.Kind() != reflect.Func || v.Type().NumIn() != 0 {
|
||||
err = NewFatalError("which is not a zero-arg function")
|
||||
return
|
||||
}
|
||||
|
||||
// Call the function and check its panic error.
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = m.wrappedMatcher.Matches(e)
|
||||
|
||||
// Set a clearer error message if the matcher said no.
|
||||
if err != nil {
|
||||
wrappedClause := ""
|
||||
if err.Error() != "" {
|
||||
wrappedClause = ", " + err.Error()
|
||||
}
|
||||
|
||||
err = errors.New(fmt.Sprintf("which panicked with: %v%s", e, wrappedClause))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
v.Call([]reflect.Value{})
|
||||
|
||||
// If we get here, the function didn't panic.
|
||||
err = errors.New("which didn't panic")
|
||||
return
|
||||
}
|
65
vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go
generated
vendored
65
vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go
generated
vendored
@ -1,65 +0,0 @@
|
||||
// Copyright 2012 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Return a matcher that matches non-nil pointers whose pointee matches the
|
||||
// wrapped matcher.
|
||||
func Pointee(m Matcher) Matcher {
|
||||
return &pointeeMatcher{m}
|
||||
}
|
||||
|
||||
type pointeeMatcher struct {
|
||||
wrapped Matcher
|
||||
}
|
||||
|
||||
func (m *pointeeMatcher) Matches(c interface{}) (err error) {
|
||||
// Make sure the candidate is of the appropriate type.
|
||||
cv := reflect.ValueOf(c)
|
||||
if !cv.IsValid() || cv.Kind() != reflect.Ptr {
|
||||
return NewFatalError("which is not a pointer")
|
||||
}
|
||||
|
||||
// Make sure the candidate is non-nil.
|
||||
if cv.IsNil() {
|
||||
return NewFatalError("")
|
||||
}
|
||||
|
||||
// Defer to the wrapped matcher. Fix up empty errors so that failure messages
|
||||
// are more helpful than just printing a pointer for "Actual".
|
||||
pointee := cv.Elem().Interface()
|
||||
err = m.wrapped.Matches(pointee)
|
||||
if err != nil && err.Error() == "" {
|
||||
s := fmt.Sprintf("whose pointee is %v", pointee)
|
||||
|
||||
if _, ok := err.(*FatalError); ok {
|
||||
err = NewFatalError(s)
|
||||
} else {
|
||||
err = errors.New(s)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *pointeeMatcher) Description() string {
|
||||
return fmt.Sprintf("pointee(%s)", m.wrapped.Description())
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2011 Aaron Jacobs. All Rights Reserved.
|
||||
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package oglematchers
|
||||
|
||||
// transformDescription returns a matcher that is equivalent to the supplied
|
||||
// one, except that it has the supplied description instead of the one attached
|
||||
// to the existing matcher.
|
||||
func transformDescription(m Matcher, newDesc string) Matcher {
|
||||
return &transformDescriptionMatcher{newDesc, m}
|
||||
}
|
||||
|
||||
type transformDescriptionMatcher struct {
|
||||
desc string
|
||||
wrappedMatcher Matcher
|
||||
}
|
||||
|
||||
func (m *transformDescriptionMatcher) Description() string {
|
||||
return m.desc
|
||||
}
|
||||
|
||||
func (m *transformDescriptionMatcher) Matches(c interface{}) error {
|
||||
return m.wrappedMatcher.Matches(c)
|
||||
}
|
94
vendor/github.com/smartystreets/assertions/messages.go
generated
vendored
94
vendor/github.com/smartystreets/assertions/messages.go
generated
vendored
@ -1,94 +0,0 @@
|
||||
package assertions
|
||||
|
||||
const ( // equality
|
||||
shouldHaveBeenEqual = "Expected: '%v'\nActual: '%v'\n(Should be equal)"
|
||||
shouldNotHaveBeenEqual = "Expected '%v'\nto NOT equal '%v'\n(but it did)!"
|
||||
shouldHaveBeenEqualTypeMismatch = "Expected: '%v' (%T)\nActual: '%v' (%T)\n(Should be equal, type mismatch)"
|
||||
shouldHaveBeenAlmostEqual = "Expected '%v' to almost equal '%v' (but it didn't)!"
|
||||
shouldHaveNotBeenAlmostEqual = "Expected '%v' to NOT almost equal '%v' (but it did)!"
|
||||
shouldHaveResembled = "Expected: '%#v'\nActual: '%#v'\n(Should resemble)!"
|
||||
shouldHaveResembledTypeMismatch = "Expected: '%#v' (%T)\nActual: '%#v' (%T)\n(Should resemble, type mismatch)"
|
||||
shouldNotHaveResembled = "Expected '%#v'\nto NOT resemble '%#v'\n(but it did)!"
|
||||
shouldBePointers = "Both arguments should be pointers "
|
||||
shouldHaveBeenNonNilPointer = shouldBePointers + "(the %s was %s)!"
|
||||
shouldHavePointedTo = "Expected '%+v' (address: '%v') and '%+v' (address: '%v') to be the same address (but their weren't)!"
|
||||
shouldNotHavePointedTo = "Expected '%+v' and '%+v' to be different references (but they matched: '%v')!"
|
||||
shouldHaveBeenNil = "Expected: nil\nActual: '%v'"
|
||||
shouldNotHaveBeenNil = "Expected '%+v' to NOT be nil (but it was)!"
|
||||
shouldHaveBeenTrue = "Expected: true\nActual: %v"
|
||||
shouldHaveBeenFalse = "Expected: false\nActual: %v"
|
||||
shouldHaveBeenZeroValue = "'%+v' should have been the zero value" //"Expected: (zero value)\nActual: %v"
|
||||
)
|
||||
|
||||
const ( // quantity comparisons
|
||||
shouldHaveBeenGreater = "Expected '%v' to be greater than '%v' (but it wasn't)!"
|
||||
shouldHaveBeenGreaterOrEqual = "Expected '%v' to be greater than or equal to '%v' (but it wasn't)!"
|
||||
shouldHaveBeenLess = "Expected '%v' to be less than '%v' (but it wasn't)!"
|
||||
shouldHaveBeenLessOrEqual = "Expected '%v' to be less than or equal to '%v' (but it wasn't)!"
|
||||
shouldHaveBeenBetween = "Expected '%v' to be between '%v' and '%v' (but it wasn't)!"
|
||||
shouldNotHaveBeenBetween = "Expected '%v' NOT to be between '%v' and '%v' (but it was)!"
|
||||
shouldHaveDifferentUpperAndLower = "The lower and upper bounds must be different values (they were both '%v')."
|
||||
shouldHaveBeenBetweenOrEqual = "Expected '%v' to be between '%v' and '%v' or equal to one of them (but it wasn't)!"
|
||||
shouldNotHaveBeenBetweenOrEqual = "Expected '%v' NOT to be between '%v' and '%v' or equal to one of them (but it was)!"
|
||||
)
|
||||
|
||||
const ( // collections
|
||||
shouldHaveContained = "Expected the container (%v) to contain: '%v' (but it didn't)!"
|
||||
shouldNotHaveContained = "Expected the container (%v) NOT to contain: '%v' (but it did)!"
|
||||
shouldHaveContainedKey = "Expected the %v to contain the key: %v (but it didn't)!"
|
||||
shouldNotHaveContainedKey = "Expected the %v NOT to contain the key: %v (but it did)!"
|
||||
shouldHaveBeenIn = "Expected '%v' to be in the container (%v), but it wasn't!"
|
||||
shouldNotHaveBeenIn = "Expected '%v' NOT to be in the container (%v), but it was!"
|
||||
shouldHaveBeenAValidCollection = "You must provide a valid container (was %v)!"
|
||||
shouldHaveBeenAValidMap = "You must provide a valid map type (was %v)!"
|
||||
shouldHaveBeenEmpty = "Expected %+v to be empty (but it wasn't)!"
|
||||
shouldNotHaveBeenEmpty = "Expected %+v to NOT be empty (but it was)!"
|
||||
shouldHaveBeenAValidInteger = "You must provide a valid integer (was %v)!"
|
||||
shouldHaveBeenAValidLength = "You must provide a valid positive integer (was %v)!"
|
||||
shouldHaveHadLength = "Expected %+v to have length equal to '%v', but it wasn't!"
|
||||
)
|
||||
|
||||
const ( // strings
|
||||
shouldHaveStartedWith = "Expected '%v'\nto start with '%v'\n(but it didn't)!"
|
||||
shouldNotHaveStartedWith = "Expected '%v'\nNOT to start with '%v'\n(but it did)!"
|
||||
shouldHaveEndedWith = "Expected '%v'\nto end with '%v'\n(but it didn't)!"
|
||||
shouldNotHaveEndedWith = "Expected '%v'\nNOT to end with '%v'\n(but it did)!"
|
||||
shouldAllBeStrings = "All arguments to this assertion must be strings (you provided: %v)."
|
||||
shouldBothBeStrings = "Both arguments to this assertion must be strings (you provided %v and %v)."
|
||||
shouldBeString = "The argument to this assertion must be a string (you provided %v)."
|
||||
shouldHaveContainedSubstring = "Expected '%s' to contain substring '%s' (but it didn't)!"
|
||||
shouldNotHaveContainedSubstring = "Expected '%s' NOT to contain substring '%s' (but it did)!"
|
||||
shouldHaveBeenBlank = "Expected '%s' to be blank (but it wasn't)!"
|
||||
shouldNotHaveBeenBlank = "Expected value to NOT be blank (but it was)!"
|
||||
)
|
||||
|
||||
const ( // panics
|
||||
shouldUseVoidNiladicFunction = "You must provide a void, niladic function as the first argument!"
|
||||
shouldHavePanickedWith = "Expected func() to panic with '%v' (but it panicked with '%v')!"
|
||||
shouldHavePanicked = "Expected func() to panic (but it didn't)!"
|
||||
shouldNotHavePanicked = "Expected func() NOT to panic (error: '%+v')!"
|
||||
shouldNotHavePanickedWith = "Expected func() NOT to panic with '%v' (but it did)!"
|
||||
)
|
||||
|
||||
const ( // type checking
|
||||
shouldHaveBeenA = "Expected '%v' to be: '%v' (but was: '%v')!"
|
||||
shouldNotHaveBeenA = "Expected '%v' to NOT be: '%v' (but it was)!"
|
||||
|
||||
shouldHaveImplemented = "Expected: '%v interface support'\nActual: '%v' does not implement the interface!"
|
||||
shouldNotHaveImplemented = "Expected '%v'\nto NOT implement '%v'\n(but it did)!"
|
||||
shouldCompareWithInterfacePointer = "The expected value must be a pointer to an interface type (eg. *fmt.Stringer)"
|
||||
shouldNotBeNilActual = "The actual value was 'nil' and should be a value or a pointer to a value!"
|
||||
)
|
||||
|
||||
const ( // time comparisons
|
||||
shouldUseTimes = "You must provide time instances as arguments to this assertion."
|
||||
shouldUseTimeSlice = "You must provide a slice of time instances as the first argument to this assertion."
|
||||
shouldUseDurationAndTime = "You must provide a duration and a time as arguments to this assertion."
|
||||
shouldHaveHappenedBefore = "Expected '%v' to happen before '%v' (it happened '%v' after)!"
|
||||
shouldHaveHappenedAfter = "Expected '%v' to happen after '%v' (it happened '%v' before)!"
|
||||
shouldHaveHappenedBetween = "Expected '%v' to happen between '%v' and '%v' (it happened '%v' outside threshold)!"
|
||||
shouldNotHaveHappenedOnOrBetween = "Expected '%v' to NOT happen on or between '%v' and '%v' (but it did)!"
|
||||
|
||||
// format params: incorrect-index, previous-index, previous-time, incorrect-index, incorrect-time
|
||||
shouldHaveBeenChronological = "The 'Time' at index [%d] should have happened after the previous one (but it didn't!):\n [%d]: %s\n [%d]: %s (see, it happened before!)"
|
||||
)
|
115
vendor/github.com/smartystreets/assertions/panic.go
generated
vendored
115
vendor/github.com/smartystreets/assertions/panic.go
generated
vendored
@ -1,115 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ShouldPanic receives a void, niladic function and expects to recover a panic.
|
||||
func ShouldPanic(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered == nil {
|
||||
message = shouldHavePanicked
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShouldNotPanic receives a void, niladic function and expects to execute the function without any panic.
|
||||
func ShouldNotPanic(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered != nil {
|
||||
message = fmt.Sprintf(shouldNotHavePanicked, recovered)
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShouldPanicWith receives a void, niladic function and expects to recover a panic with the second argument as the content.
|
||||
func ShouldPanicWith(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered == nil {
|
||||
message = shouldHavePanicked
|
||||
} else {
|
||||
if equal := ShouldEqual(recovered, expected[0]); equal != success {
|
||||
message = serializer.serialize(expected[0], recovered, fmt.Sprintf(shouldHavePanickedWith, expected[0], recovered))
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShouldNotPanicWith receives a void, niladic function and expects to recover a panic whose content differs from the second argument.
|
||||
func ShouldNotPanicWith(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered == nil {
|
||||
message = success
|
||||
} else {
|
||||
if equal := ShouldEqual(recovered, expected[0]); equal == success {
|
||||
message = fmt.Sprintf(shouldNotHavePanickedWith, expected[0])
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
141
vendor/github.com/smartystreets/assertions/quantity.go
generated
vendored
141
vendor/github.com/smartystreets/assertions/quantity.go
generated
vendored
@ -1,141 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/smartystreets/assertions/internal/oglematchers"
|
||||
)
|
||||
|
||||
// ShouldBeGreaterThan receives exactly two parameters and ensures that the first is greater than the second.
|
||||
func ShouldBeGreaterThan(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if matchError := oglematchers.GreaterThan(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenGreater, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeGreaterThanOrEqualTo receives exactly two parameters and ensures that the first is greater than or equal to the second.
|
||||
func ShouldBeGreaterThanOrEqualTo(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if matchError := oglematchers.GreaterOrEqual(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenGreaterOrEqual, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeLessThan receives exactly two parameters and ensures that the first is less than the second.
|
||||
func ShouldBeLessThan(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if matchError := oglematchers.LessThan(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenLess, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeLessThan receives exactly two parameters and ensures that the first is less than or equal to the second.
|
||||
func ShouldBeLessThanOrEqualTo(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if matchError := oglematchers.LessOrEqual(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenLess, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeBetween receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is between both bounds (but not equal to either of them).
|
||||
func ShouldBeBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if !isBetween(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldHaveBeenBetween, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeBetween receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is NOT between both bounds.
|
||||
func ShouldNotBeBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if isBetween(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldNotHaveBeenBetween, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
func deriveBounds(values []interface{}) (lower interface{}, upper interface{}, fail string) {
|
||||
lower = values[0]
|
||||
upper = values[1]
|
||||
|
||||
if ShouldNotEqual(lower, upper) != success {
|
||||
return nil, nil, fmt.Sprintf(shouldHaveDifferentUpperAndLower, lower)
|
||||
} else if ShouldBeLessThan(lower, upper) != success {
|
||||
lower, upper = upper, lower
|
||||
}
|
||||
return lower, upper, success
|
||||
}
|
||||
func isBetween(value, lower, upper interface{}) bool {
|
||||
if ShouldBeGreaterThan(value, lower) != success {
|
||||
return false
|
||||
} else if ShouldBeLessThan(value, upper) != success {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ShouldBeBetweenOrEqual receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is between both bounds or equal to one of them.
|
||||
func ShouldBeBetweenOrEqual(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if !isBetweenOrEqual(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldHaveBeenBetweenOrEqual, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeBetweenOrEqual receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is nopt between the bounds nor equal to either of them.
|
||||
func ShouldNotBeBetweenOrEqual(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if isBetweenOrEqual(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldNotHaveBeenBetweenOrEqual, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func isBetweenOrEqual(value, lower, upper interface{}) bool {
|
||||
if ShouldBeGreaterThanOrEqualTo(value, lower) != success {
|
||||
return false
|
||||
} else if ShouldBeLessThanOrEqualTo(value, upper) != success {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
59
vendor/github.com/smartystreets/assertions/serializer.go
generated
vendored
59
vendor/github.com/smartystreets/assertions/serializer.go
generated
vendored
@ -1,59 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
type Serializer interface {
|
||||
serialize(expected, actual interface{}, message string) string
|
||||
serializeDetailed(expected, actual interface{}, message string) string
|
||||
}
|
||||
|
||||
type failureSerializer struct{}
|
||||
|
||||
func (self *failureSerializer) serializeDetailed(expected, actual interface{}, message string) string {
|
||||
view := self.format(expected, actual, message, "%#v")
|
||||
serialized, err := json.Marshal(view)
|
||||
if err != nil {
|
||||
return message
|
||||
}
|
||||
return string(serialized)
|
||||
}
|
||||
|
||||
func (self *failureSerializer) serialize(expected, actual interface{}, message string) string {
|
||||
view := self.format(expected, actual, message, "%+v")
|
||||
serialized, err := json.Marshal(view)
|
||||
if err != nil {
|
||||
return message
|
||||
}
|
||||
return string(serialized)
|
||||
}
|
||||
|
||||
func (self *failureSerializer) format(expected, actual interface{}, message string, format string) reporting.FailureView {
|
||||
return reporting.FailureView{
|
||||
Message: message,
|
||||
Expected: fmt.Sprintf(format, expected),
|
||||
Actual: fmt.Sprintf(format, actual),
|
||||
}
|
||||
}
|
||||
|
||||
func newSerializer() *failureSerializer {
|
||||
return &failureSerializer{}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
// noopSerializer just gives back the original message. This is useful when we are using
|
||||
// the assertions from a context other than the web UI, that requires the JSON structure
|
||||
// provided by the failureSerializer.
|
||||
type noopSerializer struct{}
|
||||
|
||||
func (self *noopSerializer) serialize(expected, actual interface{}, message string) string {
|
||||
return message
|
||||
}
|
||||
func (self *noopSerializer) serializeDetailed(expected, actual interface{}, message string) string {
|
||||
return message
|
||||
}
|
227
vendor/github.com/smartystreets/assertions/strings.go
generated
vendored
227
vendor/github.com/smartystreets/assertions/strings.go
generated
vendored
@ -1,227 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ShouldStartWith receives exactly 2 string parameters and ensures that the first starts with the second.
|
||||
func ShouldStartWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
prefix, prefixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !prefixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldStartWith(value, prefix)
|
||||
}
|
||||
func shouldStartWith(value, prefix string) string {
|
||||
if !strings.HasPrefix(value, prefix) {
|
||||
shortval := value
|
||||
if len(shortval) > len(prefix) {
|
||||
shortval = shortval[:len(prefix)] + "..."
|
||||
}
|
||||
return serializer.serialize(prefix, shortval, fmt.Sprintf(shouldHaveStartedWith, value, prefix))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotStartWith receives exactly 2 string parameters and ensures that the first does not start with the second.
|
||||
func ShouldNotStartWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
prefix, prefixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !prefixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldNotStartWith(value, prefix)
|
||||
}
|
||||
func shouldNotStartWith(value, prefix string) string {
|
||||
if strings.HasPrefix(value, prefix) {
|
||||
if value == "" {
|
||||
value = "<empty>"
|
||||
}
|
||||
if prefix == "" {
|
||||
prefix = "<empty>"
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveStartedWith, value, prefix)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldEndWith receives exactly 2 string parameters and ensures that the first ends with the second.
|
||||
func ShouldEndWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
suffix, suffixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !suffixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldEndWith(value, suffix)
|
||||
}
|
||||
func shouldEndWith(value, suffix string) string {
|
||||
if !strings.HasSuffix(value, suffix) {
|
||||
shortval := value
|
||||
if len(shortval) > len(suffix) {
|
||||
shortval = "..." + shortval[len(shortval)-len(suffix):]
|
||||
}
|
||||
return serializer.serialize(suffix, shortval, fmt.Sprintf(shouldHaveEndedWith, value, suffix))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldEndWith receives exactly 2 string parameters and ensures that the first does not end with the second.
|
||||
func ShouldNotEndWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
suffix, suffixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !suffixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldNotEndWith(value, suffix)
|
||||
}
|
||||
func shouldNotEndWith(value, suffix string) string {
|
||||
if strings.HasSuffix(value, suffix) {
|
||||
if value == "" {
|
||||
value = "<empty>"
|
||||
}
|
||||
if suffix == "" {
|
||||
suffix = "<empty>"
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveEndedWith, value, suffix)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldContainSubstring receives exactly 2 string parameters and ensures that the first contains the second as a substring.
|
||||
func ShouldContainSubstring(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
long, longOk := actual.(string)
|
||||
short, shortOk := expected[0].(string)
|
||||
|
||||
if !longOk || !shortOk {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
if !strings.Contains(long, short) {
|
||||
return serializer.serialize(expected[0], actual, fmt.Sprintf(shouldHaveContainedSubstring, long, short))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotContainSubstring receives exactly 2 string parameters and ensures that the first does NOT contain the second as a substring.
|
||||
func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
long, longOk := actual.(string)
|
||||
short, shortOk := expected[0].(string)
|
||||
|
||||
if !longOk || !shortOk {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
if strings.Contains(long, short) {
|
||||
return fmt.Sprintf(shouldNotHaveContainedSubstring, long, short)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeBlank receives exactly 1 string parameter and ensures that it is equal to "".
|
||||
func ShouldBeBlank(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
value, ok := actual.(string)
|
||||
if !ok {
|
||||
return fmt.Sprintf(shouldBeString, reflect.TypeOf(actual))
|
||||
}
|
||||
if value != "" {
|
||||
return serializer.serialize("", value, fmt.Sprintf(shouldHaveBeenBlank, value))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeBlank receives exactly 1 string parameter and ensures that it is equal to "".
|
||||
func ShouldNotBeBlank(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
value, ok := actual.(string)
|
||||
if !ok {
|
||||
return fmt.Sprintf(shouldBeString, reflect.TypeOf(actual))
|
||||
}
|
||||
if value == "" {
|
||||
return shouldNotHaveBeenBlank
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldEqualWithout receives exactly 3 string parameters and ensures that the first is equal to the second
|
||||
// after removing all instances of the third from the first using strings.Replace(first, third, "", -1).
|
||||
func ShouldEqualWithout(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualString, ok1 := actual.(string)
|
||||
expectedString, ok2 := expected[0].(string)
|
||||
replace, ok3 := expected[1].(string)
|
||||
|
||||
if !ok1 || !ok2 || !ok3 {
|
||||
return fmt.Sprintf(shouldAllBeStrings, []reflect.Type{
|
||||
reflect.TypeOf(actual),
|
||||
reflect.TypeOf(expected[0]),
|
||||
reflect.TypeOf(expected[1]),
|
||||
})
|
||||
}
|
||||
|
||||
replaced := strings.Replace(actualString, replace, "", -1)
|
||||
if replaced == expectedString {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Expected '%s' to equal '%s' but without any '%s' (but it didn't).", actualString, expectedString, replace)
|
||||
}
|
||||
|
||||
// ShouldEqualTrimSpace receives exactly 2 string parameters and ensures that the first is equal to the second
|
||||
// after removing all leading and trailing whitespace using strings.TrimSpace(first).
|
||||
func ShouldEqualTrimSpace(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
actualString, valueIsString := actual.(string)
|
||||
_, value2IsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !value2IsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
actualString = strings.TrimSpace(actualString)
|
||||
return ShouldEqual(actualString, expected[0])
|
||||
}
|
202
vendor/github.com/smartystreets/assertions/time.go
generated
vendored
202
vendor/github.com/smartystreets/assertions/time.go
generated
vendored
@ -1,202 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ShouldHappenBefore receives exactly 2 time.Time arguments and asserts that the first happens before the second.
|
||||
func ShouldHappenBefore(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
|
||||
if !actualTime.Before(expectedTime) {
|
||||
return fmt.Sprintf(shouldHaveHappenedBefore, actualTime, expectedTime, actualTime.Sub(expectedTime))
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenOnOrBefore receives exactly 2 time.Time arguments and asserts that the first happens on or before the second.
|
||||
func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
|
||||
if actualTime.Equal(expectedTime) {
|
||||
return success
|
||||
}
|
||||
return ShouldHappenBefore(actualTime, expectedTime)
|
||||
}
|
||||
|
||||
// ShouldHappenAfter receives exactly 2 time.Time arguments and asserts that the first happens after the second.
|
||||
func ShouldHappenAfter(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if !actualTime.After(expectedTime) {
|
||||
return fmt.Sprintf(shouldHaveHappenedAfter, actualTime, expectedTime, expectedTime.Sub(actualTime))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenOnOrAfter receives exactly 2 time.Time arguments and asserts that the first happens on or after the second.
|
||||
func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if actualTime.Equal(expectedTime) {
|
||||
return success
|
||||
}
|
||||
return ShouldHappenAfter(actualTime, expectedTime)
|
||||
}
|
||||
|
||||
// ShouldHappenBetween receives exactly 3 time.Time arguments and asserts that the first happens between (not on) the second and third.
|
||||
func ShouldHappenBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
min, secondOk := expected[0].(time.Time)
|
||||
max, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
|
||||
if !actualTime.After(min) {
|
||||
return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, min.Sub(actualTime))
|
||||
}
|
||||
if !actualTime.Before(max) {
|
||||
return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, actualTime.Sub(max))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first happens between or on the second and third.
|
||||
func ShouldHappenOnOrBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
min, secondOk := expected[0].(time.Time)
|
||||
max, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if actualTime.Equal(min) || actualTime.Equal(max) {
|
||||
return success
|
||||
}
|
||||
return ShouldHappenBetween(actualTime, min, max)
|
||||
}
|
||||
|
||||
// ShouldNotHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first
|
||||
// does NOT happen between or on the second or third.
|
||||
func ShouldNotHappenOnOrBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
min, secondOk := expected[0].(time.Time)
|
||||
max, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if actualTime.Equal(min) || actualTime.Equal(max) {
|
||||
return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max)
|
||||
}
|
||||
if actualTime.After(min) && actualTime.Before(max) {
|
||||
return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments)
|
||||
// and asserts that the first time.Time happens within or on the duration specified relative to
|
||||
// the other time.Time.
|
||||
func ShouldHappenWithin(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
tolerance, secondOk := expected[0].(time.Duration)
|
||||
threshold, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseDurationAndTime
|
||||
}
|
||||
|
||||
min := threshold.Add(-tolerance)
|
||||
max := threshold.Add(tolerance)
|
||||
return ShouldHappenOnOrBetween(actualTime, min, max)
|
||||
}
|
||||
|
||||
// ShouldNotHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments)
|
||||
// and asserts that the first time.Time does NOT happen within or on the duration specified relative to
|
||||
// the other time.Time.
|
||||
func ShouldNotHappenWithin(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
tolerance, secondOk := expected[0].(time.Duration)
|
||||
threshold, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseDurationAndTime
|
||||
}
|
||||
|
||||
min := threshold.Add(-tolerance)
|
||||
max := threshold.Add(tolerance)
|
||||
return ShouldNotHappenOnOrBetween(actualTime, min, max)
|
||||
}
|
||||
|
||||
// ShouldBeChronological receives a []time.Time slice and asserts that the are
|
||||
// in chronological order starting with the first time.Time as the earliest.
|
||||
func ShouldBeChronological(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
times, ok := actual.([]time.Time)
|
||||
if !ok {
|
||||
return shouldUseTimeSlice
|
||||
}
|
||||
|
||||
var previous time.Time
|
||||
for i, current := range times {
|
||||
if i > 0 && current.Before(previous) {
|
||||
return fmt.Sprintf(shouldHaveBeenChronological,
|
||||
i, i-1, previous.String(), i, current.String())
|
||||
}
|
||||
previous = current
|
||||
}
|
||||
return ""
|
||||
}
|
112
vendor/github.com/smartystreets/assertions/type.go
generated
vendored
112
vendor/github.com/smartystreets/assertions/type.go
generated
vendored
@ -1,112 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ShouldHaveSameTypeAs receives exactly two parameters and compares their underlying types for equality.
|
||||
func ShouldHaveSameTypeAs(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
first := reflect.TypeOf(actual)
|
||||
second := reflect.TypeOf(expected[0])
|
||||
|
||||
if equal := ShouldEqual(first, second); equal != success {
|
||||
return serializer.serialize(second, first, fmt.Sprintf(shouldHaveBeenA, actual, second, first))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotHaveSameTypeAs receives exactly two parameters and compares their underlying types for inequality.
|
||||
func ShouldNotHaveSameTypeAs(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
first := reflect.TypeOf(actual)
|
||||
second := reflect.TypeOf(expected[0])
|
||||
|
||||
if equal := ShouldEqual(first, second); equal == success {
|
||||
return fmt.Sprintf(shouldNotHaveBeenA, actual, second)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldImplement receives exactly two parameters and ensures
|
||||
// that the first implements the interface type of the second.
|
||||
func ShouldImplement(actual interface{}, expectedList ...interface{}) string {
|
||||
if fail := need(1, expectedList); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
expected := expectedList[0]
|
||||
if fail := ShouldBeNil(expected); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
if fail := ShouldNotBeNil(actual); fail != success {
|
||||
return shouldNotBeNilActual
|
||||
}
|
||||
|
||||
var actualType reflect.Type
|
||||
if reflect.TypeOf(actual).Kind() != reflect.Ptr {
|
||||
actualType = reflect.PtrTo(reflect.TypeOf(actual))
|
||||
} else {
|
||||
actualType = reflect.TypeOf(actual)
|
||||
}
|
||||
|
||||
expectedType := reflect.TypeOf(expected)
|
||||
if fail := ShouldNotBeNil(expectedType); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
expectedInterface := expectedType.Elem()
|
||||
|
||||
if actualType == nil {
|
||||
return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actual)
|
||||
}
|
||||
|
||||
if !actualType.Implements(expectedInterface) {
|
||||
return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actualType)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotImplement receives exactly two parameters and ensures
|
||||
// that the first does NOT implement the interface type of the second.
|
||||
func ShouldNotImplement(actual interface{}, expectedList ...interface{}) string {
|
||||
if fail := need(1, expectedList); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
expected := expectedList[0]
|
||||
if fail := ShouldBeNil(expected); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
if fail := ShouldNotBeNil(actual); fail != success {
|
||||
return shouldNotBeNilActual
|
||||
}
|
||||
|
||||
var actualType reflect.Type
|
||||
if reflect.TypeOf(actual).Kind() != reflect.Ptr {
|
||||
actualType = reflect.PtrTo(reflect.TypeOf(actual))
|
||||
} else {
|
||||
actualType = reflect.TypeOf(actual)
|
||||
}
|
||||
|
||||
expectedType := reflect.TypeOf(expected)
|
||||
if fail := ShouldNotBeNil(expectedType); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
expectedInterface := expectedType.Elem()
|
||||
|
||||
if actualType.Implements(expectedInterface) {
|
||||
return fmt.Sprintf(shouldNotHaveImplemented, actualType, expectedInterface)
|
||||
}
|
||||
return success
|
||||
}
|
23
vendor/github.com/smartystreets/goconvey/LICENSE.md
generated
vendored
23
vendor/github.com/smartystreets/goconvey/LICENSE.md
generated
vendored
@ -1,23 +0,0 @@
|
||||
Copyright (c) 2014 SmartyStreets, LLC
|
||||
|
||||
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.
|
||||
|
||||
NOTE: Various optional and subordinate components carry their own licensing
|
||||
requirements and restrictions. Use of those components is subject to the terms
|
||||
and conditions outlined the respective license of each component.
|
68
vendor/github.com/smartystreets/goconvey/convey/assertions.go
generated
vendored
68
vendor/github.com/smartystreets/goconvey/convey/assertions.go
generated
vendored
@ -1,68 +0,0 @@
|
||||
package convey
|
||||
|
||||
import "github.com/smartystreets/assertions"
|
||||
|
||||
var (
|
||||
ShouldEqual = assertions.ShouldEqual
|
||||
ShouldNotEqual = assertions.ShouldNotEqual
|
||||
ShouldAlmostEqual = assertions.ShouldAlmostEqual
|
||||
ShouldNotAlmostEqual = assertions.ShouldNotAlmostEqual
|
||||
ShouldResemble = assertions.ShouldResemble
|
||||
ShouldNotResemble = assertions.ShouldNotResemble
|
||||
ShouldPointTo = assertions.ShouldPointTo
|
||||
ShouldNotPointTo = assertions.ShouldNotPointTo
|
||||
ShouldBeNil = assertions.ShouldBeNil
|
||||
ShouldNotBeNil = assertions.ShouldNotBeNil
|
||||
ShouldBeTrue = assertions.ShouldBeTrue
|
||||
ShouldBeFalse = assertions.ShouldBeFalse
|
||||
ShouldBeZeroValue = assertions.ShouldBeZeroValue
|
||||
|
||||
ShouldBeGreaterThan = assertions.ShouldBeGreaterThan
|
||||
ShouldBeGreaterThanOrEqualTo = assertions.ShouldBeGreaterThanOrEqualTo
|
||||
ShouldBeLessThan = assertions.ShouldBeLessThan
|
||||
ShouldBeLessThanOrEqualTo = assertions.ShouldBeLessThanOrEqualTo
|
||||
ShouldBeBetween = assertions.ShouldBeBetween
|
||||
ShouldNotBeBetween = assertions.ShouldNotBeBetween
|
||||
ShouldBeBetweenOrEqual = assertions.ShouldBeBetweenOrEqual
|
||||
ShouldNotBeBetweenOrEqual = assertions.ShouldNotBeBetweenOrEqual
|
||||
|
||||
ShouldContain = assertions.ShouldContain
|
||||
ShouldNotContain = assertions.ShouldNotContain
|
||||
ShouldContainKey = assertions.ShouldContainKey
|
||||
ShouldNotContainKey = assertions.ShouldNotContainKey
|
||||
ShouldBeIn = assertions.ShouldBeIn
|
||||
ShouldNotBeIn = assertions.ShouldNotBeIn
|
||||
ShouldBeEmpty = assertions.ShouldBeEmpty
|
||||
ShouldNotBeEmpty = assertions.ShouldNotBeEmpty
|
||||
ShouldHaveLength = assertions.ShouldHaveLength
|
||||
|
||||
ShouldStartWith = assertions.ShouldStartWith
|
||||
ShouldNotStartWith = assertions.ShouldNotStartWith
|
||||
ShouldEndWith = assertions.ShouldEndWith
|
||||
ShouldNotEndWith = assertions.ShouldNotEndWith
|
||||
ShouldBeBlank = assertions.ShouldBeBlank
|
||||
ShouldNotBeBlank = assertions.ShouldNotBeBlank
|
||||
ShouldContainSubstring = assertions.ShouldContainSubstring
|
||||
ShouldNotContainSubstring = assertions.ShouldNotContainSubstring
|
||||
|
||||
ShouldPanic = assertions.ShouldPanic
|
||||
ShouldNotPanic = assertions.ShouldNotPanic
|
||||
ShouldPanicWith = assertions.ShouldPanicWith
|
||||
ShouldNotPanicWith = assertions.ShouldNotPanicWith
|
||||
|
||||
ShouldHaveSameTypeAs = assertions.ShouldHaveSameTypeAs
|
||||
ShouldNotHaveSameTypeAs = assertions.ShouldNotHaveSameTypeAs
|
||||
ShouldImplement = assertions.ShouldImplement
|
||||
ShouldNotImplement = assertions.ShouldNotImplement
|
||||
|
||||
ShouldHappenBefore = assertions.ShouldHappenBefore
|
||||
ShouldHappenOnOrBefore = assertions.ShouldHappenOnOrBefore
|
||||
ShouldHappenAfter = assertions.ShouldHappenAfter
|
||||
ShouldHappenOnOrAfter = assertions.ShouldHappenOnOrAfter
|
||||
ShouldHappenBetween = assertions.ShouldHappenBetween
|
||||
ShouldHappenOnOrBetween = assertions.ShouldHappenOnOrBetween
|
||||
ShouldNotHappenOnOrBetween = assertions.ShouldNotHappenOnOrBetween
|
||||
ShouldHappenWithin = assertions.ShouldHappenWithin
|
||||
ShouldNotHappenWithin = assertions.ShouldNotHappenWithin
|
||||
ShouldBeChronological = assertions.ShouldBeChronological
|
||||
)
|
272
vendor/github.com/smartystreets/goconvey/convey/context.go
generated
vendored
272
vendor/github.com/smartystreets/goconvey/convey/context.go
generated
vendored
@ -1,272 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jtolds/gls"
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
type conveyErr struct {
|
||||
fmt string
|
||||
params []interface{}
|
||||
}
|
||||
|
||||
func (e *conveyErr) Error() string {
|
||||
return fmt.Sprintf(e.fmt, e.params...)
|
||||
}
|
||||
|
||||
func conveyPanic(fmt string, params ...interface{}) {
|
||||
panic(&conveyErr{fmt, params})
|
||||
}
|
||||
|
||||
const (
|
||||
missingGoTest = `Top-level calls to Convey(...) need a reference to the *testing.T.
|
||||
Hint: Convey("description here", t, func() { /* notice that the second argument was the *testing.T (t)! */ }) `
|
||||
extraGoTest = `Only the top-level call to Convey(...) needs a reference to the *testing.T.`
|
||||
noStackContext = "Convey operation made without context on goroutine stack.\n" +
|
||||
"Hint: Perhaps you meant to use `Convey(..., func(c C){...})` ?"
|
||||
differentConveySituations = "Different set of Convey statements on subsequent pass!\nDid not expect %#v."
|
||||
multipleIdenticalConvey = "Multiple convey suites with identical names: %#v"
|
||||
)
|
||||
|
||||
const (
|
||||
failureHalt = "___FAILURE_HALT___"
|
||||
|
||||
nodeKey = "node"
|
||||
)
|
||||
|
||||
///////////////////////////////// Stack Context /////////////////////////////////
|
||||
|
||||
func getCurrentContext() *context {
|
||||
ctx, ok := ctxMgr.GetValue(nodeKey)
|
||||
if ok {
|
||||
return ctx.(*context)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mustGetCurrentContext() *context {
|
||||
ctx := getCurrentContext()
|
||||
if ctx == nil {
|
||||
conveyPanic(noStackContext)
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
//////////////////////////////////// Context ////////////////////////////////////
|
||||
|
||||
// context magically handles all coordination of Convey's and So assertions.
|
||||
//
|
||||
// It is tracked on the stack as goroutine-local-storage with the gls package,
|
||||
// or explicitly if the user decides to call convey like:
|
||||
//
|
||||
// Convey(..., func(c C) {
|
||||
// c.So(...)
|
||||
// })
|
||||
//
|
||||
// This implements the `C` interface.
|
||||
type context struct {
|
||||
reporter reporting.Reporter
|
||||
|
||||
children map[string]*context
|
||||
|
||||
resets []func()
|
||||
|
||||
executedOnce bool
|
||||
expectChildRun *bool
|
||||
complete bool
|
||||
|
||||
focus bool
|
||||
failureMode FailureMode
|
||||
}
|
||||
|
||||
// rootConvey is the main entry point to a test suite. This is called when
|
||||
// there's no context in the stack already, and items must contain a `t` object,
|
||||
// or this panics.
|
||||
func rootConvey(items ...interface{}) {
|
||||
entry := discover(items)
|
||||
|
||||
if entry.Test == nil {
|
||||
conveyPanic(missingGoTest)
|
||||
}
|
||||
|
||||
expectChildRun := true
|
||||
ctx := &context{
|
||||
reporter: buildReporter(),
|
||||
|
||||
children: make(map[string]*context),
|
||||
|
||||
expectChildRun: &expectChildRun,
|
||||
|
||||
focus: entry.Focus,
|
||||
failureMode: defaultFailureMode.combine(entry.FailMode),
|
||||
}
|
||||
ctxMgr.SetValues(gls.Values{nodeKey: ctx}, func() {
|
||||
ctx.reporter.BeginStory(reporting.NewStoryReport(entry.Test))
|
||||
defer ctx.reporter.EndStory()
|
||||
|
||||
for ctx.shouldVisit() {
|
||||
ctx.conveyInner(entry.Situation, entry.Func)
|
||||
expectChildRun = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//////////////////////////////////// Methods ////////////////////////////////////
|
||||
|
||||
func (ctx *context) SkipConvey(items ...interface{}) {
|
||||
ctx.Convey(items, skipConvey)
|
||||
}
|
||||
|
||||
func (ctx *context) FocusConvey(items ...interface{}) {
|
||||
ctx.Convey(items, focusConvey)
|
||||
}
|
||||
|
||||
func (ctx *context) Convey(items ...interface{}) {
|
||||
entry := discover(items)
|
||||
|
||||
// we're a branch, or leaf (on the wind)
|
||||
if entry.Test != nil {
|
||||
conveyPanic(extraGoTest)
|
||||
}
|
||||
if ctx.focus && !entry.Focus {
|
||||
return
|
||||
}
|
||||
|
||||
var inner_ctx *context
|
||||
if ctx.executedOnce {
|
||||
var ok bool
|
||||
inner_ctx, ok = ctx.children[entry.Situation]
|
||||
if !ok {
|
||||
conveyPanic(differentConveySituations, entry.Situation)
|
||||
}
|
||||
} else {
|
||||
if _, ok := ctx.children[entry.Situation]; ok {
|
||||
conveyPanic(multipleIdenticalConvey, entry.Situation)
|
||||
}
|
||||
inner_ctx = &context{
|
||||
reporter: ctx.reporter,
|
||||
|
||||
children: make(map[string]*context),
|
||||
|
||||
expectChildRun: ctx.expectChildRun,
|
||||
|
||||
focus: entry.Focus,
|
||||
failureMode: ctx.failureMode.combine(entry.FailMode),
|
||||
}
|
||||
ctx.children[entry.Situation] = inner_ctx
|
||||
}
|
||||
|
||||
if inner_ctx.shouldVisit() {
|
||||
ctxMgr.SetValues(gls.Values{nodeKey: inner_ctx}, func() {
|
||||
inner_ctx.conveyInner(entry.Situation, entry.Func)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *context) SkipSo(stuff ...interface{}) {
|
||||
ctx.assertionReport(reporting.NewSkipReport())
|
||||
}
|
||||
|
||||
func (ctx *context) So(actual interface{}, assert assertion, expected ...interface{}) {
|
||||
if result := assert(actual, expected...); result == assertionSuccess {
|
||||
ctx.assertionReport(reporting.NewSuccessReport())
|
||||
} else {
|
||||
ctx.assertionReport(reporting.NewFailureReport(result))
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *context) Reset(action func()) {
|
||||
/* TODO: Failure mode configuration */
|
||||
ctx.resets = append(ctx.resets, action)
|
||||
}
|
||||
|
||||
func (ctx *context) Print(items ...interface{}) (int, error) {
|
||||
fmt.Fprint(ctx.reporter, items...)
|
||||
return fmt.Print(items...)
|
||||
}
|
||||
|
||||
func (ctx *context) Println(items ...interface{}) (int, error) {
|
||||
fmt.Fprintln(ctx.reporter, items...)
|
||||
return fmt.Println(items...)
|
||||
}
|
||||
|
||||
func (ctx *context) Printf(format string, items ...interface{}) (int, error) {
|
||||
fmt.Fprintf(ctx.reporter, format, items...)
|
||||
return fmt.Printf(format, items...)
|
||||
}
|
||||
|
||||
//////////////////////////////////// Private ////////////////////////////////////
|
||||
|
||||
// shouldVisit returns true iff we should traverse down into a Convey. Note
|
||||
// that just because we don't traverse a Convey this time, doesn't mean that
|
||||
// we may not traverse it on a subsequent pass.
|
||||
func (c *context) shouldVisit() bool {
|
||||
return !c.complete && *c.expectChildRun
|
||||
}
|
||||
|
||||
// conveyInner is the function which actually executes the user's anonymous test
|
||||
// function body. At this point, Convey or RootConvey has decided that this
|
||||
// function should actually run.
|
||||
func (ctx *context) conveyInner(situation string, f func(C)) {
|
||||
// Record/Reset state for next time.
|
||||
defer func() {
|
||||
ctx.executedOnce = true
|
||||
|
||||
// This is only needed at the leaves, but there's no harm in also setting it
|
||||
// when returning from branch Convey's
|
||||
*ctx.expectChildRun = false
|
||||
}()
|
||||
|
||||
// Set up+tear down our scope for the reporter
|
||||
ctx.reporter.Enter(reporting.NewScopeReport(situation))
|
||||
defer ctx.reporter.Exit()
|
||||
|
||||
// Recover from any panics in f, and assign the `complete` status for this
|
||||
// node of the tree.
|
||||
defer func() {
|
||||
ctx.complete = true
|
||||
if problem := recover(); problem != nil {
|
||||
if problem, ok := problem.(*conveyErr); ok {
|
||||
panic(problem)
|
||||
}
|
||||
if problem != failureHalt {
|
||||
ctx.reporter.Report(reporting.NewErrorReport(problem))
|
||||
}
|
||||
} else {
|
||||
for _, child := range ctx.children {
|
||||
if !child.complete {
|
||||
ctx.complete = false
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Resets are registered as the `f` function executes, so nil them here.
|
||||
// All resets are run in registration order (FIFO).
|
||||
ctx.resets = []func(){}
|
||||
defer func() {
|
||||
for _, r := range ctx.resets {
|
||||
// panics handled by the previous defer
|
||||
r()
|
||||
}
|
||||
}()
|
||||
|
||||
if f == nil {
|
||||
// if f is nil, this was either a Convey(..., nil), or a SkipConvey
|
||||
ctx.reporter.Report(reporting.NewSkipReport())
|
||||
} else {
|
||||
f(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// assertionReport is a helper for So and SkipSo which makes the report and
|
||||
// then possibly panics, depending on the current context's failureMode.
|
||||
func (ctx *context) assertionReport(r *reporting.AssertionResult) {
|
||||
ctx.reporter.Report(r)
|
||||
if r.Failure != "" && ctx.failureMode == FailureHalts {
|
||||
panic(failureHalt)
|
||||
}
|
||||
}
|
4
vendor/github.com/smartystreets/goconvey/convey/convey.goconvey
generated
vendored
4
vendor/github.com/smartystreets/goconvey/convey/convey.goconvey
generated
vendored
@ -1,4 +0,0 @@
|
||||
#ignore
|
||||
-timeout=1s
|
||||
#-covermode=count
|
||||
#-coverpkg=github.com/smartystreets/goconvey/convey,github.com/smartystreets/goconvey/convey/gotest,github.com/smartystreets/goconvey/convey/reporting
|
103
vendor/github.com/smartystreets/goconvey/convey/discovery.go
generated
vendored
103
vendor/github.com/smartystreets/goconvey/convey/discovery.go
generated
vendored
@ -1,103 +0,0 @@
|
||||
package convey
|
||||
|
||||
type actionSpecifier uint8
|
||||
|
||||
const (
|
||||
noSpecifier actionSpecifier = iota
|
||||
skipConvey
|
||||
focusConvey
|
||||
)
|
||||
|
||||
type suite struct {
|
||||
Situation string
|
||||
Test t
|
||||
Focus bool
|
||||
Func func(C) // nil means skipped
|
||||
FailMode FailureMode
|
||||
}
|
||||
|
||||
func newSuite(situation string, failureMode FailureMode, f func(C), test t, specifier actionSpecifier) *suite {
|
||||
ret := &suite{
|
||||
Situation: situation,
|
||||
Test: test,
|
||||
Func: f,
|
||||
FailMode: failureMode,
|
||||
}
|
||||
switch specifier {
|
||||
case skipConvey:
|
||||
ret.Func = nil
|
||||
case focusConvey:
|
||||
ret.Focus = true
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func discover(items []interface{}) *suite {
|
||||
name, items := parseName(items)
|
||||
test, items := parseGoTest(items)
|
||||
failure, items := parseFailureMode(items)
|
||||
action, items := parseAction(items)
|
||||
specifier, items := parseSpecifier(items)
|
||||
|
||||
if len(items) != 0 {
|
||||
conveyPanic(parseError)
|
||||
}
|
||||
|
||||
return newSuite(name, failure, action, test, specifier)
|
||||
}
|
||||
func item(items []interface{}) interface{} {
|
||||
if len(items) == 0 {
|
||||
conveyPanic(parseError)
|
||||
}
|
||||
return items[0]
|
||||
}
|
||||
func parseName(items []interface{}) (string, []interface{}) {
|
||||
if name, parsed := item(items).(string); parsed {
|
||||
return name, items[1:]
|
||||
}
|
||||
conveyPanic(parseError)
|
||||
panic("never get here")
|
||||
}
|
||||
func parseGoTest(items []interface{}) (t, []interface{}) {
|
||||
if test, parsed := item(items).(t); parsed {
|
||||
return test, items[1:]
|
||||
}
|
||||
return nil, items
|
||||
}
|
||||
func parseFailureMode(items []interface{}) (FailureMode, []interface{}) {
|
||||
if mode, parsed := item(items).(FailureMode); parsed {
|
||||
return mode, items[1:]
|
||||
}
|
||||
return FailureInherits, items
|
||||
}
|
||||
func parseAction(items []interface{}) (func(C), []interface{}) {
|
||||
switch x := item(items).(type) {
|
||||
case nil:
|
||||
return nil, items[1:]
|
||||
case func(C):
|
||||
return x, items[1:]
|
||||
case func():
|
||||
return func(C) { x() }, items[1:]
|
||||
}
|
||||
conveyPanic(parseError)
|
||||
panic("never get here")
|
||||
}
|
||||
func parseSpecifier(items []interface{}) (actionSpecifier, []interface{}) {
|
||||
if len(items) == 0 {
|
||||
return noSpecifier, items
|
||||
}
|
||||
if spec, ok := items[0].(actionSpecifier); ok {
|
||||
return spec, items[1:]
|
||||
}
|
||||
conveyPanic(parseError)
|
||||
panic("never get here")
|
||||
}
|
||||
|
||||
// This interface allows us to pass the *testing.T struct
|
||||
// throughout the internals of this package without ever
|
||||
// having to import the "testing" package.
|
||||
type t interface {
|
||||
Fail()
|
||||
}
|
||||
|
||||
const parseError = "You must provide a name (string), then a *testing.T (if in outermost scope), an optional FailureMode, and then an action (func())."
|
218
vendor/github.com/smartystreets/goconvey/convey/doc.go
generated
vendored
218
vendor/github.com/smartystreets/goconvey/convey/doc.go
generated
vendored
@ -1,218 +0,0 @@
|
||||
// Package convey contains all of the public-facing entry points to this project.
|
||||
// This means that it should never be required of the user to import any other
|
||||
// packages from this project as they serve internal purposes.
|
||||
package convey
|
||||
|
||||
import "github.com/smartystreets/goconvey/convey/reporting"
|
||||
|
||||
////////////////////////////////// suite //////////////////////////////////
|
||||
|
||||
// C is the Convey context which you can optionally obtain in your action
|
||||
// by calling Convey like:
|
||||
//
|
||||
// Convey(..., func(c C) {
|
||||
// ...
|
||||
// })
|
||||
//
|
||||
// See the documentation on Convey for more details.
|
||||
//
|
||||
// All methods in this context behave identically to the global functions of the
|
||||
// same name in this package.
|
||||
type C interface {
|
||||
Convey(items ...interface{})
|
||||
SkipConvey(items ...interface{})
|
||||
FocusConvey(items ...interface{})
|
||||
|
||||
So(actual interface{}, assert assertion, expected ...interface{})
|
||||
SkipSo(stuff ...interface{})
|
||||
|
||||
Reset(action func())
|
||||
|
||||
Println(items ...interface{}) (int, error)
|
||||
Print(items ...interface{}) (int, error)
|
||||
Printf(format string, items ...interface{}) (int, error)
|
||||
}
|
||||
|
||||
// Convey is the method intended for use when declaring the scopes of
|
||||
// a specification. Each scope has a description and a func() which may contain
|
||||
// other calls to Convey(), Reset() or Should-style assertions. Convey calls can
|
||||
// be nested as far as you see fit.
|
||||
//
|
||||
// IMPORTANT NOTE: The top-level Convey() within a Test method
|
||||
// must conform to the following signature:
|
||||
//
|
||||
// Convey(description string, t *testing.T, action func())
|
||||
//
|
||||
// All other calls should look like this (no need to pass in *testing.T):
|
||||
//
|
||||
// Convey(description string, action func())
|
||||
//
|
||||
// Don't worry, goconvey will panic if you get it wrong so you can fix it.
|
||||
//
|
||||
// Additionally, you may explicitly obtain access to the Convey context by doing:
|
||||
//
|
||||
// Convey(description string, action func(c C))
|
||||
//
|
||||
// You may need to do this if you want to pass the context through to a
|
||||
// goroutine, or to close over the context in a handler to a library which
|
||||
// calls your handler in a goroutine (httptest comes to mind).
|
||||
//
|
||||
// All Convey()-blocks also accept an optional parameter of FailureMode which sets
|
||||
// how goconvey should treat failures for So()-assertions in the block and
|
||||
// nested blocks. See the constants in this file for the available options.
|
||||
//
|
||||
// By default it will inherit from its parent block and the top-level blocks
|
||||
// default to the FailureHalts setting.
|
||||
//
|
||||
// This parameter is inserted before the block itself:
|
||||
//
|
||||
// Convey(description string, t *testing.T, mode FailureMode, action func())
|
||||
// Convey(description string, mode FailureMode, action func())
|
||||
//
|
||||
// See the examples package for, well, examples.
|
||||
func Convey(items ...interface{}) {
|
||||
if ctx := getCurrentContext(); ctx == nil {
|
||||
rootConvey(items...)
|
||||
} else {
|
||||
ctx.Convey(items...)
|
||||
}
|
||||
}
|
||||
|
||||
// SkipConvey is analagous to Convey except that the scope is not executed
|
||||
// (which means that child scopes defined within this scope are not run either).
|
||||
// The reporter will be notified that this step was skipped.
|
||||
func SkipConvey(items ...interface{}) {
|
||||
Convey(append(items, skipConvey)...)
|
||||
}
|
||||
|
||||
// FocusConvey is has the inverse effect of SkipConvey. If the top-level
|
||||
// Convey is changed to `FocusConvey`, only nested scopes that are defined
|
||||
// with FocusConvey will be run. The rest will be ignored completely. This
|
||||
// is handy when debugging a large suite that runs a misbehaving function
|
||||
// repeatedly as you can disable all but one of that function
|
||||
// without swaths of `SkipConvey` calls, just a targeted chain of calls
|
||||
// to FocusConvey.
|
||||
func FocusConvey(items ...interface{}) {
|
||||
Convey(append(items, focusConvey)...)
|
||||
}
|
||||
|
||||
// Reset registers a cleanup function to be run after each Convey()
|
||||
// in the same scope. See the examples package for a simple use case.
|
||||
func Reset(action func()) {
|
||||
mustGetCurrentContext().Reset(action)
|
||||
}
|
||||
|
||||
/////////////////////////////////// Assertions ///////////////////////////////////
|
||||
|
||||
// assertion is an alias for a function with a signature that the convey.So()
|
||||
// method can handle. Any future or custom assertions should conform to this
|
||||
// method signature. The return value should be an empty string if the assertion
|
||||
// passes and a well-formed failure message if not.
|
||||
type assertion func(actual interface{}, expected ...interface{}) string
|
||||
|
||||
const assertionSuccess = ""
|
||||
|
||||
// So is the means by which assertions are made against the system under test.
|
||||
// The majority of exported names in the assertions package begin with the word
|
||||
// 'Should' and describe how the first argument (actual) should compare with any
|
||||
// of the final (expected) arguments. How many final arguments are accepted
|
||||
// depends on the particular assertion that is passed in as the assert argument.
|
||||
// See the examples package for use cases and the assertions package for
|
||||
// documentation on specific assertion methods. A failing assertion will
|
||||
// cause t.Fail() to be invoked--you should never call this method (or other
|
||||
// failure-inducing methods) in your test code. Leave that to GoConvey.
|
||||
func So(actual interface{}, assert assertion, expected ...interface{}) {
|
||||
mustGetCurrentContext().So(actual, assert, expected...)
|
||||
}
|
||||
|
||||
// SkipSo is analagous to So except that the assertion that would have been passed
|
||||
// to So is not executed and the reporter is notified that the assertion was skipped.
|
||||
func SkipSo(stuff ...interface{}) {
|
||||
mustGetCurrentContext().SkipSo()
|
||||
}
|
||||
|
||||
// FailureMode is a type which determines how the So() blocks should fail
|
||||
// if their assertion fails. See constants further down for acceptable values
|
||||
type FailureMode string
|
||||
|
||||
const (
|
||||
|
||||
// FailureContinues is a failure mode which prevents failing
|
||||
// So()-assertions from halting Convey-block execution, instead
|
||||
// allowing the test to continue past failing So()-assertions.
|
||||
FailureContinues FailureMode = "continue"
|
||||
|
||||
// FailureHalts is the default setting for a top-level Convey()-block
|
||||
// and will cause all failing So()-assertions to halt further execution
|
||||
// in that test-arm and continue on to the next arm.
|
||||
FailureHalts FailureMode = "halt"
|
||||
|
||||
// FailureInherits is the default setting for failure-mode, it will
|
||||
// default to the failure-mode of the parent block. You should never
|
||||
// need to specify this mode in your tests..
|
||||
FailureInherits FailureMode = "inherits"
|
||||
)
|
||||
|
||||
func (f FailureMode) combine(other FailureMode) FailureMode {
|
||||
if other == FailureInherits {
|
||||
return f
|
||||
}
|
||||
return other
|
||||
}
|
||||
|
||||
var defaultFailureMode FailureMode = FailureHalts
|
||||
|
||||
// SetDefaultFailureMode allows you to specify the default failure mode
|
||||
// for all Convey blocks. It is meant to be used in an init function to
|
||||
// allow the default mode to be changdd across all tests for an entire packgae
|
||||
// but it can be used anywhere.
|
||||
func SetDefaultFailureMode(mode FailureMode) {
|
||||
if mode == FailureContinues || mode == FailureHalts {
|
||||
defaultFailureMode = mode
|
||||
} else {
|
||||
panic("You may only use the constants named 'FailureContinues' and 'FailureHalts' as default failure modes.")
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////// Print functions ////////////////////////////////////
|
||||
|
||||
// Print is analogous to fmt.Print (and it even calls fmt.Print). It ensures that
|
||||
// output is aligned with the corresponding scopes in the web UI.
|
||||
func Print(items ...interface{}) (written int, err error) {
|
||||
return mustGetCurrentContext().Print(items...)
|
||||
}
|
||||
|
||||
// Print is analogous to fmt.Println (and it even calls fmt.Println). It ensures that
|
||||
// output is aligned with the corresponding scopes in the web UI.
|
||||
func Println(items ...interface{}) (written int, err error) {
|
||||
return mustGetCurrentContext().Println(items...)
|
||||
}
|
||||
|
||||
// Print is analogous to fmt.Printf (and it even calls fmt.Printf). It ensures that
|
||||
// output is aligned with the corresponding scopes in the web UI.
|
||||
func Printf(format string, items ...interface{}) (written int, err error) {
|
||||
return mustGetCurrentContext().Printf(format, items...)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SuppressConsoleStatistics prevents automatic printing of console statistics.
|
||||
// Calling PrintConsoleStatistics explicitly will force printing of statistics.
|
||||
func SuppressConsoleStatistics() {
|
||||
reporting.SuppressConsoleStatistics()
|
||||
}
|
||||
|
||||
// ConsoleStatistics may be called at any time to print assertion statistics.
|
||||
// Generally, the best place to do this would be in a TestMain function,
|
||||
// after all tests have been run. Something like this:
|
||||
//
|
||||
// func TestMain(m *testing.M) {
|
||||
// convey.SuppressConsoleStatistics()
|
||||
// result := m.Run()
|
||||
// convey.PrintConsoleStatistics()
|
||||
// os.Exit(result)
|
||||
// }
|
||||
//
|
||||
func PrintConsoleStatistics() {
|
||||
reporting.PrintConsoleStatistics()
|
||||
}
|
28
vendor/github.com/smartystreets/goconvey/convey/gotest/utils.go
generated
vendored
28
vendor/github.com/smartystreets/goconvey/convey/gotest/utils.go
generated
vendored
@ -1,28 +0,0 @@
|
||||
// Package gotest contains internal functionality. Although this package
|
||||
// contains one or more exported names it is not intended for public
|
||||
// consumption. See the examples package for how to use this project.
|
||||
package gotest
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ResolveExternalCaller() (file string, line int, name string) {
|
||||
var caller_id uintptr
|
||||
callers := runtime.Callers(0, callStack)
|
||||
|
||||
for x := 0; x < callers; x++ {
|
||||
caller_id, file, line, _ = runtime.Caller(x)
|
||||
if strings.HasSuffix(file, "_test.go") || strings.HasSuffix(file, "_tests.go") {
|
||||
name = runtime.FuncForPC(caller_id).Name()
|
||||
return
|
||||
}
|
||||
}
|
||||
file, line, name = "<unkown file>", -1, "<unknown name>"
|
||||
return // panic?
|
||||
}
|
||||
|
||||
const maxStackDepth = 100 // This had better be enough...
|
||||
|
||||
var callStack []uintptr = make([]uintptr, maxStackDepth, maxStackDepth)
|
81
vendor/github.com/smartystreets/goconvey/convey/init.go
generated
vendored
81
vendor/github.com/smartystreets/goconvey/convey/init.go
generated
vendored
@ -1,81 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/jtolds/gls"
|
||||
"github.com/smartystreets/assertions"
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
func init() {
|
||||
assertions.GoConveyMode(true)
|
||||
|
||||
declareFlags()
|
||||
|
||||
ctxMgr = gls.NewContextManager()
|
||||
}
|
||||
|
||||
func declareFlags() {
|
||||
flag.BoolVar(&json, "json", false, "When true, emits results in JSON blocks. Default: 'false'")
|
||||
flag.BoolVar(&silent, "silent", false, "When true, all output from GoConvey is suppressed.")
|
||||
flag.BoolVar(&story, "story", false, "When true, emits story output, otherwise emits dot output. When not provided, this flag mirros the value of the '-test.v' flag")
|
||||
|
||||
if noStoryFlagProvided() {
|
||||
story = verboseEnabled
|
||||
}
|
||||
|
||||
// FYI: flag.Parse() is called from the testing package.
|
||||
}
|
||||
|
||||
func noStoryFlagProvided() bool {
|
||||
return !story && !storyDisabled
|
||||
}
|
||||
|
||||
func buildReporter() reporting.Reporter {
|
||||
selectReporter := os.Getenv("GOCONVEY_REPORTER")
|
||||
|
||||
switch {
|
||||
case testReporter != nil:
|
||||
return testReporter
|
||||
case json || selectReporter == "json":
|
||||
return reporting.BuildJsonReporter()
|
||||
case silent || selectReporter == "silent":
|
||||
return reporting.BuildSilentReporter()
|
||||
case selectReporter == "dot":
|
||||
// Story is turned on when verbose is set, so we need to check for dot reporter first.
|
||||
return reporting.BuildDotReporter()
|
||||
case story || selectReporter == "story":
|
||||
return reporting.BuildStoryReporter()
|
||||
default:
|
||||
return reporting.BuildDotReporter()
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
ctxMgr *gls.ContextManager
|
||||
|
||||
// only set by internal tests
|
||||
testReporter reporting.Reporter
|
||||
)
|
||||
|
||||
var (
|
||||
json bool
|
||||
silent bool
|
||||
story bool
|
||||
|
||||
verboseEnabled = flagFound("-test.v=true")
|
||||
storyDisabled = flagFound("-story=false")
|
||||
)
|
||||
|
||||
// flagFound parses the command line args manually for flags defined in other
|
||||
// packages. Like the '-v' flag from the "testing" package, for instance.
|
||||
func flagFound(flagValue string) bool {
|
||||
for _, arg := range os.Args {
|
||||
if arg == flagValue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
15
vendor/github.com/smartystreets/goconvey/convey/nilReporter.go
generated
vendored
15
vendor/github.com/smartystreets/goconvey/convey/nilReporter.go
generated
vendored
@ -1,15 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
type nilReporter struct{}
|
||||
|
||||
func (self *nilReporter) BeginStory(story *reporting.StoryReport) {}
|
||||
func (self *nilReporter) Enter(scope *reporting.ScopeReport) {}
|
||||
func (self *nilReporter) Report(report *reporting.AssertionResult) {}
|
||||
func (self *nilReporter) Exit() {}
|
||||
func (self *nilReporter) EndStory() {}
|
||||
func (self *nilReporter) Write(p []byte) (int, error) { return len(p), nil }
|
||||
func newNilReporter() *nilReporter { return &nilReporter{} }
|
16
vendor/github.com/smartystreets/goconvey/convey/reporting/console.go
generated
vendored
16
vendor/github.com/smartystreets/goconvey/convey/reporting/console.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type console struct{}
|
||||
|
||||
func (self *console) Write(p []byte) (n int, err error) {
|
||||
return fmt.Print(string(p))
|
||||
}
|
||||
|
||||
func NewConsole() io.Writer {
|
||||
return new(console)
|
||||
}
|
5
vendor/github.com/smartystreets/goconvey/convey/reporting/doc.go
generated
vendored
5
vendor/github.com/smartystreets/goconvey/convey/reporting/doc.go
generated
vendored
@ -1,5 +0,0 @@
|
||||
// Package reporting contains internal functionality related
|
||||
// to console reporting and output. Although this package has
|
||||
// exported names is not intended for public consumption. See the
|
||||
// examples package for how to use this project.
|
||||
package reporting
|
40
vendor/github.com/smartystreets/goconvey/convey/reporting/dot.go
generated
vendored
40
vendor/github.com/smartystreets/goconvey/convey/reporting/dot.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "fmt"
|
||||
|
||||
type dot struct{ out *Printer }
|
||||
|
||||
func (self *dot) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *dot) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *dot) Report(report *AssertionResult) {
|
||||
if report.Error != nil {
|
||||
fmt.Print(redColor)
|
||||
self.out.Insert(dotError)
|
||||
} else if report.Failure != "" {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(dotFailure)
|
||||
} else if report.Skipped {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(dotSkip)
|
||||
} else {
|
||||
fmt.Print(greenColor)
|
||||
self.out.Insert(dotSuccess)
|
||||
}
|
||||
fmt.Print(resetColor)
|
||||
}
|
||||
|
||||
func (self *dot) Exit() {}
|
||||
|
||||
func (self *dot) EndStory() {}
|
||||
|
||||
func (self *dot) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewDotReporter(out *Printer) *dot {
|
||||
self := new(dot)
|
||||
self.out = out
|
||||
return self
|
||||
}
|
33
vendor/github.com/smartystreets/goconvey/convey/reporting/gotest.go
generated
vendored
33
vendor/github.com/smartystreets/goconvey/convey/reporting/gotest.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package reporting
|
||||
|
||||
type gotestReporter struct{ test T }
|
||||
|
||||
func (self *gotestReporter) BeginStory(story *StoryReport) {
|
||||
self.test = story.Test
|
||||
}
|
||||
|
||||
func (self *gotestReporter) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *gotestReporter) Report(r *AssertionResult) {
|
||||
if !passed(r) {
|
||||
self.test.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func (self *gotestReporter) Exit() {}
|
||||
|
||||
func (self *gotestReporter) EndStory() {
|
||||
self.test = nil
|
||||
}
|
||||
|
||||
func (self *gotestReporter) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewGoTestReporter() *gotestReporter {
|
||||
return new(gotestReporter)
|
||||
}
|
||||
|
||||
func passed(r *AssertionResult) bool {
|
||||
return r.Error == nil && r.Failure == ""
|
||||
}
|
97
vendor/github.com/smartystreets/goconvey/convey/reporting/init.go
generated
vendored
97
vendor/github.com/smartystreets/goconvey/convey/reporting/init.go
generated
vendored
@ -1,97 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if !isXterm() {
|
||||
monochrome()
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
success, failure, error_ = dotSuccess, dotFailure, dotError
|
||||
}
|
||||
}
|
||||
|
||||
func BuildJsonReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewJsonReporter(out))
|
||||
}
|
||||
func BuildDotReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewDotReporter(out),
|
||||
NewProblemReporter(out),
|
||||
consoleStatistics)
|
||||
}
|
||||
func BuildStoryReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewStoryReporter(out),
|
||||
NewProblemReporter(out),
|
||||
consoleStatistics)
|
||||
}
|
||||
func BuildSilentReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewSilentProblemReporter(out))
|
||||
}
|
||||
|
||||
var (
|
||||
newline = "\n"
|
||||
success = "✔"
|
||||
failure = "✘"
|
||||
error_ = "🔥"
|
||||
skip = "⚠"
|
||||
dotSuccess = "."
|
||||
dotFailure = "x"
|
||||
dotError = "E"
|
||||
dotSkip = "S"
|
||||
errorTemplate = "* %s \nLine %d: - %v \n%s\n"
|
||||
failureTemplate = "* %s \nLine %d:\n%s\n"
|
||||
)
|
||||
|
||||
var (
|
||||
greenColor = "\033[32m"
|
||||
yellowColor = "\033[33m"
|
||||
redColor = "\033[31m"
|
||||
resetColor = "\033[0m"
|
||||
)
|
||||
|
||||
var consoleStatistics = NewStatisticsReporter(NewPrinter(NewConsole()))
|
||||
|
||||
func SuppressConsoleStatistics() { consoleStatistics.Suppress() }
|
||||
func PrintConsoleStatistics() { consoleStatistics.PrintSummary() }
|
||||
|
||||
// QuiteMode disables all console output symbols. This is only meant to be used
|
||||
// for tests that are internal to goconvey where the output is distracting or
|
||||
// otherwise not needed in the test output.
|
||||
func QuietMode() {
|
||||
success, failure, error_, skip, dotSuccess, dotFailure, dotError, dotSkip = "", "", "", "", "", "", "", ""
|
||||
}
|
||||
|
||||
func monochrome() {
|
||||
greenColor, yellowColor, redColor, resetColor = "", "", "", ""
|
||||
}
|
||||
|
||||
func isXterm() bool {
|
||||
env := fmt.Sprintf("%v", os.Environ())
|
||||
return strings.Contains(env, " TERM=isXterm") ||
|
||||
strings.Contains(env, " TERM=xterm")
|
||||
}
|
||||
|
||||
// This interface allows us to pass the *testing.T struct
|
||||
// throughout the internals of this tool without ever
|
||||
// having to import the "testing" package.
|
||||
type T interface {
|
||||
Fail()
|
||||
}
|
88
vendor/github.com/smartystreets/goconvey/convey/reporting/json.go
generated
vendored
88
vendor/github.com/smartystreets/goconvey/convey/reporting/json.go
generated
vendored
@ -1,88 +0,0 @@
|
||||
// TODO: under unit test
|
||||
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type JsonReporter struct {
|
||||
out *Printer
|
||||
currentKey []string
|
||||
current *ScopeResult
|
||||
index map[string]*ScopeResult
|
||||
scopes []*ScopeResult
|
||||
}
|
||||
|
||||
func (self *JsonReporter) depth() int { return len(self.currentKey) }
|
||||
|
||||
func (self *JsonReporter) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *JsonReporter) Enter(scope *ScopeReport) {
|
||||
self.currentKey = append(self.currentKey, scope.Title)
|
||||
ID := strings.Join(self.currentKey, "|")
|
||||
if _, found := self.index[ID]; !found {
|
||||
next := newScopeResult(scope.Title, self.depth(), scope.File, scope.Line)
|
||||
self.scopes = append(self.scopes, next)
|
||||
self.index[ID] = next
|
||||
}
|
||||
self.current = self.index[ID]
|
||||
}
|
||||
|
||||
func (self *JsonReporter) Report(report *AssertionResult) {
|
||||
self.current.Assertions = append(self.current.Assertions, report)
|
||||
}
|
||||
|
||||
func (self *JsonReporter) Exit() {
|
||||
self.currentKey = self.currentKey[:len(self.currentKey)-1]
|
||||
}
|
||||
|
||||
func (self *JsonReporter) EndStory() {
|
||||
self.report()
|
||||
self.reset()
|
||||
}
|
||||
func (self *JsonReporter) report() {
|
||||
scopes := []string{}
|
||||
for _, scope := range self.scopes {
|
||||
serialized, err := json.Marshal(scope)
|
||||
if err != nil {
|
||||
self.out.Println(jsonMarshalFailure)
|
||||
panic(err)
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
json.Indent(&buffer, serialized, "", " ")
|
||||
scopes = append(scopes, buffer.String())
|
||||
}
|
||||
self.out.Print(fmt.Sprintf("%s\n%s,\n%s\n", OpenJson, strings.Join(scopes, ","), CloseJson))
|
||||
}
|
||||
func (self *JsonReporter) reset() {
|
||||
self.scopes = []*ScopeResult{}
|
||||
self.index = map[string]*ScopeResult{}
|
||||
self.currentKey = nil
|
||||
}
|
||||
|
||||
func (self *JsonReporter) Write(content []byte) (written int, err error) {
|
||||
self.current.Output += string(content)
|
||||
return len(content), nil
|
||||
}
|
||||
|
||||
func NewJsonReporter(out *Printer) *JsonReporter {
|
||||
self := new(JsonReporter)
|
||||
self.out = out
|
||||
self.reset()
|
||||
return self
|
||||
}
|
||||
|
||||
const OpenJson = ">->->OPEN-JSON->->->" // "⌦"
|
||||
const CloseJson = "<-<-<-CLOSE-JSON<-<-<" // "⌫"
|
||||
const jsonMarshalFailure = `
|
||||
|
||||
GOCONVEY_JSON_MARSHALL_FAILURE: There was an error when attempting to convert test results to JSON.
|
||||
Please file a bug report and reference the code that caused this failure if possible.
|
||||
|
||||
Here's the panic:
|
||||
|
||||
`
|
57
vendor/github.com/smartystreets/goconvey/convey/reporting/printer.go
generated
vendored
57
vendor/github.com/smartystreets/goconvey/convey/reporting/printer.go
generated
vendored
@ -1,57 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Printer struct {
|
||||
out io.Writer
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (self *Printer) Println(message string, values ...interface{}) {
|
||||
formatted := self.format(message, values...) + newline
|
||||
self.out.Write([]byte(formatted))
|
||||
}
|
||||
|
||||
func (self *Printer) Print(message string, values ...interface{}) {
|
||||
formatted := self.format(message, values...)
|
||||
self.out.Write([]byte(formatted))
|
||||
}
|
||||
|
||||
func (self *Printer) Insert(text string) {
|
||||
self.out.Write([]byte(text))
|
||||
}
|
||||
|
||||
func (self *Printer) format(message string, values ...interface{}) string {
|
||||
var formatted string
|
||||
if len(values) == 0 {
|
||||
formatted = self.prefix + message
|
||||
} else {
|
||||
formatted = self.prefix + fmt.Sprintf(message, values...)
|
||||
}
|
||||
indented := strings.Replace(formatted, newline, newline+self.prefix, -1)
|
||||
return strings.TrimRight(indented, space)
|
||||
}
|
||||
|
||||
func (self *Printer) Indent() {
|
||||
self.prefix += pad
|
||||
}
|
||||
|
||||
func (self *Printer) Dedent() {
|
||||
if len(self.prefix) >= padLength {
|
||||
self.prefix = self.prefix[:len(self.prefix)-padLength]
|
||||
}
|
||||
}
|
||||
|
||||
func NewPrinter(out io.Writer) *Printer {
|
||||
self := new(Printer)
|
||||
self.out = out
|
||||
return self
|
||||
}
|
||||
|
||||
const space = " "
|
||||
const pad = space + space
|
||||
const padLength = len(pad)
|
80
vendor/github.com/smartystreets/goconvey/convey/reporting/problems.go
generated
vendored
80
vendor/github.com/smartystreets/goconvey/convey/reporting/problems.go
generated
vendored
@ -1,80 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "fmt"
|
||||
|
||||
type problem struct {
|
||||
silent bool
|
||||
out *Printer
|
||||
errors []*AssertionResult
|
||||
failures []*AssertionResult
|
||||
}
|
||||
|
||||
func (self *problem) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *problem) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *problem) Report(report *AssertionResult) {
|
||||
if report.Error != nil {
|
||||
self.errors = append(self.errors, report)
|
||||
} else if report.Failure != "" {
|
||||
self.failures = append(self.failures, report)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *problem) Exit() {}
|
||||
|
||||
func (self *problem) EndStory() {
|
||||
self.show(self.showErrors, redColor)
|
||||
self.show(self.showFailures, yellowColor)
|
||||
self.prepareForNextStory()
|
||||
}
|
||||
func (self *problem) show(display func(), color string) {
|
||||
if !self.silent {
|
||||
fmt.Print(color)
|
||||
}
|
||||
display()
|
||||
if !self.silent {
|
||||
fmt.Print(resetColor)
|
||||
}
|
||||
self.out.Dedent()
|
||||
}
|
||||
func (self *problem) showErrors() {
|
||||
for i, e := range self.errors {
|
||||
if i == 0 {
|
||||
self.out.Println("\nErrors:\n")
|
||||
self.out.Indent()
|
||||
}
|
||||
self.out.Println(errorTemplate, e.File, e.Line, e.Error, e.StackTrace)
|
||||
}
|
||||
}
|
||||
func (self *problem) showFailures() {
|
||||
for i, f := range self.failures {
|
||||
if i == 0 {
|
||||
self.out.Println("\nFailures:\n")
|
||||
self.out.Indent()
|
||||
}
|
||||
self.out.Println(failureTemplate, f.File, f.Line, f.Failure)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *problem) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewProblemReporter(out *Printer) *problem {
|
||||
self := new(problem)
|
||||
self.out = out
|
||||
self.prepareForNextStory()
|
||||
return self
|
||||
}
|
||||
|
||||
func NewSilentProblemReporter(out *Printer) *problem {
|
||||
self := NewProblemReporter(out)
|
||||
self.silent = true
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *problem) prepareForNextStory() {
|
||||
self.errors = []*AssertionResult{}
|
||||
self.failures = []*AssertionResult{}
|
||||
}
|
39
vendor/github.com/smartystreets/goconvey/convey/reporting/reporter.go
generated
vendored
39
vendor/github.com/smartystreets/goconvey/convey/reporting/reporter.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "io"
|
||||
|
||||
type Reporter interface {
|
||||
BeginStory(story *StoryReport)
|
||||
Enter(scope *ScopeReport)
|
||||
Report(r *AssertionResult)
|
||||
Exit()
|
||||
EndStory()
|
||||
io.Writer
|
||||
}
|
||||
|
||||
type reporters struct{ collection []Reporter }
|
||||
|
||||
func (self *reporters) BeginStory(s *StoryReport) { self.foreach(func(r Reporter) { r.BeginStory(s) }) }
|
||||
func (self *reporters) Enter(s *ScopeReport) { self.foreach(func(r Reporter) { r.Enter(s) }) }
|
||||
func (self *reporters) Report(a *AssertionResult) { self.foreach(func(r Reporter) { r.Report(a) }) }
|
||||
func (self *reporters) Exit() { self.foreach(func(r Reporter) { r.Exit() }) }
|
||||
func (self *reporters) EndStory() { self.foreach(func(r Reporter) { r.EndStory() }) }
|
||||
|
||||
func (self *reporters) Write(contents []byte) (written int, err error) {
|
||||
self.foreach(func(r Reporter) {
|
||||
written, err = r.Write(contents)
|
||||
})
|
||||
return written, err
|
||||
}
|
||||
|
||||
func (self *reporters) foreach(action func(Reporter)) {
|
||||
for _, r := range self.collection {
|
||||
action(r)
|
||||
}
|
||||
}
|
||||
|
||||
func NewReporters(collection ...Reporter) *reporters {
|
||||
self := new(reporters)
|
||||
self.collection = collection
|
||||
return self
|
||||
}
|
2
vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey
generated
vendored
2
vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey
generated
vendored
@ -1,2 +0,0 @@
|
||||
#ignore
|
||||
-timeout=1s
|
177
vendor/github.com/smartystreets/goconvey/convey/reporting/reports.go
generated
vendored
177
vendor/github.com/smartystreets/goconvey/convey/reporting/reports.go
generated
vendored
@ -1,177 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/gotest"
|
||||
)
|
||||
|
||||
////////////////// ScopeReport ////////////////////
|
||||
|
||||
type ScopeReport struct {
|
||||
Title string
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
func NewScopeReport(title string) *ScopeReport {
|
||||
file, line, _ := gotest.ResolveExternalCaller()
|
||||
self := new(ScopeReport)
|
||||
self.Title = title
|
||||
self.File = file
|
||||
self.Line = line
|
||||
return self
|
||||
}
|
||||
|
||||
////////////////// ScopeResult ////////////////////
|
||||
|
||||
type ScopeResult struct {
|
||||
Title string
|
||||
File string
|
||||
Line int
|
||||
Depth int
|
||||
Assertions []*AssertionResult
|
||||
Output string
|
||||
}
|
||||
|
||||
func newScopeResult(title string, depth int, file string, line int) *ScopeResult {
|
||||
self := new(ScopeResult)
|
||||
self.Title = title
|
||||
self.Depth = depth
|
||||
self.File = file
|
||||
self.Line = line
|
||||
self.Assertions = []*AssertionResult{}
|
||||
return self
|
||||
}
|
||||
|
||||
/////////////////// StoryReport /////////////////////
|
||||
|
||||
type StoryReport struct {
|
||||
Test T
|
||||
Name string
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
func NewStoryReport(test T) *StoryReport {
|
||||
file, line, name := gotest.ResolveExternalCaller()
|
||||
name = removePackagePath(name)
|
||||
self := new(StoryReport)
|
||||
self.Test = test
|
||||
self.Name = name
|
||||
self.File = file
|
||||
self.Line = line
|
||||
return self
|
||||
}
|
||||
|
||||
// name comes in looking like "github.com/smartystreets/goconvey/examples.TestName".
|
||||
// We only want the stuff after the last '.', which is the name of the test function.
|
||||
func removePackagePath(name string) string {
|
||||
parts := strings.Split(name, ".")
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
|
||||
/////////////////// FailureView ////////////////////////
|
||||
|
||||
type FailureView struct {
|
||||
Message string
|
||||
Expected string
|
||||
Actual string
|
||||
}
|
||||
|
||||
////////////////////AssertionResult //////////////////////
|
||||
|
||||
type AssertionResult struct {
|
||||
File string
|
||||
Line int
|
||||
Expected string
|
||||
Actual string
|
||||
Failure string
|
||||
Error interface{}
|
||||
StackTrace string
|
||||
Skipped bool
|
||||
}
|
||||
|
||||
func NewFailureReport(failure string) *AssertionResult {
|
||||
report := new(AssertionResult)
|
||||
report.File, report.Line = caller()
|
||||
report.StackTrace = stackTrace()
|
||||
parseFailure(failure, report)
|
||||
return report
|
||||
}
|
||||
func parseFailure(failure string, report *AssertionResult) {
|
||||
view := new(FailureView)
|
||||
err := json.Unmarshal([]byte(failure), view)
|
||||
if err == nil {
|
||||
report.Failure = view.Message
|
||||
report.Expected = view.Expected
|
||||
report.Actual = view.Actual
|
||||
} else {
|
||||
report.Failure = failure
|
||||
}
|
||||
}
|
||||
func NewErrorReport(err interface{}) *AssertionResult {
|
||||
report := new(AssertionResult)
|
||||
report.File, report.Line = caller()
|
||||
report.StackTrace = fullStackTrace()
|
||||
report.Error = fmt.Sprintf("%v", err)
|
||||
return report
|
||||
}
|
||||
func NewSuccessReport() *AssertionResult {
|
||||
return new(AssertionResult)
|
||||
}
|
||||
func NewSkipReport() *AssertionResult {
|
||||
report := new(AssertionResult)
|
||||
report.File, report.Line = caller()
|
||||
report.StackTrace = fullStackTrace()
|
||||
report.Skipped = true
|
||||
return report
|
||||
}
|
||||
|
||||
func caller() (file string, line int) {
|
||||
file, line, _ = gotest.ResolveExternalCaller()
|
||||
return
|
||||
}
|
||||
|
||||
func stackTrace() string {
|
||||
buffer := make([]byte, 1024*64)
|
||||
n := runtime.Stack(buffer, false)
|
||||
return removeInternalEntries(string(buffer[:n]))
|
||||
}
|
||||
func fullStackTrace() string {
|
||||
buffer := make([]byte, 1024*64)
|
||||
n := runtime.Stack(buffer, true)
|
||||
return removeInternalEntries(string(buffer[:n]))
|
||||
}
|
||||
func removeInternalEntries(stack string) string {
|
||||
lines := strings.Split(stack, newline)
|
||||
filtered := []string{}
|
||||
for _, line := range lines {
|
||||
if !isExternal(line) {
|
||||
filtered = append(filtered, line)
|
||||
}
|
||||
}
|
||||
return strings.Join(filtered, newline)
|
||||
}
|
||||
func isExternal(line string) bool {
|
||||
for _, p := range internalPackages {
|
||||
if strings.Contains(line, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NOTE: any new packages that host goconvey packages will need to be added here!
|
||||
// An alternative is to scan the goconvey directory and then exclude stuff like
|
||||
// the examples package but that's nasty too.
|
||||
var internalPackages = []string{
|
||||
"goconvey/assertions",
|
||||
"goconvey/convey",
|
||||
"goconvey/execution",
|
||||
"goconvey/gotest",
|
||||
"goconvey/reporting",
|
||||
}
|
89
vendor/github.com/smartystreets/goconvey/convey/reporting/statistics.go
generated
vendored
89
vendor/github.com/smartystreets/goconvey/convey/reporting/statistics.go
generated
vendored
@ -1,89 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (self *statistics) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *statistics) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *statistics) Report(report *AssertionResult) {
|
||||
if !self.failing && report.Failure != "" {
|
||||
self.failing = true
|
||||
}
|
||||
if !self.erroring && report.Error != nil {
|
||||
self.erroring = true
|
||||
}
|
||||
if report.Skipped {
|
||||
self.skipped += 1
|
||||
} else {
|
||||
self.total++
|
||||
}
|
||||
}
|
||||
|
||||
func (self *statistics) Exit() {}
|
||||
|
||||
func (self *statistics) EndStory() {
|
||||
if !self.suppressed {
|
||||
self.PrintSummary()
|
||||
}
|
||||
}
|
||||
|
||||
func (self *statistics) Suppress() {
|
||||
self.suppressed = true
|
||||
}
|
||||
|
||||
func (self *statistics) PrintSummary() {
|
||||
self.reportAssertions()
|
||||
self.reportSkippedSections()
|
||||
self.completeReport()
|
||||
}
|
||||
func (self *statistics) reportAssertions() {
|
||||
self.decideColor()
|
||||
self.out.Print("\n%d total %s", self.total, plural("assertion", self.total))
|
||||
}
|
||||
func (self *statistics) decideColor() {
|
||||
if self.failing && !self.erroring {
|
||||
fmt.Print(yellowColor)
|
||||
} else if self.erroring {
|
||||
fmt.Print(redColor)
|
||||
} else {
|
||||
fmt.Print(greenColor)
|
||||
}
|
||||
}
|
||||
func (self *statistics) reportSkippedSections() {
|
||||
if self.skipped > 0 {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Print(" (one or more sections skipped)")
|
||||
}
|
||||
}
|
||||
func (self *statistics) completeReport() {
|
||||
fmt.Print(resetColor)
|
||||
self.out.Print("\n")
|
||||
self.out.Print("\n")
|
||||
}
|
||||
|
||||
func (self *statistics) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewStatisticsReporter(out *Printer) *statistics {
|
||||
self := statistics{}
|
||||
self.out = out
|
||||
return &self
|
||||
}
|
||||
|
||||
type statistics struct {
|
||||
out *Printer
|
||||
total int
|
||||
failing bool
|
||||
erroring bool
|
||||
skipped int
|
||||
suppressed bool
|
||||
}
|
||||
|
||||
func plural(word string, count int) string {
|
||||
if count == 1 {
|
||||
return word
|
||||
}
|
||||
return word + "s"
|
||||
}
|
73
vendor/github.com/smartystreets/goconvey/convey/reporting/story.go
generated
vendored
73
vendor/github.com/smartystreets/goconvey/convey/reporting/story.go
generated
vendored
@ -1,73 +0,0 @@
|
||||
// TODO: in order for this reporter to be completely honest
|
||||
// we need to retrofit to be more like the json reporter such that:
|
||||
// 1. it maintains ScopeResult collections, which count assertions
|
||||
// 2. it reports only after EndStory(), so that all tick marks
|
||||
// are placed near the appropriate title.
|
||||
// 3. Under unit test
|
||||
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type story struct {
|
||||
out *Printer
|
||||
titlesById map[string]string
|
||||
currentKey []string
|
||||
}
|
||||
|
||||
func (self *story) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *story) Enter(scope *ScopeReport) {
|
||||
self.out.Indent()
|
||||
|
||||
self.currentKey = append(self.currentKey, scope.Title)
|
||||
ID := strings.Join(self.currentKey, "|")
|
||||
|
||||
if _, found := self.titlesById[ID]; !found {
|
||||
self.out.Println("")
|
||||
self.out.Print(scope.Title)
|
||||
self.out.Insert(" ")
|
||||
self.titlesById[ID] = scope.Title
|
||||
}
|
||||
}
|
||||
|
||||
func (self *story) Report(report *AssertionResult) {
|
||||
if report.Error != nil {
|
||||
fmt.Print(redColor)
|
||||
self.out.Insert(error_)
|
||||
} else if report.Failure != "" {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(failure)
|
||||
} else if report.Skipped {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(skip)
|
||||
} else {
|
||||
fmt.Print(greenColor)
|
||||
self.out.Insert(success)
|
||||
}
|
||||
fmt.Print(resetColor)
|
||||
}
|
||||
|
||||
func (self *story) Exit() {
|
||||
self.out.Dedent()
|
||||
self.currentKey = self.currentKey[:len(self.currentKey)-1]
|
||||
}
|
||||
|
||||
func (self *story) EndStory() {
|
||||
self.titlesById = make(map[string]string)
|
||||
self.out.Println("\n")
|
||||
}
|
||||
|
||||
func (self *story) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewStoryReporter(out *Printer) *story {
|
||||
self := new(story)
|
||||
self.out = out
|
||||
self.titlesById = make(map[string]string)
|
||||
return self
|
||||
}
|
58
vendor/vendor.json
vendored
58
vendor/vendor.json
vendored
@ -5,14 +5,14 @@
|
||||
{
|
||||
"checksumSHA1": "OeOvZ+3A1tRBdMD8GuS6R9zcnqA=",
|
||||
"path": "github.com/astaxie/beego/swagger",
|
||||
"revision": "a20ccde90d75695e4f0ae0353c88dba9781d366c",
|
||||
"revisionTime": "2016-12-05T14:58:29Z"
|
||||
"revision": "323a1c4214101331a4b71922c23d19b7409ac71f",
|
||||
"revisionTime": "2017-03-06T13:59:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "95wt85GTZG0zi3Zk8g2jOVFV6Zg=",
|
||||
"checksumSHA1": "epd3Y7nD7QVzTW0ppwK+q4pKo/4=",
|
||||
"path": "github.com/astaxie/beego/utils",
|
||||
"revision": "a20ccde90d75695e4f0ae0353c88dba9781d366c",
|
||||
"revisionTime": "2016-12-05T14:58:29Z"
|
||||
"revision": "323a1c4214101331a4b71922c23d19b7409ac71f",
|
||||
"revisionTime": "2017-03-06T13:59:04Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "hveFTNQ9YEyYRs6SWuXM+XU9qRI=",
|
||||
@ -27,22 +27,10 @@
|
||||
"revisionTime": "2016-01-13T11:48:05Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "dyGQP5AipmInoTQmnqvbFmUORpk=",
|
||||
"checksumSHA1": "G778A9feKkdW7ZjeDdj5qoU0Ku4=",
|
||||
"path": "github.com/gorilla/websocket",
|
||||
"revision": "a68708917c6a4f06314ab4e52493cc61359c9d42",
|
||||
"revisionTime": "2016-06-06T23:20:22Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "ZxzYc1JwJ3U6kZbw/KGuPko5lSY=",
|
||||
"path": "github.com/howeyc/fsnotify",
|
||||
"revision": "f0c08ee9c60704c1879025f2ae0ff3e000082c13",
|
||||
"revisionTime": "2015-10-03T19:46:02Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "tewA7jXVGCw1zb5mA0BDecWi4iQ=",
|
||||
"path": "github.com/jtolds/gls",
|
||||
"revision": "8ddce2a84170772b95dd5d576c48d517b22cac63",
|
||||
"revisionTime": "2016-01-05T22:08:40Z"
|
||||
"revision": "b258b4fadb573ac412f187b9f31974ea99d32f50",
|
||||
"revisionTime": "2017-03-02T22:46:13Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "dNYxHiBLalTqluak2/Z8c3RsSEM=",
|
||||
@ -56,36 +44,6 @@
|
||||
"revision": "80f8150043c80fb52dee6bc863a709cdac7ec8f8",
|
||||
"revisionTime": "2016-08-06T14:40:29Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "0DtXHkHCB8kOYM15F+Y5WYMMMuc=",
|
||||
"path": "github.com/smartystreets/assertions",
|
||||
"revision": "edb6e295a22c57a2aa353b2f0729b6eff9f9f4b7",
|
||||
"revisionTime": "2015-12-10T17:08:24Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "QCsUvPHx/Ifqm+sJmocjSvePAIc=",
|
||||
"path": "github.com/smartystreets/assertions/internal/oglematchers",
|
||||
"revision": "edb6e295a22c57a2aa353b2f0729b6eff9f9f4b7",
|
||||
"revisionTime": "2015-12-10T17:08:24Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "fQeXVv5U9dlo3ufH2vjk1GNf4Lo=",
|
||||
"path": "github.com/smartystreets/goconvey/convey",
|
||||
"revision": "a2d5d788f3afbce0989463251ccc5492fad832df",
|
||||
"revisionTime": "2015-12-28T21:47:19Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "9LakndErFi5uCXtY1KWl0iRnT4c=",
|
||||
"path": "github.com/smartystreets/goconvey/convey/gotest",
|
||||
"revision": "a2d5d788f3afbce0989463251ccc5492fad832df",
|
||||
"revisionTime": "2015-12-28T21:47:19Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "Ht2/XG8aSW7vWbwav9z5jKyTzzw=",
|
||||
"path": "github.com/smartystreets/goconvey/convey/reporting",
|
||||
"revision": "a2d5d788f3afbce0989463251ccc5492fad832df",
|
||||
"revisionTime": "2015-12-28T21:47:19Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "NIg5qnKx/D8Th7YX882++siXTDY=",
|
||||
"path": "golang.org/x/sys/unix",
|
||||
|
Loading…
Reference in New Issue
Block a user