зеркало из https://github.com/golang/dep.git
593 строки
16 KiB
Go
593 строки
16 KiB
Go
// Copyright 2017 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package dep
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"unicode"
|
|
|
|
"github.com/golang/dep/internal/test"
|
|
)
|
|
|
|
func discardLogger() *log.Logger {
|
|
return log.New(ioutil.Discard, "", 0)
|
|
}
|
|
|
|
func TestCtx_ProjectImport(t *testing.T) {
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
h.TempDir("src")
|
|
|
|
h.Setenv("GOPATH", h.Path("."))
|
|
depCtx := &Ctx{GOPATH: h.Path(".")}
|
|
|
|
importPaths := []string{
|
|
"github.com/pkg/errors",
|
|
"my/silly/thing",
|
|
}
|
|
|
|
for _, want := range importPaths {
|
|
fullpath := filepath.Join(depCtx.GOPATH, "src", want)
|
|
h.TempDir(filepath.Join("src", want))
|
|
got, err := depCtx.ImportForAbs(fullpath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != want {
|
|
t.Fatalf("expected %s, got %s", want, got)
|
|
}
|
|
}
|
|
|
|
// test where it should return an error when directly within $GOPATH/src
|
|
got, err := depCtx.ImportForAbs(filepath.Join(depCtx.GOPATH, "src"))
|
|
if err == nil || !strings.Contains(err.Error(), "GOPATH/src") {
|
|
t.Fatalf("should have gotten an error for use directly in GOPATH/src, but got %s", got)
|
|
}
|
|
|
|
// test where it should return an error
|
|
got, err = depCtx.ImportForAbs("tra/la/la/la")
|
|
if err == nil {
|
|
t.Fatalf("should have gotten an error but did not for tra/la/la/la: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestAbsoluteProjectRoot(t *testing.T) {
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
h.TempDir("src")
|
|
h.Setenv("GOPATH", h.Path("."))
|
|
depCtx := &Ctx{GOPATH: h.Path(".")}
|
|
|
|
importPaths := map[string]bool{
|
|
"github.com/pkg/errors": true,
|
|
"my/silly/thing": false,
|
|
}
|
|
|
|
for i, create := range importPaths {
|
|
if create {
|
|
h.TempDir(filepath.Join("src", i))
|
|
}
|
|
}
|
|
|
|
for i, ok := range importPaths {
|
|
got, err := depCtx.AbsForImport(i)
|
|
if ok {
|
|
h.Must(err)
|
|
want := h.Path(filepath.Join("src", i))
|
|
if got != want {
|
|
t.Fatalf("expected %s, got %q", want, got)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if err == nil {
|
|
t.Fatalf("expected %s to fail", i)
|
|
}
|
|
}
|
|
|
|
// test that a file fails
|
|
h.TempFile("src/thing/thing.go", "hello world")
|
|
_, err := depCtx.AbsForImport("thing/thing.go")
|
|
if err == nil {
|
|
t.Fatal("error should not be nil for a file found")
|
|
}
|
|
}
|
|
|
|
func TestLoadProject(t *testing.T) {
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
h.TempDir(filepath.Join("src", "test1", "sub"))
|
|
h.TempFile(filepath.Join("src", "test1", ManifestName), "")
|
|
h.TempFile(filepath.Join("src", "test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"`)
|
|
h.TempDir(filepath.Join("src", "test2", "sub"))
|
|
h.TempFile(filepath.Join("src", "test2", ManifestName), "")
|
|
|
|
var testcases = []struct {
|
|
name string
|
|
lock bool
|
|
wd string
|
|
}{
|
|
{"direct", true, filepath.Join("src", "test1")},
|
|
{"ascending", true, filepath.Join("src", "test1", "sub")},
|
|
{"without lock", false, filepath.Join("src", "test2")},
|
|
{"ascending without lock", false, filepath.Join("src", "test2", "sub")},
|
|
}
|
|
|
|
for _, tc := range testcases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx := &Ctx{
|
|
Out: discardLogger(),
|
|
Err: discardLogger(),
|
|
}
|
|
|
|
err := ctx.SetPaths(h.Path(tc.wd), h.Path("."))
|
|
if err != nil {
|
|
t.Fatalf("%+v", err)
|
|
}
|
|
|
|
p, err := ctx.LoadProject()
|
|
switch {
|
|
case err != nil:
|
|
t.Fatalf("%s: LoadProject failed: %+v", tc.wd, err)
|
|
case p.Manifest == nil:
|
|
t.Fatalf("%s: Manifest file didn't load", tc.wd)
|
|
case tc.lock && p.Lock == nil:
|
|
t.Fatalf("%s: Lock file didn't load", tc.wd)
|
|
case !tc.lock && p.Lock != nil:
|
|
t.Fatalf("%s: Non-existent Lock file loaded", tc.wd)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExplicitRootProject(t *testing.T) {
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
h.TempDir(filepath.Join("src", "test1", "sub"))
|
|
h.TempFile(filepath.Join("src", "test1", ManifestName), "")
|
|
h.TempFile(filepath.Join("src", "test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"`)
|
|
h.TempDir(filepath.Join("src", "test2", "sub"))
|
|
h.TempFile(filepath.Join("src", "test2", ManifestName), "")
|
|
h.Setenv("DEP_PROJECT_ROOT", "github.com/user/module")
|
|
|
|
type tcase struct {
|
|
name string
|
|
lock bool
|
|
wd string
|
|
}
|
|
var testcases = []tcase{
|
|
{"direct", true, filepath.Join("src", "test1")},
|
|
{"ascending", true, filepath.Join("src", "test1", "sub")},
|
|
{"without lock", false, filepath.Join("src", "test2")},
|
|
{"ascending without lock", false, filepath.Join("src", "test2", "sub")},
|
|
}
|
|
|
|
tf := func(withGOPATH bool, tc tcase, t *testing.T) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
ctx := &Ctx{
|
|
Out: discardLogger(),
|
|
Err: discardLogger(),
|
|
}
|
|
|
|
var err error
|
|
if withGOPATH {
|
|
err = ctx.SetPaths(h.Path(tc.wd), h.Path("."))
|
|
} else {
|
|
err = ctx.SetPaths(h.Path(tc.wd))
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("%+v", err)
|
|
}
|
|
ctx.ExplicitRoot = "github.com/user/module"
|
|
|
|
p, err := ctx.LoadProject()
|
|
switch {
|
|
case err != nil:
|
|
t.Fatalf("%s: LoadProject failed: %+v", tc.wd, err)
|
|
case p.Manifest == nil:
|
|
t.Fatalf("%s: Manifest file didn't load", tc.wd)
|
|
case tc.lock && p.Lock == nil:
|
|
t.Fatalf("%s: Lock file didn't load", tc.wd)
|
|
case !tc.lock && p.Lock != nil:
|
|
t.Fatalf("%s: Non-existent Lock file loaded", tc.wd)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, tc := range testcases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Run("within-GOPATH", tf(true, tc, t))
|
|
t.Run("outside-GOPATH", tf(false, tc, t))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadProjectNotFoundErrors(t *testing.T) {
|
|
tg := test.NewHelper(t)
|
|
defer tg.Cleanup()
|
|
|
|
tg.TempDir("src")
|
|
tg.TempDir("src/test1")
|
|
tg.TempDir("src/test1/sub")
|
|
tg.Setenv("GOPATH", tg.Path("."))
|
|
|
|
var testcases = []struct {
|
|
lock bool
|
|
start string
|
|
path string
|
|
}{
|
|
{true, filepath.Join("src", "test1"), ""}, //direct
|
|
{true, filepath.Join("src", "test1", "sub"), ""}, //ascending
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
ctx := &Ctx{GOPATHs: []string{tg.Path(".")}, WorkingDir: tg.Path(testcase.start)}
|
|
|
|
_, err := ctx.LoadProject()
|
|
if err == nil {
|
|
t.Errorf("%s: should have returned 'No Manifest Found' error", testcase.start)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLoadProjectManifestParseError(t *testing.T) {
|
|
tg := test.NewHelper(t)
|
|
defer tg.Cleanup()
|
|
|
|
tg.TempDir("src")
|
|
tg.TempDir("src/test1")
|
|
tg.TempFile(filepath.Join("src/test1", ManifestName), `[[constraint]]`)
|
|
tg.TempFile(filepath.Join("src/test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`)
|
|
tg.Setenv("GOPATH", tg.Path("."))
|
|
|
|
path := filepath.Join("src", "test1")
|
|
tg.Cd(tg.Path(path))
|
|
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal("failed to get working directory", err)
|
|
}
|
|
|
|
ctx := &Ctx{
|
|
GOPATH: tg.Path("."),
|
|
WorkingDir: wd,
|
|
Out: discardLogger(),
|
|
Err: discardLogger(),
|
|
}
|
|
|
|
_, err = ctx.LoadProject()
|
|
if err == nil {
|
|
t.Fatal("should have returned 'Manifest Syntax' error")
|
|
}
|
|
}
|
|
|
|
func TestLoadProjectLockParseError(t *testing.T) {
|
|
tg := test.NewHelper(t)
|
|
defer tg.Cleanup()
|
|
|
|
tg.TempDir("src")
|
|
tg.TempDir("src/test1")
|
|
tg.TempFile(filepath.Join("src/test1", ManifestName), `[[constraint]]`)
|
|
tg.TempFile(filepath.Join("src/test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`)
|
|
tg.Setenv("GOPATH", tg.Path("."))
|
|
|
|
path := filepath.Join("src", "test1")
|
|
tg.Cd(tg.Path(path))
|
|
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal("failed to get working directory", err)
|
|
}
|
|
|
|
ctx := &Ctx{
|
|
GOPATH: tg.Path("."),
|
|
WorkingDir: wd,
|
|
Out: discardLogger(),
|
|
Err: discardLogger(),
|
|
}
|
|
|
|
_, err = ctx.LoadProject()
|
|
if err == nil {
|
|
t.Fatal("should have returned 'Lock Syntax' error")
|
|
}
|
|
}
|
|
|
|
func TestLoadProjectNoSrcDir(t *testing.T) {
|
|
tg := test.NewHelper(t)
|
|
defer tg.Cleanup()
|
|
|
|
tg.TempDir("test1")
|
|
tg.TempFile(filepath.Join("test1", ManifestName), `[[constraint]]`)
|
|
tg.TempFile(filepath.Join("test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`)
|
|
tg.Setenv("GOPATH", tg.Path("."))
|
|
|
|
ctx := &Ctx{GOPATH: tg.Path(".")}
|
|
path := filepath.Join("test1")
|
|
tg.Cd(tg.Path(path))
|
|
|
|
f, _ := os.OpenFile(filepath.Join(ctx.GOPATH, "src", "test1", LockName), os.O_WRONLY, os.ModePerm)
|
|
defer f.Close()
|
|
|
|
_, err := ctx.LoadProject()
|
|
if err == nil {
|
|
t.Fatal("should have returned 'Split Absolute Root' error (no 'src' dir present)")
|
|
}
|
|
}
|
|
|
|
func TestLoadProjectGopkgFilenames(t *testing.T) {
|
|
// We are trying to skip this test on file systems which are case-sensiive. We could
|
|
// have used `fs.IsCaseSensitiveFilesystem` for this check. However, the code we are
|
|
// testing also relies on `fs.IsCaseSensitiveFilesystem`. So a bug in
|
|
// `fs.IsCaseSensitiveFilesystem` could prevent this test from being run. This is the
|
|
// only scenario where we prefer the OS heuristic over doing the actual work of
|
|
// validating filesystem case sensitivity via `fs.IsCaseSensitiveFilesystem`.
|
|
if runtime.GOOS != "windows" && runtime.GOOS != "darwin" {
|
|
t.Skip("skip this test on non-Windows, non-macOS")
|
|
}
|
|
|
|
// Here we test that a manifest filename with incorrect case throws an error. Similar
|
|
// error will also be thrown for the lock file as well which has been tested in
|
|
// `project_test.go#TestCheckGopkgFilenames`. So not repeating here.
|
|
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
invalidMfName := strings.ToLower(ManifestName)
|
|
|
|
wd := filepath.Join("src", "test")
|
|
h.TempFile(filepath.Join(wd, invalidMfName), "")
|
|
|
|
ctx := &Ctx{
|
|
Out: discardLogger(),
|
|
Err: discardLogger(),
|
|
}
|
|
|
|
err := ctx.SetPaths(h.Path(wd), h.Path("."))
|
|
if err != nil {
|
|
t.Fatalf("%+v", err)
|
|
}
|
|
|
|
_, err = ctx.LoadProject()
|
|
|
|
if err == nil {
|
|
t.Fatal("should have returned 'Manifest Filename' error")
|
|
}
|
|
|
|
expectedErrMsg := fmt.Sprintf(
|
|
"manifest filename %q does not match %q",
|
|
invalidMfName, ManifestName,
|
|
)
|
|
|
|
if err.Error() != expectedErrMsg {
|
|
t.Fatalf("unexpected error: %+v", err)
|
|
}
|
|
}
|
|
|
|
// TestCaseInsensitive is test for Windows. This should work even though set
|
|
// difference letter cases in GOPATH.
|
|
func TestCaseInsensitiveGOPATH(t *testing.T) {
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("skip this test on non-Windows")
|
|
}
|
|
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
h.TempDir("src")
|
|
h.TempDir("src/test1")
|
|
h.TempFile(filepath.Join("src/test1", ManifestName), `
|
|
[[constraint]]
|
|
name = "github.com/foo/bar"
|
|
branch = "master"`)
|
|
|
|
// Shuffle letter case
|
|
rs := []rune(strings.ToLower(h.Path(".")))
|
|
for i, r := range rs {
|
|
if unicode.IsLower(r) {
|
|
rs[i] = unicode.ToUpper(r)
|
|
} else {
|
|
rs[i] = unicode.ToLower(r)
|
|
}
|
|
}
|
|
gopath := string(rs)
|
|
h.Setenv("GOPATH", gopath)
|
|
wd := h.Path("src/test1")
|
|
|
|
depCtx := &Ctx{}
|
|
if err := depCtx.SetPaths(wd, gopath); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := depCtx.LoadProject(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ip := "github.com/pkg/errors"
|
|
fullpath := filepath.Join(depCtx.GOPATH, "src", ip)
|
|
h.TempDir(filepath.Join("src", ip))
|
|
pr, err := depCtx.ImportForAbs(fullpath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pr != ip {
|
|
t.Fatalf("expected %s, got %s", ip, pr)
|
|
}
|
|
}
|
|
|
|
func TestDetectProjectGOPATH(t *testing.T) {
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
h.TempDir(filepath.Join("sym", "symlink"))
|
|
h.TempDir(filepath.Join("go", "src", "sym", "path"))
|
|
h.TempDir(filepath.Join("go", "src", "real", "path"))
|
|
h.TempDir(filepath.Join("go-two", "src", "real", "path"))
|
|
h.TempDir(filepath.Join("go-two", "src", "sym"))
|
|
|
|
ctx := &Ctx{
|
|
GOPATHs: []string{h.Path("go"), h.Path("go-two")},
|
|
}
|
|
|
|
testcases := []struct {
|
|
name string
|
|
root string
|
|
resolvedRoot string
|
|
GOPATH string
|
|
expectErr bool
|
|
}{
|
|
{
|
|
name: "project-with-no-AbsRoot",
|
|
root: "",
|
|
resolvedRoot: filepath.Join(ctx.GOPATHs[0], "src", "real", "path"),
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "project-with-no-ResolvedAbsRoot",
|
|
root: filepath.Join(ctx.GOPATHs[0], "src", "real", "path"),
|
|
resolvedRoot: "",
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "AbsRoot-is-not-within-any-GOPATH",
|
|
root: filepath.Join(h.Path("."), "src", "real", "path"),
|
|
resolvedRoot: filepath.Join(h.Path("."), "src", "real", "path"),
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "neither-AbsRoot-nor-ResolvedAbsRoot-are-in-any-GOPATH",
|
|
root: filepath.Join(h.Path("."), "src", "sym", "path"),
|
|
resolvedRoot: filepath.Join(h.Path("."), "src", "real", "path"),
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "both-AbsRoot-and-ResolvedAbsRoot-are-in-the-same-GOPATH",
|
|
root: filepath.Join(ctx.GOPATHs[0], "src", "sym", "path"),
|
|
resolvedRoot: filepath.Join(ctx.GOPATHs[0], "src", "real", "path"),
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "AbsRoot-and-ResolvedAbsRoot-are-each-within-a-different-GOPATH",
|
|
root: filepath.Join(ctx.GOPATHs[0], "src", "sym", "path"),
|
|
resolvedRoot: filepath.Join(ctx.GOPATHs[1], "src", "real", "path"),
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "AbsRoot-is-not-a-symlink",
|
|
root: filepath.Join(ctx.GOPATHs[0], "src", "real", "path"),
|
|
resolvedRoot: filepath.Join(ctx.GOPATHs[0], "src", "real", "path"),
|
|
GOPATH: ctx.GOPATHs[0],
|
|
},
|
|
{
|
|
name: "AbsRoot-is-a-symlink-to-ResolvedAbsRoot",
|
|
root: filepath.Join(h.Path("."), "sym", "symlink"),
|
|
resolvedRoot: filepath.Join(ctx.GOPATHs[0], "src", "real", "path"),
|
|
GOPATH: ctx.GOPATHs[0],
|
|
},
|
|
}
|
|
|
|
for _, tc := range testcases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
project := &Project{
|
|
AbsRoot: tc.root,
|
|
ResolvedAbsRoot: tc.resolvedRoot,
|
|
}
|
|
|
|
GOPATH, err := ctx.DetectProjectGOPATH(project)
|
|
if !tc.expectErr && err != nil {
|
|
t.Fatalf("%+v", err)
|
|
} else if tc.expectErr && err == nil {
|
|
t.Fatalf("expected an error, got nil and gopath %s", GOPATH)
|
|
}
|
|
if GOPATH != tc.GOPATH {
|
|
t.Errorf("expected GOPATH %s, got %s", tc.GOPATH, GOPATH)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDetectGOPATH(t *testing.T) {
|
|
th := test.NewHelper(t)
|
|
defer th.Cleanup()
|
|
|
|
th.TempDir(filepath.Join("code", "src", "github.com", "username", "package"))
|
|
th.TempDir(filepath.Join("go", "src", "github.com", "username", "package"))
|
|
th.TempDir(filepath.Join("gotwo", "src", "github.com", "username", "package"))
|
|
|
|
ctx := &Ctx{GOPATHs: []string{
|
|
th.Path("go"),
|
|
th.Path("gotwo"),
|
|
}}
|
|
|
|
testcases := []struct {
|
|
GOPATH string
|
|
path string
|
|
err bool
|
|
}{
|
|
{th.Path("go"), th.Path(filepath.Join("go", "src", "github.com", "username", "package")), false},
|
|
{th.Path("go"), th.Path(filepath.Join("go", "src", "github.com", "username", "package")), false},
|
|
{th.Path("gotwo"), th.Path(filepath.Join("gotwo", "src", "github.com", "username", "package")), false},
|
|
{"", th.Path(filepath.Join("code", "src", "github.com", "username", "package")), true},
|
|
}
|
|
|
|
for _, tc := range testcases {
|
|
GOPATH, err := ctx.detectGOPATH(tc.path)
|
|
if tc.err && err == nil {
|
|
t.Error("expected error but got none")
|
|
}
|
|
if GOPATH != tc.GOPATH {
|
|
t.Errorf("expected GOPATH to be %s, got %s", GOPATH, tc.GOPATH)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDepCachedir(t *testing.T) {
|
|
h := test.NewHelper(t)
|
|
defer h.Cleanup()
|
|
|
|
h.TempDir("cache")
|
|
// Create the directory for default cachedir location.
|
|
h.TempDir(filepath.Join("go", "pkg", "dep"))
|
|
|
|
testCachedir := h.Path("cache")
|
|
gopath := h.Path("go")
|
|
discardLgr := discardLogger()
|
|
|
|
cases := []struct {
|
|
cachedir string
|
|
wantCachedir string
|
|
}{
|
|
// If `Cachedir` is not set in the context, it should use `$GOPATH/pkg/dep`.
|
|
{cachedir: "", wantCachedir: h.Path(filepath.Join("go", "pkg", "dep"))},
|
|
// If `Cachedir` is set in the context, it should use that.
|
|
{cachedir: testCachedir, wantCachedir: testCachedir},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
ctx := &Ctx{
|
|
GOPATH: gopath,
|
|
Cachedir: c.cachedir,
|
|
Out: discardLgr,
|
|
Err: discardLgr,
|
|
}
|
|
sm, err := ctx.SourceManager()
|
|
h.Must(err)
|
|
defer sm.Release()
|
|
|
|
if sm.Cachedir() != c.wantCachedir {
|
|
t.Errorf("expected cachedir to be %s, got %s", c.wantCachedir, sm.Cachedir())
|
|
}
|
|
}
|
|
}
|