diff --git a/cmd/bindown/cli_test.go b/cmd/bindown/cli_test.go index 985c0a5..5f4ed84 100644 --- a/cmd/bindown/cli_test.go +++ b/cmd/bindown/cli_test.go @@ -416,10 +416,7 @@ url_checksums: stdout: `installed foo to`, }) wantBin := filepath.Join(runner.tmpDir, "bin", "foo") - require.FileExists(t, wantBin) - stat, err := os.Stat(wantBin) - require.NoError(t, err) - testutil.AssertExecutable(t, stat.Mode()) + testutil.AssertFile(t, wantBin, true, false) }) t.Run("link raw file", func(t *testing.T) { @@ -440,11 +437,7 @@ url_checksums: stdout: `installed foo to`, }) wantBin := filepath.Join(runner.tmpDir, "bin", "foo") - require.FileExists(t, wantBin) - stat, err := os.Lstat(wantBin) - require.NoError(t, err) - testutil.AssertExecutable(t, stat.Mode()) - require.True(t, stat.Mode()&os.ModeSymlink != 0) + testutil.AssertFile(t, wantBin, true, true) }) t.Run("bin in root", func(t *testing.T) { @@ -464,10 +457,7 @@ url_checksums: stdout: `installed foo to`, }) wantBin := filepath.Join(runner.tmpDir, "bin", "foo") - require.FileExists(t, wantBin) - stat, err := os.Stat(wantBin) - require.NoError(t, err) - testutil.AssertExecutable(t, stat.Mode()) + testutil.AssertFile(t, wantBin, true, false) }) t.Run("wrong checksum", func(t *testing.T) { diff --git a/internal/bindown/config_test.go b/internal/bindown/config_test.go index 0a862c6..e63e91c 100644 --- a/internal/bindown/config_test.go +++ b/internal/bindown/config_test.go @@ -220,11 +220,7 @@ dependencies: }) require.NoError(t, err) require.Equal(t, wantStdout, stdout.String()) - require.True(t, FileExists(wantBin)) - stat, err := os.Stat(wantBin) - require.NoError(t, err) - require.False(t, stat.IsDir()) - testutil.AssertExecutable(t, stat.Mode()) + testutil.AssertFile(t, wantBin, true, false) }) t.Run("bin in root", func(t *testing.T) { diff --git a/internal/testutil/testutil.go b/internal/testutil/testutil.go index 96a58ef..c85351d 100644 --- a/internal/testutil/testutil.go +++ b/internal/testutil/testutil.go @@ -2,18 +2,53 @@ package testutil import ( "bytes" + "fmt" "io/fs" "net/http" "net/http/httptest" "os" + "os/exec" "path/filepath" "runtime" + "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +var bindownBinOnce sync.Once + +func BindownBin() string { + bindownBinPath := filepath.Join(RepoRoot(), "tmp", "_test", "bindown") + bindownBinOnce.Do(func() { + cmd := exec.Command(goExec(), "build", "-o", bindownBinPath, "./cmd/bindown") + cmd.Dir = RepoRoot() + err := cmd.Run() + if err != nil { + panic(fmt.Sprintf("error building bindown: %v", err)) + } + }) + return bindownBinPath +} + +// goExec returns te path to the go executable to use for tests. +func goExec() string { + goRoot := runtime.GOROOT() + if goRoot != "" { + p := filepath.Join(goRoot, "bin", "go") + info, err := os.Stat(p) + if err == nil && !info.IsDir() { + return p + } + } + p, err := exec.LookPath("go") + if err != nil { + panic("unable to find go executable") + } + return p +} + // ServeFile starts an HTTP server func ServeFile(t *testing.T, file, path, query string) *httptest.Server { t.Helper() @@ -58,11 +93,45 @@ func ServeFiles(t *testing.T, files map[string]string) *httptest.Server { return ts } -func AssertExecutable(t *testing.T, mode fs.FileMode) { +// AssertFile asserts that the file at filename exists and has the given properties. +func AssertFile(t *testing.T, filename string, wantExecutable, wantLink bool) bool { t.Helper() - // Windows doesn't have executable bits + linfo, err := os.Lstat(filename) + if !assert.NoError(t, err) { + return false + } + var ok bool + if wantLink { + ok = assert.True(t, linfo.Mode()&fs.ModeSymlink != 0, "expected %s to be a symlink", filename) + } else { + ok = assert.False(t, linfo.Mode()&fs.ModeSymlink != 0, "expected %s to not be a symlink", filename) + } + if !ok { + return false + } + // windows doesn't have executable bit so we can't check it if runtime.GOOS == "windows" { - return + return false + } + info, err := os.Stat(filename) + if !assert.NoError(t, err) { + return false + } + if wantExecutable { + ok = assert.True(t, info.Mode()&0o110 != 0, "expected %s to be executable", filename) + } else { + ok = assert.False(t, info.Mode()&0o110 != 0, "expected %s to not be executable", filename) + } + return ok +} + +// RepoRoot returns the absolute path to the root of this repo +func RepoRoot() string { + _, filename, _, _ := runtime.Caller(0) + dir := filepath.Join(filepath.Dir(filename), "..", "..") + abs, err := filepath.Abs(dir) + if err != nil { + panic(err) } - assert.Equal(t, fs.FileMode(0o110), mode&0o110) + return abs }