Commit c2e6046d authored by Anthony Fok's avatar Anthony Fok

Update upstream source from tag 'upstream/1.4.0'

Update to upstream version '1.4.0'
with Debian dir 7eddb747582afca1c7d3afd7894ae7acbdd5dcc5
parents 2fbe4d6d 2738d87c
language: go
go_import_path: github.com/frankban/quicktest
go:
- "1.7"
- "1.8"
- "1.9"
- "1.10"
- "1.11.x"
- "1.12.x"
- 1.x
- master
script:
- go get -v github.com/rogpeppe/godeps
- $GOPATH/bin/godeps -u dependencies.tsv
- GO111MODULE=on go test -v ./...
- GO111MODULE=on go test -race ./...
# Make is only required when using Go < 1.11.
# On newer Go versions dependency management is handled by Go modules.
default: test
$(GOPATH)/bin/godeps:
go get -v github.com/rogpeppe/godeps
deps: $(GOPATH)/bin/godeps
$(GOPATH)/bin/godeps -u dependencies.tsv
create-deps: $(GOPATH)/bin/godeps
$(GOPATH)/bin/godeps -t ./... > dependencies.tsv
.PHONY: install
install: deps
go install -v ./...
.PHONY: test
test: deps
go test -v ./...
......@@ -7,6 +7,8 @@ import (
"fmt"
"reflect"
"regexp"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
......@@ -61,6 +63,9 @@ func (c *equalsChecker) Check(got interface{}, args []interface{}, note func(key
}
}()
if want := args[0]; got != want {
if _, ok := got.(error); ok && want == nil {
return errors.New("got non-nil error")
}
return errors.New("values are not equal")
}
return nil
......@@ -75,15 +80,21 @@ func (c *equalsChecker) Check(got interface{}, args []interface{}, note func(key
// c.Assert(got, qt.CmpEquals(), []int{42, 47}) // Same as qt.DeepEquals.
//
func CmpEquals(opts ...cmp.Option) Checker {
return cmpEquals(testing.Verbose, opts...)
}
func cmpEquals(verbose func() bool, opts ...cmp.Option) Checker {
return &cmpEqualsChecker{
argNames: []string{"got", "want"},
opts: opts,
verbose: verbose,
}
}
type cmpEqualsChecker struct {
argNames
opts cmp.Options
opts cmp.Options
verbose func() bool
}
// Check implements Checker.Check by checking that got == args[0] according to
......@@ -99,8 +110,14 @@ func (c *cmpEqualsChecker) Check(got interface{}, args []interface{}, note func(
}()
want := args[0]
if diff := cmp.Diff(got, want, c.opts...); diff != "" {
// Only output values when the verbose flag is set.
if c.verbose() {
note("diff (-got +want)", Unquoted(diff))
return errors.New("values are not deep equal")
}
note("error", Unquoted("values are not deep equal"))
note("diff (-got +want)", Unquoted(diff))
return errors.New("values are not deep equal")
return ErrSilent
}
return nil
}
......@@ -142,7 +159,6 @@ func (c *matchesChecker) Check(got interface{}, args []interface{}, note func(ke
case string:
return match(v, pattern, "value does not match regexp", note)
case fmt.Stringer:
note("value.String()", v.String())
return match(v.String(), pattern, "value.String() does not match regexp", note)
}
note("value", got)
......@@ -166,15 +182,14 @@ type errorMatchesChecker struct {
// Check implements Checker.Check by checking that got is an error whose
// Error() matches args[0].
func (c *errorMatchesChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error {
if got == nil {
return errors.New("got nil error but want non-nil")
}
err, ok := got.(error)
if !ok {
note("got", got)
return BadCheckf("first argument is not an error")
}
if err == nil {
return errors.New("no error found")
}
note("error message", err.Error())
return match(err.Error(), args[0], "error does not match regexp", note)
}
......@@ -326,9 +341,7 @@ func (c *satisfiesChecker) Check(got interface{}, args []interface{}, note func(
note("predicate function", predicate)
return BadCheckf("cannot use value of type %v as type %v in argument to predicate function", v.Type(), t)
}
result := f.Call([]reflect.Value{v})[0].Interface().(bool)
note("result", result)
if result {
if f.Call([]reflect.Value{v})[0].Interface().(bool) {
return nil
}
return fmt.Errorf("value does not satisfy predicate function")
......@@ -365,6 +378,155 @@ func (c *notChecker) Check(got interface{}, args []interface{}, note func(key st
return errors.New("unexpected success")
}
// Contains is a checker that checks that a map, slice, array
// or string contains a value. It's the same as using
// Any(Equals), except that it has a special case
// for strings - if the first argument is a string,
// the second argument must also be a string
// and strings.Contains will be used.
//
// For example:
//
// c.Assert("hello world", qt.Contains, "world")
// c.Assert([]int{3,5,7,99}, qt.Contains, 7)
var Contains Checker = &containsChecker{
argNames: []string{"got", "want"},
}
type containsChecker struct {
argNames
}
// Check implements Checker.Check by checking that got contains args[0].
func (c *containsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error {
if got, ok := got.(string); ok {
want, ok := args[0].(string)
if !ok {
return BadCheckf("strings can only contain strings, not %T", args[0])
}
if strings.Contains(got, want) {
return nil
}
return errors.New("no substring match found")
}
return Any(Equals).Check(got, args, note)
}
// Any returns a Checker that uses the given checker to check elements
// of a slice or array or the values from a map. It succeeds if any element
// passes the check.
//
// For example:
//
// c.Assert([]int{3,5,7,99}, qt.Any(qt.Equals), 7)
// c.Assert([][]string{{"a", "b"}, {"c", "d"}}, qt.Any(qt.DeepEquals), []string{"c", "d"})
//
// See also All and Contains.
func Any(c Checker) Checker {
return &anyChecker{
argNames: append([]string{"container"}, c.ArgNames()[1:]...),
elemChecker: c,
}
}
type anyChecker struct {
argNames
elemChecker Checker
}
// Check implements Checker.Check by checking that one of the elements of
// got passes the c.elemChecker check.
func (c *anyChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error {
iter, err := newIter(got)
if err != nil {
return BadCheckf("%v", err)
}
for iter.next() {
// For the time being, discard the notes added by the sub-checker,
// because it's not clear what a good behaviour would be.
// Should we print all the failed check for all elements? If there's only
// one element in the container, the answer is probably yes,
// but let's leave it for now.
err := c.elemChecker.Check(
iter.value().Interface(),
args,
func(key string, value interface{}) {},
)
if err == nil {
return nil
}
if IsBadCheck(err) {
return BadCheckf("at %s: %v", iter.key(), err)
}
}
return errors.New("no matching element found")
}
// All returns a Checker that uses the given checker to check elements
// of slice or array or the values of a map. It succeeds if all elements
// pass the check.
// On failure it prints the error from the first index that failed.
//
// For example:
//
// c.Assert([]int{3, 5, 8}, qt.All(qt.Not(qt.Equals)), 0)
// c.Assert([][]string{{"a", "b"}, {"a", "b"}}, qt.All(qt.DeepEquals), []string{"c", "d"})
//
// See also Any and Contains.
func All(c Checker) Checker {
return &allChecker{
argNames: append([]string{"container"}, c.ArgNames()[1:]...),
elemChecker: c,
}
}
type allChecker struct {
argNames
elemChecker Checker
}
// Check implement Checker.Check by checking that all the elements of got
// pass the c.elemChecker check.
func (c *allChecker) Check(got interface{}, args []interface{}, notef func(key string, value interface{})) error {
iter, err := newIter(got)
if err != nil {
return BadCheckf("%v", err)
}
for iter.next() {
// Store any notes added by the checker so
// we can add our own note at the start
// to say which element failed.
var notes []note
err := c.elemChecker.Check(
iter.value().Interface(),
args,
func(key string, val interface{}) {
notes = append(notes, note{key, val})
},
)
if err == nil {
continue
}
if IsBadCheck(err) {
return BadCheckf("at %s: %v", iter.key(), err)
}
notef("error", Unquoted("mismatch at "+iter.key()))
// TODO should we print the whole container value in
// verbose mode?
if err != ErrSilent {
// If the error's not silent, the checker is expecting
// the caller to print the error and the value that failed.
notef("error", Unquoted(err.Error()))
notef("first mismatched element", iter.value().Interface())
}
for _, n := range notes {
notef(n.key, n.value)
}
return ErrSilent
}
return nil
}
// argNames helps implementing Checker.ArgNames.
type argNames []string
......
This diff is collapsed.
github.com/google/go-cmp git 3af367b6b30c263d47e8895973edcca9a49cf029 2018-02-02T21:19:42Z
github.com/kr/pretty git 73f6ac0b30a98e433b289500d779f50c1a6f0712 2018-05-06T08:33:45Z
github.com/kr/text git e2ffdb16a802fe2bb95e2e35ff34f0e53aeef34f 2018-05-06T08:24:08Z
......@@ -4,6 +4,7 @@ package quicktest_test
import (
"errors"
"fmt"
"testing"
qt "github.com/frankban/quicktest"
......@@ -23,3 +24,30 @@ func TestIsBadCheck(t *testing.T) {
err = errors.New("bad wolf")
assertBool(t, qt.IsBadCheck(err), false)
}
var errBadWolf = &errTest{
msg: "bad wolf",
formatted: true,
}
// errTest is an error type used in tests.
type errTest struct {
msg string
formatted bool
}
// Error implements error.
func (err *errTest) Error() string {
return err.msg
}
// Format implements fmt.Formatter.
func (err *errTest) Format(f fmt.State, c rune) {
if !f.Flag('+') || c != 'v' {
fmt.Fprint(f, "unexpected verb for formatting the error")
}
fmt.Fprint(f, err.Error())
if err.formatted {
fmt.Fprint(f, "\n file:line")
}
}
// Licensed under the MIT license, see LICENCE file for details.
package quicktest
var Prefixf = prefixf
// WithVerbosity returns the given checker with a verbosity level of v.
// A copy of the original checker is made if mutating it is required.
func WithVerbosity(c Checker, v bool) Checker {
if c, ok := c.(*cmpEqualsChecker); ok {
c := *c
c.verbose = func() bool {
return v
}
return &c
}
return c
}
// Licensed under the MIT license, see LICENCE file for details.
package quicktest
import (
"fmt"
"strconv"
"strings"
"github.com/kr/pretty"
)
// Format formats the given value as a string. It is used to print values in
// test failures unless that's changed by calling C.SetFormat.
func Format(v interface{}) string {
switch v := v.(type) {
case error:
return formatErr(v)
case fmt.Stringer:
return "s" + quoteString(v.String())
case string:
return quoteString(v)
}
// The pretty.Sprint equivalent does not quote string values.
return fmt.Sprintf("%# v", pretty.Formatter(v))
}
func formatErr(err error) string {
s := fmt.Sprintf("%+v", err)
if s != err.Error() {
// The error has formatted itself with additional information.
// Leave that as is.
return s
}
return "e" + quoteString(s)
}
func quoteString(s string) string {
// TODO think more about what to do about multi-line strings.
if strings.Contains(s, `"`) && !strings.Contains(s, "\n") && strconv.CanBackquote(s) {
return "`" + s + "`"
}
return strconv.Quote(s)
}
type formatFunc func(interface{}) string
// Licensed under the MIT license, see LICENCE file for details.
package quicktest_test
import (
"bytes"
"testing"
qt "github.com/frankban/quicktest"
)
var formatTests = []struct {
about string
value interface{}
want string
}{{
about: "error value",
value: errBadWolf,
want: "bad wolf\n file:line",
}, {
about: "error value: not formatted",
value: &errTest{
msg: "exterminate!",
},
want: `e"exterminate!"`,
}, {
about: "error value: with quotes",
value: &errTest{
msg: `cannot open "/no/such/file"`,
},
want: "e`cannot open \"/no/such/file\"`",
}, {
about: "error value: multi-line",
value: &errTest{
msg: `err:
"these are the voyages"`,
},
want: `e"err:\n\"these are the voyages\""`,
}, {
about: "error value: with backquotes",
value: &errTest{
msg: "cannot `open` \"file\"",
},
want: `e"cannot ` + "`open`" + ` \"file\""`,
}, {
about: "stringer",
value: bytes.NewBufferString("I am a stringer"),
want: `s"I am a stringer"`,
}, {
about: "stringer: with quotes",
value: bytes.NewBufferString(`I say "hello"`),
want: "s`I say \"hello\"`",
}, {
about: "string",
value: "these are the voyages",
want: `"these are the voyages"`,
}, {
about: "string: with quotes",
value: `here is a quote: "`,
want: "`here is a quote: \"`",
}, {
about: "string: multi-line",
value: `foo
"bar"
`,
want: `"foo\n\"bar\"\n"`,
}, {
about: "string: with backquotes",
value: `"` + "`",
want: `"\"` + "`\"",
}, {
about: "slice",
value: []int{1, 2, 3},
want: "[]int{1, 2, 3}",
}, {
about: "time",
value: goTime,
want: `s"2012-03-28 00:00:00 +0000 UTC"`,
}}
func TestFormat(t *testing.T) {
for _, test := range formatTests {
t.Run(test.about, func(t *testing.T) {
got := qt.Format(test.value)
if got != test.want {
t.Fatalf("format:\ngot %q\nwant %q", got, test.want)
}
})
}
}
module github.com/frankban/quicktest
require (
github.com/google/go-cmp v0.2.0
github.com/google/go-cmp v0.3.0
github.com/kr/pretty v0.1.0
)
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
......
// Licensed under the MIT license, see LICENCE file for details.
package quicktest
import (
"fmt"
"reflect"
)
// containerIter provides an interface for iterating over a container
// (map, slice or array).
type containerIter interface {
// next advances to the next item in the container.
next() bool
// key returns the current key as a string.
key() string
// value returns the current value.
value() reflect.Value
}
// newIter returns an iterator over x which must be a map, slice
// or array.
func newIter(x interface{}) (containerIter, error) {
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Map:
return newMapIter(v), nil
case reflect.Slice, reflect.Array:
return &sliceIter{
index: -1,
v: v,
}, nil
default:
return nil, fmt.Errorf("map, slice or array required")
}
}
// sliceIter implements containerIter for slices and arrays.
type sliceIter struct {
v reflect.Value
index int
}
func (i *sliceIter) next() bool {
i.index++
return i.index < i.v.Len()
}
func (i *sliceIter) value() reflect.Value {
return i.v.Index(i.index)
}
func (i *sliceIter) key() string {
return fmt.Sprintf("index %d", i.index)
}
// Licensed under the MIT license, see LICENCE file for details.
// +build go1.12
package quicktest
import (
"fmt"
"reflect"
)
func newMapIter(v reflect.Value) containerIter {
return mapIter{v.MapRange()}
}
// mapIter implements containerIter for maps.
type mapIter struct {
iter *reflect.MapIter
}
func (i mapIter) next() bool {
return i.iter.Next()
}
func (i mapIter) key() string {
return fmt.Sprintf("key %#v", i.iter.Key())
}
func (i mapIter) value() reflect.Value {
return i.iter.Value()
}
// Licensed under the MIT license, see LICENCE file for details.
// +build !go1.12
package quicktest
import (
"fmt"
"reflect"
)
func newMapIter(v reflect.Value) containerIter {
return &mapIter{
v: v,
keys: v.MapKeys(),
index: -1,
}
}
// mapIter implements containerIter for maps prior to the
// introduction of reflect.Value.MapRange in Go 1.12.
type mapIter struct {
v reflect.Value
keys []reflect.Value
index int
}
func (i *mapIter) next() bool {
i.index++
return i.index < len(i.keys)
}
func (i *mapIter) value() reflect.Value {
v := i.v.MapIndex(i.keys[i.index])
if !v.IsValid() {
// We've probably got a NaN key; we can't
// get NaN keys from maps with reflect,
// so just return the zero value.
return reflect.Zero(i.v.Type().Elem())
}
return v
}
func (i *mapIter) key() string {
return fmt.Sprintf("key %#v", i.keys[i.index])
}
......@@ -9,13 +9,13 @@ import (
)
// Patch sets a variable to a temporary value for the duration of the
// test (until c.Cleanup is called).
// test (until c.Done is called).
//
// It sets the value pointed to by the given destination to the given
// value, which must be assignable to the element type of the
// destination.
//
// When c.Cleanup is called, the destination is set to its original
// When c.Done is called, the destination is set to its original
// value.
func (c *C) Patch(dest, value interface{}) {
destv := reflect.ValueOf(dest).Elem()
......@@ -28,20 +28,20 @@ func (c *C) Patch(dest, value interface{}) {
valuev = reflect.Zero(destv.Type())
}
destv.Set(valuev)
c.AddCleanup(func() {
c.Defer(func() {
destv.Set(oldv)
})
}
// Setenv sets an environment variable to a temporary value for the
// duration of the test (until c.Cleanup is called).
// duration of the test (until c.Done is called).
//
// When c.Cleanup is called, the environment variable will be returned
// When c.Done is called, the environment variable will be returned
// to its original value.
func (c *C) Setenv(name, val string) {
oldVal := os.Getenv(name)
os.Setenv(name, val)
c.AddCleanup(func() {
c.Defer(func() {
os.Setenv(name, oldVal)
})
}
......@@ -49,11 +49,11 @@ func (c *C) Setenv(name, val string) {
// Mkdir makes a temporary directory and returns its name.
//
// The directory and its contents will be removed when
// c.Cleanup is called.
// c.Done is called.
func (c *C) Mkdir() string {
name, err := ioutil.TempDir("", "quicktest-")
c.Assert(err, Equals, nil)
c.AddCleanup(func() {
c.Defer(func() {
err := os.RemoveAll(name)
c.Check(err, Equals, nil)
})
......
......@@ -16,7 +16,7 @@ func TestPatchSetInt(t *testing.T) {
i := 99
c.Patch(&i, 88)
c.Assert(i, qt.Equals, 88)
c.Cleanup()
c.Done()
c.Assert(i, qt.Equals, 99)
}
......@@ -27,7 +27,7 @@ func TestPatchSetError(t *testing.T) {
err := oldErr
c.Patch(&err, newErr)
c.Assert(err, qt.Equals, newErr)
c.Cleanup()
c.Done()
c.Assert(err, qt.Equals, oldErr)
}
......@@ -37,7 +37,7 @@ func TestPatchSetErrorToNil(t *testing.T) {
err := oldErr
c.Patch(&err, nil)
c.Assert(err, qt.Equals, nil)
c.Cleanup()
c.Done()
c.Assert(err, qt.Equals, oldErr)
}
......@@ -47,7 +47,7 @@ func TestPatchSetMapToNil(t *testing.T) {
m := oldMap
c.Patch(&m, nil)
c.Assert(m, qt.IsNil)
c.Cleanup()
c.Done()
c.Assert(m, qt.DeepEquals, oldMap)
}
......@@ -64,7 +64,7 @@ func TestSetenv(t *testing.T) {
os.Setenv(envName, "initial")
c.Setenv(envName, "new value")
c.Check(os.Getenv(envName), qt.Equals, "new value")
c.Cleanup()
c.Done()
c.Check(os.Getenv(envName), qt.Equals, "initial")
}
......@@ -78,7 +78,7 @@ func TestMkdir(t *testing.T) {
f, err := os.Create(filepath.Join(dir, "hello"))
c.Assert(err, qt.Equals, nil)
f.Close()
c.Cleanup()
c.Done()
_, err = os.Stat(dir)
c.Assert(err, qt.Not(qt.IsNil))
}
......@@ -16,7 +16,7 @@ an HTTP server before running each test, and tears it down afterwards:
fmt.Fprintf(w, "%s %s", req.Method, req.URL.Path)
}
srv := httptest.NewServer(http.HandlerFunc(hnd))