Merge pull request #6762 from mxpv/testify

Drop gotest.tools
This commit is contained in:
Phil Estes 2022-04-02 17:25:32 -04:00 committed by GitHub
commit aaf64c455a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 356 additions and 3678 deletions

View File

@ -32,9 +32,7 @@ import (
"testing"
"github.com/containerd/fifo"
"github.com/google/go-cmp/cmp/cmpopts"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"github.com/stretchr/testify/assert"
)
func assertHasPrefix(t *testing.T, s, prefix string) {
@ -52,7 +50,7 @@ func TestNewFIFOSetInDir(t *testing.T) {
root := t.TempDir()
fifos, err := NewFIFOSetInDir(root, "theid", true)
assert.NilError(t, err)
assert.NoError(t, err)
dir := filepath.Dir(fifos.Stdin)
assertHasPrefix(t, dir, root)
@ -64,20 +62,19 @@ func TestNewFIFOSetInDir(t *testing.T) {
Terminal: true,
},
}
assert.Assert(t, is.DeepEqual(fifos, expected, cmpFIFOSet))
assert.Equal(t, fifos.Config, expected.Config)
files, err := os.ReadDir(root)
assert.NilError(t, err)
assert.Check(t, is.Len(files, 1))
assert.NoError(t, err)
assert.Len(t, files, 1)
assert.NilError(t, fifos.Close())
assert.Nil(t, fifos.Close())
files, err = os.ReadDir(root)
assert.NilError(t, err)
assert.Check(t, is.Len(files, 0))
assert.NoError(t, err)
assert.Len(t, files, 0)
}
var cmpFIFOSet = cmpopts.IgnoreUnexported(FIFOSet{})
func TestNewAttach(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("setupFIFOProducers not yet implemented on windows")
@ -97,25 +94,25 @@ func TestNewAttach(t *testing.T) {
attacher := NewAttach(withBytesBuffers)
fifos, err := NewFIFOSetInDir("", "theid", false)
assert.NilError(t, err)
assert.NoError(t, err)
attachedFifos, err := attacher(fifos)
assert.NilError(t, err)
assert.NoError(t, err)
defer attachedFifos.Close()
producers := setupFIFOProducers(t, attachedFifos.Config())
initProducers(t, producers, expectedStdout, expectedStderr)
actualStdin, err := io.ReadAll(producers.Stdin)
assert.NilError(t, err)
assert.NoError(t, err)
attachedFifos.Wait()
attachedFifos.Cancel()
assert.NilError(t, attachedFifos.Close())
assert.Nil(t, attachedFifos.Close())
assert.Check(t, is.Equal(expectedStdout, stdout.String()))
assert.Check(t, is.Equal(expectedStderr, stderr.String()))
assert.Check(t, is.Equal(expectedStdin, string(actualStdin)))
assert.Equal(t, expectedStdout, stdout.String())
assert.Equal(t, expectedStderr, stderr.String())
assert.Equal(t, expectedStdin, string(actualStdin))
}
type producers struct {
@ -132,41 +129,41 @@ func setupFIFOProducers(t *testing.T, fifos Config) producers {
)
pipes.Stdin, err = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_RDONLY, 0)
assert.NilError(t, err)
assert.NoError(t, err)
pipes.Stdout, err = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_WRONLY, 0)
assert.NilError(t, err)
assert.NoError(t, err)
pipes.Stderr, err = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_WRONLY, 0)
assert.NilError(t, err)
assert.NoError(t, err)
return pipes
}
func initProducers(t *testing.T, producers producers, stdout, stderr string) {
_, err := producers.Stdout.Write([]byte(stdout))
assert.NilError(t, err)
assert.NilError(t, producers.Stdout.Close())
assert.NoError(t, err)
assert.Nil(t, producers.Stdout.Close())
_, err = producers.Stderr.Write([]byte(stderr))
assert.NilError(t, err)
assert.NilError(t, producers.Stderr.Close())
assert.NoError(t, err)
assert.Nil(t, producers.Stderr.Close())
}
func TestBinaryIOArgs(t *testing.T) {
res, err := BinaryIO("/file.bin", map[string]string{"id": "1"})("")
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stdout)
assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stderr)
}
func TestBinaryIOAbsolutePath(t *testing.T) {
res, err := BinaryIO("/full/path/bin", nil)("!")
assert.NilError(t, err)
assert.NoError(t, err)
// Test parse back
parsed, err := url.Parse(res.Config().Stdout)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, "binary", parsed.Scheme)
assert.Equal(t, "/full/path/bin", parsed.Path)
}
@ -178,13 +175,13 @@ func TestBinaryIOFailOnRelativePath(t *testing.T) {
func TestLogFileAbsolutePath(t *testing.T) {
res, err := LogFile("/full/path/file.txt")("!")
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, "file:///full/path/file.txt", res.Config().Stdout)
assert.Equal(t, "file:///full/path/file.txt", res.Config().Stderr)
// Test parse back
parsed, err := url.Parse(res.Config().Stdout)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, "file", parsed.Scheme)
assert.Equal(t, "/full/path/file.txt", parsed.Path)
}

View File

@ -24,7 +24,7 @@ import (
"path/filepath"
"testing"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
func TestOpenFifos(t *testing.T) {
@ -53,7 +53,7 @@ func TestOpenFifos(t *testing.T) {
}
for _, scenario := range scenarios {
_, err := openFifos(context.Background(), scenario)
assert.Assert(t, err != nil, scenario)
assert.Error(t, err, scenario)
}
}

View File

@ -19,7 +19,7 @@ package cio
import (
"testing"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
func TestNewFifoSetInDir_NoTerminal(t *testing.T) {
@ -28,10 +28,10 @@ func TestNewFifoSetInDir_NoTerminal(t *testing.T) {
t.Fatalf("NewFifoSetInDir failed with: %v", err)
}
assert.Assert(t, !set.Terminal, "FIFOSet.Terminal should be false")
assert.Assert(t, set.Stdin != "", "FIFOSet.Stdin should be set")
assert.Assert(t, set.Stdout != "", "FIFOSet.Stdout should be set")
assert.Assert(t, set.Stderr != "", "FIFOSet.Stderr should be set")
assert.True(t, !set.Terminal, "FIFOSet.Terminal should be false")
assert.NotEmpty(t, set.Stdin, "FIFOSet.Stdin should be set")
assert.NotEmpty(t, set.Stdout, "FIFOSet.Stdout should be set")
assert.NotEmpty(t, set.Stderr, "FIFOSet.Stderr should be set")
}
func TestNewFifoSetInDir_Terminal(t *testing.T) {
@ -40,8 +40,8 @@ func TestNewFifoSetInDir_Terminal(t *testing.T) {
t.Fatalf("NewFifoSetInDir failed with: %v", err)
}
assert.Assert(t, set.Terminal, "FIFOSet.Terminal should be false")
assert.Assert(t, set.Stdin != "", "FIFOSet.Stdin should be set")
assert.Assert(t, set.Stdout != "", "FIFOSet.Stdout should be set")
assert.Assert(t, set.Stderr == "", "FIFOSet.Stderr should not be set")
assert.True(t, set.Terminal, "FIFOSet.Terminal should be true")
assert.NotEmpty(t, set.Stdin, "FIFOSet.Stdin should be set")
assert.NotEmpty(t, set.Stdout, "FIFOSet.Stdout should be set")
assert.Empty(t, set.Stderr, "FIFOSet.Stderr should not be set")
}

View File

@ -26,8 +26,7 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/opencontainers/go-digest"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"github.com/stretchr/testify/assert"
)
type copySource struct {
@ -81,9 +80,9 @@ func TestCopy(t *testing.T) {
testcase.source.size,
testcase.source.digest)
assert.NilError(t, err)
assert.Check(t, is.Equal(testcase.source.digest, testcase.writer.committedDigest))
assert.Check(t, is.Equal(testcase.expected, testcase.writer.String()))
assert.NoError(t, err)
assert.Equal(t, testcase.source.digest, testcase.writer.committedDigest)
assert.Equal(t, testcase.expected, testcase.writer.String())
})
}
}

View File

@ -19,14 +19,16 @@ package local
import (
"testing"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTryLock(t *testing.T) {
err := tryLock("testref")
assert.NilError(t, err)
assert.NoError(t, err)
defer unlock("testref")
err = tryLock("testref")
assert.ErrorContains(t, err, "ref testref locked for ")
require.NotNil(t, err)
assert.Contains(t, err.Error(), "ref testref locked for ")
}

View File

@ -39,7 +39,7 @@ import (
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
type memoryLabelStore struct {
@ -351,7 +351,7 @@ func checkWrite(ctx context.Context, t checker, cs content.Store, dgst digest.Di
func TestWriterTruncateRecoversFromIncompleteWrite(t *testing.T) {
cs, err := NewStore(t.TempDir())
assert.NilError(t, err)
assert.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -362,26 +362,26 @@ func TestWriterTruncateRecoversFromIncompleteWrite(t *testing.T) {
setupIncompleteWrite(ctx, t, cs, ref, total)
writer, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: total}))
assert.NilError(t, err)
assert.NoError(t, err)
assert.NilError(t, writer.Truncate(0))
assert.Nil(t, writer.Truncate(0))
_, err = writer.Write(contentB)
assert.NilError(t, err)
assert.NoError(t, err)
dgst := digest.FromBytes(contentB)
err = writer.Commit(ctx, total, dgst)
assert.NilError(t, err)
assert.NoError(t, err)
}
func setupIncompleteWrite(ctx context.Context, t *testing.T, cs content.Store, ref string, total int64) {
writer, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: total}))
assert.NilError(t, err)
assert.NoError(t, err)
_, err = writer.Write([]byte("bad data"))
assert.NilError(t, err)
assert.NoError(t, err)
assert.NilError(t, writer.Close())
assert.Nil(t, writer.Close())
}
func TestWriteReadEmptyFileTimestamp(t *testing.T) {

View File

@ -32,9 +32,9 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log/logtest"
"github.com/containerd/containerd/pkg/testutil"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
const (
@ -271,7 +271,7 @@ func checkResumeWriter(ctx context.Context, t *testing.T, cs content.Store) {
}
checkStatus(t, w1, expected, dgstFirst, preStart, postStart, preUpdate, postUpdate)
assert.NilError(t, w1.Close(), "close first writer")
assert.Nil(t, w1.Close(), "close first writer")
w2, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: 256, Digest: dgst}))
if err != nil {
@ -295,7 +295,7 @@ func checkResumeWriter(ctx context.Context, t *testing.T, cs content.Store) {
}
postCommit := time.Now()
assert.NilError(t, w2.Close(), "close second writer")
assert.Nil(t, w2.Close(), "close second writer")
info := content.Info{
Digest: dgst,
Size: 256,

View File

@ -6,7 +6,7 @@ package apparmor
import (
"testing"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
func TestCleanProfileName(t *testing.T) {

View File

@ -23,7 +23,7 @@ import (
"time"
"github.com/containerd/containerd/gc"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
func TestPauseThreshold(t *testing.T) {

2
go.mod
View File

@ -68,7 +68,6 @@ require (
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
google.golang.org/grpc v1.43.0
google.golang.org/protobuf v1.27.1
gotest.tools/v3 v3.0.3
k8s.io/api v0.22.5
k8s.io/apimachinery v0.22.5
k8s.io/apiserver v0.22.5
@ -122,7 +121,6 @@ require (
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
gopkg.in/inf.v0 v0.9.1 // indirect

18
go.sum
View File

@ -78,7 +78,6 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY=
@ -99,7 +98,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@ -123,7 +121,6 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
@ -280,7 +277,6 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@ -401,7 +397,6 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
@ -611,7 +606,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
@ -662,11 +656,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -681,7 +673,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -691,7 +682,6 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -781,13 +771,11 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
@ -1045,7 +1033,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -1150,7 +1137,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1167,7 +1153,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1255,12 +1240,10 @@ golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4X
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1381,7 +1364,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
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=

View File

@ -26,7 +26,7 @@ import (
"github.com/containerd/containerd/pkg/ttrpcutil"
"github.com/containerd/ttrpc"
"github.com/gogo/protobuf/types"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
func TestClientTTRPC_New(t *testing.T) {
@ -34,10 +34,10 @@ func TestClientTTRPC_New(t *testing.T) {
t.Skip()
}
client, err := ttrpcutil.NewClient(address + ".ttrpc")
assert.NilError(t, err)
assert.NoError(t, err)
err = client.Close()
assert.NilError(t, err)
assert.NoError(t, err)
}
func TestClientTTRPC_Reconnect(t *testing.T) {
@ -45,13 +45,13 @@ func TestClientTTRPC_Reconnect(t *testing.T) {
t.Skip()
}
client, err := ttrpcutil.NewClient(address + ".ttrpc")
assert.NilError(t, err)
assert.NoError(t, err)
err = client.Reconnect()
assert.NilError(t, err)
assert.NoError(t, err)
service, err := client.EventsService()
assert.NilError(t, err)
assert.NoError(t, err)
// Send test request to make sure its alive after reconnect
_, err = service.Forward(context.Background(), &v1.ForwardRequest{
@ -62,10 +62,10 @@ func TestClientTTRPC_Reconnect(t *testing.T) {
Event: &types.Any{},
},
})
assert.NilError(t, err)
assert.NoError(t, err)
err = client.Close()
assert.NilError(t, err)
assert.NoError(t, err)
}
func TestClientTTRPC_Close(t *testing.T) {
@ -73,17 +73,17 @@ func TestClientTTRPC_Close(t *testing.T) {
t.Skip()
}
client, err := ttrpcutil.NewClient(address + ".ttrpc")
assert.NilError(t, err)
assert.NoError(t, err)
service, err := client.EventsService()
assert.NilError(t, err)
assert.NoError(t, err)
err = client.Close()
assert.NilError(t, err)
assert.NoError(t, err)
_, err = service.Forward(context.Background(), &v1.ForwardRequest{Envelope: &v1.Envelope{}})
assert.Equal(t, err, ttrpc.ErrClosed)
err = client.Close()
assert.NilError(t, err)
assert.NoError(t, err)
}

View File

@ -25,7 +25,7 @@ import (
"github.com/containerd/containerd/images/converter/uncompress"
"github.com/containerd/containerd/platforms"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
// TestConvert creates an image from testImage, with the following conversion:
@ -72,7 +72,7 @@ func TestConvert(t *testing.T) {
}
// Assert that the image does not have any extra arch.
assert.Equal(t, 1, len(plats))
assert.Check(t, defPlat.Match(plats[0]))
assert.True(t, defPlat.Match(plats[0]))
// Assert that the media type is converted to OCI and also uncompressed
mani, err := images.Manifest(ctx, cs, dstImg.Target, defPlat)

View File

@ -16,8 +16,8 @@ require (
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
gotest.tools/v3 v3.0.3
)
replace (

View File

@ -1068,10 +1068,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
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=

View File

@ -20,7 +20,7 @@ import (
"context"
"testing"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
func TestLoggerContext(t *testing.T) {
@ -28,5 +28,5 @@ func TestLoggerContext(t *testing.T) {
ctx = WithLogger(ctx, G(ctx).WithField("test", "one"))
assert.Equal(t, GetLogger(ctx).Data["test"], "one")
assert.Equal(t, G(ctx), GetLogger(ctx)) // these should be the same.
assert.Same(t, G(ctx), GetLogger(ctx)) // these should be the same.
}

View File

@ -34,9 +34,9 @@ import (
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
"github.com/google/go-cmp/cmp"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
bolt "go.etcd.io/bbolt"
"gotest.tools/v3/assert"
)
func init() {
@ -724,7 +724,8 @@ func checkContainersEqual(t *testing.T, a, b *containers.Container, format strin
return true
}),
)
assert.DeepEqual(t, a, b, opt)
assert.True(t, cmp.Equal(a, b, opt))
}
func testEnv(t *testing.T) (context.Context, *bolt.DB, func()) {

View File

@ -27,14 +27,14 @@ import (
// so we use continuity/testutil instead.
"github.com/containerd/continuity/testutil"
"github.com/containerd/continuity/testutil/loopback"
"github.com/stretchr/testify/assert"
exec "golang.org/x/sys/execabs"
"gotest.tools/v3/assert"
)
func checkLookup(t *testing.T, fsType, mntPoint, dir string) {
t.Helper()
info, err := Lookup(dir)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, fsType, info.FSType)
assert.Equal(t, mntPoint, info.Mountpoint)
}
@ -61,7 +61,7 @@ func testLookup(t *testing.T, fsType string) {
testutil.Unmount(t, mnt)
loop.Close()
}()
assert.Check(t, strings.HasPrefix(loop.Device, "/dev/loop"))
assert.True(t, strings.HasPrefix(loop.Device, "/dev/loop"))
checkLookup(t, fsType, mnt, mnt)
newMnt := t.TempDir()
@ -105,11 +105,11 @@ func TestLookupWithOverlay(t *testing.T) {
testdir := filepath.Join(overlay, "testdir")
err := os.Mkdir(testdir, 0777)
assert.NilError(t, err)
assert.NoError(t, err)
testfile := filepath.Join(overlay, "testfile")
_, err = os.Create(testfile)
assert.NilError(t, err)
assert.NoError(t, err)
checkLookup(t, "overlay", overlay, testdir)
checkLookup(t, "overlay", overlay, testfile)

View File

@ -25,14 +25,14 @@ import (
"testing"
"github.com/containerd/containerd/mount"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
// Unmount unmounts a given mountPoint and sets t.Error if it fails
func Unmount(t testing.TB, mountPoint string) {
t.Log("unmount", mountPoint)
err := mount.UnmountAll(mountPoint, umountflags)
assert.NilError(t, err)
assert.NoError(t, err)
}
// RequiresRoot skips tests that require root, unless the test.root flag has

View File

@ -27,7 +27,7 @@ import (
"net/url"
"testing"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
)
func TestFetcherOpen(t *testing.T) {

View File

@ -21,8 +21,7 @@ import (
"testing"
"github.com/containerd/containerd/reference"
"gotest.tools/v3/assert"
"gotest.tools/v3/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestRepositoryScope(t *testing.T) {
@ -51,7 +50,7 @@ func TestRepositoryScope(t *testing.T) {
for _, x := range testCases {
t.Run(x.refspec.String(), func(t *testing.T) {
actual, err := RepositoryScope(x.refspec, x.push)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, x.expected, actual)
})
}
@ -97,7 +96,7 @@ func TestGetTokenScopes(t *testing.T) {
for _, tc := range testCases {
ctx := context.WithValue(context.TODO(), tokenScopesKey{}, tc.scopesInCtx)
actual := GetTokenScopes(ctx, tc.commonScopes)
assert.DeepEqual(t, tc.expected, actual)
assert.Equal(t, tc.expected, actual)
}
}
@ -107,7 +106,5 @@ func TestCustomScope(t *testing.T) {
ctx = ContextWithAppendPullRepositoryScope(ctx, "foo/bar")
scopes := GetTokenScopes(ctx, []string{})
assert.Assert(t, cmp.Len(scopes, 2))
assert.Check(t, cmp.Equal(scopes[0], "repository:foo/bar:pull"))
assert.Check(t, cmp.Equal(scopes[1], scope))
assert.Equal(t, []string{"repository:foo/bar:pull", scope}, scopes)
}

View File

@ -22,7 +22,7 @@ import (
"sort"
"testing"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
"github.com/containerd/containerd/plugin"
)
@ -48,16 +48,16 @@ func TestMergeConfigs(t *testing.T) {
}
err := mergeConfig(a, b)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, a.Version, 2)
assert.Equal(t, a.Root, "new_root")
assert.Equal(t, a.State, "old_state")
assert.Equal(t, a.OOMScore, 2)
assert.DeepEqual(t, a.RequiredPlugins, []string{"old_plugin", "new_plugin1", "new_plugin2"})
assert.DeepEqual(t, a.DisabledPlugins, []string{"old_plugin"})
assert.DeepEqual(t, a.Timeouts, map[string]string{"a": "1", "b": "2"})
assert.DeepEqual(t, a.StreamProcessors, map[string]StreamProcessor{"1": {Path: "3"}, "2": {Path: "5"}})
assert.Equal(t, 2, a.Version)
assert.Equal(t, "new_root", a.Root)
assert.Equal(t, "old_state", a.State)
assert.Equal(t, 2, a.OOMScore)
assert.Equal(t, []string{"old_plugin", "new_plugin1", "new_plugin2"}, a.RequiredPlugins)
assert.Equal(t, []string{"old_plugin"}, a.DisabledPlugins)
assert.Equal(t, map[string]string{"a": "1", "b": "2"}, a.Timeouts)
assert.Equal(t, map[string]StreamProcessor{"1": {Path: "3"}, "2": {Path: "5"}}, a.StreamProcessors)
}
func TestResolveImports(t *testing.T) {
@ -65,7 +65,7 @@ func TestResolveImports(t *testing.T) {
for _, filename := range []string{"config_1.toml", "config_2.toml", "test.toml"} {
err := os.WriteFile(filepath.Join(tempDir, filename), []byte(""), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
}
imports, err := resolveImports(filepath.Join(tempDir, "root.toml"), []string{
@ -73,9 +73,9 @@ func TestResolveImports(t *testing.T) {
filepath.Join(tempDir, "./test.toml"), // Path clean up
"current.toml", // Resolve current working dir
})
assert.NilError(t, err)
assert.NoError(t, err)
assert.DeepEqual(t, imports, []string{
assert.Equal(t, imports, []string{
filepath.Join(tempDir, "config_1.toml"),
filepath.Join(tempDir, "config_2.toml"),
filepath.Join(tempDir, "test.toml"),
@ -97,14 +97,14 @@ root = "/var/lib/containerd"
path := filepath.Join(tempDir, "config.toml")
err := os.WriteFile(path, []byte(data), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
var out Config
err = LoadConfig(path, &out)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, 2, out.Version)
assert.Equal(t, "/var/lib/containerd", out.Root)
assert.DeepEqual(t, map[string]StreamProcessor{
assert.Equal(t, map[string]StreamProcessor{
"io.containerd.processor.v1.pigz": {
Accepts: []string{"application/vnd.docker.image.rootfs.diff.tar.gzip"},
Path: "unpigz",
@ -126,18 +126,18 @@ disabled_plugins = ["io.containerd.v1.xyz"]
tempDir := t.TempDir()
err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
var out Config
err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, 2, out.Version)
assert.Equal(t, "/var/lib/containerd", out.Root)
assert.DeepEqual(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
assert.Equal(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
}
func TestLoadConfigWithCircularImports(t *testing.T) {
@ -154,21 +154,21 @@ imports = ["data1.toml", "data2.toml"]
tempDir := t.TempDir()
err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
var out Config
err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, 2, out.Version)
assert.Equal(t, "/var/lib/containerd", out.Root)
assert.DeepEqual(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
assert.Equal(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
sort.Strings(out.Imports)
assert.DeepEqual(t, []string{
assert.Equal(t, []string{
filepath.Join(tempDir, "data1.toml"),
filepath.Join(tempDir, "data2.toml"),
}, out.Imports)
@ -185,15 +185,15 @@ version = 2
path := filepath.Join(tempDir, "config.toml")
err := os.WriteFile(path, []byte(data), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
var out Config
err = LoadConfig(path, &out)
assert.NilError(t, err)
assert.NoError(t, err)
pluginConfig := map[string]interface{}{}
_, err = out.Decode(&plugin.Registration{Type: "io.containerd.runtime.v1", ID: "linux", Config: &pluginConfig})
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, true, pluginConfig["shim_debug"])
}
@ -207,14 +207,14 @@ func TestDecodePluginInV1Config(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.toml")
err := os.WriteFile(path, []byte(data), 0600)
assert.NilError(t, err)
assert.NoError(t, err)
var out Config
err = LoadConfig(path, &out)
assert.NilError(t, err)
assert.NoError(t, err)
pluginConfig := map[string]interface{}{}
_, err = out.Decode(&plugin.Registration{ID: "linux", Config: &pluginConfig})
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, true, pluginConfig["shim_debug"])
}

View File

@ -20,8 +20,7 @@ import (
"testing"
srvconfig "github.com/containerd/containerd/services/server/config"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestCreateTopLevelDirectoriesErrorsWithSamePathForRootAndState(t *testing.T) {
@ -30,7 +29,7 @@ func TestCreateTopLevelDirectoriesErrorsWithSamePathForRootAndState(t *testing.T
Root: path,
State: path,
})
assert.Check(t, is.Error(err, "root and state must be different paths"))
assert.EqualError(t, err, "root and state must be different paths")
}
func TestCreateTopLevelDirectoriesWithEmptyStatePath(t *testing.T) {
@ -40,7 +39,7 @@ func TestCreateTopLevelDirectoriesWithEmptyStatePath(t *testing.T) {
Root: rootPath,
State: statePath,
})
assert.Check(t, is.Error(err, "state must be specified"))
assert.EqualError(t, err, "state must be specified")
}
func TestCreateTopLevelDirectoriesWithEmptyRootPath(t *testing.T) {
@ -50,5 +49,5 @@ func TestCreateTopLevelDirectoriesWithEmptyRootPath(t *testing.T) {
Root: rootPath,
State: statePath,
})
assert.Check(t, is.Error(err, "root must be specified"))
assert.EqualError(t, err, "root must be specified")
}

View File

@ -32,7 +32,7 @@ import (
"github.com/containerd/continuity/fs/fstest"
"github.com/sirupsen/logrus"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshots"
@ -64,14 +64,14 @@ func BenchmarkNative(b *testing.B) {
}
snapshotter, err := native.NewSnapshotter(nativeRootPath)
assert.NilError(b, err)
assert.Nil(b, err)
defer func() {
err = snapshotter.Close()
assert.NilError(b, err)
assert.Nil(b, err)
err = os.RemoveAll(nativeRootPath)
assert.NilError(b, err)
assert.Nil(b, err)
}()
benchmarkSnapshotter(b, snapshotter)
@ -83,14 +83,14 @@ func BenchmarkOverlay(b *testing.B) {
}
snapshotter, err := overlay.NewSnapshotter(overlayRootPath)
assert.NilError(b, err, "failed to create overlay snapshotter")
assert.Nil(b, err, "failed to create overlay snapshotter")
defer func() {
err = snapshotter.Close()
assert.NilError(b, err)
assert.Nil(b, err)
err = os.RemoveAll(overlayRootPath)
assert.NilError(b, err)
assert.Nil(b, err)
}()
benchmarkSnapshotter(b, snapshotter)
@ -114,17 +114,17 @@ func BenchmarkDeviceMapper(b *testing.B) {
ctx := context.Background()
snapshotter, err := devmapper.NewSnapshotter(ctx, config)
assert.NilError(b, err)
assert.Nil(b, err)
defer func() {
err := snapshotter.ResetPool(ctx)
assert.NilError(b, err)
assert.Nil(b, err)
err = snapshotter.Close()
assert.NilError(b, err)
assert.Nil(b, err)
err = os.RemoveAll(dmRootPath)
assert.NilError(b, err)
assert.Nil(b, err)
}()
benchmarkSnapshotter(b, snapshotter)
@ -184,19 +184,19 @@ func benchmarkSnapshotter(b *testing.B, snapshotter snapshots.Snapshotter) {
timer = time.Now()
mounts, err := snapshotter.Prepare(ctx, current, parent)
assert.NilError(b, err)
assert.Nil(b, err)
prepareDuration += time.Since(timer)
timer = time.Now()
err = mount.WithTempMount(ctx, mounts, layers[l].Apply)
assert.NilError(b, err)
assert.Nil(b, err)
writeDuration += time.Since(timer)
parent = fmt.Sprintf("committed-%d", atomic.AddInt64(&layerIndex, 1))
timer = time.Now()
err = snapshotter.Commit(ctx, parent, current)
assert.NilError(b, err)
assert.Nil(b, err)
commitDuration += time.Since(timer)
}
}

View File

@ -25,8 +25,7 @@ import (
"github.com/hashicorp/go-multierror"
"github.com/pelletier/go-toml"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestLoadConfig(t *testing.T) {
@ -37,28 +36,27 @@ func TestLoadConfig(t *testing.T) {
}
file, err := os.CreateTemp("", "devmapper-config-")
assert.NilError(t, err)
assert.NoError(t, err)
encoder := toml.NewEncoder(file)
err = encoder.Encode(&expected)
assert.NilError(t, err)
assert.NoError(t, err)
defer func() {
err := file.Close()
assert.NilError(t, err)
assert.NoError(t, err)
err = os.Remove(file.Name())
assert.NilError(t, err)
assert.NoError(t, err)
}()
loaded, err := LoadConfig(file.Name())
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, loaded.RootPath, expected.RootPath)
assert.Equal(t, loaded.PoolName, expected.PoolName)
assert.Equal(t, loaded.BaseImageSize, expected.BaseImageSize)
assert.Assert(t, loaded.BaseImageSizeBytes == 128*1024*1024)
assert.True(t, loaded.BaseImageSizeBytes == 128*1024*1024)
}
func TestLoadConfigInvalidPath(t *testing.T) {
@ -66,7 +64,7 @@ func TestLoadConfigInvalidPath(t *testing.T) {
assert.Equal(t, os.ErrNotExist, err)
_, err = LoadConfig("/dev/null")
assert.Assert(t, err != nil)
assert.NotNil(t, err)
}
func TestParseInvalidData(t *testing.T) {
@ -81,15 +79,15 @@ func TestParseInvalidData(t *testing.T) {
func TestFieldValidation(t *testing.T) {
config := &Config{}
err := config.Validate()
assert.Assert(t, err != nil)
assert.NotNil(t, err)
multErr := (err).(*multierror.Error)
assert.Assert(t, is.Len(multErr.Errors, 4))
assert.Len(t, multErr.Errors, 4)
assert.Assert(t, multErr.Errors[0] != nil, "pool_name is empty")
assert.Assert(t, multErr.Errors[1] != nil, "root_path is empty")
assert.Assert(t, multErr.Errors[2] != nil, "base_image_size is empty")
assert.Assert(t, multErr.Errors[3] != nil, "filesystem type cannot be empty")
assert.NotNil(t, multErr.Errors[0], "pool_name is empty")
assert.NotNil(t, multErr.Errors[1], "root_path is empty")
assert.NotNil(t, multErr.Errors[2], "base_image_size is empty")
assert.NotNil(t, multErr.Errors[3], "filesystem type cannot be empty")
}
func TestExistingPoolFieldValidation(t *testing.T) {
@ -101,5 +99,5 @@ func TestExistingPoolFieldValidation(t *testing.T) {
}
err := config.Validate()
assert.NilError(t, err)
assert.NoError(t, err)
}

View File

@ -24,13 +24,11 @@ import (
"strings"
"testing"
"github.com/docker/go-units"
"golang.org/x/sys/unix"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/pkg/testutil"
"github.com/docker/go-units"
"github.com/stretchr/testify/assert"
"golang.org/x/sys/unix"
)
const (
@ -50,23 +48,23 @@ func TestDMSetup(t *testing.T) {
defer func() {
err := mount.DetachLoopDevice(loopDataDevice, loopMetaDevice)
assert.NilError(t, err, "failed to detach loop devices for data image: %s and meta image: %s", dataImage, metaImage)
assert.Nil(t, err, "failed to detach loop devices for data image: %s and meta image: %s", dataImage, metaImage)
}()
t.Run("CreatePool", func(t *testing.T) {
err := CreatePool(testPoolName, loopDataDevice, loopMetaDevice, 128)
assert.NilError(t, err, "failed to create thin-pool with %s %s", loopDataDevice, loopMetaDevice)
assert.Nil(t, err, "failed to create thin-pool with %s %s", loopDataDevice, loopMetaDevice)
table, err := Table(testPoolName)
t.Logf("table: %s", table)
assert.NilError(t, err)
assert.Assert(t, strings.HasPrefix(table, "0 32768 thin-pool"))
assert.Assert(t, strings.HasSuffix(table, "128 32768 1 skip_block_zeroing"))
assert.NoError(t, err)
assert.True(t, strings.HasPrefix(table, "0 32768 thin-pool"))
assert.True(t, strings.HasSuffix(table, "128 32768 1 skip_block_zeroing"))
})
t.Run("ReloadPool", func(t *testing.T) {
err := ReloadPool(testPoolName, loopDataDevice, loopMetaDevice, 256)
assert.NilError(t, err, "failed to reload thin-pool")
assert.Nil(t, err, "failed to reload thin-pool")
})
t.Run("CreateDevice", testCreateDevice)
@ -82,7 +80,7 @@ func TestDMSetup(t *testing.T) {
t.Run("RemovePool", func(t *testing.T) {
err := RemoveDevice(testPoolName, RemoveWithForce, RemoveWithRetries)
assert.NilError(t, err, "failed to remove thin-pool")
assert.Nil(t, err, "failed to remove thin-pool")
})
t.Run("Version", testVersion)
@ -90,116 +88,116 @@ func TestDMSetup(t *testing.T) {
func testCreateDevice(t *testing.T) {
err := CreateDevice(testPoolName, deviceID)
assert.NilError(t, err, "failed to create test device")
assert.Nil(t, err, "failed to create test device")
err = CreateDevice(testPoolName, deviceID)
assert.Assert(t, err == unix.EEXIST)
assert.True(t, err == unix.EEXIST)
infos, err := Info(testPoolName)
assert.NilError(t, err)
assert.Assert(t, is.Len(infos, 1), "got unexpected number of device infos")
assert.NoError(t, err)
assert.Len(t, infos, 1, "got unexpected number of device infos")
}
func testCreateSnapshot(t *testing.T) {
err := CreateSnapshot(testPoolName, snapshotID, deviceID)
assert.NilError(t, err)
assert.NoError(t, err)
}
func testDeleteSnapshot(t *testing.T) {
err := DeleteDevice(testPoolName, snapshotID)
assert.NilError(t, err, "failed to send delete message")
assert.Nil(t, err, "failed to send delete message")
err = DeleteDevice(testPoolName, snapshotID)
assert.Assert(t, err == unix.ENODATA)
assert.Equal(t, err, unix.ENODATA)
}
func testActivateDevice(t *testing.T) {
err := ActivateDevice(testPoolName, testDeviceName, 1, 1024, "")
assert.NilError(t, err, "failed to activate device")
assert.Nil(t, err, "failed to activate device")
err = ActivateDevice(testPoolName, testDeviceName, 1, 1024, "")
assert.Equal(t, err, unix.EBUSY)
if _, err := os.Stat("/dev/mapper/" + testDeviceName); err != nil && !os.IsExist(err) {
assert.NilError(t, err, "failed to stat device")
assert.Nil(t, err, "failed to stat device")
}
list, err := Info(testPoolName)
assert.NilError(t, err)
assert.Assert(t, is.Len(list, 1))
assert.NoError(t, err)
assert.Len(t, list, 1)
info := list[0]
assert.Equal(t, testPoolName, info.Name)
assert.Assert(t, info.TableLive)
assert.True(t, info.TableLive)
}
func testDeviceStatus(t *testing.T) {
status, err := Status(testDeviceName)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, int64(0), status.Offset)
assert.Equal(t, int64(2), status.Length)
assert.Equal(t, "thin", status.Target)
assert.DeepEqual(t, status.Params, []string{"0", "-"})
assert.Equal(t, status.Params, []string{"0", "-"})
}
func testSuspendResumeDevice(t *testing.T) {
err := SuspendDevice(testDeviceName)
assert.NilError(t, err)
assert.NoError(t, err)
err = SuspendDevice(testDeviceName)
assert.NilError(t, err)
assert.NoError(t, err)
list, err := Info(testDeviceName)
assert.NilError(t, err)
assert.Assert(t, is.Len(list, 1))
assert.NoError(t, err)
assert.Len(t, list, 1)
info := list[0]
assert.Assert(t, info.Suspended)
assert.True(t, info.Suspended)
err = ResumeDevice(testDeviceName)
assert.NilError(t, err)
assert.NoError(t, err)
err = ResumeDevice(testDeviceName)
assert.NilError(t, err)
assert.NoError(t, err)
}
func testDiscardBlocks(t *testing.T) {
err := DiscardBlocks(testDeviceName)
assert.NilError(t, err, "failed to discard blocks")
assert.Nil(t, err, "failed to discard blocks")
}
func testRemoveDevice(t *testing.T) {
err := RemoveDevice(testPoolName)
assert.Assert(t, err == unix.EBUSY, "removing thin-pool with dependencies shouldn't be allowed")
assert.Equal(t, err, unix.EBUSY, "removing thin-pool with dependencies shouldn't be allowed")
err = RemoveDevice(testDeviceName, RemoveWithRetries)
assert.NilError(t, err, "failed to remove thin-device")
assert.Nil(t, err, "failed to remove thin-device")
}
func testVersion(t *testing.T) {
version, err := Version()
assert.NilError(t, err)
assert.Assert(t, version != "")
assert.NoError(t, err)
assert.NotEmpty(t, version)
}
func createLoopbackDevice(t *testing.T, dir string) (string, string) {
file, err := os.CreateTemp(dir, "dmsetup-tests-")
assert.NilError(t, err)
assert.NoError(t, err)
size, err := units.RAMInBytes("16Mb")
assert.NilError(t, err)
assert.NoError(t, err)
err = file.Truncate(size)
assert.NilError(t, err)
assert.NoError(t, err)
err = file.Close()
assert.NilError(t, err)
assert.NoError(t, err)
imagePath := file.Name()
loopDevice, err := mount.AttachLoopDevice(imagePath)
assert.NilError(t, err)
assert.NoError(t, err)
return imagePath, loopDevice
}

View File

@ -26,9 +26,8 @@ import (
"strconv"
"testing"
"github.com/stretchr/testify/assert"
"go.etcd.io/bbolt"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
var (
@ -47,16 +46,16 @@ func TestPoolMetadata_AddDevice(t *testing.T) {
}
err := store.AddDevice(testCtx, expected)
assert.NilError(t, err)
assert.NoError(t, err)
result, err := store.GetDevice(testCtx, "test2")
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected.Name, result.Name)
assert.Equal(t, expected.ParentName, result.ParentName)
assert.Equal(t, expected.Size, result.Size)
assert.Equal(t, expected.State, result.State)
assert.Assert(t, result.DeviceID != 0)
assert.NotZero(t, result.DeviceID, 0)
assert.Equal(t, expected.DeviceID, result.DeviceID)
}
@ -65,7 +64,7 @@ func TestPoolMetadata_AddDeviceRollback(t *testing.T) {
defer cleanupStore(t, store)
err := store.AddDevice(testCtx, &DeviceInfo{Name: ""})
assert.Assert(t, err != nil)
assert.True(t, err != nil)
_, err = store.GetDevice(testCtx, "")
assert.Equal(t, ErrNotFound, err)
@ -76,10 +75,10 @@ func TestPoolMetadata_AddDeviceDuplicate(t *testing.T) {
defer cleanupStore(t, store)
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
assert.NilError(t, err)
assert.NoError(t, err)
err = store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
assert.Assert(t, errors.Is(err, ErrAlreadyExists))
assert.True(t, errors.Is(err, ErrAlreadyExists))
}
func TestPoolMetadata_ReuseDeviceID(t *testing.T) {
@ -88,21 +87,21 @@ func TestPoolMetadata_ReuseDeviceID(t *testing.T) {
info1 := &DeviceInfo{Name: "test1"}
err := store.AddDevice(testCtx, info1)
assert.NilError(t, err)
assert.NoError(t, err)
info2 := &DeviceInfo{Name: "test2"}
err = store.AddDevice(testCtx, info2)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Assert(t, info1.DeviceID != info2.DeviceID)
assert.Assert(t, info1.DeviceID != 0)
assert.NotEqual(t, info1.DeviceID, info2.DeviceID)
assert.NotZero(t, info1.DeviceID)
err = store.RemoveDevice(testCtx, info2.Name)
assert.NilError(t, err)
assert.NoError(t, err)
info3 := &DeviceInfo{Name: "test3"}
err = store.AddDevice(testCtx, info3)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, info2.DeviceID, info3.DeviceID)
}
@ -112,10 +111,10 @@ func TestPoolMetadata_RemoveDevice(t *testing.T) {
defer cleanupStore(t, store)
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
assert.NilError(t, err)
assert.NoError(t, err)
err = store.RemoveDevice(testCtx, "test")
assert.NilError(t, err)
assert.NoError(t, err)
_, err = store.GetDevice(testCtx, "test")
assert.Equal(t, ErrNotFound, err)
@ -133,7 +132,7 @@ func TestPoolMetadata_UpdateDevice(t *testing.T) {
}
err := store.AddDevice(testCtx, oldInfo)
assert.NilError(t, err)
assert.NoError(t, err)
err = store.UpdateDevice(testCtx, oldInfo.Name, func(info *DeviceInfo) error {
info.ParentName = "test5"
@ -142,14 +141,14 @@ func TestPoolMetadata_UpdateDevice(t *testing.T) {
return nil
})
assert.NilError(t, err)
assert.NoError(t, err)
newInfo, err := store.GetDevice(testCtx, "test1")
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, "test1", newInfo.Name)
assert.Equal(t, "test5", newInfo.ParentName)
assert.Assert(t, newInfo.Size == 6)
assert.EqualValues(t, newInfo.Size, 6)
assert.Equal(t, Created, newInfo.State)
}
@ -159,15 +158,15 @@ func TestPoolMetadata_MarkFaulty(t *testing.T) {
info := &DeviceInfo{Name: "test"}
err := store.AddDevice(testCtx, info)
assert.NilError(t, err)
assert.NoError(t, err)
err = store.MarkFaulty(testCtx, "test")
assert.NilError(t, err)
assert.NoError(t, err)
saved, err := store.GetDevice(testCtx, info.Name)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, saved.State, Faulty)
assert.Assert(t, saved.DeviceID > 0)
assert.True(t, saved.DeviceID > 0)
// Make sure a device ID marked as faulty as well
err = store.db.View(func(tx *bbolt.Tx) error {
@ -177,7 +176,7 @@ func TestPoolMetadata_MarkFaulty(t *testing.T) {
assert.Equal(t, value[0], byte(deviceFaulty))
return nil
})
assert.NilError(t, err)
assert.NoError(t, err)
}
func TestPoolMetadata_WalkDevices(t *testing.T) {
@ -185,10 +184,10 @@ func TestPoolMetadata_WalkDevices(t *testing.T) {
defer cleanupStore(t, store)
err := store.AddDevice(testCtx, &DeviceInfo{Name: "device1", DeviceID: 1, State: Created})
assert.NilError(t, err)
assert.NoError(t, err)
err = store.AddDevice(testCtx, &DeviceInfo{Name: "device2", DeviceID: 2, State: Faulty})
assert.NilError(t, err)
assert.NoError(t, err)
called := 0
err = store.WalkDevices(testCtx, func(info *DeviceInfo) error {
@ -208,7 +207,7 @@ func TestPoolMetadata_WalkDevices(t *testing.T) {
return nil
})
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, called, 2)
}
@ -217,14 +216,14 @@ func TestPoolMetadata_GetDeviceNames(t *testing.T) {
defer cleanupStore(t, store)
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test1"})
assert.NilError(t, err)
assert.NoError(t, err)
err = store.AddDevice(testCtx, &DeviceInfo{Name: "test2"})
assert.NilError(t, err)
assert.NoError(t, err)
names, err := store.GetDeviceNames(testCtx)
assert.NilError(t, err)
assert.Assert(t, is.Len(names, 2))
assert.NoError(t, err)
assert.Len(t, names, 2)
assert.Equal(t, "test1", names[0])
assert.Equal(t, "test2", names[1])
@ -233,12 +232,12 @@ func TestPoolMetadata_GetDeviceNames(t *testing.T) {
func createStore(t *testing.T) (store *PoolMetadata) {
path := filepath.Join(t.TempDir(), "test.db")
metadata, err := NewPoolMetadata(path)
assert.NilError(t, err)
assert.NoError(t, err)
return metadata
}
func cleanupStore(t *testing.T, store *PoolMetadata) {
err := store.Close()
assert.NilError(t, err, "failed to close metadata store")
assert.Nil(t, err, "failed to close metadata store")
}

View File

@ -32,8 +32,8 @@ import (
"github.com/containerd/containerd/snapshots/devmapper/dmsetup"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
exec "golang.org/x/sys/execabs"
"gotest.tools/v3/assert"
)
const (
@ -68,12 +68,12 @@ func TestPoolDevice(t *testing.T) {
poolName := fmt.Sprintf("test-pool-device-%d", time.Now().Nanosecond())
err := dmsetup.CreatePool(poolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize)
assert.NilError(t, err, "failed to create pool %q", poolName)
assert.Nil(t, err, "failed to create pool %q", poolName)
defer func() {
// Detach loop devices and remove images
err := mount.DetachLoopDevice(loopDataDevice, loopMetaDevice)
assert.NilError(t, err)
assert.NoError(t, err)
}()
config := &Config{
@ -85,12 +85,12 @@ func TestPoolDevice(t *testing.T) {
}
pool, err := NewPoolDevice(ctx, config)
assert.NilError(t, err, "can't create device pool")
assert.Assert(t, pool != nil)
assert.Nil(t, err, "can't create device pool")
assert.True(t, pool != nil)
defer func() {
err := pool.RemovePool(ctx)
assert.NilError(t, err, "can't close device pool")
assert.Nil(t, err, "can't close device pool")
}()
// Create thin devices
@ -108,7 +108,7 @@ func TestPoolDevice(t *testing.T) {
// Write v1 test file on 'thin-1' device
thin1TestFilePath := filepath.Join(thin1MountPath, "TEST")
err := os.WriteFile(thin1TestFilePath, []byte("test file (v1)"), 0700)
assert.NilError(t, err, "failed to write test file v1 on '%s' volume", thinDevice1)
assert.Nil(t, err, "failed to write test file v1 on '%s' volume", thinDevice1)
return nil
})
@ -122,24 +122,24 @@ func TestPoolDevice(t *testing.T) {
err = mount.WithTempMount(ctx, getMounts(thinDevice1), func(thin1MountPath string) error {
thin1TestFilePath := filepath.Join(thin1MountPath, "TEST")
err = os.WriteFile(thin1TestFilePath, []byte("test file (v2)"), 0700)
assert.NilError(t, err, "failed to write test file v2 on 'thin-1' volume after taking snapshot")
assert.Nil(t, err, "failed to write test file v2 on 'thin-1' volume after taking snapshot")
return nil
})
assert.NilError(t, err)
assert.NoError(t, err)
// Mount 'snap-1' and make sure TEST file is v1
err = mount.WithTempMount(ctx, getMounts(snapDevice1), func(snap1MountPath string) error {
// Read test file from snapshot device and make sure it's v1
fileData, err := os.ReadFile(filepath.Join(snap1MountPath, "TEST"))
assert.NilError(t, err, "couldn't read test file from '%s' device", snapDevice1)
assert.Nil(t, err, "couldn't read test file from '%s' device", snapDevice1)
assert.Equal(t, "test file (v1)", string(fileData), "test file content is invalid on snapshot")
return nil
})
assert.NilError(t, err)
assert.NoError(t, err)
t.Run("DeactivateDevice", func(t *testing.T) {
testDeactivateThinDevice(t, pool)
@ -157,17 +157,17 @@ func TestPoolDevice(t *testing.T) {
snapDevice := "snap2"
err := pool.CreateSnapshotDevice(ctx, thinDevice1, snapDevice, device1Size)
assert.NilError(t, err)
assert.NoError(t, err)
info, err := pool.metadata.GetDevice(ctx, snapDevice)
assert.NilError(t, err)
assert.NoError(t, err)
// Simulate a case that the device cannot be activated.
err = pool.DeactivateDevice(ctx, info.Name, false, false)
assert.NilError(t, err)
assert.NoError(t, err)
err = pool.rollbackActivate(ctx, info, err)
assert.NilError(t, err)
assert.NoError(t, err)
})
}
@ -176,16 +176,16 @@ func TestPoolDeviceMarkFaulty(t *testing.T) {
defer cleanupStore(t, store)
err := store.AddDevice(testCtx, &DeviceInfo{Name: "1", State: Unknown})
assert.NilError(t, err)
assert.NoError(t, err)
// Note: do not use 'Activated' here because pool.ensureDeviceStates() will
// try to activate the real dm device, which will fail on a faked device.
err = store.AddDevice(testCtx, &DeviceInfo{Name: "2", State: Deactivated})
assert.NilError(t, err)
assert.NoError(t, err)
pool := &PoolDevice{metadata: store}
err = pool.ensureDeviceStates(testCtx)
assert.NilError(t, err)
assert.NoError(t, err)
called := 0
err = pool.metadata.WalkDevices(testCtx, func(info *DeviceInfo) error {
@ -204,7 +204,7 @@ func TestPoolDeviceMarkFaulty(t *testing.T) {
return nil
})
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, 2, called)
}
@ -212,24 +212,24 @@ func testCreateThinDevice(t *testing.T, pool *PoolDevice) {
ctx := context.Background()
err := pool.CreateThinDevice(ctx, thinDevice1, device1Size)
assert.NilError(t, err, "can't create first thin device")
assert.Nil(t, err, "can't create first thin device")
err = pool.CreateThinDevice(ctx, thinDevice1, device1Size)
assert.Assert(t, err != nil, "device pool allows duplicated device names")
assert.True(t, err != nil, "device pool allows duplicated device names")
err = pool.CreateThinDevice(ctx, thinDevice2, device2Size)
assert.NilError(t, err, "can't create second thin device")
assert.Nil(t, err, "can't create second thin device")
deviceInfo1, err := pool.metadata.GetDevice(ctx, thinDevice1)
assert.NilError(t, err)
assert.NoError(t, err)
deviceInfo2, err := pool.metadata.GetDevice(ctx, thinDevice2)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Assert(t, deviceInfo1.DeviceID != deviceInfo2.DeviceID, "assigned device ids should be different")
assert.True(t, deviceInfo1.DeviceID != deviceInfo2.DeviceID, "assigned device ids should be different")
usage, err := pool.GetUsage(thinDevice1)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Equal(t, usage, int64(0))
}
@ -242,16 +242,16 @@ func testMakeFileSystem(t *testing.T, pool *PoolDevice) {
}
output, err := exec.Command("mkfs.ext4", args...).CombinedOutput()
assert.NilError(t, err, "failed to make filesystem on '%s': %s", thinDevice1, string(output))
assert.Nil(t, err, "failed to make filesystem on '%s': %s", thinDevice1, string(output))
usage, err := pool.GetUsage(thinDevice1)
assert.NilError(t, err)
assert.Assert(t, usage > 0)
assert.NoError(t, err)
assert.True(t, usage > 0)
}
func testCreateSnapshot(t *testing.T, pool *PoolDevice) {
err := pool.CreateSnapshotDevice(context.Background(), thinDevice1, snapDevice1, device1Size)
assert.NilError(t, err, "failed to create snapshot from '%s' volume", thinDevice1)
assert.Nil(t, err, "failed to create snapshot from '%s' volume", thinDevice1)
}
func testDeactivateThinDevice(t *testing.T, pool *PoolDevice) {
@ -261,21 +261,21 @@ func testDeactivateThinDevice(t *testing.T, pool *PoolDevice) {
}
for _, deviceName := range deviceList {
assert.Assert(t, pool.IsActivated(deviceName))
assert.True(t, pool.IsActivated(deviceName))
err := pool.DeactivateDevice(context.Background(), deviceName, false, true)
assert.NilError(t, err, "failed to remove '%s'", deviceName)
assert.Nil(t, err, "failed to remove '%s'", deviceName)
assert.Assert(t, !pool.IsActivated(deviceName))
assert.False(t, pool.IsActivated(deviceName))
}
}
func testRemoveThinDevice(t *testing.T, pool *PoolDevice) {
err := pool.RemoveDevice(testCtx, thinDevice1)
assert.NilError(t, err, "should delete thin device from pool")
assert.Nil(t, err, "should delete thin device from pool")
err = pool.RemoveDevice(testCtx, thinDevice2)
assert.NilError(t, err, "should delete thin device from pool")
assert.Nil(t, err, "should delete thin device from pool")
}
func getMounts(thinDeviceName string) []mount.Mount {
@ -289,21 +289,21 @@ func getMounts(thinDeviceName string) []mount.Mount {
func createLoopbackDevice(t *testing.T, dir string) (string, string) {
file, err := os.CreateTemp(dir, testsPrefix)
assert.NilError(t, err)
assert.NoError(t, err)
size, err := units.RAMInBytes("128Mb")
assert.NilError(t, err)
assert.NoError(t, err)
err = file.Truncate(size)
assert.NilError(t, err)
assert.NoError(t, err)
err = file.Close()
assert.NilError(t, err)
assert.NoError(t, err)
imagePath := file.Name()
loopDevice, err := mount.AttachLoopDevice(imagePath)
assert.NilError(t, err)
assert.NoError(t, err)
return imagePath, loopDevice
}

View File

@ -29,7 +29,7 @@ import (
"github.com/containerd/continuity/fs/fstest"
"github.com/hashicorp/go-multierror"
"github.com/sirupsen/logrus"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/assert"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/namespaces"
@ -61,7 +61,7 @@ func TestSnapshotterSuite(t *testing.T) {
t.Run("DevMapperUsage", func(t *testing.T) {
snapshotter, closer, err := snapshotterFn(ctx, t.TempDir())
assert.NilError(t, err)
assert.NoError(t, err)
defer closer()
testUsage(t, snapshotter)
@ -75,16 +75,16 @@ func testUsage(t *testing.T, snapshotter snapshots.Snapshotter) {
// Create empty base layer
_, err := snapshotter.Prepare(ctx, "prepare-1", "")
assert.NilError(t, err)
assert.NoError(t, err)
emptyLayerUsage, err := snapshotter.Usage(ctx, "prepare-1")
assert.NilError(t, err)
assert.NoError(t, err)
// Should be > 0 as just written file system also consumes blocks
assert.Assert(t, emptyLayerUsage.Size > 0)
assert.Greater(t, emptyLayerUsage.Size, int64(0))
err = snapshotter.Commit(ctx, "layer-1", "prepare-1")
assert.NilError(t, err)
assert.NoError(t, err)
// Create child layer with 1MB file
@ -94,19 +94,19 @@ func testUsage(t *testing.T, snapshotter snapshots.Snapshotter) {
)
mounts, err := snapshotter.Prepare(ctx, "prepare-2", "layer-1")
assert.NilError(t, err)
assert.NoError(t, err)
err = mount.WithTempMount(ctx, mounts, baseApplier.Apply)
assert.NilError(t, err)
assert.NoError(t, err)
err = snapshotter.Commit(ctx, "layer-2", "prepare-2")
assert.NilError(t, err)
assert.NoError(t, err)
layer2Usage, err := snapshotter.Usage(ctx, "layer-2")
assert.NilError(t, err)
assert.NoError(t, err)
// Should be at least 1 MB + fs metadata
assert.Check(t, layer2Usage.Size >= sizeBytes,
assert.GreaterOrEqual(t, layer2Usage.Size, sizeBytes,
"%d > %d", layer2Usage.Size, sizeBytes)
}
@ -114,26 +114,26 @@ func TestMkfsExt4(t *testing.T) {
ctx := context.Background()
// We test the default setting which is lazy init is disabled
err := mkfs(ctx, "ext4", "nodiscard,lazy_itable_init=0,lazy_journal_init=0", "")
assert.ErrorContains(t, err, `mkfs.ext4 couldn't initialize ""`)
assert.Contains(t, err.Error(), `mkfs.ext4 couldn't initialize ""`)
}
func TestMkfsExt4NonDefault(t *testing.T) {
ctx := context.Background()
// We test a non default setting where we enable lazy init for ext4
err := mkfs(ctx, "ext4", "nodiscard", "")
assert.ErrorContains(t, err, `mkfs.ext4 couldn't initialize ""`)
assert.Contains(t, err.Error(), `mkfs.ext4 couldn't initialize ""`)
}
func TestMkfsXfs(t *testing.T) {
ctx := context.Background()
err := mkfs(ctx, "xfs", "", "")
assert.ErrorContains(t, err, `mkfs.xfs couldn't initialize ""`)
assert.Contains(t, err.Error(), `mkfs.xfs couldn't initialize ""`)
}
func TestMkfsXfsNonDefault(t *testing.T) {
ctx := context.Background()
err := mkfs(ctx, "xfs", "noquota", "")
assert.ErrorContains(t, err, `mkfs.xfs couldn't initialize ""`)
assert.Contains(t, err.Error(), `mkfs.xfs couldn't initialize ""`)
}
func TestMultipleXfsMounts(t *testing.T) {
@ -152,7 +152,7 @@ func TestMultipleXfsMounts(t *testing.T) {
FileSystemType: "xfs",
}
snapshotter, closer, err := createSnapshotter(ctx, t, config)
assert.NilError(t, err)
assert.NoError(t, err)
defer closer()
var (
@ -162,27 +162,27 @@ func TestMultipleXfsMounts(t *testing.T) {
// Create base layer
mounts, err := snapshotter.Prepare(ctx, "prepare-1", "")
assert.NilError(t, err)
assert.NoError(t, err)
root1 := t.TempDir()
defer func() {
mount.UnmountAll(root1, 0)
}()
err = mount.All(mounts, root1)
assert.NilError(t, err)
assert.NoError(t, err)
baseApplier.Apply(root1)
snapshotter.Commit(ctx, "layer-1", "prepare-1")
// Create one child layer
mounts, err = snapshotter.Prepare(ctx, "prepare-2", "layer-1")
assert.NilError(t, err)
assert.NoError(t, err)
root2 := t.TempDir()
defer func() {
mount.UnmountAll(root2, 0)
}()
err = mount.All(mounts, root2)
assert.NilError(t, err)
assert.NoError(t, err)
}
func createSnapshotter(ctx context.Context, t *testing.T, config *Config) (snapshots.Snapshotter, func() error, error) {
@ -191,7 +191,7 @@ func createSnapshotter(ctx context.Context, t *testing.T, config *Config) (snaps
_, loopMetaDevice := createLoopbackDevice(t, config.RootPath)
err := dmsetup.CreatePool(config.PoolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize)
assert.NilError(t, err, "failed to create pool %q", config.PoolName)
assert.Nil(t, err, "failed to create pool %q", config.PoolName)
snap, err := NewSnapshotter(ctx, config)
if err != nil {

View File

@ -26,8 +26,7 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/snapshots"
"github.com/google/go-cmp/cmp"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"github.com/stretchr/testify/assert"
)
type testFunc func(context.Context, *testing.T, *MetaStore)
@ -214,29 +213,29 @@ var baseInfo = map[string]snapshots.Info{
func assertNotExist(t *testing.T, err error) {
t.Helper()
assert.Assert(t, errdefs.IsNotFound(err), "got %+v", err)
assert.True(t, errdefs.IsNotFound(err), "got %+v", err)
}
func assertNotActive(t *testing.T, err error) {
t.Helper()
assert.Assert(t, errdefs.IsFailedPrecondition(err), "got %+v", err)
assert.True(t, errdefs.IsFailedPrecondition(err), "got %+v", err)
}
func assertNotCommitted(t *testing.T, err error) {
t.Helper()
assert.Assert(t, errdefs.IsInvalidArgument(err), "got %+v", err)
assert.True(t, errdefs.IsInvalidArgument(err), "got %+v", err)
}
func assertExist(t *testing.T, err error) {
t.Helper()
assert.Assert(t, errdefs.IsAlreadyExists(err), "got %+v", err)
assert.True(t, errdefs.IsAlreadyExists(err), "got %+v", err)
}
func testGetInfo(ctx context.Context, t *testing.T, _ *MetaStore) {
for key, expected := range baseInfo {
_, info, _, err := GetInfo(ctx, key)
assert.NilError(t, err, "on key %v", key)
assert.Check(t, is.DeepEqual(expected, info, cmpSnapshotInfo), "on key %v", key)
assert.Nil(t, err, "on key %v", key)
assert.Truef(t, cmp.Equal(expected, info, cmpSnapshotInfo), "on key %v", key)
}
}
@ -276,8 +275,8 @@ func testWalk(ctx context.Context, t *testing.T, _ *MetaStore) {
found[info.Name] = info
return nil
})
assert.NilError(t, err)
assert.Assert(t, is.DeepEqual(baseInfo, found, cmpSnapshotInfo))
assert.NoError(t, err)
assert.True(t, cmp.Equal(baseInfo, found, cmpSnapshotInfo))
}
func testGetSnapshot(ctx context.Context, t *testing.T, ms *MetaStore) {
@ -326,8 +325,8 @@ func testGetSnapshot(ctx context.Context, t *testing.T, ms *MetaStore) {
test := func(ctx context.Context, t *testing.T, ms *MetaStore) {
for key, expected := range snapshotMap {
s, err := GetSnapshot(ctx, key)
assert.NilError(t, err, "failed to get snapshot %s", key)
assert.Check(t, is.DeepEqual(expected, s), "on key %s", key)
assert.Nil(t, err, "failed to get snapshot %s", key)
assert.Equalf(t, expected, s, "on key %s", key)
}
}

View File

@ -35,8 +35,7 @@ import (
"github.com/containerd/containerd/pkg/testutil"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/continuity/fs/fstest"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"github.com/stretchr/testify/assert"
)
// SnapshotterFunc is used in SnapshotterSuite
@ -173,8 +172,8 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
t.Fatalf("failure reason: %+v", err)
}
assert.Check(t, is.Equal("", si.Parent))
assert.Check(t, is.Equal(snapshots.KindCommitted, si.Kind))
assert.Empty(t, si.Parent)
assert.Equal(t, snapshots.KindCommitted, si.Kind)
_, err = snapshotter.Stat(ctx, preparing)
if err == nil {
@ -209,8 +208,8 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
t.Fatal(err)
}
assert.Check(t, is.Equal(committed, ni.Parent))
assert.Check(t, is.Equal(snapshots.KindActive, ni.Kind))
assert.Equal(t, committed, ni.Parent)
assert.Equal(t, snapshots.KindActive, ni.Kind)
nextCommitted := filepath.Join(work, "committed-next")
if err := snapshotter.Commit(ctx, nextCommitted, next, opt); err != nil {
@ -222,8 +221,8 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
t.Fatalf("failure reason: %+v", err)
}
assert.Check(t, is.Equal(committed, si2.Parent))
assert.Check(t, is.Equal(snapshots.KindCommitted, si2.Kind))
assert.Equal(t, committed, si2.Parent)
assert.Equal(t, snapshots.KindCommitted, si2.Kind)
_, err = snapshotter.Stat(ctx, next)
if err == nil {
@ -235,7 +234,7 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
si2.Name: si2,
}
walked := map[string]snapshots.Info{} // walk is not ordered
assert.NilError(t, snapshotter.Walk(ctx, func(ctx context.Context, si snapshots.Info) error {
assert.Nil(t, snapshotter.Walk(ctx, func(ctx context.Context, si snapshots.Info) error {
walked[si.Name] = si
return nil
}))
@ -246,7 +245,7 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
t.Errorf("Missing stat for %v", ek)
continue
}
assert.Check(t, is.DeepEqual(ev, av))
assert.Equal(t, ev, av)
}
nextnext := filepath.Join(work, "nextnextlayer")
@ -269,10 +268,16 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
}
testutil.Unmount(t, nextnext)
assert.NilError(t, snapshotter.Remove(ctx, nextnext))
assert.Assert(t, is.ErrorContains(snapshotter.Remove(ctx, committed), "remove"))
assert.NilError(t, snapshotter.Remove(ctx, nextCommitted))
assert.NilError(t, snapshotter.Remove(ctx, committed))
assert.Nil(t, snapshotter.Remove(ctx, nextnext))
err = snapshotter.Remove(ctx, committed)
assert.NotNil(t, err)
if err != nil {
assert.Contains(t, err.Error(), "remove")
}
assert.Nil(t, snapshotter.Remove(ctx, nextCommitted))
assert.Nil(t, snapshotter.Remove(ctx, committed))
}
// Create a New Layer on top of base layer with Prepare, Stat on new layer, should return Active layer.
@ -304,9 +309,9 @@ func checkSnapshotterStatActive(ctx context.Context, t *testing.T, snapshotter s
if err != nil {
t.Fatal(err)
}
assert.Check(t, is.Equal(si.Name, preparing))
assert.Check(t, is.Equal(snapshots.KindActive, si.Kind))
assert.Check(t, is.Equal("", si.Parent))
assert.Equal(t, si.Name, preparing)
assert.Equal(t, snapshots.KindActive, si.Kind)
assert.Equal(t, "", si.Parent)
}
// Commit a New Layer on top of base layer with Prepare & Commit , Stat on new layer, should return Committed layer.
@ -343,9 +348,9 @@ func checkSnapshotterStatCommitted(ctx context.Context, t *testing.T, snapshotte
if err != nil {
t.Fatal(err)
}
assert.Check(t, is.Equal(si.Name, committed))
assert.Check(t, is.Equal(snapshots.KindCommitted, si.Kind))
assert.Check(t, is.Equal("", si.Parent))
assert.Equal(t, si.Name, committed)
assert.Equal(t, snapshots.KindCommitted, si.Kind)
assert.Equal(t, "", si.Parent)
}
@ -418,9 +423,9 @@ func checkSnapshotterTransitivity(ctx context.Context, t *testing.T, snapshotter
}
// Test the transivity
assert.Check(t, is.Equal("", siA.Parent))
assert.Check(t, is.Equal(snapA, siB.Parent))
assert.Check(t, is.Equal("", siParentB.Parent))
assert.Equal(t, "", siA.Parent)
assert.Equal(t, snapA, siB.Parent)
assert.Equal(t, "", siParentB.Parent)
}
@ -450,7 +455,7 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter
}
_, err = snapshotter.View(ctx, newLayer, snapA, opt)
assert.Check(t, err != nil)
assert.True(t, err != nil)
// Two Prepare with same key
prepLayer := filepath.Join(work, "prepLayer")
@ -464,7 +469,7 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter
}
_, err = snapshotter.Prepare(ctx, prepLayer, snapA, opt)
assert.Check(t, err != nil)
assert.True(t, err != nil)
// Two View with same key
viewLayer := filepath.Join(work, "viewLayer")
@ -478,7 +483,7 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter
}
_, err = snapshotter.View(ctx, viewLayer, snapA, opt)
assert.Check(t, err != nil)
assert.True(t, err != nil)
}
@ -809,8 +814,8 @@ func checkSnapshotterViewReadonly(ctx context.Context, t *testing.T, snapshotter
t.Fatalf("write to %q should fail (EROFS) but did not fail", testfile)
}
testutil.Unmount(t, viewMountPoint)
assert.NilError(t, snapshotter.Remove(ctx, view))
assert.NilError(t, snapshotter.Remove(ctx, committed))
assert.Nil(t, snapshotter.Remove(ctx, view))
assert.Nil(t, snapshotter.Remove(ctx, committed))
}
// Move files from base layer to new location in intermediate layer.

View File

@ -24,16 +24,16 @@ import (
"time"
"github.com/containerd/containerd/pkg/userns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
exec "golang.org/x/sys/execabs"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestSetPositiveOomScoreAdjustment(t *testing.T) {
// Setting a *positive* OOM score adjust does not require privileged
_, adjustment, err := adjustOom(123)
assert.NilError(t, err)
assert.Check(t, is.Equal(adjustment, 123))
assert.NoError(t, err)
assert.EqualValues(t, adjustment, 123)
}
func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) {
@ -43,8 +43,8 @@ func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) {
}
_, adjustment, err := adjustOom(-123)
assert.NilError(t, err)
assert.Check(t, is.Equal(adjustment, -123))
assert.NoError(t, err)
assert.EqualValues(t, adjustment, -123)
}
func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T) {
@ -54,31 +54,33 @@ func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T)
}
initial, adjustment, err := adjustOom(-123)
assert.NilError(t, err)
assert.Check(t, is.Equal(adjustment, initial))
assert.NoError(t, err)
assert.EqualValues(t, adjustment, initial)
}
func TestSetOOMScoreBoundaries(t *testing.T) {
err := SetOOMScore(0, OOMScoreAdjMax+1)
assert.ErrorContains(t, err, fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMax+1))
require.NotNil(t, err)
assert.Contains(t, err.Error(), fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMax+1))
err = SetOOMScore(0, OOMScoreAdjMin-1)
assert.ErrorContains(t, err, fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMin-1))
require.NotNil(t, err)
assert.Contains(t, err.Error(), fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMin-1))
_, adjustment, err := adjustOom(OOMScoreAdjMax)
assert.NilError(t, err)
assert.Check(t, is.Equal(adjustment, OOMScoreAdjMax))
assert.NoError(t, err)
assert.EqualValues(t, adjustment, OOMScoreAdjMax)
score, err := GetOOMScoreAdj(os.Getpid())
assert.NilError(t, err)
assert.NoError(t, err)
if score == OOMScoreAdjMin {
// We won't be able to set the score lower than the parent process. This
// could also be tested if the parent process does not have a oom-score-adj
// set, but GetOOMScoreAdj does not distinguish between "not set" and
// "score is set, but zero".
_, adjustment, err = adjustOom(OOMScoreAdjMin)
assert.NilError(t, err)
assert.Check(t, is.Equal(adjustment, OOMScoreAdjMin))
assert.NoError(t, err)
assert.EqualValues(t, adjustment, OOMScoreAdjMin)
}
}

View File

@ -1,148 +0,0 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package cmpopts provides common options for the cmp package.
package cmpopts
import (
"math"
"reflect"
"time"
"github.com/google/go-cmp/cmp"
)
func equateAlways(_, _ interface{}) bool { return true }
// EquateEmpty returns a Comparer option that determines all maps and slices
// with a length of zero to be equal, regardless of whether they are nil.
//
// EquateEmpty can be used in conjunction with SortSlices and SortMaps.
func EquateEmpty() cmp.Option {
return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways))
}
func isEmpty(x, y interface{}) bool {
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
return (x != nil && y != nil && vx.Type() == vy.Type()) &&
(vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) &&
(vx.Len() == 0 && vy.Len() == 0)
}
// EquateApprox returns a Comparer option that determines float32 or float64
// values to be equal if they are within a relative fraction or absolute margin.
// This option is not used when either x or y is NaN or infinite.
//
// The fraction determines that the difference of two values must be within the
// smaller fraction of the two values, while the margin determines that the two
// values must be within some absolute margin.
// To express only a fraction or only a margin, use 0 for the other parameter.
// The fraction and margin must be non-negative.
//
// The mathematical expression used is equivalent to:
// |x-y| ≤ max(fraction*min(|x|, |y|), margin)
//
// EquateApprox can be used in conjunction with EquateNaNs.
func EquateApprox(fraction, margin float64) cmp.Option {
if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) {
panic("margin or fraction must be a non-negative number")
}
a := approximator{fraction, margin}
return cmp.Options{
cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)),
cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)),
}
}
type approximator struct{ frac, marg float64 }
func areRealF64s(x, y float64) bool {
return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0)
}
func areRealF32s(x, y float32) bool {
return areRealF64s(float64(x), float64(y))
}
func (a approximator) compareF64(x, y float64) bool {
relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y))
return math.Abs(x-y) <= math.Max(a.marg, relMarg)
}
func (a approximator) compareF32(x, y float32) bool {
return a.compareF64(float64(x), float64(y))
}
// EquateNaNs returns a Comparer option that determines float32 and float64
// NaN values to be equal.
//
// EquateNaNs can be used in conjunction with EquateApprox.
func EquateNaNs() cmp.Option {
return cmp.Options{
cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)),
cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)),
}
}
func areNaNsF64s(x, y float64) bool {
return math.IsNaN(x) && math.IsNaN(y)
}
func areNaNsF32s(x, y float32) bool {
return areNaNsF64s(float64(x), float64(y))
}
// EquateApproxTime returns a Comparer option that determines two non-zero
// time.Time values to be equal if they are within some margin of one another.
// If both times have a monotonic clock reading, then the monotonic time
// difference will be used. The margin must be non-negative.
func EquateApproxTime(margin time.Duration) cmp.Option {
if margin < 0 {
panic("margin must be a non-negative number")
}
a := timeApproximator{margin}
return cmp.FilterValues(areNonZeroTimes, cmp.Comparer(a.compare))
}
func areNonZeroTimes(x, y time.Time) bool {
return !x.IsZero() && !y.IsZero()
}
type timeApproximator struct {
margin time.Duration
}
func (a timeApproximator) compare(x, y time.Time) bool {
// Avoid subtracting times to avoid overflow when the
// difference is larger than the largest representible duration.
if x.After(y) {
// Ensure x is always before y
x, y = y, x
}
// We're within the margin if x+margin >= y.
// Note: time.Time doesn't have AfterOrEqual method hence the negation.
return !x.Add(a.margin).Before(y)
}
// AnyError is an error that matches any non-nil error.
var AnyError anyError
type anyError struct{}
func (anyError) Error() string { return "any error" }
func (anyError) Is(err error) bool { return err != nil }
// EquateErrors returns a Comparer option that determines errors to be equal
// if errors.Is reports them to match. The AnyError error can be used to
// match any non-nil error.
func EquateErrors() cmp.Option {
return cmp.FilterValues(areConcreteErrors, cmp.Comparer(compareErrors))
}
// areConcreteErrors reports whether x and y are types that implement error.
// The input types are deliberately of the interface{} type rather than the
// error type so that we can handle situations where the current type is an
// interface{}, but the underlying concrete types both happen to implement
// the error interface.
func areConcreteErrors(x, y interface{}) bool {
_, ok1 := x.(error)
_, ok2 := y.(error)
return ok1 && ok2
}

View File

@ -1,15 +0,0 @@
// Copyright 2021, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.13
package cmpopts
import "errors"
func compareErrors(x, y interface{}) bool {
xe := x.(error)
ye := y.(error)
return errors.Is(xe, ye) || errors.Is(ye, xe)
}

View File

@ -1,18 +0,0 @@
// Copyright 2021, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.13
// TODO(≥go1.13): For support on <go1.13, we use the xerrors package.
// Drop this file when we no longer support older Go versions.
package cmpopts
import "golang.org/x/xerrors"
func compareErrors(x, y interface{}) bool {
xe := x.(error)
ye := y.(error)
return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
}

View File

@ -1,206 +0,0 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"fmt"
"reflect"
"unicode"
"unicode/utf8"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/internal/function"
)
// IgnoreFields returns an Option that ignores fields of the
// given names on a single struct type. It respects the names of exported fields
// that are forwarded due to struct embedding.
// The struct type is specified by passing in a value of that type.
//
// The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a
// specific sub-field that is embedded or nested within the parent struct.
func IgnoreFields(typ interface{}, names ...string) cmp.Option {
sf := newStructFilter(typ, names...)
return cmp.FilterPath(sf.filter, cmp.Ignore())
}
// IgnoreTypes returns an Option that ignores all values assignable to
// certain types, which are specified by passing in a value of each type.
func IgnoreTypes(typs ...interface{}) cmp.Option {
tf := newTypeFilter(typs...)
return cmp.FilterPath(tf.filter, cmp.Ignore())
}
type typeFilter []reflect.Type
func newTypeFilter(typs ...interface{}) (tf typeFilter) {
for _, typ := range typs {
t := reflect.TypeOf(typ)
if t == nil {
// This occurs if someone tries to pass in sync.Locker(nil)
panic("cannot determine type; consider using IgnoreInterfaces")
}
tf = append(tf, t)
}
return tf
}
func (tf typeFilter) filter(p cmp.Path) bool {
if len(p) < 1 {
return false
}
t := p.Last().Type()
for _, ti := range tf {
if t.AssignableTo(ti) {
return true
}
}
return false
}
// IgnoreInterfaces returns an Option that ignores all values or references of
// values assignable to certain interface types. These interfaces are specified
// by passing in an anonymous struct with the interface types embedded in it.
// For example, to ignore sync.Locker, pass in struct{sync.Locker}{}.
func IgnoreInterfaces(ifaces interface{}) cmp.Option {
tf := newIfaceFilter(ifaces)
return cmp.FilterPath(tf.filter, cmp.Ignore())
}
type ifaceFilter []reflect.Type
func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) {
t := reflect.TypeOf(ifaces)
if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct {
panic("input must be an anonymous struct")
}
for i := 0; i < t.NumField(); i++ {
fi := t.Field(i)
switch {
case !fi.Anonymous:
panic("struct cannot have named fields")
case fi.Type.Kind() != reflect.Interface:
panic("embedded field must be an interface type")
case fi.Type.NumMethod() == 0:
// This matches everything; why would you ever want this?
panic("cannot ignore empty interface")
default:
tf = append(tf, fi.Type)
}
}
return tf
}
func (tf ifaceFilter) filter(p cmp.Path) bool {
if len(p) < 1 {
return false
}
t := p.Last().Type()
for _, ti := range tf {
if t.AssignableTo(ti) {
return true
}
if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) {
return true
}
}
return false
}
// IgnoreUnexported returns an Option that only ignores the immediate unexported
// fields of a struct, including anonymous fields of unexported types.
// In particular, unexported fields within the struct's exported fields
// of struct types, including anonymous fields, will not be ignored unless the
// type of the field itself is also passed to IgnoreUnexported.
//
// Avoid ignoring unexported fields of a type which you do not control (i.e. a
// type from another repository), as changes to the implementation of such types
// may change how the comparison behaves. Prefer a custom Comparer instead.
func IgnoreUnexported(typs ...interface{}) cmp.Option {
ux := newUnexportedFilter(typs...)
return cmp.FilterPath(ux.filter, cmp.Ignore())
}
type unexportedFilter struct{ m map[reflect.Type]bool }
func newUnexportedFilter(typs ...interface{}) unexportedFilter {
ux := unexportedFilter{m: make(map[reflect.Type]bool)}
for _, typ := range typs {
t := reflect.TypeOf(typ)
if t == nil || t.Kind() != reflect.Struct {
panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
}
ux.m[t] = true
}
return ux
}
func (xf unexportedFilter) filter(p cmp.Path) bool {
sf, ok := p.Index(-1).(cmp.StructField)
if !ok {
return false
}
return xf.m[p.Index(-2).Type()] && !isExported(sf.Name())
}
// isExported reports whether the identifier is exported.
func isExported(id string) bool {
r, _ := utf8.DecodeRuneInString(id)
return unicode.IsUpper(r)
}
// IgnoreSliceElements returns an Option that ignores elements of []V.
// The discard function must be of the form "func(T) bool" which is used to
// ignore slice elements of type V, where V is assignable to T.
// Elements are ignored if the function reports true.
func IgnoreSliceElements(discardFunc interface{}) cmp.Option {
vf := reflect.ValueOf(discardFunc)
if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() {
panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
}
return cmp.FilterPath(func(p cmp.Path) bool {
si, ok := p.Index(-1).(cmp.SliceIndex)
if !ok {
return false
}
if !si.Type().AssignableTo(vf.Type().In(0)) {
return false
}
vx, vy := si.Values()
if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() {
return true
}
if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() {
return true
}
return false
}, cmp.Ignore())
}
// IgnoreMapEntries returns an Option that ignores entries of map[K]V.
// The discard function must be of the form "func(T, R) bool" which is used to
// ignore map entries of type K and V, where K and V are assignable to T and R.
// Entries are ignored if the function reports true.
func IgnoreMapEntries(discardFunc interface{}) cmp.Option {
vf := reflect.ValueOf(discardFunc)
if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() {
panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
}
return cmp.FilterPath(func(p cmp.Path) bool {
mi, ok := p.Index(-1).(cmp.MapIndex)
if !ok {
return false
}
if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) {
return false
}
k := mi.Key()
vx, vy := mi.Values()
if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() {
return true
}
if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() {
return true
}
return false
}, cmp.Ignore())
}

View File

@ -1,147 +0,0 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"fmt"
"reflect"
"sort"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/internal/function"
)
// SortSlices returns a Transformer option that sorts all []V.
// The less function must be of the form "func(T, T) bool" which is used to
// sort any slice with element type V that is assignable to T.
//
// The less function must be:
// • Deterministic: less(x, y) == less(x, y)
// • Irreflexive: !less(x, x)
// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
//
// The less function does not have to be "total". That is, if !less(x, y) and
// !less(y, x) for two elements x and y, their relative order is maintained.
//
// SortSlices can be used in conjunction with EquateEmpty.
func SortSlices(lessFunc interface{}) cmp.Option {
vf := reflect.ValueOf(lessFunc)
if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
panic(fmt.Sprintf("invalid less function: %T", lessFunc))
}
ss := sliceSorter{vf.Type().In(0), vf}
return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort))
}
type sliceSorter struct {
in reflect.Type // T
fnc reflect.Value // func(T, T) bool
}
func (ss sliceSorter) filter(x, y interface{}) bool {
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
if !(x != nil && y != nil && vx.Type() == vy.Type()) ||
!(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) ||
(vx.Len() <= 1 && vy.Len() <= 1) {
return false
}
// Check whether the slices are already sorted to avoid an infinite
// recursion cycle applying the same transform to itself.
ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) })
ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) })
return !ok1 || !ok2
}
func (ss sliceSorter) sort(x interface{}) interface{} {
src := reflect.ValueOf(x)
dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len())
for i := 0; i < src.Len(); i++ {
dst.Index(i).Set(src.Index(i))
}
sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) })
ss.checkSort(dst)
return dst.Interface()
}
func (ss sliceSorter) checkSort(v reflect.Value) {
start := -1 // Start of a sequence of equal elements.
for i := 1; i < v.Len(); i++ {
if ss.less(v, i-1, i) {
// Check that first and last elements in v[start:i] are equal.
if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) {
panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i)))
}
start = -1
} else if start == -1 {
start = i
}
}
}
func (ss sliceSorter) less(v reflect.Value, i, j int) bool {
vx, vy := v.Index(i), v.Index(j)
return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
}
// SortMaps returns a Transformer option that flattens map[K]V types to be a
// sorted []struct{K, V}. The less function must be of the form
// "func(T, T) bool" which is used to sort any map with key K that is
// assignable to T.
//
// Flattening the map into a slice has the property that cmp.Equal is able to
// use Comparers on K or the K.Equal method if it exists.
//
// The less function must be:
// • Deterministic: less(x, y) == less(x, y)
// • Irreflexive: !less(x, x)
// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
// • Total: if x != y, then either less(x, y) or less(y, x)
//
// SortMaps can be used in conjunction with EquateEmpty.
func SortMaps(lessFunc interface{}) cmp.Option {
vf := reflect.ValueOf(lessFunc)
if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
panic(fmt.Sprintf("invalid less function: %T", lessFunc))
}
ms := mapSorter{vf.Type().In(0), vf}
return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort))
}
type mapSorter struct {
in reflect.Type // T
fnc reflect.Value // func(T, T) bool
}
func (ms mapSorter) filter(x, y interface{}) bool {
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
return (x != nil && y != nil && vx.Type() == vy.Type()) &&
(vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) &&
(vx.Len() != 0 || vy.Len() != 0)
}
func (ms mapSorter) sort(x interface{}) interface{} {
src := reflect.ValueOf(x)
outType := reflect.StructOf([]reflect.StructField{
{Name: "K", Type: src.Type().Key()},
{Name: "V", Type: src.Type().Elem()},
})
dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len())
for i, k := range src.MapKeys() {
v := reflect.New(outType).Elem()
v.Field(0).Set(k)
v.Field(1).Set(src.MapIndex(k))
dst.Index(i).Set(v)
}
sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) })
ms.checkSort(dst)
return dst.Interface()
}
func (ms mapSorter) checkSort(v reflect.Value) {
for i := 1; i < v.Len(); i++ {
if !ms.less(v, i-1, i) {
panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i)))
}
}
}
func (ms mapSorter) less(v reflect.Value, i, j int) bool {
vx, vy := v.Index(i).Field(0), v.Index(j).Field(0)
return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
}

View File

@ -1,187 +0,0 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"fmt"
"reflect"
"strings"
"github.com/google/go-cmp/cmp"
)
// filterField returns a new Option where opt is only evaluated on paths that
// include a specific exported field on a single struct type.
// The struct type is specified by passing in a value of that type.
//
// The name may be a dot-delimited string (e.g., "Foo.Bar") to select a
// specific sub-field that is embedded or nested within the parent struct.
func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option {
// TODO: This is currently unexported over concerns of how helper filters
// can be composed together easily.
// TODO: Add tests for FilterField.
sf := newStructFilter(typ, name)
return cmp.FilterPath(sf.filter, opt)
}
type structFilter struct {
t reflect.Type // The root struct type to match on
ft fieldTree // Tree of fields to match on
}
func newStructFilter(typ interface{}, names ...string) structFilter {
// TODO: Perhaps allow * as a special identifier to allow ignoring any
// number of path steps until the next field match?
// This could be useful when a concrete struct gets transformed into
// an anonymous struct where it is not possible to specify that by type,
// but the transformer happens to provide guarantees about the names of
// the transformed fields.
t := reflect.TypeOf(typ)
if t == nil || t.Kind() != reflect.Struct {
panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
}
var ft fieldTree
for _, name := range names {
cname, err := canonicalName(t, name)
if err != nil {
panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err))
}
ft.insert(cname)
}
return structFilter{t, ft}
}
func (sf structFilter) filter(p cmp.Path) bool {
for i, ps := range p {
if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) {
return true
}
}
return false
}
// fieldTree represents a set of dot-separated identifiers.
//
// For example, inserting the following selectors:
// Foo
// Foo.Bar.Baz
// Foo.Buzz
// Nuka.Cola.Quantum
//
// Results in a tree of the form:
// {sub: {
// "Foo": {ok: true, sub: {
// "Bar": {sub: {
// "Baz": {ok: true},
// }},
// "Buzz": {ok: true},
// }},
// "Nuka": {sub: {
// "Cola": {sub: {
// "Quantum": {ok: true},
// }},
// }},
// }}
type fieldTree struct {
ok bool // Whether this is a specified node
sub map[string]fieldTree // The sub-tree of fields under this node
}
// insert inserts a sequence of field accesses into the tree.
func (ft *fieldTree) insert(cname []string) {
if ft.sub == nil {
ft.sub = make(map[string]fieldTree)
}
if len(cname) == 0 {
ft.ok = true
return
}
sub := ft.sub[cname[0]]
sub.insert(cname[1:])
ft.sub[cname[0]] = sub
}
// matchPrefix reports whether any selector in the fieldTree matches
// the start of path p.
func (ft fieldTree) matchPrefix(p cmp.Path) bool {
for _, ps := range p {
switch ps := ps.(type) {
case cmp.StructField:
ft = ft.sub[ps.Name()]
if ft.ok {
return true
}
if len(ft.sub) == 0 {
return false
}
case cmp.Indirect:
default:
return false
}
}
return false
}
// canonicalName returns a list of identifiers where any struct field access
// through an embedded field is expanded to include the names of the embedded
// types themselves.
//
// For example, suppose field "Foo" is not directly in the parent struct,
// but actually from an embedded struct of type "Bar". Then, the canonical name
// of "Foo" is actually "Bar.Foo".
//
// Suppose field "Foo" is not directly in the parent struct, but actually
// a field in two different embedded structs of types "Bar" and "Baz".
// Then the selector "Foo" causes a panic since it is ambiguous which one it
// refers to. The user must specify either "Bar.Foo" or "Baz.Foo".
func canonicalName(t reflect.Type, sel string) ([]string, error) {
var name string
sel = strings.TrimPrefix(sel, ".")
if sel == "" {
return nil, fmt.Errorf("name must not be empty")
}
if i := strings.IndexByte(sel, '.'); i < 0 {
name, sel = sel, ""
} else {
name, sel = sel[:i], sel[i:]
}
// Type must be a struct or pointer to struct.
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("%v must be a struct", t)
}
// Find the canonical name for this current field name.
// If the field exists in an embedded struct, then it will be expanded.
sf, _ := t.FieldByName(name)
if !isExported(name) {
// Avoid using reflect.Type.FieldByName for unexported fields due to
// buggy behavior with regard to embeddeding and unexported fields.
// See https://golang.org/issue/4876 for details.
sf = reflect.StructField{}
for i := 0; i < t.NumField() && sf.Name == ""; i++ {
if t.Field(i).Name == name {
sf = t.Field(i)
}
}
}
if sf.Name == "" {
return []string{name}, fmt.Errorf("does not exist")
}
var ss []string
for i := range sf.Index {
ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name)
}
if sel == "" {
return ss, nil
}
ssPost, err := canonicalName(sf.Type, sel)
return append(ss, ssPost...), err
}

View File

@ -1,35 +0,0 @@
// Copyright 2018, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"github.com/google/go-cmp/cmp"
)
type xformFilter struct{ xform cmp.Option }
func (xf xformFilter) filter(p cmp.Path) bool {
for _, ps := range p {
if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform {
return false
}
}
return true
}
// AcyclicTransformer returns a Transformer with a filter applied that ensures
// that the transformer cannot be recursively applied upon its own output.
//
// An example use case is a transformer that splits a string by lines:
// AcyclicTransformer("SplitLines", func(s string) []string{
// return strings.Split(s, "\n")
// })
//
// Had this been an unfiltered Transformer instead, this would result in an
// infinite cycle converting a string to []string to [][]string and so on.
func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option {
xf := xformFilter{cmp.Transformer(name, xformFunc)}
return cmp.FilterPath(xf.filter, xf.xform)
}

27
vendor/golang.org/x/xerrors/LICENSE generated vendored
View File

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

22
vendor/golang.org/x/xerrors/PATENTS generated vendored
View File

@ -1,22 +0,0 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

2
vendor/golang.org/x/xerrors/README generated vendored
View File

@ -1,2 +0,0 @@
This repository holds the transition packages for the new Go 1.13 error values.
See golang.org/design/29934-error-values.

View File

@ -1,193 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"bytes"
"fmt"
"io"
"reflect"
"strconv"
)
// FormatError calls the FormatError method of f with an errors.Printer
// configured according to s and verb, and writes the result to s.
func FormatError(f Formatter, s fmt.State, verb rune) {
// Assuming this function is only called from the Format method, and given
// that FormatError takes precedence over Format, it cannot be called from
// any package that supports errors.Formatter. It is therefore safe to
// disregard that State may be a specific printer implementation and use one
// of our choice instead.
// limitations: does not support printing error as Go struct.
var (
sep = " " // separator before next error
p = &state{State: s}
direct = true
)
var err error = f
switch verb {
// Note that this switch must match the preference order
// for ordinary string printing (%#v before %+v, and so on).
case 'v':
if s.Flag('#') {
if stringer, ok := err.(fmt.GoStringer); ok {
io.WriteString(&p.buf, stringer.GoString())
goto exit
}
// proceed as if it were %v
} else if s.Flag('+') {
p.printDetail = true
sep = "\n - "
}
case 's':
case 'q', 'x', 'X':
// Use an intermediate buffer in the rare cases that precision,
// truncation, or one of the alternative verbs (q, x, and X) are
// specified.
direct = false
default:
p.buf.WriteString("%!")
p.buf.WriteRune(verb)
p.buf.WriteByte('(')
switch {
case err != nil:
p.buf.WriteString(reflect.TypeOf(f).String())
default:
p.buf.WriteString("<nil>")
}
p.buf.WriteByte(')')
io.Copy(s, &p.buf)
return
}
loop:
for {
switch v := err.(type) {
case Formatter:
err = v.FormatError((*printer)(p))
case fmt.Formatter:
v.Format(p, 'v')
break loop
default:
io.WriteString(&p.buf, v.Error())
break loop
}
if err == nil {
break
}
if p.needColon || !p.printDetail {
p.buf.WriteByte(':')
p.needColon = false
}
p.buf.WriteString(sep)
p.inDetail = false
p.needNewline = false
}
exit:
width, okW := s.Width()
prec, okP := s.Precision()
if !direct || (okW && width > 0) || okP {
// Construct format string from State s.
format := []byte{'%'}
if s.Flag('-') {
format = append(format, '-')
}
if s.Flag('+') {
format = append(format, '+')
}
if s.Flag(' ') {
format = append(format, ' ')
}
if okW {
format = strconv.AppendInt(format, int64(width), 10)
}
if okP {
format = append(format, '.')
format = strconv.AppendInt(format, int64(prec), 10)
}
format = append(format, string(verb)...)
fmt.Fprintf(s, string(format), p.buf.String())
} else {
io.Copy(s, &p.buf)
}
}
var detailSep = []byte("\n ")
// state tracks error printing state. It implements fmt.State.
type state struct {
fmt.State
buf bytes.Buffer
printDetail bool
inDetail bool
needColon bool
needNewline bool
}
func (s *state) Write(b []byte) (n int, err error) {
if s.printDetail {
if len(b) == 0 {
return 0, nil
}
if s.inDetail && s.needColon {
s.needNewline = true
if b[0] == '\n' {
b = b[1:]
}
}
k := 0
for i, c := range b {
if s.needNewline {
if s.inDetail && s.needColon {
s.buf.WriteByte(':')
s.needColon = false
}
s.buf.Write(detailSep)
s.needNewline = false
}
if c == '\n' {
s.buf.Write(b[k:i])
k = i + 1
s.needNewline = true
}
}
s.buf.Write(b[k:])
if !s.inDetail {
s.needColon = true
}
} else if !s.inDetail {
s.buf.Write(b)
}
return len(b), nil
}
// printer wraps a state to implement an xerrors.Printer.
type printer state
func (s *printer) Print(args ...interface{}) {
if !s.inDetail || s.printDetail {
fmt.Fprint((*state)(s), args...)
}
}
func (s *printer) Printf(format string, args ...interface{}) {
if !s.inDetail || s.printDetail {
fmt.Fprintf((*state)(s), format, args...)
}
}
func (s *printer) Detail() bool {
s.inDetail = true
return s.printDetail
}

View File

@ -1 +0,0 @@
issuerepo: golang/go

22
vendor/golang.org/x/xerrors/doc.go generated vendored
View File

@ -1,22 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package xerrors implements functions to manipulate errors.
//
// This package is based on the Go 2 proposal for error values:
// https://golang.org/design/29934-error-values
//
// These functions were incorporated into the standard library's errors package
// in Go 1.13:
// - Is
// - As
// - Unwrap
//
// Also, Errorf's %w verb was incorporated into fmt.Errorf.
//
// Use this package to get equivalent behavior in all supported Go versions.
//
// No other features of this package were included in Go 1.13, and at present
// there are no plans to include any of them.
package xerrors // import "golang.org/x/xerrors"

View File

@ -1,33 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import "fmt"
// errorString is a trivial implementation of error.
type errorString struct {
s string
frame Frame
}
// New returns an error that formats as the given text.
//
// The returned error contains a Frame set to the caller's location and
// implements Formatter to show this information when printed with details.
func New(text string) error {
return &errorString{text, Caller(1)}
}
func (e *errorString) Error() string {
return e.s
}
func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) }
func (e *errorString) FormatError(p Printer) (next error) {
p.Print(e.s)
e.frame.Format(p)
return nil
}

187
vendor/golang.org/x/xerrors/fmt.go generated vendored
View File

@ -1,187 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"fmt"
"strings"
"unicode"
"unicode/utf8"
"golang.org/x/xerrors/internal"
)
const percentBangString = "%!"
// Errorf formats according to a format specifier and returns the string as a
// value that satisfies error.
//
// The returned error includes the file and line number of the caller when
// formatted with additional detail enabled. If the last argument is an error
// the returned error's Format method will return it if the format string ends
// with ": %s", ": %v", or ": %w". If the last argument is an error and the
// format string ends with ": %w", the returned error implements an Unwrap
// method returning it.
//
// If the format specifier includes a %w verb with an error operand in a
// position other than at the end, the returned error will still implement an
// Unwrap method returning the operand, but the error's Format method will not
// return the wrapped error.
//
// It is invalid to include more than one %w verb or to supply it with an
// operand that does not implement the error interface. The %w verb is otherwise
// a synonym for %v.
func Errorf(format string, a ...interface{}) error {
format = formatPlusW(format)
// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
wrap := strings.HasSuffix(format, ": %w")
idx, format2, ok := parsePercentW(format)
percentWElsewhere := !wrap && idx >= 0
if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) {
err := errorAt(a, len(a)-1)
if err == nil {
return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
}
// TODO: this is not entirely correct. The error value could be
// printed elsewhere in format if it mixes numbered with unnumbered
// substitutions. With relatively small changes to doPrintf we can
// have it optionally ignore extra arguments and pass the argument
// list in its entirety.
msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
frame := Frame{}
if internal.EnableTrace {
frame = Caller(1)
}
if wrap {
return &wrapError{msg, err, frame}
}
return &noWrapError{msg, err, frame}
}
// Support %w anywhere.
// TODO: don't repeat the wrapped error's message when %w occurs in the middle.
msg := fmt.Sprintf(format2, a...)
if idx < 0 {
return &noWrapError{msg, nil, Caller(1)}
}
err := errorAt(a, idx)
if !ok || err == nil {
// Too many %ws or argument of %w is not an error. Approximate the Go
// 1.13 fmt.Errorf message.
return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)}
}
frame := Frame{}
if internal.EnableTrace {
frame = Caller(1)
}
return &wrapError{msg, err, frame}
}
func errorAt(args []interface{}, i int) error {
if i < 0 || i >= len(args) {
return nil
}
err, ok := args[i].(error)
if !ok {
return nil
}
return err
}
// formatPlusW is used to avoid the vet check that will barf at %w.
func formatPlusW(s string) string {
return s
}
// Return the index of the only %w in format, or -1 if none.
// Also return a rewritten format string with %w replaced by %v, and
// false if there is more than one %w.
// TODO: handle "%[N]w".
func parsePercentW(format string) (idx int, newFormat string, ok bool) {
// Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go.
idx = -1
ok = true
n := 0
sz := 0
var isW bool
for i := 0; i < len(format); i += sz {
if format[i] != '%' {
sz = 1
continue
}
// "%%" is not a format directive.
if i+1 < len(format) && format[i+1] == '%' {
sz = 2
continue
}
sz, isW = parsePrintfVerb(format[i:])
if isW {
if idx >= 0 {
ok = false
} else {
idx = n
}
// "Replace" the last character, the 'w', with a 'v'.
p := i + sz - 1
format = format[:p] + "v" + format[p+1:]
}
n++
}
return idx, format, ok
}
// Parse the printf verb starting with a % at s[0].
// Return how many bytes it occupies and whether the verb is 'w'.
func parsePrintfVerb(s string) (int, bool) {
// Assume only that the directive is a sequence of non-letters followed by a single letter.
sz := 0
var r rune
for i := 1; i < len(s); i += sz {
r, sz = utf8.DecodeRuneInString(s[i:])
if unicode.IsLetter(r) {
return i + sz, r == 'w'
}
}
return len(s), false
}
type noWrapError struct {
msg string
err error
frame Frame
}
func (e *noWrapError) Error() string {
return fmt.Sprint(e)
}
func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
func (e *noWrapError) FormatError(p Printer) (next error) {
p.Print(e.msg)
e.frame.Format(p)
return e.err
}
type wrapError struct {
msg string
err error
frame Frame
}
func (e *wrapError) Error() string {
return fmt.Sprint(e)
}
func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
func (e *wrapError) FormatError(p Printer) (next error) {
p.Print(e.msg)
e.frame.Format(p)
return e.err
}
func (e *wrapError) Unwrap() error {
return e.err
}

View File

@ -1,34 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
// A Formatter formats error messages.
type Formatter interface {
error
// FormatError prints the receiver's first error and returns the next error in
// the error chain, if any.
FormatError(p Printer) (next error)
}
// A Printer formats error messages.
//
// The most common implementation of Printer is the one provided by package fmt
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
// typically provide their own implementations.
type Printer interface {
// Print appends args to the message output.
Print(args ...interface{})
// Printf writes a formatted string.
Printf(format string, args ...interface{})
// Detail reports whether error detail is requested.
// After the first call to Detail, all text written to the Printer
// is formatted as additional detail, or ignored when
// detail has not been requested.
// If Detail returns false, the caller can avoid printing the detail at all.
Detail() bool
}

56
vendor/golang.org/x/xerrors/frame.go generated vendored
View File

@ -1,56 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"runtime"
)
// A Frame contains part of a call stack.
type Frame struct {
// Make room for three PCs: the one we were asked for, what it called,
// and possibly a PC for skipPleaseUseCallersFrames. See:
// https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169
frames [3]uintptr
}
// Caller returns a Frame that describes a frame on the caller's stack.
// The argument skip is the number of frames to skip over.
// Caller(0) returns the frame for the caller of Caller.
func Caller(skip int) Frame {
var s Frame
runtime.Callers(skip+1, s.frames[:])
return s
}
// location reports the file, line, and function of a frame.
//
// The returned function may be "" even if file and line are not.
func (f Frame) location() (function, file string, line int) {
frames := runtime.CallersFrames(f.frames[:])
if _, ok := frames.Next(); !ok {
return "", "", 0
}
fr, ok := frames.Next()
if !ok {
return "", "", 0
}
return fr.Function, fr.File, fr.Line
}
// Format prints the stack as error detail.
// It should be called from an error's Format implementation
// after printing any other error detail.
func (f Frame) Format(p Printer) {
if p.Detail() {
function, file, line := f.location()
if function != "" {
p.Printf("%s\n ", function)
}
if file != "" {
p.Printf("%s:%d\n", file, line)
}
}
}

View File

@ -1,8 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package internal
// EnableTrace indicates whether stack information should be recorded in errors.
var EnableTrace = true

106
vendor/golang.org/x/xerrors/wrap.go generated vendored
View File

@ -1,106 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"reflect"
)
// A Wrapper provides context around another error.
type Wrapper interface {
// Unwrap returns the next error in the error chain.
// If there is no next error, Unwrap returns nil.
Unwrap() error
}
// Opaque returns an error with the same error formatting as err
// but that does not match err and cannot be unwrapped.
func Opaque(err error) error {
return noWrapper{err}
}
type noWrapper struct {
error
}
func (e noWrapper) FormatError(p Printer) (next error) {
if f, ok := e.error.(Formatter); ok {
return f.FormatError(p)
}
p.Print(e.error)
return nil
}
// Unwrap returns the result of calling the Unwrap method on err, if err implements
// Unwrap. Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
u, ok := err.(Wrapper)
if !ok {
return nil
}
return u.Unwrap()
}
// Is reports whether any error in err's chain matches target.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
func Is(err, target error) bool {
if target == nil {
return err == target
}
isComparable := reflect.TypeOf(target).Comparable()
for {
if isComparable && err == target {
return true
}
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
// TODO: consider supporing target.Is(err). This would allow
// user-definable predicates, but also may allow for coping with sloppy
// APIs, thereby making it easier to get away with them.
if err = Unwrap(err); err == nil {
return false
}
}
}
// As finds the first error in err's chain that matches the type to which target
// points, and if so, sets the target to its value and returns true. An error
// matches a type if it is assignable to the target type, or if it has a method
// As(interface{}) bool such that As(target) returns true. As will panic if target
// is not a non-nil pointer to a type which implements error or is of interface type.
//
// The As method should set the target to its value and return true if err
// matches the type to which target points.
func As(err error, target interface{}) bool {
if target == nil {
panic("errors: target cannot be nil")
}
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
targetType := typ.Elem()
for err != nil {
if reflect.TypeOf(err).AssignableTo(targetType) {
val.Elem().Set(reflect.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
return true
}
err = Unwrap(err)
}
return false
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()

View File

@ -1,13 +0,0 @@
Copyright 2018 gotest.tools authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,219 +0,0 @@
/*Package assert provides assertions for comparing expected values to actual
values. When an assertion fails a helpful error message is printed.
Assert and Check
Assert() and Check() both accept a Comparison, and fail the test when the
comparison fails. The one difference is that Assert() will end the test execution
immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
return the value of the comparison, then proceed with the rest of the test case.
Example usage
The example below shows assert used with some common types.
import (
"testing"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestEverything(t *testing.T) {
// booleans
assert.Assert(t, ok)
assert.Assert(t, !missing)
// primitives
assert.Equal(t, count, 1)
assert.Equal(t, msg, "the message")
assert.Assert(t, total != 10) // NotEqual
// errors
assert.NilError(t, closer.Close())
assert.Error(t, err, "the exact error message")
assert.ErrorContains(t, err, "includes this")
assert.ErrorType(t, err, os.IsNotExist)
// complex types
assert.DeepEqual(t, result, myStruct{Name: "title"})
assert.Assert(t, is.Len(items, 3))
assert.Assert(t, len(sequence) != 0) // NotEmpty
assert.Assert(t, is.Contains(mapping, "key"))
// pointers and interface
assert.Assert(t, is.Nil(ref))
assert.Assert(t, ref != nil) // NotNil
}
Comparisons
Package http://pkg.go.dev/gotest.tools/v3/assert/cmp provides
many common comparisons. Additional comparisons can be written to compare
values in other ways. See the example Assert (CustomComparison).
Automated migration from testify
gty-migrate-from-testify is a command which translates Go source code from
testify assertions to the assertions provided by this package.
See http://pkg.go.dev/gotest.tools/v3/assert/cmd/gty-migrate-from-testify.
*/
package assert // import "gotest.tools/v3/assert"
import (
gocmp "github.com/google/go-cmp/cmp"
"gotest.tools/v3/assert/cmp"
"gotest.tools/v3/internal/assert"
)
// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
type BoolOrComparison interface{}
// TestingT is the subset of testing.T used by the assert package.
type TestingT interface {
FailNow()
Fail()
Log(args ...interface{})
}
type helperT interface {
Helper()
}
// Assert performs a comparison. If the comparison fails, the test is marked as
// failed, a failure message is logged, and execution is stopped immediately.
//
// The comparison argument may be one of three types:
// bool
// True is success. False is a failure.
// The failure message will contain the literal source code of the expression.
// cmp.Comparison
// Uses cmp.Result.Success() to check for success of failure.
// The comparison is responsible for producing a helpful failure message.
// http://pkg.go.dev/gotest.tools/v3/assert/cmp provides many common comparisons.
// error
// A nil value is considered success.
// A non-nil error is a failure, err.Error() is used as the failure message.
func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsFromComparisonCall, comparison, msgAndArgs...) {
t.FailNow()
}
}
// Check performs a comparison. If the comparison fails the test is marked as
// failed, a failure message is logged, and Check returns false. Otherwise returns
// true.
//
// See Assert for details about the comparison arg and failure messages.
func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) bool {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsFromComparisonCall, comparison, msgAndArgs...) {
t.Fail()
return false
}
return true
}
// NilError fails the test immediately if err is not nil.
// This is equivalent to Assert(t, err)
func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsAfterT, err, msgAndArgs...) {
t.FailNow()
}
}
// Equal uses the == operator to assert two values are equal and fails the test
// if they are not equal.
//
// If the comparison fails Equal will use the variable names for x and y as part
// of the failure message to identify the actual and expected values.
//
// If either x or y are a multi-line string the failure message will include a
// unified diff of the two values. If the values only differ by whitespace
// the unified diff will be augmented by replacing whitespace characters with
// visible characters to identify the whitespace difference.
//
// This is equivalent to Assert(t, cmp.Equal(x, y)).
func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsAfterT, cmp.Equal(x, y), msgAndArgs...) {
t.FailNow()
}
}
// DeepEqual uses google/go-cmp (https://godoc.org/github.com/google/go-cmp/cmp)
// to assert two values are equal and fails the test if they are not equal.
//
// Package http://pkg.go.dev/gotest.tools/v3/assert/opt provides some additional
// commonly used Options.
//
// This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsAfterT, cmp.DeepEqual(x, y, opts...)) {
t.FailNow()
}
}
// Error fails the test if err is nil, or the error message is not the expected
// message.
// Equivalent to Assert(t, cmp.Error(err, message)).
func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsAfterT, cmp.Error(err, message), msgAndArgs...) {
t.FailNow()
}
}
// ErrorContains fails the test if err is nil, or the error message does not
// contain the expected substring.
// Equivalent to Assert(t, cmp.ErrorContains(err, substring)).
func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...) {
t.FailNow()
}
}
// ErrorType fails the test if err is nil, or err is not the expected type.
// Equivalent to Assert(t, cmp.ErrorType(err, expected)).
//
// Expected can be one of:
// func(error) bool
// Function should return true if the error is the expected type.
// type struct{}, type &struct{}
// A struct or a pointer to a struct.
// Fails if the error is not of the same type as expected.
// type &interface{}
// A pointer to an interface type.
// Fails if err does not implement the interface.
// reflect.Type
// Fails if err does not implement the reflect.Type
func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !assert.Eval(t, assert.ArgsAfterT, cmp.ErrorType(err, expected), msgAndArgs...) {
t.FailNow()
}
}

View File

@ -1,365 +0,0 @@
/*Package cmp provides Comparisons for Assert and Check*/
package cmp // import "gotest.tools/v3/assert/cmp"
import (
"fmt"
"reflect"
"regexp"
"strings"
"github.com/google/go-cmp/cmp"
"gotest.tools/v3/internal/format"
)
// Comparison is a function which compares values and returns ResultSuccess if
// the actual value matches the expected value. If the values do not match the
// Result will contain a message about why it failed.
type Comparison func() Result
// DeepEqual compares two values using google/go-cmp
// (https://godoc.org/github.com/google/go-cmp/cmp)
// and succeeds if the values are equal.
//
// The comparison can be customized using comparison Options.
// Package http://pkg.go.dev/gotest.tools/v3/assert/opt provides some additional
// commonly used Options.
func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
return func() (result Result) {
defer func() {
if panicmsg, handled := handleCmpPanic(recover()); handled {
result = ResultFailure(panicmsg)
}
}()
diff := cmp.Diff(x, y, opts...)
if diff == "" {
return ResultSuccess
}
return multiLineDiffResult(diff)
}
}
func handleCmpPanic(r interface{}) (string, bool) {
if r == nil {
return "", false
}
panicmsg, ok := r.(string)
if !ok {
panic(r)
}
switch {
case strings.HasPrefix(panicmsg, "cannot handle unexported field"):
return panicmsg, true
}
panic(r)
}
func toResult(success bool, msg string) Result {
if success {
return ResultSuccess
}
return ResultFailure(msg)
}
// RegexOrPattern may be either a *regexp.Regexp or a string that is a valid
// regexp pattern.
type RegexOrPattern interface{}
// Regexp succeeds if value v matches regular expression re.
//
// Example:
// assert.Assert(t, cmp.Regexp("^[0-9a-f]{32}$", str))
// r := regexp.MustCompile("^[0-9a-f]{32}$")
// assert.Assert(t, cmp.Regexp(r, str))
func Regexp(re RegexOrPattern, v string) Comparison {
match := func(re *regexp.Regexp) Result {
return toResult(
re.MatchString(v),
fmt.Sprintf("value %q does not match regexp %q", v, re.String()))
}
return func() Result {
switch regex := re.(type) {
case *regexp.Regexp:
return match(regex)
case string:
re, err := regexp.Compile(regex)
if err != nil {
return ResultFailure(err.Error())
}
return match(re)
default:
return ResultFailure(fmt.Sprintf("invalid type %T for regex pattern", regex))
}
}
}
// Equal succeeds if x == y. See assert.Equal for full documentation.
func Equal(x, y interface{}) Comparison {
return func() Result {
switch {
case x == y:
return ResultSuccess
case isMultiLineStringCompare(x, y):
diff := format.UnifiedDiff(format.DiffConfig{A: x.(string), B: y.(string)})
return multiLineDiffResult(diff)
}
return ResultFailureTemplate(`
{{- printf "%v" .Data.x}} (
{{- with callArg 0 }}{{ formatNode . }} {{end -}}
{{- printf "%T" .Data.x -}}
) != {{ printf "%v" .Data.y}} (
{{- with callArg 1 }}{{ formatNode . }} {{end -}}
{{- printf "%T" .Data.y -}}
)`,
map[string]interface{}{"x": x, "y": y})
}
}
func isMultiLineStringCompare(x, y interface{}) bool {
strX, ok := x.(string)
if !ok {
return false
}
strY, ok := y.(string)
if !ok {
return false
}
return strings.Contains(strX, "\n") || strings.Contains(strY, "\n")
}
func multiLineDiffResult(diff string) Result {
return ResultFailureTemplate(`
--- {{ with callArg 0 }}{{ formatNode . }}{{else}}{{end}}
+++ {{ with callArg 1 }}{{ formatNode . }}{{else}}{{end}}
{{ .Data.diff }}`,
map[string]interface{}{"diff": diff})
}
// Len succeeds if the sequence has the expected length.
func Len(seq interface{}, expected int) Comparison {
return func() (result Result) {
defer func() {
if e := recover(); e != nil {
result = ResultFailure(fmt.Sprintf("type %T does not have a length", seq))
}
}()
value := reflect.ValueOf(seq)
length := value.Len()
if length == expected {
return ResultSuccess
}
msg := fmt.Sprintf("expected %s (length %d) to have length %d", seq, length, expected)
return ResultFailure(msg)
}
}
// Contains succeeds if item is in collection. Collection may be a string, map,
// slice, or array.
//
// If collection is a string, item must also be a string, and is compared using
// strings.Contains().
// If collection is a Map, contains will succeed if item is a key in the map.
// If collection is a slice or array, item is compared to each item in the
// sequence using reflect.DeepEqual().
func Contains(collection interface{}, item interface{}) Comparison {
return func() Result {
colValue := reflect.ValueOf(collection)
if !colValue.IsValid() {
return ResultFailure(fmt.Sprintf("nil does not contain items"))
}
msg := fmt.Sprintf("%v does not contain %v", collection, item)
itemValue := reflect.ValueOf(item)
switch colValue.Type().Kind() {
case reflect.String:
if itemValue.Type().Kind() != reflect.String {
return ResultFailure("string may only contain strings")
}
return toResult(
strings.Contains(colValue.String(), itemValue.String()),
fmt.Sprintf("string %q does not contain %q", collection, item))
case reflect.Map:
if itemValue.Type() != colValue.Type().Key() {
return ResultFailure(fmt.Sprintf(
"%v can not contain a %v key", colValue.Type(), itemValue.Type()))
}
return toResult(colValue.MapIndex(itemValue).IsValid(), msg)
case reflect.Slice, reflect.Array:
for i := 0; i < colValue.Len(); i++ {
if reflect.DeepEqual(colValue.Index(i).Interface(), item) {
return ResultSuccess
}
}
return ResultFailure(msg)
default:
return ResultFailure(fmt.Sprintf("type %T does not contain items", collection))
}
}
}
// Panics succeeds if f() panics.
func Panics(f func()) Comparison {
return func() (result Result) {
defer func() {
if err := recover(); err != nil {
result = ResultSuccess
}
}()
f()
return ResultFailure("did not panic")
}
}
// Error succeeds if err is a non-nil error, and the error message equals the
// expected message.
func Error(err error, message string) Comparison {
return func() Result {
switch {
case err == nil:
return ResultFailure("expected an error, got nil")
case err.Error() != message:
return ResultFailure(fmt.Sprintf(
"expected error %q, got %s", message, formatErrorMessage(err)))
}
return ResultSuccess
}
}
// ErrorContains succeeds if err is a non-nil error, and the error message contains
// the expected substring.
func ErrorContains(err error, substring string) Comparison {
return func() Result {
switch {
case err == nil:
return ResultFailure("expected an error, got nil")
case !strings.Contains(err.Error(), substring):
return ResultFailure(fmt.Sprintf(
"expected error to contain %q, got %s", substring, formatErrorMessage(err)))
}
return ResultSuccess
}
}
type causer interface {
Cause() error
}
func formatErrorMessage(err error) string {
if _, ok := err.(causer); ok {
return fmt.Sprintf("%q\n%+v", err, err)
}
// This error was not wrapped with github.com/pkg/errors
return fmt.Sprintf("%q", err)
}
// Nil succeeds if obj is a nil interface, pointer, or function.
//
// Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,
// maps, and channels.
func Nil(obj interface{}) Comparison {
msgFunc := func(value reflect.Value) string {
return fmt.Sprintf("%v (type %s) is not nil", reflect.Indirect(value), value.Type())
}
return isNil(obj, msgFunc)
}
func isNil(obj interface{}, msgFunc func(reflect.Value) string) Comparison {
return func() Result {
if obj == nil {
return ResultSuccess
}
value := reflect.ValueOf(obj)
kind := value.Type().Kind()
if kind >= reflect.Chan && kind <= reflect.Slice {
if value.IsNil() {
return ResultSuccess
}
return ResultFailure(msgFunc(value))
}
return ResultFailure(fmt.Sprintf("%v (type %s) can not be nil", value, value.Type()))
}
}
// ErrorType succeeds if err is not nil and is of the expected type.
//
// Expected can be one of:
// func(error) bool
// Function should return true if the error is the expected type.
// type struct{}, type &struct{}
// A struct or a pointer to a struct.
// Fails if the error is not of the same type as expected.
// type &interface{}
// A pointer to an interface type.
// Fails if err does not implement the interface.
// reflect.Type
// Fails if err does not implement the reflect.Type
func ErrorType(err error, expected interface{}) Comparison {
return func() Result {
switch expectedType := expected.(type) {
case func(error) bool:
return cmpErrorTypeFunc(err, expectedType)
case reflect.Type:
if expectedType.Kind() == reflect.Interface {
return cmpErrorTypeImplementsType(err, expectedType)
}
return cmpErrorTypeEqualType(err, expectedType)
case nil:
return ResultFailure(fmt.Sprintf("invalid type for expected: nil"))
}
expectedType := reflect.TypeOf(expected)
switch {
case expectedType.Kind() == reflect.Struct, isPtrToStruct(expectedType):
return cmpErrorTypeEqualType(err, expectedType)
case isPtrToInterface(expectedType):
return cmpErrorTypeImplementsType(err, expectedType.Elem())
}
return ResultFailure(fmt.Sprintf("invalid type for expected: %T", expected))
}
}
func cmpErrorTypeFunc(err error, f func(error) bool) Result {
if f(err) {
return ResultSuccess
}
actual := "nil"
if err != nil {
actual = fmt.Sprintf("%s (%T)", err, err)
}
return ResultFailureTemplate(`error is {{ .Data.actual }}
{{- with callArg 1 }}, not {{ formatNode . }}{{end -}}`,
map[string]interface{}{"actual": actual})
}
func cmpErrorTypeEqualType(err error, expectedType reflect.Type) Result {
if err == nil {
return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
}
errValue := reflect.ValueOf(err)
if errValue.Type() == expectedType {
return ResultSuccess
}
return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
}
func cmpErrorTypeImplementsType(err error, expectedType reflect.Type) Result {
if err == nil {
return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
}
errValue := reflect.ValueOf(err)
if errValue.Type().Implements(expectedType) {
return ResultSuccess
}
return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
}
func isPtrToInterface(typ reflect.Type) bool {
return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Interface
}
func isPtrToStruct(typ reflect.Type) bool {
return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct
}

View File

@ -1,99 +0,0 @@
package cmp
import (
"bytes"
"fmt"
"go/ast"
"text/template"
"gotest.tools/v3/internal/source"
)
// A Result of a Comparison.
type Result interface {
Success() bool
}
// StringResult is an implementation of Result that reports the error message
// string verbatim and does not provide any templating or formatting of the
// message.
type StringResult struct {
success bool
message string
}
// Success returns true if the comparison was successful.
func (r StringResult) Success() bool {
return r.success
}
// FailureMessage returns the message used to provide additional information
// about the failure.
func (r StringResult) FailureMessage() string {
return r.message
}
// ResultSuccess is a constant which is returned by a ComparisonWithResult to
// indicate success.
var ResultSuccess = StringResult{success: true}
// ResultFailure returns a failed Result with a failure message.
func ResultFailure(message string) StringResult {
return StringResult{message: message}
}
// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
// is returned with the error message as the failure message.
func ResultFromError(err error) Result {
if err == nil {
return ResultSuccess
}
return ResultFailure(err.Error())
}
type templatedResult struct {
template string
data map[string]interface{}
}
func (r templatedResult) Success() bool {
return false
}
func (r templatedResult) FailureMessage(args []ast.Expr) string {
msg, err := renderMessage(r, args)
if err != nil {
return fmt.Sprintf("failed to render failure message: %s", err)
}
return msg
}
// ResultFailureTemplate returns a Result with a template string and data which
// can be used to format a failure message. The template may access data from .Data,
// the comparison args with the callArg function, and the formatNode function may
// be used to format the call args.
func ResultFailureTemplate(template string, data map[string]interface{}) Result {
return templatedResult{template: template, data: data}
}
func renderMessage(result templatedResult, args []ast.Expr) (string, error) {
tmpl := template.New("failure").Funcs(template.FuncMap{
"formatNode": source.FormatNode,
"callArg": func(index int) ast.Expr {
if index >= len(args) {
return nil
}
return args[index]
},
})
var err error
tmpl, err = tmpl.Parse(result.template)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = tmpl.Execute(buf, map[string]interface{}{
"Data": result.data,
})
return buf.String(), err
}

View File

@ -1,143 +0,0 @@
package assert
import (
"fmt"
"go/ast"
"go/token"
"reflect"
"gotest.tools/v3/assert/cmp"
"gotest.tools/v3/internal/format"
"gotest.tools/v3/internal/source"
)
// LogT is the subset of testing.T used by the assert package.
type LogT interface {
Log(args ...interface{})
}
type helperT interface {
Helper()
}
const failureMessage = "assertion failed: "
// Eval the comparison and print a failure messages if the comparison has failed.
// nolint: gocyclo
func Eval(
t LogT,
argSelector argSelector,
comparison interface{},
msgAndArgs ...interface{},
) bool {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
var success bool
switch check := comparison.(type) {
case bool:
if check {
return true
}
logFailureFromBool(t, msgAndArgs...)
// Undocumented legacy comparison without Result type
case func() (success bool, message string):
success = runCompareFunc(t, check, msgAndArgs...)
case nil:
return true
case error:
msg := failureMsgFromError(check)
t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
case cmp.Comparison:
success = RunComparison(t, argSelector, check, msgAndArgs...)
case func() cmp.Result:
success = RunComparison(t, argSelector, check, msgAndArgs...)
default:
t.Log(fmt.Sprintf("invalid Comparison: %v (%T)", check, check))
}
return success
}
func runCompareFunc(
t LogT,
f func() (success bool, message string),
msgAndArgs ...interface{},
) bool {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if success, message := f(); !success {
t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
return false
}
return true
}
func logFailureFromBool(t LogT, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
const stackIndex = 3 // Assert()/Check(), assert(), logFailureFromBool()
args, err := source.CallExprArgs(stackIndex)
if err != nil {
t.Log(err.Error())
return
}
const comparisonArgIndex = 1 // Assert(t, comparison)
if len(args) <= comparisonArgIndex {
t.Log(failureMessage + "but assert failed to find the expression to print")
return
}
msg, err := boolFailureMessage(args[comparisonArgIndex])
if err != nil {
t.Log(err.Error())
msg = "expression is false"
}
t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
}
func failureMsgFromError(err error) string {
// Handle errors with non-nil types
v := reflect.ValueOf(err)
if v.Kind() == reflect.Ptr && v.IsNil() {
return fmt.Sprintf("error is not nil: error has type %T", err)
}
return "error is not nil: " + err.Error()
}
func boolFailureMessage(expr ast.Expr) (string, error) {
if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
x, err := source.FormatNode(binaryExpr.X)
if err != nil {
return "", err
}
y, err := source.FormatNode(binaryExpr.Y)
if err != nil {
return "", err
}
return x + " is " + y, nil
}
if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
x, err := source.FormatNode(unaryExpr.X)
if err != nil {
return "", err
}
return x + " is true", nil
}
formatted, err := source.FormatNode(expr)
if err != nil {
return "", err
}
return "expression is false: " + formatted, nil
}

View File

@ -1,125 +0,0 @@
package assert
import (
"fmt"
"go/ast"
"gotest.tools/v3/assert/cmp"
"gotest.tools/v3/internal/format"
"gotest.tools/v3/internal/source"
)
// RunComparison and return Comparison.Success. If the comparison fails a messages
// will be printed using t.Log.
func RunComparison(
t LogT,
argSelector argSelector,
f cmp.Comparison,
msgAndArgs ...interface{},
) bool {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
result := f()
if result.Success() {
return true
}
var message string
switch typed := result.(type) {
case resultWithComparisonArgs:
const stackIndex = 3 // Assert/Check, assert, RunComparison
args, err := source.CallExprArgs(stackIndex)
if err != nil {
t.Log(err.Error())
}
message = typed.FailureMessage(filterPrintableExpr(argSelector(args)))
case resultBasic:
message = typed.FailureMessage()
default:
message = fmt.Sprintf("comparison returned invalid Result type: %T", result)
}
t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
return false
}
type resultWithComparisonArgs interface {
FailureMessage(args []ast.Expr) string
}
type resultBasic interface {
FailureMessage() string
}
// filterPrintableExpr filters the ast.Expr slice to only include Expr that are
// easy to read when printed and contain relevant information to an assertion.
//
// Ident and SelectorExpr are included because they print nicely and the variable
// names may provide additional context to their values.
// BasicLit and CompositeLit are excluded because their source is equivalent to
// their value, which is already available.
// Other types are ignored for now, but could be added if they are relevant.
func filterPrintableExpr(args []ast.Expr) []ast.Expr {
result := make([]ast.Expr, len(args))
for i, arg := range args {
if isShortPrintableExpr(arg) {
result[i] = arg
continue
}
if starExpr, ok := arg.(*ast.StarExpr); ok {
result[i] = starExpr.X
continue
}
}
return result
}
func isShortPrintableExpr(expr ast.Expr) bool {
switch expr.(type) {
case *ast.Ident, *ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr:
return true
case *ast.BinaryExpr, *ast.UnaryExpr:
return true
default:
// CallExpr, ParenExpr, TypeAssertExpr, KeyValueExpr, StarExpr
return false
}
}
type argSelector func([]ast.Expr) []ast.Expr
// ArgsAfterT selects args starting at position 1. Used when the caller has a
// testing.T as the first argument, and the args to select should follow it.
func ArgsAfterT(args []ast.Expr) []ast.Expr {
if len(args) < 1 {
return nil
}
return args[1:]
}
// ArgsFromComparisonCall selects args from the CallExpression at position 1.
// Used when the caller has a testing.T as the first argument, and the args to
// select are passed to the cmp.Comparison at position 1.
func ArgsFromComparisonCall(args []ast.Expr) []ast.Expr {
if len(args) <= 1 {
return nil
}
if callExpr, ok := args[1].(*ast.CallExpr); ok {
return callExpr.Args
}
return nil
}
// ArgsAtZeroIndex selects args from the CallExpression at position 1.
// Used when the caller accepts a single cmp.Comparison argument.
func ArgsAtZeroIndex(args []ast.Expr) []ast.Expr {
if len(args) == 0 {
return nil
}
if callExpr, ok := args[0].(*ast.CallExpr); ok {
return callExpr.Args
}
return nil
}

View File

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

View File

@ -1,423 +0,0 @@
/*Package difflib is a partial port of Python difflib module.
Original source: https://github.com/pmezard/go-difflib
This file is trimmed to only the parts used by this repository.
*/
package difflib // import "gotest.tools/v3/internal/difflib"
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
// Match stores line numbers of size of match
type Match struct {
A int
B int
Size int
}
// OpCode identifies the type of diff
type OpCode struct {
Tag byte
I1 int
I2 int
J1 int
J2 int
}
// SequenceMatcher compares sequence of strings. The basic
// algorithm predates, and is a little fancier than, an algorithm
// published in the late 1980's by Ratcliff and Obershelp under the
// hyperbolic name "gestalt pattern matching". The basic idea is to find
// the longest contiguous matching subsequence that contains no "junk"
// elements (R-O doesn't address junk). The same idea is then applied
// recursively to the pieces of the sequences to the left and to the right
// of the matching subsequence. This does not yield minimal edit
// sequences, but does tend to yield matches that "look right" to people.
//
// SequenceMatcher tries to compute a "human-friendly diff" between two
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
// longest *contiguous* & junk-free matching subsequence. That's what
// catches peoples' eyes. The Windows(tm) windiff has another interesting
// notion, pairing up elements that appear uniquely in each sequence.
// That, and the method here, appear to yield more intuitive difference
// reports than does diff. This method appears to be the least vulnerable
// to synching up on blocks of "junk lines", though (like blank lines in
// ordinary text files, or maybe "<P>" lines in HTML files). That may be
// because this is the only method of the 3 that has a *concept* of
// "junk" <wink>.
//
// Timing: Basic R-O is cubic time worst case and quadratic time expected
// case. SequenceMatcher is quadratic time for the worst case and has
// expected-case behavior dependent in a complicated way on how many
// elements the sequences have in common; best case time is linear.
type SequenceMatcher struct {
a []string
b []string
b2j map[string][]int
IsJunk func(string) bool
autoJunk bool
bJunk map[string]struct{}
matchingBlocks []Match
fullBCount map[string]int
bPopular map[string]struct{}
opCodes []OpCode
}
// NewMatcher returns a new SequenceMatcher
func NewMatcher(a, b []string) *SequenceMatcher {
m := SequenceMatcher{autoJunk: true}
m.SetSeqs(a, b)
return &m
}
// SetSeqs sets two sequences to be compared.
func (m *SequenceMatcher) SetSeqs(a, b []string) {
m.SetSeq1(a)
m.SetSeq2(b)
}
// SetSeq1 sets the first sequence to be compared. The second sequence to be compared is
// not changed.
//
// SequenceMatcher computes and caches detailed information about the second
// sequence, so if you want to compare one sequence S against many sequences,
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
// sequences.
//
// See also SetSeqs() and SetSeq2().
func (m *SequenceMatcher) SetSeq1(a []string) {
if &a == &m.a {
return
}
m.a = a
m.matchingBlocks = nil
m.opCodes = nil
}
// SetSeq2 sets the second sequence to be compared. The first sequence to be compared is
// not changed.
func (m *SequenceMatcher) SetSeq2(b []string) {
if &b == &m.b {
return
}
m.b = b
m.matchingBlocks = nil
m.opCodes = nil
m.fullBCount = nil
m.chainB()
}
func (m *SequenceMatcher) chainB() {
// Populate line -> index mapping
b2j := map[string][]int{}
for i, s := range m.b {
indices := b2j[s]
indices = append(indices, i)
b2j[s] = indices
}
// Purge junk elements
m.bJunk = map[string]struct{}{}
if m.IsJunk != nil {
junk := m.bJunk
for s := range b2j {
if m.IsJunk(s) {
junk[s] = struct{}{}
}
}
for s := range junk {
delete(b2j, s)
}
}
// Purge remaining popular elements
popular := map[string]struct{}{}
n := len(m.b)
if m.autoJunk && n >= 200 {
ntest := n/100 + 1
for s, indices := range b2j {
if len(indices) > ntest {
popular[s] = struct{}{}
}
}
for s := range popular {
delete(b2j, s)
}
}
m.bPopular = popular
m.b2j = b2j
}
func (m *SequenceMatcher) isBJunk(s string) bool {
_, ok := m.bJunk[s]
return ok
}
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
//
// If IsJunk is not defined:
//
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
// alo <= i <= i+k <= ahi
// blo <= j <= j+k <= bhi
// and for all (i',j',k') meeting those conditions,
// k >= k'
// i <= i'
// and if i == i', j <= j'
//
// In other words, of all maximal matching blocks, return one that
// starts earliest in a, and of all those maximal matching blocks that
// start earliest in a, return the one that starts earliest in b.
//
// If IsJunk is defined, first the longest matching block is
// determined as above, but with the additional restriction that no
// junk element appears in the block. Then that block is extended as
// far as possible by matching (only) junk elements on both sides. So
// the resulting block never matches on junk except as identical junk
// happens to be adjacent to an "interesting" match.
//
// If no blocks match, return (alo, blo, 0).
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
// CAUTION: stripping common prefix or suffix would be incorrect.
// E.g.,
// ab
// acab
// Longest matching block is "ab", but if common prefix is
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
// strip, so ends up claiming that ab is changed to acab by
// inserting "ca" in the middle. That's minimal but unintuitive:
// "it's obvious" that someone inserted "ac" at the front.
// Windiff ends up at the same place as diff, but by pairing up
// the unique 'b's and then matching the first two 'a's.
besti, bestj, bestsize := alo, blo, 0
// find longest junk-free match
// during an iteration of the loop, j2len[j] = length of longest
// junk-free match ending with a[i-1] and b[j]
j2len := map[int]int{}
for i := alo; i != ahi; i++ {
// look at all instances of a[i] in b; note that because
// b2j has no junk keys, the loop is skipped if a[i] is junk
newj2len := map[int]int{}
for _, j := range m.b2j[m.a[i]] {
// a[i] matches b[j]
if j < blo {
continue
}
if j >= bhi {
break
}
k := j2len[j-1] + 1
newj2len[j] = k
if k > bestsize {
besti, bestj, bestsize = i-k+1, j-k+1, k
}
}
j2len = newj2len
}
// Extend the best by non-junk elements on each end. In particular,
// "popular" non-junk elements aren't in b2j, which greatly speeds
// the inner loop above, but also means "the best" match so far
// doesn't contain any junk *or* popular non-junk elements.
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
!m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize += 1
}
// Now that we have a wholly interesting match (albeit possibly
// empty!), we may as well suck up the matching junk on each
// side of it too. Can't think of a good reason not to, and it
// saves post-processing the (possibly considerable) expense of
// figuring out what to do with it. In the case of an empty
// interesting match, this is clearly the right thing to do,
// because no other kind of match is possible in the regions.
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize += 1
}
return Match{A: besti, B: bestj, Size: bestsize}
}
// GetMatchingBlocks returns a list of triples describing matching subsequences.
//
// Each triple is of the form (i, j, n), and means that
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
// adjacent triples in the list, and the second is not the last triple in the
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
// adjacent equal blocks.
//
// The last triple is a dummy, (len(a), len(b), 0), and is the only
// triple with n==0.
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
if m.matchingBlocks != nil {
return m.matchingBlocks
}
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
match := m.findLongestMatch(alo, ahi, blo, bhi)
i, j, k := match.A, match.B, match.Size
if match.Size > 0 {
if alo < i && blo < j {
matched = matchBlocks(alo, i, blo, j, matched)
}
matched = append(matched, match)
if i+k < ahi && j+k < bhi {
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
}
}
return matched
}
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
// It's possible that we have adjacent equal blocks in the
// matching_blocks list now.
nonAdjacent := []Match{}
i1, j1, k1 := 0, 0, 0
for _, b := range matched {
// Is this block adjacent to i1, j1, k1?
i2, j2, k2 := b.A, b.B, b.Size
if i1+k1 == i2 && j1+k1 == j2 {
// Yes, so collapse them -- this just increases the length of
// the first block by the length of the second, and the first
// block so lengthened remains the block to compare against.
k1 += k2
} else {
// Not adjacent. Remember the first block (k1==0 means it's
// the dummy we started with), and make the second block the
// new block to compare against.
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
i1, j1, k1 = i2, j2, k2
}
}
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
m.matchingBlocks = nonAdjacent
return m.matchingBlocks
}
// GetOpCodes returns a list of 5-tuples describing how to turn a into b.
//
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
// tuple preceding it, and likewise for j1 == the previous j2.
//
// The tags are characters, with these meanings:
//
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
//
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
//
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
//
// 'e' (equal): a[i1:i2] == b[j1:j2]
func (m *SequenceMatcher) GetOpCodes() []OpCode {
if m.opCodes != nil {
return m.opCodes
}
i, j := 0, 0
matching := m.GetMatchingBlocks()
opCodes := make([]OpCode, 0, len(matching))
for _, m := range matching {
// invariant: we've pumped out correct diffs to change
// a[:i] into b[:j], and the next matching block is
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
// out a diff to change a[i:ai] into b[j:bj], pump out
// the matching block, and move (i,j) beyond the match
ai, bj, size := m.A, m.B, m.Size
tag := byte(0)
if i < ai && j < bj {
tag = 'r'
} else if i < ai {
tag = 'd'
} else if j < bj {
tag = 'i'
}
if tag > 0 {
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
}
i, j = ai+size, bj+size
// the list of matching blocks is terminated by a
// sentinel with size 0
if size > 0 {
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
}
}
m.opCodes = opCodes
return m.opCodes
}
// GetGroupedOpCodes isolates change clusters by eliminating ranges with no changes.
//
// Return a generator of groups with up to n lines of context.
// Each group is in the same format as returned by GetOpCodes().
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
if n < 0 {
n = 3
}
codes := m.GetOpCodes()
if len(codes) == 0 {
codes = []OpCode{{'e', 0, 1, 0, 1}}
}
// Fixup leading and trailing groups if they show no changes.
if codes[0].Tag == 'e' {
c := codes[0]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
}
if codes[len(codes)-1].Tag == 'e' {
c := codes[len(codes)-1]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
}
nn := n + n
groups := [][]OpCode{}
group := []OpCode{}
for _, c := range codes {
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
// End the current group and start a new one whenever
// there is a large range with no changes.
if c.Tag == 'e' && i2-i1 > nn {
group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
j1, min(j2, j1+n)})
groups = append(groups, group)
group = []OpCode{}
i1, j1 = max(i1, i2-n), max(j1, j2-n)
}
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
}
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
groups = append(groups, group)
}
return groups
}

View File

@ -1,161 +0,0 @@
package format
import (
"bytes"
"fmt"
"strings"
"unicode"
"gotest.tools/v3/internal/difflib"
)
const (
contextLines = 2
)
// DiffConfig for a unified diff
type DiffConfig struct {
A string
B string
From string
To string
}
// UnifiedDiff is a modified version of difflib.WriteUnifiedDiff with better
// support for showing the whitespace differences.
func UnifiedDiff(conf DiffConfig) string {
a := strings.SplitAfter(conf.A, "\n")
b := strings.SplitAfter(conf.B, "\n")
groups := difflib.NewMatcher(a, b).GetGroupedOpCodes(contextLines)
if len(groups) == 0 {
return ""
}
buf := new(bytes.Buffer)
writeFormat := func(format string, args ...interface{}) {
buf.WriteString(fmt.Sprintf(format, args...))
}
writeLine := func(prefix string, s string) {
buf.WriteString(prefix + s)
}
if hasWhitespaceDiffLines(groups, a, b) {
writeLine = visibleWhitespaceLine(writeLine)
}
formatHeader(writeFormat, conf)
for _, group := range groups {
formatRangeLine(writeFormat, group)
for _, opCode := range group {
in, out := a[opCode.I1:opCode.I2], b[opCode.J1:opCode.J2]
switch opCode.Tag {
case 'e':
formatLines(writeLine, " ", in)
case 'r':
formatLines(writeLine, "-", in)
formatLines(writeLine, "+", out)
case 'd':
formatLines(writeLine, "-", in)
case 'i':
formatLines(writeLine, "+", out)
}
}
}
return buf.String()
}
// hasWhitespaceDiffLines returns true if any diff groups is only different
// because of whitespace characters.
func hasWhitespaceDiffLines(groups [][]difflib.OpCode, a, b []string) bool {
for _, group := range groups {
in, out := new(bytes.Buffer), new(bytes.Buffer)
for _, opCode := range group {
if opCode.Tag == 'e' {
continue
}
for _, line := range a[opCode.I1:opCode.I2] {
in.WriteString(line)
}
for _, line := range b[opCode.J1:opCode.J2] {
out.WriteString(line)
}
}
if removeWhitespace(in.String()) == removeWhitespace(out.String()) {
return true
}
}
return false
}
func removeWhitespace(s string) string {
var result []rune
for _, r := range s {
if !unicode.IsSpace(r) {
result = append(result, r)
}
}
return string(result)
}
func visibleWhitespaceLine(ws func(string, string)) func(string, string) {
mapToVisibleSpace := func(r rune) rune {
switch r {
case '\n':
case ' ':
return '·'
case '\t':
return '▷'
case '\v':
return '▽'
case '\r':
return '↵'
case '\f':
return '↓'
default:
if unicode.IsSpace(r) {
return '<27>'
}
}
return r
}
return func(prefix, s string) {
ws(prefix, strings.Map(mapToVisibleSpace, s))
}
}
func formatHeader(wf func(string, ...interface{}), conf DiffConfig) {
if conf.From != "" || conf.To != "" {
wf("--- %s\n", conf.From)
wf("+++ %s\n", conf.To)
}
}
func formatRangeLine(wf func(string, ...interface{}), group []difflib.OpCode) {
first, last := group[0], group[len(group)-1]
range1 := formatRangeUnified(first.I1, last.I2)
range2 := formatRangeUnified(first.J1, last.J2)
wf("@@ -%s +%s @@\n", range1, range2)
}
// Convert range to the "ed" format
func formatRangeUnified(start, stop int) string {
// Per the diff spec at http://www.unix.org/single_unix_specification/
beginning := start + 1 // lines start numbering with one
length := stop - start
if length == 1 {
return fmt.Sprintf("%d", beginning)
}
if length == 0 {
beginning-- // empty ranges begin at line just before the range
}
return fmt.Sprintf("%d,%d", beginning, length)
}
func formatLines(writeLine func(string, string), prefix string, lines []string) {
for _, line := range lines {
writeLine(prefix, line)
}
// Add a newline if the last line is missing one so that the diff displays
// properly.
if !strings.HasSuffix(lines[len(lines)-1], "\n") {
writeLine("", "\n")
}
}

View File

@ -1,27 +0,0 @@
package format // import "gotest.tools/v3/internal/format"
import "fmt"
// Message accepts a msgAndArgs varargs and formats it using fmt.Sprintf
func Message(msgAndArgs ...interface{}) string {
switch len(msgAndArgs) {
case 0:
return ""
case 1:
return fmt.Sprintf("%v", msgAndArgs[0])
default:
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
}
}
// WithCustomMessage accepts one or two messages and formats them appropriately
func WithCustomMessage(source string, msgAndArgs ...interface{}) string {
custom := Message(msgAndArgs...)
switch {
case custom == "":
return source
case source == "":
return custom
}
return fmt.Sprintf("%s: %s", source, custom)
}

View File

@ -1,53 +0,0 @@
package source
import (
"go/ast"
"go/token"
"github.com/pkg/errors"
)
func scanToDeferLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
var matchedNode ast.Node
ast.Inspect(node, func(node ast.Node) bool {
switch {
case node == nil || matchedNode != nil:
return false
case fileset.Position(node.End()).Line == lineNum:
if funcLit, ok := node.(*ast.FuncLit); ok {
matchedNode = funcLit
return false
}
}
return true
})
debug("defer line node: %s", debugFormatNode{matchedNode})
return matchedNode
}
func guessDefer(node ast.Node) (ast.Node, error) {
defers := collectDefers(node)
switch len(defers) {
case 0:
return nil, errors.New("failed to expression in defer")
case 1:
return defers[0].Call, nil
default:
return nil, errors.Errorf(
"ambiguous call expression: multiple (%d) defers in call block",
len(defers))
}
}
func collectDefers(node ast.Node) []*ast.DeferStmt {
var defers []*ast.DeferStmt
ast.Inspect(node, func(node ast.Node) bool {
if d, ok := node.(*ast.DeferStmt); ok {
defers = append(defers, d)
debug("defer: %s", debugFormatNode{d})
return false
}
return true
})
return defers
}

View File

@ -1,181 +0,0 @@
package source // import "gotest.tools/v3/internal/source"
import (
"bytes"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
"runtime"
"strconv"
"strings"
"github.com/pkg/errors"
)
const baseStackIndex = 1
// FormattedCallExprArg returns the argument from an ast.CallExpr at the
// index in the call stack. The argument is formatted using FormatNode.
func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
args, err := CallExprArgs(stackIndex + 1)
if err != nil {
return "", err
}
if argPos >= len(args) {
return "", errors.New("failed to find expression")
}
return FormatNode(args[argPos])
}
// CallExprArgs returns the ast.Expr slice for the args of an ast.CallExpr at
// the index in the call stack.
func CallExprArgs(stackIndex int) ([]ast.Expr, error) {
_, filename, lineNum, ok := runtime.Caller(baseStackIndex + stackIndex)
if !ok {
return nil, errors.New("failed to get call stack")
}
debug("call stack position: %s:%d", filename, lineNum)
node, err := getNodeAtLine(filename, lineNum)
if err != nil {
return nil, err
}
debug("found node: %s", debugFormatNode{node})
return getCallExprArgs(node)
}
func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
fileset := token.NewFileSet()
astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse source file: %s", filename)
}
if node := scanToLine(fileset, astFile, lineNum); node != nil {
return node, nil
}
if node := scanToDeferLine(fileset, astFile, lineNum); node != nil {
node, err := guessDefer(node)
if err != nil || node != nil {
return node, err
}
}
return nil, errors.Errorf(
"failed to find an expression on line %d in %s", lineNum, filename)
}
func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
var matchedNode ast.Node
ast.Inspect(node, func(node ast.Node) bool {
switch {
case node == nil || matchedNode != nil:
return false
case nodePosition(fileset, node).Line == lineNum:
matchedNode = node
return false
}
return true
})
return matchedNode
}
// In golang 1.9 the line number changed from being the line where the statement
// ended to the line where the statement began.
func nodePosition(fileset *token.FileSet, node ast.Node) token.Position {
if goVersionBefore19 {
return fileset.Position(node.End())
}
return fileset.Position(node.Pos())
}
// GoVersionLessThan returns true if runtime.Version() is semantically less than
// version major.minor. Returns false if a release version can not be parsed from
// runtime.Version().
func GoVersionLessThan(major, minor int64) bool {
version := runtime.Version()
// not a release version
if !strings.HasPrefix(version, "go") {
return false
}
version = strings.TrimPrefix(version, "go")
parts := strings.Split(version, ".")
if len(parts) < 2 {
return false
}
rMajor, err := strconv.ParseInt(parts[0], 10, 32)
if err != nil {
return false
}
if rMajor != major {
return rMajor < major
}
rMinor, err := strconv.ParseInt(parts[1], 10, 32)
if err != nil {
return false
}
return rMinor < minor
}
var goVersionBefore19 = GoVersionLessThan(1, 9)
func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
visitor := &callExprVisitor{}
ast.Walk(visitor, node)
if visitor.expr == nil {
return nil, errors.New("failed to find call expression")
}
debug("callExpr: %s", debugFormatNode{visitor.expr})
return visitor.expr.Args, nil
}
type callExprVisitor struct {
expr *ast.CallExpr
}
func (v *callExprVisitor) Visit(node ast.Node) ast.Visitor {
if v.expr != nil || node == nil {
return nil
}
debug("visit: %s", debugFormatNode{node})
switch typed := node.(type) {
case *ast.CallExpr:
v.expr = typed
return nil
case *ast.DeferStmt:
ast.Walk(v, typed.Call.Fun)
return nil
}
return v
}
// FormatNode using go/format.Node and return the result as a string
func FormatNode(node ast.Node) (string, error) {
buf := new(bytes.Buffer)
err := format.Node(buf, token.NewFileSet(), node)
return buf.String(), err
}
var debugEnabled = os.Getenv("GOTESTTOOLS_DEBUG") != ""
func debug(format string, args ...interface{}) {
if debugEnabled {
fmt.Fprintf(os.Stderr, "DEBUG: "+format+"\n", args...)
}
}
type debugFormatNode struct {
ast.Node
}
func (n debugFormatNode) String() string {
out, err := FormatNode(n.Node)
if err != nil {
return fmt.Sprintf("failed to format %s: %s", n.Node, err)
}
return fmt.Sprintf("(%T) %s", n.Node, out)
}

13
vendor/modules.txt vendored
View File

@ -243,7 +243,6 @@ github.com/golang/protobuf/ptypes/wrappers
# github.com/google/go-cmp v0.5.6
## explicit; go 1.8
github.com/google/go-cmp/cmp
github.com/google/go-cmp/cmp/cmpopts
github.com/google/go-cmp/cmp/internal/diff
github.com/google/go-cmp/cmp/internal/flags
github.com/google/go-cmp/cmp/internal/function
@ -513,10 +512,6 @@ golang.org/x/text/unicode/norm
# golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
## explicit
golang.org/x/time/rate
# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
## explicit; go 1.11
golang.org/x/xerrors
golang.org/x/xerrors/internal
# google.golang.org/appengine v1.6.7
## explicit; go 1.11
google.golang.org/appengine/internal
@ -633,14 +628,6 @@ gopkg.in/yaml.v2
# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
## explicit
gopkg.in/yaml.v3
# gotest.tools/v3 v3.0.3
## explicit; go 1.11
gotest.tools/v3/assert
gotest.tools/v3/assert/cmp
gotest.tools/v3/internal/assert
gotest.tools/v3/internal/difflib
gotest.tools/v3/internal/format
gotest.tools/v3/internal/source
# k8s.io/api v0.22.5
## explicit; go 1.16
k8s.io/api/authentication/v1