Add missing deps
This commit is contained in:
@@ -36,10 +36,12 @@ require (
|
||||
github.com/lib/pq v1.1.0 // indirect
|
||||
github.com/markbates/goth v1.50.0
|
||||
github.com/minio/minio-go/v6 v6.0.39
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/prometheus/client_golang v0.9.3
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
|
||||
github.com/schollz/progressbar v1.0.0 // indirect
|
||||
github.com/schollz/progressbar/v2 v2.15.0
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/spf13/afero v1.2.2
|
||||
@@ -48,15 +50,17 @@ require (
|
||||
github.com/spf13/pflag v1.0.3 // indirect
|
||||
github.com/steinfletcher/apitest v1.3.8
|
||||
github.com/steinfletcher/apitest-jsonpath v1.3.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/titpetric/factory v0.0.0-20190806200833-ae4b02b9e034
|
||||
go.uber.org/atomic v1.5.0
|
||||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
|
||||
google.golang.org/grpc v1.22.1
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/ini.v1 v1.51.0 // indirect
|
||||
gopkg.in/mail.v2 v2.3.1
|
||||
gopkg.in/square/go-jose.v2 v2.3.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.4
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
)
|
||||
|
||||
@@ -157,6 +157,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/pingcap/errors v0.11.1 h1:BXFZ6MdDd2U1uJUa2sRAWTmm+nieEzuyYM0R4aUTcC8=
|
||||
github.com/pingcap/errors v0.11.1/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
@@ -183,6 +185,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/schollz/progressbar v1.0.0 h1:gbyFReLHDkZo8mxy/dLWMr+Mpb1MokGJ1FqCiqacjZM=
|
||||
github.com/schollz/progressbar v1.0.0/go.mod h1:/l9I7PC3L3erOuz54ghIRKUEFcosiWfLvJv+Eq26UMs=
|
||||
github.com/schollz/progressbar/v2 v2.15.0 h1:dVzHQ8fHRmtPjD3K10jT3Qgn/+H+92jhPrhmxIJfDz8=
|
||||
github.com/schollz/progressbar/v2 v2.15.0/go.mod h1:UdPq3prGkfQ7MOzZKlDRpYKcFqEMczbD7YmbPgpzKMI=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
@@ -211,10 +215,13 @@ github.com/steinfletcher/apitest-jsonpath v1.3.0 h1:mq6ILNSPtjher/QMp1q93BUgASvj
|
||||
github.com/steinfletcher/apitest-jsonpath v1.3.0/go.mod h1:3wP64zeeW8CNUN1g01ZaH0fnVco4s4a6z7KcLTTR6e0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/titpetric/factory v0.0.0-20190806200833-ae4b02b9e034 h1:H2WfXOKTtF37QV4McGIRH37zNa00NgZjRJ/5wwxqSv8=
|
||||
github.com/titpetric/factory v0.0.0-20190806200833-ae4b02b9e034/go.mod h1:VFd2XRrQZoX9cOxpeZezKpOlXDwU/dbRejKLjwP+xY8=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
@@ -335,6 +342,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
@@ -349,6 +358,8 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.0
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Mitchell Hashimoto
|
||||
|
||||
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.
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# colorstring [](https://travis-ci.org/mitchellh/colorstring)
|
||||
|
||||
colorstring is a [Go](http://www.golang.org) library for outputting colored
|
||||
strings to a console using a simple inline syntax in your string to specify
|
||||
the color to print as.
|
||||
|
||||
For example, the string `[blue]hello [red]world` would output the text
|
||||
"hello world" in two colors. The API of colorstring allows for easily disabling
|
||||
colors, adding aliases, etc.
|
||||
|
||||
## Installation
|
||||
|
||||
Standard `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/mitchellh/colorstring
|
||||
```
|
||||
|
||||
## Usage & Example
|
||||
|
||||
For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/colorstring).
|
||||
|
||||
Usage is easy enough:
|
||||
|
||||
```go
|
||||
colorstring.Println("[blue]Hello [red]World!")
|
||||
```
|
||||
|
||||
Additionally, the `Colorize` struct can be used to set options such as
|
||||
custom colors, color disabling, etc.
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
// colorstring provides functions for colorizing strings for terminal
|
||||
// output.
|
||||
package colorstring
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Color colorizes your strings using the default settings.
|
||||
//
|
||||
// Strings given to Color should use the syntax `[color]` to specify the
|
||||
// color for text following. For example: `[blue]Hello` will return "Hello"
|
||||
// in blue. See DefaultColors for all the supported colors and attributes.
|
||||
//
|
||||
// If an unrecognized color is given, it is ignored and assumed to be part
|
||||
// of the string. For example: `[hi]world` will result in "[hi]world".
|
||||
//
|
||||
// A color reset is appended to the end of every string. This will reset
|
||||
// the color of following strings when you output this text to the same
|
||||
// terminal session.
|
||||
//
|
||||
// If you want to customize any of this behavior, use the Colorize struct.
|
||||
func Color(v string) string {
|
||||
return def.Color(v)
|
||||
}
|
||||
|
||||
// ColorPrefix returns the color sequence that prefixes the given text.
|
||||
//
|
||||
// This is useful when wrapping text if you want to inherit the color
|
||||
// of the wrapped text. For example, "[green]foo" will return "[green]".
|
||||
// If there is no color sequence, then this will return "".
|
||||
func ColorPrefix(v string) string {
|
||||
return def.ColorPrefix(v)
|
||||
}
|
||||
|
||||
// Colorize colorizes your strings, giving you the ability to customize
|
||||
// some of the colorization process.
|
||||
//
|
||||
// The options in Colorize can be set to customize colorization. If you're
|
||||
// only interested in the defaults, just use the top Color function directly,
|
||||
// which creates a default Colorize.
|
||||
type Colorize struct {
|
||||
// Colors maps a color string to the code for that color. The code
|
||||
// is a string so that you can use more complex colors to set foreground,
|
||||
// background, attributes, etc. For example, "boldblue" might be
|
||||
// "1;34"
|
||||
Colors map[string]string
|
||||
|
||||
// If true, color attributes will be ignored. This is useful if you're
|
||||
// outputting to a location that doesn't support colors and you just
|
||||
// want the strings returned.
|
||||
Disable bool
|
||||
|
||||
// Reset, if true, will reset the color after each colorization by
|
||||
// adding a reset code at the end.
|
||||
Reset bool
|
||||
}
|
||||
|
||||
// Color colorizes a string according to the settings setup in the struct.
|
||||
//
|
||||
// For more details on the syntax, see the top-level Color function.
|
||||
func (c *Colorize) Color(v string) string {
|
||||
matches := parseRe.FindAllStringIndex(v, -1)
|
||||
if len(matches) == 0 {
|
||||
return v
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
colored := false
|
||||
m := []int{0, 0}
|
||||
for _, nm := range matches {
|
||||
// Write the text in between this match and the last
|
||||
result.WriteString(v[m[1]:nm[0]])
|
||||
m = nm
|
||||
|
||||
var replace string
|
||||
if code, ok := c.Colors[v[m[0]+1:m[1]-1]]; ok {
|
||||
colored = true
|
||||
|
||||
if !c.Disable {
|
||||
replace = fmt.Sprintf("\033[%sm", code)
|
||||
}
|
||||
} else {
|
||||
replace = v[m[0]:m[1]]
|
||||
}
|
||||
|
||||
result.WriteString(replace)
|
||||
}
|
||||
result.WriteString(v[m[1]:])
|
||||
|
||||
if colored && c.Reset && !c.Disable {
|
||||
// Write the clear byte at the end
|
||||
result.WriteString("\033[0m")
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
// ColorPrefix returns the first color sequence that exists in this string.
|
||||
//
|
||||
// For example: "[green]foo" would return "[green]". If no color sequence
|
||||
// exists, then "" is returned. This is especially useful when wrapping
|
||||
// colored texts to inherit the color of the wrapped text.
|
||||
func (c *Colorize) ColorPrefix(v string) string {
|
||||
return prefixRe.FindString(strings.TrimSpace(v))
|
||||
}
|
||||
|
||||
// DefaultColors are the default colors used when colorizing.
|
||||
//
|
||||
// If the color is surrounded in underscores, such as "_blue_", then that
|
||||
// color will be used for the background color.
|
||||
var DefaultColors map[string]string
|
||||
|
||||
func init() {
|
||||
DefaultColors = map[string]string{
|
||||
// Default foreground/background colors
|
||||
"default": "39",
|
||||
"_default_": "49",
|
||||
|
||||
// Foreground colors
|
||||
"black": "30",
|
||||
"red": "31",
|
||||
"green": "32",
|
||||
"yellow": "33",
|
||||
"blue": "34",
|
||||
"magenta": "35",
|
||||
"cyan": "36",
|
||||
"light_gray": "37",
|
||||
"dark_gray": "90",
|
||||
"light_red": "91",
|
||||
"light_green": "92",
|
||||
"light_yellow": "93",
|
||||
"light_blue": "94",
|
||||
"light_magenta": "95",
|
||||
"light_cyan": "96",
|
||||
"white": "97",
|
||||
|
||||
// Background colors
|
||||
"_black_": "40",
|
||||
"_red_": "41",
|
||||
"_green_": "42",
|
||||
"_yellow_": "43",
|
||||
"_blue_": "44",
|
||||
"_magenta_": "45",
|
||||
"_cyan_": "46",
|
||||
"_light_gray_": "47",
|
||||
"_dark_gray_": "100",
|
||||
"_light_red_": "101",
|
||||
"_light_green_": "102",
|
||||
"_light_yellow_": "103",
|
||||
"_light_blue_": "104",
|
||||
"_light_magenta_": "105",
|
||||
"_light_cyan_": "106",
|
||||
"_white_": "107",
|
||||
|
||||
// Attributes
|
||||
"bold": "1",
|
||||
"dim": "2",
|
||||
"underline": "4",
|
||||
"blink_slow": "5",
|
||||
"blink_fast": "6",
|
||||
"invert": "7",
|
||||
"hidden": "8",
|
||||
|
||||
// Reset to reset everything to their defaults
|
||||
"reset": "0",
|
||||
"reset_bold": "21",
|
||||
}
|
||||
|
||||
def = Colorize{
|
||||
Colors: DefaultColors,
|
||||
Reset: true,
|
||||
}
|
||||
}
|
||||
|
||||
var def Colorize
|
||||
var parseReRaw = `\[[a-z0-9_-]+\]`
|
||||
var parseRe = regexp.MustCompile(`(?i)` + parseReRaw)
|
||||
var prefixRe = regexp.MustCompile(`^(?i)(` + parseReRaw + `)+`)
|
||||
|
||||
// Print is a convenience wrapper for fmt.Print with support for color codes.
|
||||
//
|
||||
// Print formats using the default formats for its operands and writes to
|
||||
// standard output with support for color codes. Spaces are added between
|
||||
// operands when neither is a string. It returns the number of bytes written
|
||||
// and any write error encountered.
|
||||
func Print(a string) (n int, err error) {
|
||||
return fmt.Print(Color(a))
|
||||
}
|
||||
|
||||
// Println is a convenience wrapper for fmt.Println with support for color
|
||||
// codes.
|
||||
//
|
||||
// Println formats using the default formats for its operands and writes to
|
||||
// standard output with support for color codes. Spaces are always added
|
||||
// between operands and a newline is appended. It returns the number of bytes
|
||||
// written and any write error encountered.
|
||||
func Println(a string) (n int, err error) {
|
||||
return fmt.Println(Color(a))
|
||||
}
|
||||
|
||||
// Printf is a convenience wrapper for fmt.Printf with support for color codes.
|
||||
//
|
||||
// Printf formats according to a format specifier and writes to standard output
|
||||
// with support for color codes. It returns the number of bytes written and any
|
||||
// write error encountered.
|
||||
func Printf(format string, a ...interface{}) (n int, err error) {
|
||||
return fmt.Printf(Color(format), a...)
|
||||
}
|
||||
|
||||
// Fprint is a convenience wrapper for fmt.Fprint with support for color codes.
|
||||
//
|
||||
// Fprint formats using the default formats for its operands and writes to w
|
||||
// with support for color codes. Spaces are added between operands when neither
|
||||
// is a string. It returns the number of bytes written and any write error
|
||||
// encountered.
|
||||
func Fprint(w io.Writer, a string) (n int, err error) {
|
||||
return fmt.Fprint(w, Color(a))
|
||||
}
|
||||
|
||||
// Fprintln is a convenience wrapper for fmt.Fprintln with support for color
|
||||
// codes.
|
||||
//
|
||||
// Fprintln formats using the default formats for its operands and writes to w
|
||||
// with support for color codes. Spaces are always added between operands and a
|
||||
// newline is appended. It returns the number of bytes written and any write
|
||||
// error encountered.
|
||||
func Fprintln(w io.Writer, a string) (n int, err error) {
|
||||
return fmt.Fprintln(w, Color(a))
|
||||
}
|
||||
|
||||
// Fprintf is a convenience wrapper for fmt.Fprintf with support for color
|
||||
// codes.
|
||||
//
|
||||
// Fprintf formats according to a format specifier and writes to w with support
|
||||
// for color codes. It returns the number of bytes written and any write error
|
||||
// encountered.
|
||||
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(w, Color(format), a...)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
module github.com/mitchellh/colorstring
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
.idea/
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- tip
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Zack
|
||||
|
||||
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.
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
# progressbar
|
||||
|
||||
[](https://travis-ci.org/schollz/progressbar)
|
||||
[](https://goreportcard.com/report/github.com/schollz/progressbar)
|
||||
[](https://gocover.io/github.com/schollz/progressbar)
|
||||
[](https://godoc.org/github.com/schollz/progressbar)
|
||||
|
||||
A very simple thread-safe progress bar which should work on every OS without problems. I needed a progressbar for [croc](https://github.com/schollz/croc) and everything I tried had problems, so I made another one. In order to be OS agnostic I do not plan to support [multi-line outputs](https://github.com/schollz/progressbar/issues/6).
|
||||
|
||||

|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
go get -u github.com/schollz/progressbar/v2
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic usage
|
||||
|
||||
```golang
|
||||
bar := progressbar.New(100)
|
||||
for i := 0; i < 100; i++ {
|
||||
bar.Add(1)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
```
|
||||
|
||||
which looks like:
|
||||
|
||||
```bash
|
||||
100% |████████████████████████████████████████| [1s:0s]
|
||||
```
|
||||
|
||||
The times at the end show the elapsed time and the remaining time, respectively.
|
||||
|
||||
### Long running processes
|
||||
|
||||
For long running processes, you might want to render from a 0% state.
|
||||
|
||||
```golang
|
||||
// Renders the bar right on construction
|
||||
bar := progressbar.NewOptions(100, progressbar.OptionSetRenderBlankState(true))
|
||||
```
|
||||
|
||||
Alternatively, when you want to delay rendering, but still want to render a 0% state
|
||||
```golang
|
||||
bar := progressbar.NewOptions(100)
|
||||
|
||||
// Render the current state, which is 0% in this case
|
||||
bar.RenderBlank()
|
||||
|
||||
// Emulate work
|
||||
for i := 0; i < 10; i++ {
|
||||
time.Sleep(10 * time.Minute)
|
||||
bar.Add(10)
|
||||
}
|
||||
```
|
||||
|
||||
### Use a custom writer
|
||||
|
||||
The default writer is standard output (os.Stdout), but you can set it to whatever satisfies io.Writer.
|
||||
```golang
|
||||
bar := NewOptions(
|
||||
10,
|
||||
OptionSetTheme(Theme{Saucer: "#", SaucerPadding: "-", BarStart: ">", BarEnd: "<"}),
|
||||
OptionSetWidth(10),
|
||||
OptionSetWriter(&buf),
|
||||
)
|
||||
|
||||
bar.Add(5)
|
||||
result := strings.TrimSpace(buf.String())
|
||||
|
||||
// Result equals:
|
||||
// 50% >#####-----< [0s:0s]
|
||||
|
||||
```
|
||||
|
||||
### Progress for I/O operations
|
||||
|
||||
The `progressbar` implements an `io.Writer` so it can automatically detect the number of bytes written to a stream, so you can use it as a progressbar for an `io.Reader`.
|
||||
|
||||
```golang
|
||||
urlToGet := "https://github.com/schollz/croc/releases/download/v4.1.4/croc_v4.1.4_Windows-64bit_GUI.zip"
|
||||
req, _ := http.NewRequest("GET", urlToGet, nil)
|
||||
resp, _ := http.DefaultClient.Do(req)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var out io.Writer
|
||||
f, _ := os.OpenFile("croc_v4.1.4_Windows-64bit_GUI.zip", os.O_CREATE|os.O_WRONLY, 0644)
|
||||
out = f
|
||||
defer f.Close()
|
||||
|
||||
bar := progressbar.NewOptions(
|
||||
int(resp.ContentLength),
|
||||
progressbar.OptionSetBytes(int(resp.ContentLength)),
|
||||
)
|
||||
out = io.MultiWriter(out, bar)
|
||||
io.Copy(out, resp.Body)
|
||||
```
|
||||
|
||||
See the tests for another example.
|
||||
|
||||
### Changing max value
|
||||
|
||||
The `progressbar` implements `ChangeMax` and `ChangeMax64` functions to change the max value of the progress bar.
|
||||
|
||||
```golang
|
||||
bar := progressbar.New(100)
|
||||
bar.ChangeMax(200) // Change the max of the progress bar to 200, not 100
|
||||
```
|
||||
|
||||
You can also use `ChangeMax64` to minimize casting in the library.
|
||||
See the tests for another example.
|
||||
|
||||
### Displaying Total Increment Over Predicted Time
|
||||
|
||||
By default the progress bar will attempt to predict the remaining amount of time left. This can be change to
|
||||
just show the current increment over the total maximum amount set for the progress bar. Do this by using the
|
||||
`OptionSetPredictTime` option during progress bar creation.
|
||||
|
||||
```golang
|
||||
bar := progressbar.NewOptions(100, progressbar.OptionSetPredictTime(false))
|
||||
bar.Add(20)
|
||||
|
||||
// this result equals:
|
||||
// "20% |██ | [20:100]"
|
||||
|
||||
// default result equals:
|
||||
// "20% |██ | [3s:15s]"
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests are welcome. Feel free to...
|
||||
|
||||
- Revise documentation
|
||||
- Add new features
|
||||
- Fix bugs
|
||||
- Suggest improvements
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks [@Dynom](https://github.com/dynom) for massive improvements in version 2.0!
|
||||
|
||||
Thanks [@CrushedPixel](https://github.com/CrushedPixel) for adding descriptions and color code support!
|
||||
|
||||
Thanks [@MrMe42](https://github.com/MrMe42) for adding some minor features!
|
||||
|
||||
Thanks [@tehstun](https://github.com/tehstun) for some great PRs!
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
module github.com/schollz/progressbar/v2
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
|
||||
github.com/stretchr/testify v1.3.0
|
||||
)
|
||||
|
||||
go 1.13
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
+583
@@ -0,0 +1,583 @@
|
||||
package progressbar
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/colorstring"
|
||||
)
|
||||
|
||||
// ProgressBar is a thread-safe, simple
|
||||
// progress bar
|
||||
type ProgressBar struct {
|
||||
state state
|
||||
config config
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// State is the basic properties of the bar
|
||||
type State struct {
|
||||
CurrentPercent float64
|
||||
CurrentBytes float64
|
||||
MaxBytes int64
|
||||
SecondsSince float64
|
||||
SecondsLeft float64
|
||||
KBsPerSecond float64
|
||||
}
|
||||
|
||||
type state struct {
|
||||
currentNum int64
|
||||
currentPercent int
|
||||
lastPercent int
|
||||
currentSaucerSize int
|
||||
|
||||
lastShown time.Time
|
||||
startTime time.Time
|
||||
|
||||
counterTime time.Time
|
||||
counterNumSinceLast int64
|
||||
counterLastTenRates []float64
|
||||
|
||||
maxLineWidth int
|
||||
currentBytes float64
|
||||
finished bool
|
||||
}
|
||||
|
||||
type config struct {
|
||||
max int64 // max number of the counter
|
||||
width int
|
||||
writer io.Writer
|
||||
theme Theme
|
||||
renderWithBlankState bool
|
||||
description string
|
||||
|
||||
// whether the output is expected to contain color codes
|
||||
colorCodes bool
|
||||
maxBytes int64
|
||||
|
||||
// show the iterations per second
|
||||
showIterationsPerSecond bool
|
||||
showIterationsCount bool
|
||||
|
||||
// whether the progress bar should attempt to predict the finishing
|
||||
// time of the progress based on the start time and the average
|
||||
// number of seconds between increments.
|
||||
predictTime bool
|
||||
|
||||
// minimum time to wait in between updates
|
||||
throttleDuration time.Duration
|
||||
|
||||
// clear bar once finished
|
||||
clearOnFinish bool
|
||||
|
||||
onCompletion func()
|
||||
}
|
||||
|
||||
// Theme defines the elements of the bar
|
||||
type Theme struct {
|
||||
Saucer string
|
||||
SaucerHead string
|
||||
SaucerPadding string
|
||||
BarStart string
|
||||
BarEnd string
|
||||
}
|
||||
|
||||
// Option is the type all options need to adhere to
|
||||
type Option func(p *ProgressBar)
|
||||
|
||||
// OptionSetWidth sets the width of the bar
|
||||
func OptionSetWidth(s int) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.width = s
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetTheme sets the elements the bar is constructed of
|
||||
func OptionSetTheme(t Theme) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.theme = t
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetWriter sets the output writer (defaults to os.StdOut)
|
||||
func OptionSetWriter(w io.Writer) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.writer = w
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetRenderBlankState sets whether or not to render a 0% bar on construction
|
||||
func OptionSetRenderBlankState(r bool) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.renderWithBlankState = r
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetDescription sets the description of the bar to render in front of it
|
||||
func OptionSetDescription(description string) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.description = description
|
||||
}
|
||||
}
|
||||
|
||||
// OptionEnableColorCodes enables or disables support for color codes
|
||||
// using mitchellh/colorstring
|
||||
func OptionEnableColorCodes(colorCodes bool) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.colorCodes = colorCodes
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetBytes will also print the bytes/second
|
||||
func OptionSetBytes(maxBytes int) Option {
|
||||
return OptionSetBytes64(int64(maxBytes))
|
||||
}
|
||||
|
||||
// OptionSetBytes64 will also print the bytes/second
|
||||
func OptionSetBytes64(maxBytes int64) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.maxBytes = maxBytes
|
||||
}
|
||||
}
|
||||
|
||||
// OptionSetPredictTime will also attempt to predict the time remaining.
|
||||
func OptionSetPredictTime(predictTime bool) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.predictTime = predictTime
|
||||
}
|
||||
}
|
||||
|
||||
// OptionShowCount will also print current count out of total
|
||||
func OptionShowCount() Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.showIterationsCount = true
|
||||
}
|
||||
}
|
||||
|
||||
// OptionShowIts will also print the iterations/second
|
||||
func OptionShowIts() Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.showIterationsPerSecond = true
|
||||
}
|
||||
}
|
||||
|
||||
// OptionThrottle will wait the specified duration before updating again. The default
|
||||
// duration is 0 seconds.
|
||||
func OptionThrottle(duration time.Duration) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.throttleDuration = duration
|
||||
}
|
||||
}
|
||||
|
||||
// OptionClearOnFinish will clear the bar once its finished
|
||||
func OptionClearOnFinish() Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.clearOnFinish = true
|
||||
}
|
||||
}
|
||||
|
||||
func OptionOnCompletion(cmpl func()) Option {
|
||||
return func(p *ProgressBar) {
|
||||
p.config.onCompletion = cmpl
|
||||
}
|
||||
}
|
||||
|
||||
var defaultTheme = Theme{Saucer: "█", SaucerPadding: " ", BarStart: "|", BarEnd: "|"}
|
||||
|
||||
// NewOptions constructs a new instance of ProgressBar, with any options you specify
|
||||
func NewOptions(max int, options ...Option) *ProgressBar {
|
||||
return NewOptions64(int64(max), options...)
|
||||
}
|
||||
|
||||
// NewOptions64 constructs a new instance of ProgressBar, with any options you specify
|
||||
func NewOptions64(max int64, options ...Option) *ProgressBar {
|
||||
b := ProgressBar{
|
||||
state: getBasicState(),
|
||||
config: config{
|
||||
writer: os.Stdout,
|
||||
theme: defaultTheme,
|
||||
width: 40,
|
||||
max: max,
|
||||
throttleDuration: 0 * time.Nanosecond,
|
||||
predictTime: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
o(&b)
|
||||
}
|
||||
|
||||
if b.config.renderWithBlankState {
|
||||
b.RenderBlank()
|
||||
}
|
||||
|
||||
return &b
|
||||
}
|
||||
|
||||
func getBasicState() state {
|
||||
now := time.Now()
|
||||
return state{
|
||||
startTime: now,
|
||||
lastShown: now,
|
||||
counterTime: now,
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a new ProgressBar
|
||||
// with the specified maximum
|
||||
func New(max int) *ProgressBar {
|
||||
return NewOptions(max)
|
||||
}
|
||||
|
||||
// RenderBlank renders the current bar state, you can use this to render a 0% state
|
||||
func (p *ProgressBar) RenderBlank() error {
|
||||
return p.render()
|
||||
}
|
||||
|
||||
// Reset will reset the clock that is used
|
||||
// to calculate current time and the time left.
|
||||
func (p *ProgressBar) Reset() {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
p.state = getBasicState()
|
||||
}
|
||||
|
||||
// Finish will fill the bar to full
|
||||
func (p *ProgressBar) Finish() error {
|
||||
if p == nil {
|
||||
return fmt.Errorf("progressbar is nil")
|
||||
}
|
||||
p.lock.Lock()
|
||||
p.state.currentNum = p.config.max
|
||||
p.lock.Unlock()
|
||||
return p.Add(0)
|
||||
}
|
||||
|
||||
// Add will add the specified amount to the progressbar
|
||||
func (p *ProgressBar) Add(num int) error {
|
||||
return p.Add64(int64(num))
|
||||
}
|
||||
|
||||
// Set wil set the bar to a current number
|
||||
func (p *ProgressBar) Set(num int) error {
|
||||
return p.Set64(int64(num))
|
||||
}
|
||||
|
||||
// Set64 wil set the bar to a current number
|
||||
func (p *ProgressBar) Set64(num int64) error {
|
||||
p.lock.Lock()
|
||||
toAdd := int64(num) - p.state.currentNum
|
||||
p.lock.Unlock()
|
||||
return p.Add64(toAdd)
|
||||
}
|
||||
|
||||
// Add64 will add the specified amount to the progressbar
|
||||
func (p *ProgressBar) Add64(num int64) error {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if p.config.max == 0 {
|
||||
return errors.New("max must be greater than 0")
|
||||
}
|
||||
p.state.currentNum += num
|
||||
|
||||
// reset the countdown timer every second to take rolling average
|
||||
p.state.counterNumSinceLast += num
|
||||
if time.Since(p.state.counterTime).Seconds() > 0.5 && time.Since(p.state.counterTime).Seconds() > 0 {
|
||||
p.state.counterLastTenRates = append(p.state.counterLastTenRates, float64(p.state.counterNumSinceLast)/time.Since(p.state.counterTime).Seconds())
|
||||
if len(p.state.counterLastTenRates) > 10 {
|
||||
p.state.counterLastTenRates = p.state.counterLastTenRates[1:]
|
||||
}
|
||||
p.state.counterTime = time.Now()
|
||||
p.state.counterNumSinceLast = 0
|
||||
}
|
||||
|
||||
percent := float64(p.state.currentNum) / float64(p.config.max)
|
||||
p.state.currentSaucerSize = int(percent * float64(p.config.width))
|
||||
p.state.currentPercent = int(percent * 100)
|
||||
updateBar := p.state.currentPercent != p.state.lastPercent && p.state.currentPercent > 0
|
||||
|
||||
p.state.currentBytes = float64(percent) * float64(p.config.maxBytes)
|
||||
p.state.lastPercent = p.state.currentPercent
|
||||
if p.state.currentNum > p.config.max {
|
||||
return errors.New("current number exceeds max")
|
||||
}
|
||||
|
||||
// always update if show bytes/second or its/second
|
||||
if updateBar || p.config.showIterationsPerSecond || p.config.maxBytes > 0 {
|
||||
return p.render()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clear erases the progress bar from the current line
|
||||
func (p *ProgressBar) Clear() error {
|
||||
return clearProgressBar(p.config, p.state)
|
||||
}
|
||||
|
||||
// Describe will change the description shown before the progress, which
|
||||
// can be changed on the fly (as for a slow running process).
|
||||
func (p *ProgressBar) Describe(description string) {
|
||||
p.config.description = description
|
||||
}
|
||||
|
||||
// New64 returns a new ProgressBar
|
||||
// with the specified maximum
|
||||
func New64(max int64) *ProgressBar {
|
||||
return NewOptions64(max)
|
||||
}
|
||||
|
||||
// ChangeMax takes in a int
|
||||
// and changes the max value
|
||||
// of the progress bar
|
||||
func (p *ProgressBar) ChangeMax(newMax int) {
|
||||
p.config.max = int64(newMax)
|
||||
}
|
||||
|
||||
// ChangeMax64 is basically
|
||||
// the same as ChangeMax,
|
||||
// but takes in a int64
|
||||
// to avoid casting
|
||||
func (p *ProgressBar) ChangeMax64(newMax int64) {
|
||||
p.config.max = newMax
|
||||
}
|
||||
|
||||
// Get the max of a bar
|
||||
func (p *ProgressBar) GetMax() int {
|
||||
return int(p.config.max)
|
||||
}
|
||||
|
||||
// Same as GetMax, but returns int64
|
||||
func (p *ProgressBar) GetMax64() int64 {
|
||||
return p.config.max
|
||||
}
|
||||
|
||||
// render renders the progress bar, updating the maximum
|
||||
// rendered line width. this function is not thread-safe,
|
||||
// so it must be called with an acquired lock.
|
||||
func (p *ProgressBar) render() error {
|
||||
// make sure that the rendering is not happening too quickly
|
||||
// but always show if the currentNum reaches the max
|
||||
if time.Since(p.state.lastShown).Nanoseconds() < p.config.throttleDuration.Nanoseconds() &&
|
||||
p.state.currentNum < p.config.max {
|
||||
return nil
|
||||
}
|
||||
|
||||
// first, clear the existing progress bar
|
||||
err := clearProgressBar(p.config, p.state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if the progress bar is finished
|
||||
if !p.state.finished && p.state.currentNum >= p.config.max {
|
||||
p.state.finished = true
|
||||
if !p.config.clearOnFinish {
|
||||
renderProgressBar(p.config, p.state)
|
||||
}
|
||||
|
||||
if p.config.onCompletion != nil {
|
||||
p.config.onCompletion()
|
||||
}
|
||||
}
|
||||
if p.state.finished {
|
||||
return nil
|
||||
}
|
||||
|
||||
// then, re-render the current progress bar
|
||||
w, err := renderProgressBar(p.config, p.state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w > p.state.maxLineWidth {
|
||||
p.state.maxLineWidth = w
|
||||
}
|
||||
|
||||
p.state.lastShown = time.Now()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// State returns the current state
|
||||
func (p *ProgressBar) State() State {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
s := State{}
|
||||
s.CurrentPercent = float64(p.state.currentNum) / float64(p.config.max)
|
||||
s.CurrentBytes = p.state.currentBytes
|
||||
s.MaxBytes = p.config.maxBytes
|
||||
s.SecondsSince = time.Since(p.state.startTime).Seconds()
|
||||
if p.state.currentNum > 0 {
|
||||
s.SecondsLeft = s.SecondsSince / float64(p.state.currentNum) * (float64(p.config.max) - float64(p.state.currentNum))
|
||||
}
|
||||
s.KBsPerSecond = float64(p.state.currentBytes) / 1000.0 / s.SecondsSince
|
||||
return s
|
||||
}
|
||||
|
||||
// regex matching ansi escape codes
|
||||
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
|
||||
|
||||
func renderProgressBar(c config, s state) (int, error) {
|
||||
leftBrac := ""
|
||||
rightBrac := ""
|
||||
saucer := ""
|
||||
bytesString := ""
|
||||
|
||||
averageRate := average(s.counterLastTenRates)
|
||||
if len(s.counterLastTenRates) == 0 || s.finished {
|
||||
// if no average samples, or if finished,
|
||||
// then average rate should be the total rate
|
||||
averageRate = float64(s.currentNum) / time.Since(s.startTime).Seconds()
|
||||
}
|
||||
|
||||
if s.currentSaucerSize > 0 {
|
||||
saucer = strings.Repeat(c.theme.Saucer, s.currentSaucerSize-1)
|
||||
saucerHead := c.theme.SaucerHead
|
||||
if saucerHead == "" || s.currentSaucerSize == c.width {
|
||||
// use the saucer for the saucer head if it hasn't been set
|
||||
// to preserve backwards compatibility
|
||||
saucerHead = c.theme.Saucer
|
||||
}
|
||||
saucer += saucerHead
|
||||
}
|
||||
|
||||
// add on bytes string if max bytes option was set
|
||||
kbPerSecond := averageRate / float64(c.max) * float64(c.maxBytes) / 1000.0
|
||||
|
||||
if kbPerSecond > 1000.0 {
|
||||
bytesString = fmt.Sprintf("(%2.1f MB/s)", kbPerSecond/1000.0)
|
||||
} else if kbPerSecond > 0 {
|
||||
bytesString = fmt.Sprintf("(%2.1f kB/s)", kbPerSecond)
|
||||
}
|
||||
|
||||
if c.showIterationsPerSecond && !c.showIterationsCount {
|
||||
// replace bytesString if used
|
||||
bytesString = fmt.Sprintf("(%2.0f it/s)", averageRate)
|
||||
} else if !c.showIterationsPerSecond && c.showIterationsCount {
|
||||
bytesString = fmt.Sprintf("(%d/%d)", s.currentNum, c.max)
|
||||
} else if c.showIterationsPerSecond && c.showIterationsCount {
|
||||
bytesString = fmt.Sprintf("(%d/%d, %2.0f it/s)", s.currentNum, c.max, averageRate)
|
||||
}
|
||||
|
||||
if c.predictTime {
|
||||
// Predict the time
|
||||
|
||||
leftBrac = (time.Duration(time.Since(s.startTime).Seconds()) * time.Second).String()
|
||||
rightBrac = (time.Duration((1/averageRate)*(float64(c.max)-float64(s.currentNum))) * time.Second).String()
|
||||
} else {
|
||||
// Give x out of y
|
||||
|
||||
leftBrac = strconv.Itoa(int(s.currentNum))
|
||||
rightBrac = strconv.Itoa(int(c.max))
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("\r%s%4d%% %s%s%s%s %s [%s:%s]",
|
||||
c.description,
|
||||
s.currentPercent,
|
||||
c.theme.BarStart,
|
||||
saucer,
|
||||
strings.Repeat(c.theme.SaucerPadding, c.width-s.currentSaucerSize),
|
||||
c.theme.BarEnd,
|
||||
bytesString,
|
||||
leftBrac,
|
||||
rightBrac,
|
||||
)
|
||||
|
||||
if c.colorCodes {
|
||||
// convert any color codes in the progress bar into the respective ANSI codes
|
||||
str = colorstring.Color(str)
|
||||
}
|
||||
|
||||
// the width of the string, if printed to the console
|
||||
// does not include the carriage return character
|
||||
cleanString := strings.Replace(str, "\r", "", -1)
|
||||
|
||||
if c.colorCodes {
|
||||
// the ANSI codes for the colors do not take up space in the console output,
|
||||
// so they do not count towards the output string width
|
||||
cleanString = ansiRegex.ReplaceAllString(cleanString, "")
|
||||
}
|
||||
|
||||
// get the amount of runes in the string instead of the
|
||||
// character count of the string, as some runes span multiple characters.
|
||||
// see https://stackoverflow.com/a/12668840/2733724
|
||||
stringWidth := len([]rune(cleanString))
|
||||
|
||||
return stringWidth, writeString(c, str)
|
||||
}
|
||||
|
||||
func clearProgressBar(c config, s state) error {
|
||||
// fill the current line with enough spaces
|
||||
// to overwrite the progress bar and jump
|
||||
// back to the beginning of the line
|
||||
str := fmt.Sprintf("\r%s\r", strings.Repeat(" ", s.maxLineWidth))
|
||||
return writeString(c, str)
|
||||
}
|
||||
|
||||
func writeString(c config, str string) error {
|
||||
if _, err := io.WriteString(c.writer, str); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f, ok := c.writer.(*os.File); ok {
|
||||
// ignore any errors in Sync(), as stdout
|
||||
// can't be synced on some operating systems
|
||||
// like Debian 9 (Stretch)
|
||||
f.Sync()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reader is the progressbar io.Reader struct
|
||||
type Reader struct {
|
||||
io.Reader
|
||||
bar *ProgressBar
|
||||
}
|
||||
|
||||
// Read will read the data and add the number of bytes to the progressbar
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
n, err = r.Reader.Read(p)
|
||||
r.bar.Add(n)
|
||||
return
|
||||
}
|
||||
|
||||
// Close the reader when it implements io.Closer
|
||||
func (r *Reader) Close() (err error) {
|
||||
if closer, ok := r.Reader.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Write implement io.Writer
|
||||
func (p *ProgressBar) Write(b []byte) (n int, err error) {
|
||||
n = len(b)
|
||||
p.Add(n)
|
||||
return
|
||||
}
|
||||
|
||||
// Read implement io.Reader
|
||||
func (p *ProgressBar) Read(b []byte) (n int, err error) {
|
||||
n = len(b)
|
||||
p.Add(n)
|
||||
return
|
||||
}
|
||||
|
||||
func average(xs []float64) float64 {
|
||||
total := 0.0
|
||||
for _, v := range xs {
|
||||
total += v
|
||||
}
|
||||
return total / float64(len(xs))
|
||||
}
|
||||
+67
-11
@@ -32,7 +32,8 @@ func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args
|
||||
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -160,7 +161,8 @@ func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
||||
return False(t, value, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -267,7 +269,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
|
||||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -325,14 +327,6 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
|
||||
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Lenf asserts that the specified object has specific length.
|
||||
// Lenf also fails if the object has a type that len() not accept.
|
||||
//
|
||||
@@ -369,6 +363,17 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args .
|
||||
return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Nilf asserts that the specified object is nil.
|
||||
//
|
||||
// assert.Nilf(t, err, "error message %s", "formatted")
|
||||
@@ -379,6 +384,15 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool
|
||||
return Nil(t, object, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoDirExists(t, path, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NoErrorf asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
@@ -392,6 +406,15 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||
return NoError(t, err, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoFileExists(t, path, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
@@ -462,6 +485,19 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
|
||||
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
@@ -491,6 +527,18 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool
|
||||
return Panics(t, f, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
@@ -557,6 +605,14 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim
|
||||
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Zerof asserts that i is the zero value for its type.
|
||||
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
|
||||
+134
-22
@@ -53,7 +53,8 @@ func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string,
|
||||
return Containsf(a.t, s, contains, msg, args...)
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -61,7 +62,8 @@ func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
|
||||
return DirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -309,7 +311,8 @@ func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
|
||||
return Falsef(a.t, value, msg, args...)
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -317,7 +320,8 @@ func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
|
||||
return FileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -521,7 +525,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}
|
||||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
||||
// a.InDelta(math.Pi, 22/7.0, 0.01)
|
||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -563,7 +567,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del
|
||||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -639,22 +643,6 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
||||
return JSONEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
@@ -727,6 +715,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i
|
||||
return Lessf(a.t, e1, e2, msg, args...)
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Never(a.t, condition, waitFor, tick, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Neverf(a.t, condition, waitFor, tick, msg, args...)
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// a.Nil(err)
|
||||
@@ -747,6 +757,24 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) b
|
||||
return Nilf(a.t, object, msg, args...)
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoDirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoDirExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
@@ -773,6 +801,24 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
|
||||
return NoErrorf(a.t, err, msg, args...)
|
||||
}
|
||||
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoFileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoFileExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
@@ -913,6 +959,32 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
|
||||
return NotRegexpf(a.t, rx, str, msg, args...)
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSame(ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NotSame(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NotSamef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
@@ -961,6 +1033,30 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||
return Panics(a.t, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithError("crazy error", func(){ GoCrazy() })
|
||||
func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return PanicsWithError(a.t, errString, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return PanicsWithErrorf(a.t, errString, f, msg, args...)
|
||||
}
|
||||
|
||||
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
@@ -1103,6 +1199,22 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta
|
||||
return WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Zero asserts that i is the zero value for its type.
|
||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
|
||||
+173
-45
@@ -11,6 +11,7 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
@@ -21,7 +22,7 @@ import (
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
|
||||
|
||||
// TestingT is an interface wrapper around *testing.T
|
||||
type TestingT interface {
|
||||
@@ -351,6 +352,19 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
|
||||
|
||||
}
|
||||
|
||||
// validateEqualArgs checks whether provided arguments can be safely used in the
|
||||
// Equal/NotEqual functions.
|
||||
func validateEqualArgs(expected, actual interface{}) error {
|
||||
if expected == nil && actual == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if isFunction(expected) || isFunction(actual) {
|
||||
return errors.New("cannot take func type as argument")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Same asserts that two pointers reference the same object.
|
||||
//
|
||||
// assert.Same(t, ptr1, ptr2)
|
||||
@@ -362,18 +376,7 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
|
||||
if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
|
||||
return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
|
||||
}
|
||||
|
||||
expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
|
||||
if expectedType != actualType {
|
||||
return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
|
||||
expectedType, actualType), msgAndArgs...)
|
||||
}
|
||||
|
||||
if expected != actual {
|
||||
if !samePointers(expected, actual) {
|
||||
return Fail(t, fmt.Sprintf("Not same: \n"+
|
||||
"expected: %p %#v\n"+
|
||||
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
|
||||
@@ -382,6 +385,42 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
|
||||
return true
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSame(t, ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
if samePointers(expected, actual) {
|
||||
return Fail(t, fmt.Sprintf(
|
||||
"Expected and actual point to the same object: %p %#v",
|
||||
expected, expected), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// samePointers compares two generic interface objects and returns whether
|
||||
// they point to the same object
|
||||
func samePointers(first, second interface{}) bool {
|
||||
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
|
||||
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
|
||||
return false
|
||||
}
|
||||
|
||||
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
|
||||
if firstType != secondType {
|
||||
return false
|
||||
}
|
||||
|
||||
// compare pointer addresses
|
||||
return first == second
|
||||
}
|
||||
|
||||
// formatUnequalValues takes two values of arbitrary types and returns string
|
||||
// representations appropriate to be presented to the user.
|
||||
//
|
||||
@@ -393,9 +432,11 @@ func formatUnequalValues(expected, actual interface{}) (e string, a string) {
|
||||
return fmt.Sprintf("%T(%#v)", expected, expected),
|
||||
fmt.Sprintf("%T(%#v)", actual, actual)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#v", expected),
|
||||
fmt.Sprintf("%#v", actual)
|
||||
switch expected.(type) {
|
||||
case time.Duration:
|
||||
return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
|
||||
}
|
||||
return fmt.Sprintf("%#v", expected), fmt.Sprintf("%#v", actual)
|
||||
}
|
||||
|
||||
// EqualValues asserts that two objects are equal or convertable to the same types
|
||||
@@ -901,15 +942,17 @@ func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
|
||||
type PanicTestFunc func()
|
||||
|
||||
// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
|
||||
func didPanic(f PanicTestFunc) (bool, interface{}) {
|
||||
func didPanic(f PanicTestFunc) (bool, interface{}, string) {
|
||||
|
||||
didPanic := false
|
||||
var message interface{}
|
||||
var stack string
|
||||
func() {
|
||||
|
||||
defer func() {
|
||||
if message = recover(); message != nil {
|
||||
didPanic = true
|
||||
stack = string(debug.Stack())
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -918,7 +961,7 @@ func didPanic(f PanicTestFunc) (bool, interface{}) {
|
||||
|
||||
}()
|
||||
|
||||
return didPanic, message
|
||||
return didPanic, message, stack
|
||||
|
||||
}
|
||||
|
||||
@@ -930,7 +973,7 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
|
||||
if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||
}
|
||||
|
||||
@@ -946,12 +989,34 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
funcDidPanic, panicValue := didPanic(f)
|
||||
funcDidPanic, panicValue, panickedStack := didPanic(f)
|
||||
if !funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||
}
|
||||
if panicValue != expected {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
|
||||
func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
funcDidPanic, panicValue, panickedStack := didPanic(f)
|
||||
if !funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||
}
|
||||
panicErr, ok := panicValue.(error)
|
||||
if !ok || panicErr.Error() != errString {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -965,8 +1030,8 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...)
|
||||
if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -1026,7 +1091,7 @@ func toFloat(x interface{}) (float64, bool) {
|
||||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
||||
// assert.InDelta(t, math.Pi, 22/7.0, 0.01)
|
||||
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -1314,7 +1379,8 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -1332,7 +1398,24 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
info, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
if info.IsDir() {
|
||||
return true
|
||||
}
|
||||
return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...)
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -1350,6 +1433,25 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
info, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return true
|
||||
}
|
||||
return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...)
|
||||
}
|
||||
|
||||
// JSONEq asserts that two JSON strings are equivalent.
|
||||
//
|
||||
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
||||
@@ -1439,15 +1541,6 @@ func diff(expected interface{}, actual interface{}) string {
|
||||
return "\n\nDiff:\n" + diff
|
||||
}
|
||||
|
||||
// validateEqualArgs checks whether provided arguments can be safely used in the
|
||||
// Equal/NotEqual functions.
|
||||
func validateEqualArgs(expected, actual interface{}) error {
|
||||
if isFunction(expected) || isFunction(actual) {
|
||||
return errors.New("cannot take func type as argument")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isFunction(arg interface{}) bool {
|
||||
if arg == nil {
|
||||
return false
|
||||
@@ -1475,24 +1568,59 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
ch := make(chan bool, 1)
|
||||
|
||||
timer := time.NewTimer(waitFor)
|
||||
ticker := time.NewTicker(tick)
|
||||
checkPassed := make(chan bool)
|
||||
defer timer.Stop()
|
||||
|
||||
ticker := time.NewTicker(tick)
|
||||
defer ticker.Stop()
|
||||
defer close(checkPassed)
|
||||
for {
|
||||
|
||||
for tick := ticker.C; ; {
|
||||
select {
|
||||
case <-timer.C:
|
||||
return Fail(t, "Condition never satisfied", msgAndArgs...)
|
||||
case result := <-checkPassed:
|
||||
if result {
|
||||
case <-tick:
|
||||
tick = nil
|
||||
go func() { ch <- condition() }()
|
||||
case v := <-ch:
|
||||
if v {
|
||||
return true
|
||||
}
|
||||
case <-ticker.C:
|
||||
go func() {
|
||||
checkPassed <- condition()
|
||||
}()
|
||||
tick = ticker.C
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
ch := make(chan bool, 1)
|
||||
|
||||
timer := time.NewTimer(waitFor)
|
||||
defer timer.Stop()
|
||||
|
||||
ticker := time.NewTicker(tick)
|
||||
defer ticker.Stop()
|
||||
|
||||
for tick := ticker.C; ; {
|
||||
select {
|
||||
case <-timer.C:
|
||||
return true
|
||||
case <-tick:
|
||||
tick = nil
|
||||
go func() { ch <- condition() }()
|
||||
case v := <-ch:
|
||||
if v {
|
||||
return Fail(t, "Condition satisfied", msgAndArgs...)
|
||||
}
|
||||
tick = ticker.C
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,4 +13,4 @@ func New(t TestingT) *Assertions {
|
||||
}
|
||||
}
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs"
|
||||
|
||||
+1
-1
@@ -13,4 +13,4 @@ func New(t TestingT) *Assertions {
|
||||
}
|
||||
}
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs"
|
||||
|
||||
+176
-34
@@ -66,7 +66,8 @@ func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -77,7 +78,8 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -275,12 +277,12 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) {
|
||||
//
|
||||
// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
|
||||
func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||
if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
@@ -289,12 +291,12 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
|
||||
//
|
||||
// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||
if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
|
||||
return
|
||||
}
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
@@ -394,7 +396,8 @@ func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -405,7 +408,8 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -660,7 +664,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
|
||||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
||||
// assert.InDelta(t, math.Pi, 22/7.0, 0.01)
|
||||
func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -717,7 +721,7 @@ func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta f
|
||||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -820,28 +824,6 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEqf(t, expected, actual, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
@@ -932,6 +914,34 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Never(t, condition, waitFor, tick, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Neverf(t, condition, waitFor, tick, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// assert.Nil(t, err)
|
||||
@@ -958,6 +968,30 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoDirExists(t, path, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoDirExistsf(t, path, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
@@ -990,6 +1024,30 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoFileExists(t, path, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoFileExistsf(t, path, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
@@ -1166,6 +1224,38 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSame(t, ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NotSame(t, expected, actual, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NotSamef(t, expected, actual, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
@@ -1229,6 +1319,36 @@ func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
|
||||
func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.PanicsWithError(t, errString, f, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.PanicsWithErrorf(t, errString, f, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
@@ -1410,6 +1530,28 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEqf(t, expected, actual, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Zero asserts that i is the zero value for its type.
|
||||
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
|
||||
+134
-22
@@ -54,7 +54,8 @@ func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string,
|
||||
Containsf(a.t, s, contains, msg, args...)
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -62,7 +63,8 @@ func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
|
||||
DirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -310,7 +312,8 @@ func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
|
||||
Falsef(a.t, value, msg, args...)
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -318,7 +321,8 @@ func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
|
||||
FileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -522,7 +526,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}
|
||||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
||||
// a.InDelta(math.Pi, 22/7.0, 0.01)
|
||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -564,7 +568,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del
|
||||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
@@ -640,22 +644,6 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
||||
JSONEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
@@ -728,6 +716,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i
|
||||
Lessf(a.t, e1, e2, msg, args...)
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
Never(a.t, condition, waitFor, tick, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
Neverf(a.t, condition, waitFor, tick, msg, args...)
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// a.Nil(err)
|
||||
@@ -748,6 +758,24 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
|
||||
Nilf(a.t, object, msg, args...)
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoDirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoDirExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
@@ -774,6 +802,24 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
|
||||
NoErrorf(a.t, err, msg, args...)
|
||||
}
|
||||
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoFileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoFileExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
@@ -914,6 +960,32 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
|
||||
NotRegexpf(a.t, rx, str, msg, args...)
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSame(ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NotSame(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NotSamef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
@@ -962,6 +1034,30 @@ func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
Panics(a.t, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithError("crazy error", func(){ GoCrazy() })
|
||||
func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
PanicsWithError(a.t, errString, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
PanicsWithErrorf(a.t, errString, f, msg, args...)
|
||||
}
|
||||
|
||||
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
@@ -1104,6 +1200,22 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta
|
||||
WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Zero asserts that i is the zero value for its type.
|
||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
|
||||
+1
-1
@@ -26,4 +26,4 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{})
|
||||
// for table driven tests.
|
||||
type ErrorAssertionFunc func(TestingT, error, ...interface{})
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs"
|
||||
|
||||
+11
-7
@@ -1,12 +1,16 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- tip
|
||||
- "1.4.x"
|
||||
- "1.5.x"
|
||||
- "1.6.x"
|
||||
- "1.7.x"
|
||||
- "1.8.x"
|
||||
- "1.9.x"
|
||||
- "1.10.x"
|
||||
- "1.11.x"
|
||||
- "1.12.x"
|
||||
- "1.13.x"
|
||||
- "tip"
|
||||
|
||||
go_import_path: gopkg.in/yaml.v2
|
||||
|
||||
+8
-6
@@ -319,10 +319,14 @@ func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unm
|
||||
}
|
||||
|
||||
const (
|
||||
// 400,000 decode operations is ~500kb of dense object declarations, or ~5kb of dense object declarations with 10000% alias expansion
|
||||
// 400,000 decode operations is ~500kb of dense object declarations, or
|
||||
// ~5kb of dense object declarations with 10000% alias expansion
|
||||
alias_ratio_range_low = 400000
|
||||
// 4,000,000 decode operations is ~5MB of dense object declarations, or ~4.5MB of dense object declarations with 10% alias expansion
|
||||
|
||||
// 4,000,000 decode operations is ~5MB of dense object declarations, or
|
||||
// ~4.5MB of dense object declarations with 10% alias expansion
|
||||
alias_ratio_range_high = 4000000
|
||||
|
||||
// alias_ratio_range is the range over which we scale allowed alias ratios
|
||||
alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
|
||||
)
|
||||
@@ -784,8 +788,7 @@ func (d *decoder) merge(n *node, out reflect.Value) {
|
||||
case mappingNode:
|
||||
d.unmarshal(n, out)
|
||||
case aliasNode:
|
||||
an, ok := d.doc.anchors[n.value]
|
||||
if ok && an.kind != mappingNode {
|
||||
if n.alias != nil && n.alias.kind != mappingNode {
|
||||
failWantMap()
|
||||
}
|
||||
d.unmarshal(n, out)
|
||||
@@ -794,8 +797,7 @@ func (d *decoder) merge(n *node, out reflect.Value) {
|
||||
for i := len(n.children) - 1; i >= 0; i-- {
|
||||
ni := n.children[i]
|
||||
if ni.kind == aliasNode {
|
||||
an, ok := d.doc.anchors[ni.value]
|
||||
if ok && an.kind != mappingNode {
|
||||
if ni.alias != nil && ni.alias.kind != mappingNode {
|
||||
failWantMap()
|
||||
}
|
||||
} else if ni.kind != mappingNode {
|
||||
|
||||
+54
-55
@@ -626,30 +626,17 @@ func trace(args ...interface{}) func() {
|
||||
func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
|
||||
// While we need more tokens to fetch, do it.
|
||||
for {
|
||||
// Check if we really need to fetch more tokens.
|
||||
need_more_tokens := false
|
||||
|
||||
if parser.tokens_head == len(parser.tokens) {
|
||||
// Queue is empty.
|
||||
need_more_tokens = true
|
||||
} else {
|
||||
// Check if any potential simple key may occupy the head position.
|
||||
if !yaml_parser_stale_simple_keys(parser) {
|
||||
if parser.tokens_head != len(parser.tokens) {
|
||||
// If queue is non-empty, check if any potential simple key may
|
||||
// occupy the head position.
|
||||
head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
|
||||
if !ok {
|
||||
break
|
||||
} else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
|
||||
return false
|
||||
} else if !valid {
|
||||
break
|
||||
}
|
||||
|
||||
for i := range parser.simple_keys {
|
||||
simple_key := &parser.simple_keys[i]
|
||||
if simple_key.possible && simple_key.token_number == parser.tokens_parsed {
|
||||
need_more_tokens = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are finished.
|
||||
if !need_more_tokens {
|
||||
break
|
||||
}
|
||||
// Fetch the next token.
|
||||
if !yaml_parser_fetch_next_token(parser) {
|
||||
@@ -678,11 +665,6 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove obsolete potential simple keys.
|
||||
if !yaml_parser_stale_simple_keys(parser) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check the indentation level against the current column.
|
||||
if !yaml_parser_unroll_indent(parser, parser.mark.column) {
|
||||
return false
|
||||
@@ -837,29 +819,30 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
|
||||
"found character that cannot start any token")
|
||||
}
|
||||
|
||||
// Check the list of potential simple keys and remove the positions that
|
||||
// cannot contain simple keys anymore.
|
||||
func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {
|
||||
// Check for a potential simple key for each flow level.
|
||||
for i := range parser.simple_keys {
|
||||
simple_key := &parser.simple_keys[i]
|
||||
|
||||
// The specification requires that a simple key
|
||||
//
|
||||
// - is limited to a single line,
|
||||
// - is shorter than 1024 characters.
|
||||
if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {
|
||||
|
||||
// Check if the potential simple key to be removed is required.
|
||||
if simple_key.required {
|
||||
return yaml_parser_set_scanner_error(parser,
|
||||
"while scanning a simple key", simple_key.mark,
|
||||
"could not find expected ':'")
|
||||
}
|
||||
simple_key.possible = false
|
||||
}
|
||||
func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
|
||||
if !simple_key.possible {
|
||||
return false, true
|
||||
}
|
||||
return true
|
||||
|
||||
// The 1.2 specification says:
|
||||
//
|
||||
// "If the ? indicator is omitted, parsing needs to see past the
|
||||
// implicit key to recognize it as such. To limit the amount of
|
||||
// lookahead required, the “:” indicator must appear at most 1024
|
||||
// Unicode characters beyond the start of the key. In addition, the key
|
||||
// is restricted to a single line."
|
||||
//
|
||||
if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
|
||||
// Check if the potential simple key to be removed is required.
|
||||
if simple_key.required {
|
||||
return false, yaml_parser_set_scanner_error(parser,
|
||||
"while scanning a simple key", simple_key.mark,
|
||||
"could not find expected ':'")
|
||||
}
|
||||
simple_key.possible = false
|
||||
return false, true
|
||||
}
|
||||
return true, true
|
||||
}
|
||||
|
||||
// Check if a simple key may start at the current position and add it if
|
||||
@@ -879,13 +862,14 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
|
||||
possible: true,
|
||||
required: required,
|
||||
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
|
||||
mark: parser.mark,
|
||||
}
|
||||
simple_key.mark = parser.mark
|
||||
|
||||
if !yaml_parser_remove_simple_key(parser) {
|
||||
return false
|
||||
}
|
||||
parser.simple_keys[len(parser.simple_keys)-1] = simple_key
|
||||
parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -900,9 +884,10 @@ func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
|
||||
"while scanning a simple key", parser.simple_keys[i].mark,
|
||||
"could not find expected ':'")
|
||||
}
|
||||
// Remove the key from the stack.
|
||||
parser.simple_keys[i].possible = false
|
||||
delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
|
||||
}
|
||||
// Remove the key from the stack.
|
||||
parser.simple_keys[i].possible = false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -912,7 +897,12 @@ const max_flow_level = 10000
|
||||
// Increase the flow level and resize the simple key list if needed.
|
||||
func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
|
||||
// Reset the simple key on the next level.
|
||||
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
|
||||
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
|
||||
possible: false,
|
||||
required: false,
|
||||
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
|
||||
mark: parser.mark,
|
||||
})
|
||||
|
||||
// Increase the flow level.
|
||||
parser.flow_level++
|
||||
@@ -928,7 +918,9 @@ func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
|
||||
func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
|
||||
if parser.flow_level > 0 {
|
||||
parser.flow_level--
|
||||
parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
|
||||
last := len(parser.simple_keys) - 1
|
||||
delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
|
||||
parser.simple_keys = parser.simple_keys[:last]
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -1005,6 +997,8 @@ func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
|
||||
// Initialize the simple key stack.
|
||||
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
|
||||
|
||||
parser.simple_keys_by_tok = make(map[int]int)
|
||||
|
||||
// A simple key is allowed at the beginning of the stream.
|
||||
parser.simple_key_allowed = true
|
||||
|
||||
@@ -1286,7 +1280,11 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
|
||||
simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
|
||||
|
||||
// Have we found a simple key?
|
||||
if simple_key.possible {
|
||||
if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
|
||||
return false
|
||||
|
||||
} else if valid {
|
||||
|
||||
// Create the KEY token and insert it into the queue.
|
||||
token := yaml_token_t{
|
||||
typ: yaml_KEY_TOKEN,
|
||||
@@ -1304,6 +1302,7 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
|
||||
|
||||
// Remove the simple key.
|
||||
simple_key.possible = false
|
||||
delete(parser.simple_keys_by_tok, simple_key.token_number)
|
||||
|
||||
// A simple key cannot follow another simple key.
|
||||
parser.simple_key_allowed = false
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ func UnmarshalStrict(in []byte, out interface{}) (err error) {
|
||||
return unmarshal(in, out, true)
|
||||
}
|
||||
|
||||
// A Decorder reads and decodes YAML values from an input stream.
|
||||
// A Decoder reads and decodes YAML values from an input stream.
|
||||
type Decoder struct {
|
||||
strict bool
|
||||
parser *parser
|
||||
|
||||
+1
@@ -579,6 +579,7 @@ type yaml_parser_t struct {
|
||||
|
||||
simple_key_allowed bool // May a simple key occur at the current position?
|
||||
simple_keys []yaml_simple_key_t // The stack of simple keys.
|
||||
simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
|
||||
|
||||
// Parser stuff
|
||||
|
||||
|
||||
Vendored
+6
-2
@@ -106,6 +106,8 @@ github.com/minio/minio-go/v6/pkg/s3signer
|
||||
github.com/minio/minio-go/v6/pkg/set
|
||||
# github.com/minio/sha256-simd v0.1.1
|
||||
github.com/minio/sha256-simd
|
||||
# github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
|
||||
github.com/mitchellh/colorstring
|
||||
# github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/go-homedir
|
||||
# github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
@@ -133,6 +135,8 @@ github.com/prometheus/procfs/internal/fs
|
||||
# github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd
|
||||
github.com/rwcarlsen/goexif/exif
|
||||
github.com/rwcarlsen/goexif/tiff
|
||||
# github.com/schollz/progressbar/v2 v2.15.0
|
||||
github.com/schollz/progressbar/v2
|
||||
# github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009
|
||||
github.com/sony/sonyflake
|
||||
# github.com/spf13/afero v1.2.2
|
||||
@@ -148,7 +152,7 @@ github.com/spf13/pflag
|
||||
github.com/steinfletcher/apitest
|
||||
# github.com/steinfletcher/apitest-jsonpath v1.3.0
|
||||
github.com/steinfletcher/apitest-jsonpath
|
||||
# github.com/stretchr/testify v1.4.0
|
||||
# github.com/stretchr/testify v1.5.1
|
||||
github.com/stretchr/testify/require
|
||||
github.com/stretchr/testify/assert
|
||||
# github.com/titpetric/factory v0.0.0-20190806200833-ae4b02b9e034
|
||||
@@ -285,7 +289,7 @@ gopkg.in/mail.v2
|
||||
gopkg.in/square/go-jose.v2
|
||||
gopkg.in/square/go-jose.v2/cipher
|
||||
gopkg.in/square/go-jose.v2/json
|
||||
# gopkg.in/yaml.v2 v2.2.4
|
||||
# gopkg.in/yaml.v2 v2.2.8
|
||||
gopkg.in/yaml.v2
|
||||
# honnef.co/go/tools v0.0.1-2019.2.3
|
||||
honnef.co/go/tools/cmd/staticcheck
|
||||
|
||||
Reference in New Issue
Block a user