diff --git a/cmd/jb/init.go b/cmd/jb/init.go index 8734f24..9c86642 100644 --- a/cmd/jb/init.go +++ b/cmd/jb/init.go @@ -18,13 +18,13 @@ import ( "io/ioutil" "path/filepath" - "github.com/jsonnet-bundler/jsonnet-bundler/pkg" + kingpin "gopkg.in/alecthomas/kingpin.v2" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "gopkg.in/alecthomas/kingpin.v2" ) func initCommand(dir string) int { - exists, err := pkg.FileExists(jsonnetfile.File) + exists, err := jsonnetfile.Exists(jsonnetfile.File) if err != nil { kingpin.Errorf("Failed to check for jsonnetfile.json: %v", err) return 1 diff --git a/cmd/jb/install.go b/cmd/jb/install.go index 78b5d64..7d64b6f 100644 --- a/cmd/jb/install.go +++ b/cmd/jb/install.go @@ -15,104 +15,79 @@ package main import ( - "context" "encoding/json" "io/ioutil" "os" "path/filepath" + "reflect" + + "github.com/pkg/errors" + kingpin "gopkg.in/alecthomas/kingpin.v2" "github.com/jsonnet-bundler/jsonnet-bundler/pkg" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "gopkg.in/alecthomas/kingpin.v2" ) -func installCommand(dir, jsonnetHome string, uris ...string) int { +func installCommand(dir, jsonnetHome string, uris []string) int { if dir == "" { dir = "." } - filename, isLock, err := jsonnetfile.Choose(dir) - if err != nil { - kingpin.Fatalf("failed to choose jsonnetfile: %v", err) - return 1 + jsonnetFile, err := jsonnetfile.Load(filepath.Join(dir, jsonnetfile.File)) + kingpin.FatalIfError(err, "failed to load jsonnetfile") + + lockFile, err := jsonnetfile.Load(filepath.Join(dir, jsonnetfile.LockFile)) + if !os.IsNotExist(err) { + kingpin.FatalIfError(err, "failed to load lockfile") } - jsonnetFile, err := jsonnetfile.Load(filename) - if err != nil { - kingpin.Fatalf("failed to load jsonnetfile: %v", err) - return 1 - } + kingpin.FatalIfError( + os.MkdirAll(filepath.Join(dir, jsonnetHome, ".tmp"), os.ModePerm), + "creating vendor folder") - if len(uris) > 0 { - for _, uri := range uris { - newDep := parseDependency(dir, uri) - if newDep == nil { - kingpin.Errorf("ignoring unrecognized uri: %s", uri) - continue - } + for _, u := range uris { + d := parseDependency(dir, u) + if d == nil { + kingpin.Fatalf("Unable to parse package URI `%s`", u) + } - oldDeps := jsonnetFile.Dependencies - newDeps := []spec.Dependency{} - oldDepReplaced := false - for _, d := range oldDeps { - if d.Name == newDep.Name { - newDeps = append(newDeps, *newDep) - oldDepReplaced = true - } else { - newDeps = append(newDeps, d) - } - } + if !depEqual(jsonnetFile.Dependencies[d.Name], *d) { + // the dep passed on the cli is different from the jsonnetFile + jsonnetFile.Dependencies[d.Name] = *d - if !oldDepReplaced { - newDeps = append(newDeps, *newDep) - } - - jsonnetFile.Dependencies = newDeps + // we want to install the passed version (ignore the lock) + delete(lockFile.Dependencies, d.Name) } } - srcPath := filepath.Join(jsonnetHome) - err = os.MkdirAll(srcPath, os.ModePerm) - if err != nil { - kingpin.Fatalf("failed to create jsonnet home path: %v", err) - return 3 - } + locked, err := pkg.Ensure(jsonnetFile, jsonnetHome, lockFile.Dependencies) + kingpin.FatalIfError(err, "failed to install packages") - lock, err := pkg.Install(context.TODO(), isLock, filename, jsonnetFile, jsonnetHome) - if err != nil { - kingpin.Fatalf("failed to install: %v", err) - return 3 - } - - // If installing from lock file there is no need to write any files back. - if !isLock { - b, err := json.MarshalIndent(jsonnetFile, "", " ") - if err != nil { - kingpin.Fatalf("failed to encode jsonnet file: %v", err) - return 3 - } - b = append(b, []byte("\n")...) - - err = ioutil.WriteFile(filepath.Join(dir, jsonnetfile.File), b, 0644) - if err != nil { - kingpin.Fatalf("failed to write jsonnet file: %v", err) - return 3 - } - - b, err = json.MarshalIndent(lock, "", " ") - if err != nil { - kingpin.Fatalf("failed to encode jsonnet file: %v", err) - return 3 - } - b = append(b, []byte("\n")...) - - err = ioutil.WriteFile(filepath.Join(dir, jsonnetfile.LockFile), b, 0644) - if err != nil { - kingpin.Fatalf("failed to write lock file: %v", err) - return 3 - } - } + kingpin.FatalIfError( + writeJSONFile(filepath.Join(dir, jsonnetfile.File), jsonnetFile), + "updating jsonnetfile.json") + kingpin.FatalIfError( + writeJSONFile(filepath.Join(dir, jsonnetfile.LockFile), spec.JsonnetFile{Dependencies: locked}), + "updating jsonnetfile.lock.json") return 0 } + +func depEqual(d1, d2 spec.Dependency) bool { + name := d1.Name == d2.Name + version := d1.Version == d2.Version + source := reflect.DeepEqual(d1.Source, d2.Source) + + return name && version && source +} + +func writeJSONFile(name string, d interface{}) error { + b, err := json.MarshalIndent(d, "", " ") + if err != nil { + return errors.Wrap(err, "encoding json") + } + b = append(b, []byte("\n")...) + + return ioutil.WriteFile(name, b, 0644) +} diff --git a/cmd/jb/install_test.go b/cmd/jb/install_test.go index 89c1de9..2bf44c5 100644 --- a/cmd/jb/install_test.go +++ b/cmd/jb/install_test.go @@ -21,8 +21,9 @@ import ( "os" "testing" - "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" "github.com/stretchr/testify/assert" + + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" ) func TestInstallCommand(t *testing.T) { @@ -43,7 +44,7 @@ func TestInstallCommand(t *testing.T) { URIs: []string{"github.com/jsonnet-bundler/jsonnet-bundler@v0.1.0"}, ExpectedCode: 0, ExpectedJsonnetFile: []byte(`{"dependencies": [{"name": "jsonnet-bundler", "source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "v0.1.0"}]}`), - ExpectedJsonnetLockFile: []byte(`{"dependencies": [{"name": "jsonnet-bundler", "source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "080f157c7fb85ad0281ea78f6c641eaa570a582f"}]}`), + ExpectedJsonnetLockFile: []byte(`{"dependencies": [{"name": "jsonnet-bundler", "source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "080f157c7fb85ad0281ea78f6c641eaa570a582f", "sum": "W1uI550rQ66axRpPXA2EZDquyPg/5PHZlvUz1NEzefg="}]}`), }, { Name: "Relative", URIs: []string{"jsonnet/foobar"}, @@ -73,7 +74,7 @@ func TestInstallCommand(t *testing.T) { jsonnetFileContent(t, jsonnetfile.File, []byte(`{}`)) - installCommand("", "vendor", tc.URIs...) + installCommand("", "vendor", tc.URIs) jsonnetFileContent(t, jsonnetfile.File, tc.ExpectedJsonnetFile) jsonnetFileContent(t, jsonnetfile.LockFile, tc.ExpectedJsonnetLockFile) diff --git a/cmd/jb/main.go b/cmd/jb/main.go index 221a56e..fd25873 100644 --- a/cmd/jb/main.go +++ b/cmd/jb/main.go @@ -20,11 +20,12 @@ import ( "path" "path/filepath" "regexp" - "strings" + + "github.com/fatih/color" + "github.com/pkg/errors" + kingpin "gopkg.in/alecthomas/kingpin.v2" "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/pkg/errors" - "gopkg.in/alecthomas/kingpin.v2" ) const ( @@ -34,10 +35,10 @@ const ( ) var ( - gitSSHRegex = regexp.MustCompile("git\\+ssh://git@([^:]+):([^/]+)/([^/]+).git") - gitSSHWithVersionRegex = regexp.MustCompile("git\\+ssh://git@([^:]+):([^/]+)/([^/]+).git@(.*)") - gitSSHWithPathRegex = regexp.MustCompile("git\\+ssh://git@([^:]+):([^/]+)/([^/]+).git/(.*)") - gitSSHWithPathAndVersionRegex = regexp.MustCompile("git\\+ssh://git@([^:]+):([^/]+)/([^/]+).git/(.*)@(.*)") + gitSSHRegex = regexp.MustCompile(`git\+ssh://git@([^:]+):([^/]+)/([^/]+).git`) + gitSSHWithVersionRegex = regexp.MustCompile(`git\+ssh://git@([^:]+):([^/]+)/([^/]+).git@(.*)`) + gitSSHWithPathRegex = regexp.MustCompile(`git\+ssh://git@([^:]+):([^/]+)/([^/]+).git/(.*)`) + gitSSHWithPathAndVersionRegex = regexp.MustCompile(`git\+ssh://git@([^:]+):([^/]+)/([^/]+).git/(.*)@(.*)`) githubSlugRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)") githubSlugWithVersionRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)@(.*)") @@ -54,6 +55,8 @@ func Main() int { JsonnetHome string }{} + color.Output = color.Error + a := kingpin.New(filepath.Base(os.Args[0]), "A jsonnet package manager") a.HelpFlag.Short('h') @@ -83,63 +86,60 @@ func Main() int { case initCmd.FullCommand(): return initCommand(workdir) case installCmd.FullCommand(): - return installCommand(workdir, cfg.JsonnetHome, *installCmdURIs...) + return installCommand(workdir, cfg.JsonnetHome, *installCmdURIs) case updateCmd.FullCommand(): - return updateCommand(cfg.JsonnetHome) + return updateCommand(workdir, cfg.JsonnetHome) default: - installCommand(workdir, cfg.JsonnetHome) + installCommand(workdir, cfg.JsonnetHome, []string{}) } return 0 } func parseDependency(dir, uri string) *spec.Dependency { - if d := parseGitSSHDependency(uri); d != nil { - return d - } - - if d := parseGithubDependency(uri); d != nil { - return d - } - - if d := parseLocalDependency(dir, uri); d != nil { - return d - } - - return nil -} - -func parseGitSSHDependency(p string) *spec.Dependency { - if !gitSSHRegex.MatchString(p) { + if uri == "" { return nil } + if githubSlugRegex.MatchString(uri) { + return parseGithubDependency(uri) + } + + if gitSSHRegex.MatchString(uri) { + return parseGitSSHDependency(uri) + } + + return parseLocalDependency(dir, uri) +} + +func parseGitSSHDependency(p string) *spec.Dependency { subdir := "" host := "" org := "" repo := "" version := "master" - if gitSSHWithPathAndVersionRegex.MatchString(p) { + switch { + case gitSSHWithPathAndVersionRegex.MatchString(p): matches := gitSSHWithPathAndVersionRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] repo = matches[3] subdir = matches[4] version = matches[5] - } else if gitSSHWithPathRegex.MatchString(p) { + case gitSSHWithPathRegex.MatchString(p): matches := gitSSHWithPathRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] repo = matches[3] subdir = matches[4] - } else if gitSSHWithVersionRegex.MatchString(p) { + case gitSSHWithVersionRegex.MatchString(p): matches := gitSSHWithVersionRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] repo = matches[3] version = matches[4] - } else { + default: matches := gitSSHRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] @@ -212,16 +212,6 @@ func parseGithubDependency(p string) *spec.Dependency { } func parseLocalDependency(dir, p string) *spec.Dependency { - if p == "" { - return nil - } - if strings.HasPrefix(p, "github.com") { - return nil - } - if strings.HasPrefix(p, "git+ssh") { - return nil - } - clean := filepath.Clean(p) abs := filepath.Join(dir, clean) diff --git a/cmd/jb/main_test.go b/cmd/jb/main_test.go index 3a4007e..b7fc0a4 100644 --- a/cmd/jb/main_test.go +++ b/cmd/jb/main_test.go @@ -18,8 +18,9 @@ import ( "os" "testing" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" "github.com/stretchr/testify/assert" + + "github.com/jsonnet-bundler/jsonnet-bundler/spec" ) func TestParseDependency(t *testing.T) { diff --git a/cmd/jb/update.go b/cmd/jb/update.go index 9496d31..25f2f64 100644 --- a/cmd/jb/update.go +++ b/cmd/jb/update.go @@ -15,50 +15,39 @@ package main import ( - "context" - "encoding/json" - "io/ioutil" "net/url" "os" + "path/filepath" + + kingpin "gopkg.in/alecthomas/kingpin.v2" "github.com/jsonnet-bundler/jsonnet-bundler/pkg" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "gopkg.in/alecthomas/kingpin.v2" + "github.com/jsonnet-bundler/jsonnet-bundler/spec" ) -func updateCommand(jsonnetHome string, urls ...*url.URL) int { - m, err := pkg.LoadJsonnetfile(jsonnetfile.File) - if err != nil { - kingpin.Fatalf("failed to load jsonnetfile: %v", err) - return 1 +func updateCommand(dir, jsonnetHome string, urls ...*url.URL) int { + if dir == "" { + dir = "." } - err = os.MkdirAll(jsonnetHome, os.ModePerm) - if err != nil { - kingpin.Fatalf("failed to create jsonnet home path: %v", err) - return 3 - } + jsonnetFile, err := jsonnetfile.Load(filepath.Join(dir, jsonnetfile.File)) + kingpin.FatalIfError(err, "failed to load jsonnetfile") - // When updating, the lockfile is explicitly ignored. - isLock := false - lock, err := pkg.Install(context.TODO(), isLock, jsonnetfile.File, m, jsonnetHome) - if err != nil { - kingpin.Fatalf("failed to install: %v", err) - return 3 - } + kingpin.FatalIfError( + os.MkdirAll(filepath.Join(dir, jsonnetHome, ".tmp"), os.ModePerm), + "creating vendor folder") - b, err := json.MarshalIndent(lock, "", " ") - if err != nil { - kingpin.Fatalf("failed to encode jsonnet file: %v", err) - return 3 - } - b = append(b, []byte("\n")...) - - err = ioutil.WriteFile(jsonnetfile.LockFile, b, 0644) - if err != nil { - kingpin.Fatalf("failed to write lock file: %v", err) - return 3 - } + // When updating, locks are ignored. + locks := map[string]spec.Dependency{} + locked, err := pkg.Ensure(jsonnetFile, jsonnetHome, locks) + kingpin.FatalIfError(err, "failed to install packages") + kingpin.FatalIfError( + writeJSONFile(filepath.Join(dir, jsonnetfile.File), jsonnetFile), + "updating jsonnetfile.json") + kingpin.FatalIfError( + writeJSONFile(filepath.Join(dir, jsonnetfile.LockFile), spec.JsonnetFile{Dependencies: locked}), + "updating jsonnetfile.lock.json") return 0 } diff --git a/pkg/git.go b/pkg/git.go index dfaa035..71cc3e0 100644 --- a/pkg/git.go +++ b/pkg/git.go @@ -31,8 +31,9 @@ import ( "strings" "github.com/fatih/color" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" "github.com/pkg/errors" + + "github.com/jsonnet-bundler/jsonnet-bundler/spec" ) type GitPackage struct { diff --git a/pkg/jsonnetfile/jsonnetfile.go b/pkg/jsonnetfile/jsonnetfile.go index 5dbdb3a..a6cb124 100644 --- a/pkg/jsonnetfile/jsonnetfile.go +++ b/pkg/jsonnetfile/jsonnetfile.go @@ -18,56 +18,40 @@ import ( "encoding/json" "io/ioutil" "os" - "path" + + "github.com/pkg/errors" "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/pkg/errors" ) -const File = "jsonnetfile.json" -const LockFile = "jsonnetfile.lock.json" +const ( + File = "jsonnetfile.json" + LockFile = "jsonnetfile.lock.json" +) var ErrNoFile = errors.New("no jsonnetfile") -func Choose(dir string) (string, bool, error) { - jsonnetfileLock := path.Join(dir, LockFile) - jsonnetfile := path.Join(dir, File) - - lockExists, err := fileExists(jsonnetfileLock) - if err != nil { - return "", false, err - } - if lockExists { - return jsonnetfileLock, true, nil - } - - fileExists, err := fileExists(jsonnetfile) - if err != nil { - return "", false, err - } - if fileExists { - return jsonnetfile, false, nil - } - - return "", false, ErrNoFile -} - +// Load reads a jsonnetfile.(lock).json from disk func Load(filepath string) (spec.JsonnetFile, error) { - m := spec.JsonnetFile{} + m := spec.New() bytes, err := ioutil.ReadFile(filepath) if err != nil { - return m, errors.Wrap(err, "failed to read file") + return m, err } if err := json.Unmarshal(bytes, &m); err != nil { return m, errors.Wrap(err, "failed to unmarshal file") } + if m.Dependencies == nil { + m.Dependencies = make(map[string]spec.Dependency) + } return m, nil } -func fileExists(path string) (bool, error) { +// Exists returns whether the file at the given path exists +func Exists(path string) (bool, error) { _, err := os.Stat(path) if os.IsNotExist(err) { return false, nil diff --git a/pkg/jsonnetfile/jsonnetfile_test.go b/pkg/jsonnetfile/jsonnetfile_test.go index b984dd8..76a0230 100644 --- a/pkg/jsonnetfile/jsonnetfile_test.go +++ b/pkg/jsonnetfile/jsonnetfile_test.go @@ -18,75 +18,18 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/stretchr/testify/assert" ) const notExist = "/this/does/not/exist" -func TestChoose(t *testing.T) { - testcases := []struct { - Name string - Jsonnetfile []byte - JsonnetfileLock []byte - ExpectedFilename string - ExpectedLock bool - ExpectedError error - }{{ - Name: "NoFiles", - ExpectedFilename: "", - ExpectedLock: false, - ExpectedError: jsonnetfile.ErrNoFile, - }, { - Name: "Jsonnetfile", - Jsonnetfile: []byte(`{}`), - ExpectedFilename: jsonnetfile.File, - ExpectedLock: false, - ExpectedError: nil, - }, { - Name: "JsonnetfileLock", - Jsonnetfile: []byte(`{}`), - JsonnetfileLock: []byte(`{}`), - ExpectedFilename: jsonnetfile.LockFile, - ExpectedLock: true, - ExpectedError: nil, - }} - - for _, tc := range testcases { - t.Run(tc.Name, func(t *testing.T) { - dir, err := ioutil.TempDir("", "jsonnetfile-choose") - assert.Nil(t, err) - defer os.Remove(dir) - - if tc.Jsonnetfile != nil { - err := ioutil.WriteFile(filepath.Join(dir, jsonnetfile.File), tc.Jsonnetfile, os.ModePerm) - assert.NoError(t, err) - } - if tc.JsonnetfileLock != nil { - err := ioutil.WriteFile(filepath.Join(dir, jsonnetfile.LockFile), tc.JsonnetfileLock, os.ModePerm) - assert.NoError(t, err) - } - - filename, isLock, err := jsonnetfile.Choose(dir) - - assert.Equal(t, tc.ExpectedFilename, strings.TrimPrefix(filename, dir+"/")) - assert.Equal(t, tc.ExpectedLock, isLock) - - if tc.ExpectedError != nil { - assert.EqualError(t, err, tc.ExpectedError.Error()) - } else { - assert.NoError(t, err) - } - }) - } -} - func TestLoad(t *testing.T) { - empty := spec.JsonnetFile{} + empty := spec.New() jsonnetfileContent := `{ "dependencies": [ @@ -104,17 +47,18 @@ func TestLoad(t *testing.T) { } ` jsonnetFileExpected := spec.JsonnetFile{ - Dependencies: []spec.Dependency{{ - Name: "foobar", - Source: spec.Source{ - GitSource: &spec.GitSource{ - Remote: "https://github.com/foobar/foobar", - Subdir: "", + Dependencies: map[string]spec.Dependency{ + "foobar": { + Name: "foobar", + Source: spec.Source{ + GitSource: &spec.GitSource{ + Remote: "https://github.com/foobar/foobar", + Subdir: "", + }, }, - }, - Version: "master", - DepSource: "", - }}, + Version: "master", + DepSource: "", + }}, } { @@ -159,3 +103,26 @@ func TestLoad(t *testing.T) { assert.Equal(t, jsonnetFileExpected, jf) } } + +func TestFileExists(t *testing.T) { + { + exists, err := jsonnetfile.Exists(notExist) + assert.False(t, exists) + assert.Nil(t, err) + } + { + tempFile, err := ioutil.TempFile("", "jb-exists") + if err != nil { + t.Fatal(err) + } + + defer func() { + err := os.Remove(tempFile.Name()) + assert.Nil(t, err) + }() + + exists, err := jsonnetfile.Exists(tempFile.Name()) + assert.True(t, exists) + assert.Nil(t, err) + } +} diff --git a/pkg/packages.go b/pkg/packages.go index a5b1494..53565a5 100644 --- a/pkg/packages.go +++ b/pkg/packages.go @@ -16,166 +16,209 @@ package pkg import ( "context" - "encoding/json" + "crypto/sha256" + "encoding/base64" "fmt" + "io" "os" - "path" "path/filepath" "github.com/fatih/color" + "github.com/pkg/errors" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/pkg/errors" ) var ( VersionMismatch = errors.New("multiple colliding versions specified") ) -func Install(ctx context.Context, isLock bool, dependencySourceIdentifier string, m spec.JsonnetFile, dir string) (*spec.JsonnetFile, error) { - lockfile := &spec.JsonnetFile{} - for _, dep := range m.Dependencies { +// Ensure receives all direct packages as, the directory to vendor in and all known locks. +// It then makes sure all direct and nested dependencies are present in vendor at the correct version: +// +// If the package is locked and the files in vendor match the sha256 checksum, +// nothing needs to be done. Otherwise, the package is retrieved from the +// upstream source and added into vendor. If previously locked, the sums are +// checked as well. +// In case a (nested) package is already present in the lock, +// the one from the lock takes precedence. This allows the user to set the +// desired version in case by `jb install`ing it. +// +// Finally, all unknown files and directories are removed from vendor/ +func Ensure(direct spec.JsonnetFile, vendorDir string, locks map[string]spec.Dependency) (map[string]spec.Dependency, error) { + // ensure all required files are in vendor + deps, err := ensure(direct.Dependencies, vendorDir, locks) + if err != nil { + return nil, err + } - tmp := filepath.Join(dir, ".tmp") - err := os.MkdirAll(tmp, os.ModePerm) - if err != nil { - return nil, errors.Wrap(err, "failed to create general tmp dir") - } - - var p Interface - if dep.Source.GitSource != nil { - p = NewGitPackage(dep.Source.GitSource) - } - if dep.Source.LocalSource != nil { - p = NewLocalPackage(dep.Source.LocalSource) - } - - lockVersion, err := p.Install(ctx, dep.Name, dir, dep.Version) - if err != nil { - return nil, errors.Wrap(err, "failed to install package") - } - - color.Green(">>> Installed %s version %s\n", dep.Name, dep.Version) - - destPath := path.Join(dir, dep.Name) - - lockfile.Dependencies, err = insertDependency(lockfile.Dependencies, spec.Dependency{ - Name: dep.Name, - Source: dep.Source, - Version: lockVersion, - DepSource: dependencySourceIdentifier, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to insert dependency to lock dependencies") - } - - // If dependencies are being installed from a lock file, the transitive - // dependencies are not questioned, the locked dependencies are just - // installed. - if isLock { - continue - } - - filepath, isLock, err := ChooseJsonnetFile(destPath) - if err != nil { - return nil, err - } - depsDeps, err := LoadJsonnetfile(filepath) - // It is ok for dependencies not to have a JsonnetFile, it just means - // they do not have transitive dependencies of their own. - if err != nil && !os.IsNotExist(err) { - return nil, err - } - - depsInstalledByDependency, err := Install(ctx, isLock, filepath, depsDeps, dir) - if err != nil { - return nil, err - } - - for _, d := range depsInstalledByDependency.Dependencies { - lockfile.Dependencies, err = insertDependency(lockfile.Dependencies, d) - if err != nil { - return nil, errors.Wrap(err, "failed to insert dependency to lock dependencies") + // cleanup unknown dirs from vendor/ + f, err := os.Open(vendorDir) + if err != nil { + return nil, err + } + names, err := f.Readdirnames(0) + if err != nil { + return nil, err + } + for _, name := range names { + if _, ok := deps[name]; !ok { + dir := filepath.Join(vendorDir, name) + if err := os.RemoveAll(dir); err != nil { + return nil, err + } + if name != ".tmp" { + color.Magenta("CLEAN %s", dir) } } } - return lockfile, nil + // return the final lockfile contents + return deps, nil } -func insertDependency(deps []spec.Dependency, newDep spec.Dependency) ([]spec.Dependency, error) { - if len(deps) == 0 { - return []spec.Dependency{newDep}, nil +func ensure(direct map[string]spec.Dependency, vendorDir string, locks map[string]spec.Dependency) (map[string]spec.Dependency, error) { + deps := make(map[string]spec.Dependency) + + for _, d := range direct { + l, present := locks[d.Name] + + // already locked and the integrity is intact + if present { + d.Version = locks[d.Name].Version + + if check(l, vendorDir) { + deps[d.Name] = l + continue + } + } + expectedSum := locks[d.Name].Sum + + // either not present or not intact: download again + dir := filepath.Join(vendorDir, d.Name) + os.RemoveAll(dir) + + locked, err := download(d, vendorDir) + if err != nil { + return nil, errors.Wrap(err, "downloading") + } + if expectedSum != "" && locked.Sum != expectedSum { + return nil, fmt.Errorf("checksum mismatch for %s. Expected %s but got %s", d.Name, expectedSum, locked.Sum) + } + deps[d.Name] = *locked + // we settled on a new version, add it to the locks for recursion + locks[d.Name] = *locked } - res := []spec.Dependency{} - newDepPreviouslyPresent := false for _, d := range deps { - if d.Name == newDep.Name { - if d.Version != newDep.Version { - return nil, fmt.Errorf("multiple colliding versions specified for %s: %s (from %s) and %s (from %s)", d.Name, d.Version, d.DepSource, newDep.Version, newDep.DepSource) + f, err := jsonnetfile.Load(filepath.Join(vendorDir, d.Name, jsonnetfile.File)) + if err != nil { + if os.IsNotExist(err) { + continue + } + return nil, err + } + + nested, err := ensure(f.Dependencies, vendorDir, locks) + if err != nil { + return nil, err + } + + for _, d := range nested { + if _, ok := deps[d.Name]; !ok { + deps[d.Name] = d } - res = append(res, d) - newDepPreviouslyPresent = true - } else { - res = append(res, d) } } - if !newDepPreviouslyPresent { - res = append(res, newDep) - } - return res, nil + return deps, nil } -func FileExists(path string) (bool, error) { - _, err := os.Stat(path) - if os.IsNotExist(err) { - return false, nil - } - if err != nil { - return false, err +// download retrieves a package from a remote upstream. The checksum of the +// files is generated afterwards. +func download(d spec.Dependency, vendorDir string) (*spec.Dependency, error) { + var p Interface + switch { + case d.Source.GitSource != nil: + p = NewGitPackage(d.Source.GitSource) + case d.Source.LocalSource != nil: + p = NewLocalPackage(d.Source.LocalSource) } - return true, nil + if p == nil { + return nil, errors.New("either git or local source is required") + } + + version, err := p.Install(context.TODO(), d.Name, vendorDir, d.Version) + if err != nil { + return nil, err + } + + var sum string + if d.Source.LocalSource == nil { + sum = hashDir(filepath.Join(vendorDir, d.Name)) + } + + return &spec.Dependency{ + Name: d.Name, + Source: d.Source, + Version: version, + Sum: sum, + }, nil } -func ChooseJsonnetFile(dir string) (string, bool, error) { - lockfilePath := path.Join(dir, jsonnetfile.LockFile) - jsonnetfilePath := path.Join(dir, jsonnetfile.File) - filename := lockfilePath - isLock := true - - lockExists, err := FileExists(filepath.Join(dir, jsonnetfile.LockFile)) - if err != nil { - return "", false, err +// check returns whether the files present at the vendor/ folder match the +// sha256 sum of the package. local-directory dependencies are not checked as +// their purpose is to change during development where integrity checking would +// be a hindrance. +func check(d spec.Dependency, vendorDir string) bool { + // assume a local dependency is intact as long as it exists + if d.Source.LocalSource != nil { + x, err := jsonnetfile.Exists(filepath.Join(vendorDir, d.Name)) + if err != nil { + return false + } + return x } - if !lockExists { - filename = jsonnetfilePath - isLock = false + if d.Sum == "" { + // no sum available, need to download + return false } - return filename, isLock, err + dir := filepath.Join(vendorDir, d.Name) + sum := hashDir(dir) + return d.Sum == sum } -func LoadJsonnetfile(filepath string) (spec.JsonnetFile, error) { - m := spec.JsonnetFile{} +// hashDir computes the checksum of a directory by concatenating all files and +// hashing this data using sha256. This can be memory heavy with lots of data, +// but jsonnet files should be fairly small +func hashDir(dir string) string { + hasher := sha256.New() - if _, err := os.Stat(filepath); err != nil { - return m, err - } + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } - f, err := os.Open(filepath) - if err != nil { - return m, err - } - defer f.Close() + if info.IsDir() { + return nil + } - err = json.NewDecoder(f).Decode(&m) - if err != nil { - return m, err - } + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() - return m, nil + if _, err := io.Copy(hasher, f); err != nil { + return err + } + + return nil + }) + + return base64.StdEncoding.EncodeToString(hasher.Sum(nil)) } diff --git a/pkg/packages_test.go b/pkg/packages_test.go index 3316c02..fec03d4 100644 --- a/pkg/packages_test.go +++ b/pkg/packages_test.go @@ -13,128 +13,3 @@ // limitations under the License. package pkg - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/stretchr/testify/assert" -) - -const NotExist = "/this/does/not/exist" - -func TestInsertDependency(t *testing.T) { - deps := []spec.Dependency{{Name: "test1", Version: "latest"}} - dep := spec.Dependency{Name: "test2", Version: "latest"} - - res, err := insertDependency(deps, dep) - if err != nil { - t.Fatal(err) - } - - if len(res) != 2 { - t.Fatal("Incorrectly inserted") - } -} - -func TestFileExists(t *testing.T) { - { - exists, err := FileExists(NotExist) - assert.False(t, exists) - assert.Nil(t, err) - } - { - tempFile, err := ioutil.TempFile("", "jb-exists") - if err != nil { - t.Fatal(err) - } - - defer func() { - err := os.Remove(tempFile.Name()) - assert.Nil(t, err) - }() - - exists, err := FileExists(tempFile.Name()) - assert.True(t, exists) - assert.Nil(t, err) - } -} - -func TestLoadJsonnetfile(t *testing.T) { - empty := spec.JsonnetFile{} - - jsonnetfileContent := `{ - "dependencies": [ - { - "name": "foobar", - "source": { - "git": { - "remote": "https://github.com/foobar/foobar", - "subdir": "" - } - }, - "version": "master" - } - ] -} -` - jsonnetFileExpected := spec.JsonnetFile{ - Dependencies: []spec.Dependency{{ - Name: "foobar", - Source: spec.Source{ - GitSource: &spec.GitSource{ - Remote: "https://github.com/foobar/foobar", - Subdir: "", - }, - }, - Version: "master", - DepSource: "", - }}, - } - - { - jf, err := LoadJsonnetfile(NotExist) - assert.Equal(t, empty, jf) - assert.Error(t, err) - } - { - tempDir, err := ioutil.TempDir("", "jb-load-jsonnetfile") - if err != nil { - t.Fatal(err) - } - defer func() { - err := os.RemoveAll(tempDir) - assert.Nil(t, err) - }() - - tempFile := filepath.Join(tempDir, jsonnetfile.File) - err = ioutil.WriteFile(tempFile, []byte(`{}`), os.ModePerm) - assert.Nil(t, err) - - jf, err := LoadJsonnetfile(tempFile) - assert.Nil(t, err) - assert.Equal(t, empty, jf) - } - { - tempDir, err := ioutil.TempDir("", "jb-load-jsonnetfile") - if err != nil { - t.Fatal(err) - } - defer func() { - err := os.RemoveAll(tempDir) - assert.Nil(t, err) - }() - - tempFile := filepath.Join(tempDir, jsonnetfile.File) - err = ioutil.WriteFile(tempFile, []byte(jsonnetfileContent), os.ModePerm) - assert.Nil(t, err) - - jf, err := LoadJsonnetfile(tempFile) - assert.Nil(t, err) - assert.Equal(t, jsonnetFileExpected, jf) - } -} diff --git a/spec/spec.go b/spec/spec.go index 0eafee9..6d1bf2c 100644 --- a/spec/spec.go +++ b/spec/spec.go @@ -14,14 +14,63 @@ package spec +import ( + "encoding/json" + "sort" +) + +// JsonnetFile is the structure of a `.json` file describing a set of jsonnet +// dependencies. It is used for both, the jsonnetFile and the lockFile. type JsonnetFile struct { + Dependencies map[string]Dependency +} + +// New returns a new JsonnetFile with the dependencies map initialized +func New() JsonnetFile { + return JsonnetFile{ + Dependencies: make(map[string]Dependency), + } +} + +// jsonFile is the json representation of a JsonnetFile, which is different for +// compatibility reasons. +type jsonFile struct { Dependencies []Dependency `json:"dependencies"` } +// UnmarshalJSON unmarshals a `jsonFile`'s json into a JsonnetFile +func (jf *JsonnetFile) UnmarshalJSON(data []byte) error { + var s jsonFile + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + jf.Dependencies = make(map[string]Dependency) + for _, d := range s.Dependencies { + jf.Dependencies[d.Name] = d + } + return nil +} + +// MarshalJSON serializes a JsonnetFile into json of the format of a `jsonFile` +func (jf JsonnetFile) MarshalJSON() ([]byte, error) { + var s jsonFile + for _, d := range jf.Dependencies { + s.Dependencies = append(s.Dependencies, d) + } + + sort.SliceStable(s.Dependencies, func(i int, j int) bool { + return s.Dependencies[i].Name < s.Dependencies[j].Name + }) + + return json.Marshal(s) +} + type Dependency struct { Name string `json:"name"` Source Source `json:"source"` Version string `json:"version"` + Sum string `json:"sum,omitempty"` DepSource string `json:"-"` } diff --git a/spec/spec_test.go b/spec/spec_test.go new file mode 100644 index 0000000..3b7607f --- /dev/null +++ b/spec/spec_test.go @@ -0,0 +1,109 @@ +// Copyright 2018 jsonnet-bundler 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. + +package spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const jsonJF = `{ + "dependencies": [ + { + "name": "grafana-builder", + "source": { + "git": { + "remote": "https://github.com/grafana/jsonnet-libs", + "subdir": "grafana-builder" + } + }, + "version": "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + "sum": "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=" + }, + { + "name": "prometheus-mixin", + "source": { + "git": { + "remote": "https://github.com/prometheus/prometheus", + "subdir": "documentation/prometheus-mixin" + } + }, + "version": "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + "sum": "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=" + } + ] +}` + +func testData() JsonnetFile { + return JsonnetFile{ + Dependencies: map[string]Dependency{ + "grafana-builder": { + Name: "grafana-builder", + Source: Source{ + GitSource: &GitSource{ + Remote: "https://github.com/grafana/jsonnet-libs", + Subdir: "grafana-builder", + }, + }, + Version: "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + Sum: "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=", + }, + "prometheus-mixin": { + Name: "prometheus-mixin", + Source: Source{ + GitSource: &GitSource{ + Remote: "https://github.com/prometheus/prometheus", + Subdir: "documentation/prometheus-mixin", + }, + }, + Version: "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + Sum: "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=", + }, + }, + } +} + +// TestUnmarshal checks that unmarshalling works +func TestUnmarshal(t *testing.T) { + var dst JsonnetFile + err := json.Unmarshal([]byte(jsonJF), &dst) + require.NoError(t, err) + assert.Equal(t, testData(), dst) +} + +// TestMarshal checks that marshalling works +func TestMarshal(t *testing.T) { + data, err := json.Marshal(testData()) + require.NoError(t, err) + assert.JSONEq(t, jsonJF, string(data)) +} + +// TestRemarshal checks that unmarshalling a previously marshalled object yields +// the same object +func TestRemarshal(t *testing.T) { + jf := testData() + + data, err := json.Marshal(jf) + require.NoError(t, err) + + var dst JsonnetFile + err = json.Unmarshal(data, &dst) + require.NoError(t, err) + + assert.Equal(t, jf, dst) +} diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go new file mode 100644 index 0000000..169de39 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -0,0 +1,28 @@ +// Package require implements the same assertions as the `assert` package but +// stops test execution when a test fails. +// +// Example Usage +// +// The following is a complete example using require in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/require" +// ) +// +// func TestSomething(t *testing.T) { +// +// var a string = "Hello" +// var b string = "Hello" +// +// require.Equal(t, a, b, "The two words should be the same.") +// +// } +// +// Assertions +// +// The `require` package have same global functions as in the `assert` package, +// but instead of returning a boolean result they call `t.FailNow()`. +// +// Every assertion function also takes an optional string message as the final argument, +// allowing custom error messages to be appended to the message the assertion method outputs. +package require diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go new file mode 100644 index 0000000..ac71d40 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go @@ -0,0 +1,16 @@ +package require + +// Assertions provides assertion methods around the +// TestingT interface. +type Assertions struct { + t TestingT +} + +// New makes a new Assertions object for the specified TestingT. +func New(t TestingT) *Assertions { + return &Assertions{ + t: t, + } +} + +//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go new file mode 100644 index 0000000..535f293 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -0,0 +1,1227 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) { + if assert.Condition(t, comp, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Conditionf uses a Comparison to assert a complex condition. +func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) { + if assert.Conditionf(t, comp, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") +func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if assert.Contains(t, s, contains, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if assert.Containsf(t, s, contains, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +func DirExists(t TestingT, path string, msgAndArgs ...interface{}) { + if assert.DirExists(t, path, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +func DirExistsf(t TestingT, path string, msg string, args ...interface{}) { + if assert.DirExistsf(t, path, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) +func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) { + if assert.ElementsMatch(t, listA, listB, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) { + if assert.ElementsMatchf(t, listA, listB, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Empty(t, obj) +func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if assert.Empty(t, object, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Emptyf(t, obj, "error message %s", "formatted") +func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if assert.Emptyf(t, object, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Equal asserts that two objects are equal. +// +// assert.Equal(t, 123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if assert.Equal(t, expected, actual, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) +func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { + if assert.EqualError(t, theError, errString, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) { + if assert.EqualErrorf(t, theError, errString, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if assert.EqualValues(t, expected, actual, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123)) +func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if assert.EqualValuesf(t, expected, actual, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Equalf asserts that two objects are equal. +// +// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if assert.Equalf(t, expected, actual, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } +func Error(t TestingT, err error, msgAndArgs ...interface{}) { + if assert.Error(t, err, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func Errorf(t TestingT, err error, msg string, args ...interface{}) { + if assert.Errorf(t, err, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if assert.Exactly(t, expected, actual, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123)) +func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if assert.Exactlyf(t, expected, actual, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Fail reports a failure through +func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if assert.Fail(t, failureMessage, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// FailNow fails test +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if assert.FailNow(t, failureMessage, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// FailNowf fails test +func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if assert.FailNowf(t, failureMessage, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Failf reports a failure through +func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if assert.Failf(t, failureMessage, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// False asserts that the specified value is false. +// +// assert.False(t, myBool) +func False(t TestingT, value bool, msgAndArgs ...interface{}) { + if assert.False(t, value, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Falsef asserts that the specified value is false. +// +// assert.Falsef(t, myBool, "error message %s", "formatted") +func Falsef(t TestingT, value bool, msg string, args ...interface{}) { + if assert.Falsef(t, value, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +func FileExists(t TestingT, path string, msgAndArgs ...interface{}) { + if assert.FileExists(t, path, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +func FileExistsf(t TestingT, path string, msg string, args ...interface{}) { + if assert.FileExistsf(t, path, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if assert.Implements(t, interfaceObject, object, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) +func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if assert.Implementsf(t, interfaceObject, object, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01) +func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if assert.InDelta(t, expected, actual, delta, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) +func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if assert.InDeltaf(t, expected, actual, delta, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if assert.IsType(t, expectedType, object, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// IsTypef asserts that the specified objects are of the same type. +func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if assert.IsTypef(t, expectedType, object, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if assert.JSONEq(t, expected, actual, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if assert.JSONEqf(t, expected, actual, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(t, mySlice, 3) +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { + if assert.Len(t, object, length, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) { + if assert.Lenf(t, object, length, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if assert.Nil(t, object, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Nilf asserts that the specified object is nil. +// +// assert.Nilf(t, err, "error message %s", "formatted") +func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if assert.Nilf(t, object, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) { + if assert.NoError(t, err, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { + if assert.NoErrorf(t, err, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") +func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if assert.NotContains(t, s, contains, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if assert.NotContainsf(t, s, contains, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if assert.NotEmpty(t, object, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if assert.NotEmptyf(t, object, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotEqual asserts that the specified values are NOT equal. +// +// assert.NotEqual(t, obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if assert.NotEqual(t, expected, actual, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if assert.NotEqualf(t, expected, actual, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if assert.NotNil(t, object, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotNilf asserts that the specified object is not nil. +// +// assert.NotNilf(t, err, "error message %s", "formatted") +func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if assert.NotNilf(t, object, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if assert.NotPanics(t, f, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if assert.NotPanicsf(t, f, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") +func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if assert.NotRegexp(t, rx, str, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if assert.NotRegexpf(t, rx, str, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if assert.NotSubset(t, list, subset, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if assert.NotSubsetf(t, list, subset, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotZero asserts that i is not the zero value for its type. +func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if assert.NotZero(t, i, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// NotZerof asserts that i is not the zero value for its type. +func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if assert.NotZerof(t, i, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if assert.Panics(t, f, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if assert.PanicsWithValue(t, expected, f, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { + if assert.PanicsWithValuef(t, expected, f, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if assert.Panicsf(t, f, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Regexp asserts that a specified regexp matches a string. +// +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") +func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if assert.Regexp(t, rx, str, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Regexpf asserts that a specified regexp matches a string. +// +// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if assert.Regexpf(t, rx, str, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if assert.Subset(t, list, subset, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if assert.Subsetf(t, list, subset, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// True asserts that the specified value is true. +// +// assert.True(t, myBool) +func True(t TestingT, value bool, msgAndArgs ...interface{}) { + if assert.True(t, value, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Truef asserts that the specified value is true. +// +// assert.Truef(t, myBool, "error message %s", "formatted") +func Truef(t TestingT, value bool, msg string, args ...interface{}) { + if assert.Truef(t, value, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { + if assert.WithinDurationf(t, expected, actual, delta, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Zero asserts that i is the zero value for its type. +func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if assert.Zero(t, i, msgAndArgs...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} + +// Zerof asserts that i is the zero value for its type. +func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if assert.Zerof(t, i, msg, args...) { + return + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl new file mode 100644 index 0000000..6ffc751 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl @@ -0,0 +1,6 @@ +{{.Comment}} +func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { + if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } + if h, ok := t.(tHelper); ok { h.Helper() } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go new file mode 100644 index 0000000..9fe41db --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -0,0 +1,957 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Condition(a.t, comp, msgAndArgs...) +} + +// Conditionf uses a Comparison to assert a complex condition. +func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Conditionf(a.t, comp, msg, args...) +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") +func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Contains(a.t, s, contains, msgAndArgs...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Containsf(a.t, s, contains, msg, args...) +} + +// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + DirExists(a.t, path, msgAndArgs...) +} + +// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + DirExistsf(a.t, path, msg, args...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) +func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ElementsMatch(a.t, listA, listB, msgAndArgs...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ElementsMatchf(a.t, listA, listB, msg, args...) +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Empty(obj) +func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Empty(a.t, object, msgAndArgs...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Emptyf(obj, "error message %s", "formatted") +func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Emptyf(a.t, object, msg, args...) +} + +// Equal asserts that two objects are equal. +// +// a.Equal(123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Equal(a.t, expected, actual, msgAndArgs...) +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) +func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualError(a.t, theError, errString, msgAndArgs...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualErrorf(a.t, theError, errString, msg, args...) +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValues(uint32(123), int32(123)) +func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123)) +func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualValuesf(a.t, expected, actual, msg, args...) +} + +// Equalf asserts that two objects are equal. +// +// a.Equalf(123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Equalf(a.t, expected, actual, msg, args...) +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } +func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Error(a.t, err, msgAndArgs...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Errorf(a.t, err, msg, args...) +} + +// Exactly asserts that two objects are equal in value and type. +// +// a.Exactly(int32(123), int64(123)) +func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Exactly(a.t, expected, actual, msgAndArgs...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123)) +func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Exactlyf(a.t, expected, actual, msg, args...) +} + +// Fail reports a failure through +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Fail(a.t, failureMessage, msgAndArgs...) +} + +// FailNow fails test +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FailNow(a.t, failureMessage, msgAndArgs...) +} + +// FailNowf fails test +func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FailNowf(a.t, failureMessage, msg, args...) +} + +// Failf reports a failure through +func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Failf(a.t, failureMessage, msg, args...) +} + +// False asserts that the specified value is false. +// +// a.False(myBool) +func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + False(a.t, value, msgAndArgs...) +} + +// Falsef asserts that the specified value is false. +// +// a.Falsef(myBool, "error message %s", "formatted") +func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Falsef(a.t, value, msg, args...) +} + +// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FileExists(a.t, path, msgAndArgs...) +} + +// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FileExistsf(a.t, path, msg, args...) +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPError(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPErrorf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPRedirectf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccessf(a.t, handler, method, url, values, msg, args...) +} + +// Implements asserts that an object is implemented by the specified interface. +// +// a.Implements((*MyInterface)(nil), new(MyObject)) +func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Implements(a.t, interfaceObject, object, msgAndArgs...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) +func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Implementsf(a.t, interfaceObject, object, msg, args...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// a.InDelta(math.Pi, (22 / 7.0), 0.01) +func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaSlicef(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) +func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaf(a.t, expected, actual, delta, msg, args...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonf(a.t, expected, actual, epsilon, msg, args...) +} + +// IsType asserts that the specified objects are of the same type. +func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsType(a.t, expectedType, object, msgAndArgs...) +} + +// IsTypef asserts that the specified objects are of the same type. +func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsTypef(a.t, expectedType, object, msg, args...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + JSONEq(a.t, expected, actual, msgAndArgs...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + JSONEqf(a.t, expected, actual, msg, args...) +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// a.Len(mySlice, 3) +func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Len(a.t, object, length, msgAndArgs...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// a.Lenf(mySlice, 3, "error message %s", "formatted") +func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Lenf(a.t, object, length, msg, args...) +} + +// Nil asserts that the specified object is nil. +// +// a.Nil(err) +func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Nil(a.t, object, msgAndArgs...) +} + +// Nilf asserts that the specified object is nil. +// +// a.Nilf(err, "error message %s", "formatted") +func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Nilf(a.t, object, msg, args...) +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoError(a.t, err, msgAndArgs...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoErrorf(a.t, err, msg, args...) +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") +func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotContains(a.t, s, contains, msgAndArgs...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotContainsf(a.t, s, contains, msg, args...) +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEmpty(a.t, object, msgAndArgs...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEmptyf(a.t, object, msg, args...) +} + +// NotEqual asserts that the specified values are NOT equal. +// +// a.NotEqual(obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqual(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualf(a.t, expected, actual, msg, args...) +} + +// NotNil asserts that the specified object is not nil. +// +// a.NotNil(err) +func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotNil(a.t, object, msgAndArgs...) +} + +// NotNilf asserts that the specified object is not nil. +// +// a.NotNilf(err, "error message %s", "formatted") +func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotNilf(a.t, object, msg, args...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanics(func(){ RemainCalm() }) +func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotPanics(a.t, f, msgAndArgs...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotPanicsf(a.t, f, msg, args...) +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") +func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotRegexp(a.t, rx, str, msgAndArgs...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotRegexpf(a.t, rx, str, msg, args...) +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSubset(a.t, list, subset, msgAndArgs...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSubsetf(a.t, list, subset, msg, args...) +} + +// NotZero asserts that i is not the zero value for its type. +func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotZero(a.t, i, msgAndArgs...) +} + +// NotZerof asserts that i is not the zero value for its type. +func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotZerof(a.t, i, msg, args...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panics(func(){ GoCrazy() }) +func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Panics(a.t, f, msgAndArgs...) +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithValue(a.t, expected, f, msgAndArgs...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithValuef(a.t, expected, f, msg, args...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Panicsf(a.t, f, msg, args...) +} + +// Regexp asserts that a specified regexp matches a string. +// +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") +func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Regexp(a.t, rx, str, msgAndArgs...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Regexpf(a.t, rx, str, msg, args...) +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Subset(a.t, list, subset, msgAndArgs...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Subsetf(a.t, list, subset, msg, args...) +} + +// True asserts that the specified value is true. +// +// a.True(myBool) +func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + True(a.t, value, msgAndArgs...) +} + +// Truef asserts that the specified value is true. +// +// a.Truef(myBool, "error message %s", "formatted") +func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Truef(a.t, value, msg, args...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinDurationf(a.t, expected, actual, delta, msg, args...) +} + +// Zero asserts that i is the zero value for its type. +func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Zero(a.t, i, msgAndArgs...) +} + +// Zerof asserts that i is the zero value for its type. +func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Zerof(a.t, i, msg, args...) +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl new file mode 100644 index 0000000..54124df --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentWithoutT "a"}} +func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { + if h, ok := a.t.(tHelper); ok { h.Helper() } + {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) +} diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go new file mode 100644 index 0000000..6b85c5e --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/requirements.go @@ -0,0 +1,29 @@ +package require + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Errorf(format string, args ...interface{}) + FailNow() +} + +type tHelper interface { + Helper() +} + +// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful +// for table driven tests. +type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) + +// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful +// for table driven tests. +type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) + +// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful +// for table driven tests. +type BoolAssertionFunc func(TestingT, bool, ...interface{}) + +// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful +// for table driven tests. +type ErrorAssertionFunc func(TestingT, error, ...interface{}) + +//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs diff --git a/vendor/modules.txt b/vendor/modules.txt index bd6e13c..ff94255 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -17,6 +17,7 @@ github.com/pkg/errors github.com/pmezard/go-difflib/difflib # github.com/stretchr/testify v1.3.0 github.com/stretchr/testify/assert +github.com/stretchr/testify/require # golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa golang.org/x/sys/unix # gopkg.in/alecthomas/kingpin.v2 v2.2.6