| // Copyright 2015 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. |
| |
| // Tests for vendoring semantics. |
| |
| package main_test |
| |
| import ( |
| "bytes" |
| "fmt" |
| "internal/testenv" |
| "os" |
| "path/filepath" |
| "regexp" |
| "strings" |
| "testing" |
| ) |
| |
| func TestVendorImports(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) |
| tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...", "vend/vendor/...", "vend/x/vendor/...") |
| want := ` |
| vend [vend/vendor/p r] |
| vend/dir1 [] |
| vend/hello [fmt vend/vendor/strings] |
| vend/subdir [vend/vendor/p r] |
| vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r vend/dir1 vend/vendor/vend/dir1/dir2] |
| vend/x/invalid [vend/x/invalid/vendor/foo] |
| vend/vendor/p [] |
| vend/vendor/q [] |
| vend/vendor/strings [] |
| vend/vendor/vend/dir1/dir2 [] |
| vend/x/vendor/p [] |
| vend/x/vendor/p/p [notfound] |
| vend/x/vendor/r [] |
| ` |
| want = strings.Replace(want+"\t", "\n\t\t", "\n", -1) |
| want = strings.TrimPrefix(want, "\n") |
| |
| have := tg.stdout.String() |
| |
| if have != want { |
| t.Errorf("incorrect go list output:\n%s", diffSortedOutputs(have, want)) |
| } |
| } |
| |
| func TestVendorBuild(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) |
| tg.run("build", "vend/x") |
| } |
| |
| func TestVendorRun(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) |
| tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello")) |
| tg.run("run", "hello.go") |
| tg.grepStdout("hello, world", "missing hello world output") |
| } |
| |
| func TestVendorGOPATH(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| changeVolume := func(s string, f func(s string) string) string { |
| vol := filepath.VolumeName(s) |
| return f(vol) + s[len(vol):] |
| } |
| gopath := changeVolume(filepath.Join(tg.pwd(), "testdata"), strings.ToLower) |
| tg.setenv("GOPATH", gopath) |
| cd := changeVolume(filepath.Join(tg.pwd(), "testdata/src/vend/hello"), strings.ToUpper) |
| tg.cd(cd) |
| tg.run("run", "hello.go") |
| tg.grepStdout("hello, world", "missing hello world output") |
| } |
| |
| func TestVendorTest(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) |
| tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello")) |
| tg.run("test", "-v") |
| tg.grepStdout("TestMsgInternal", "missing use in internal test") |
| tg.grepStdout("TestMsgExternal", "missing use in external test") |
| } |
| |
| func TestVendorInvalid(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) |
| |
| tg.runFail("build", "vend/x/invalid") |
| tg.grepStderr("must be imported as foo", "missing vendor import error") |
| } |
| |
| func TestVendorImportError(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) |
| |
| tg.runFail("build", "vend/x/vendor/p/p") |
| |
| re := regexp.MustCompile(`cannot find package "notfound" in any of: |
| .*[\\/]testdata[\\/]src[\\/]vend[\\/]x[\\/]vendor[\\/]notfound \(vendor tree\) |
| .*[\\/]testdata[\\/]src[\\/]vend[\\/]vendor[\\/]notfound |
| .*[\\/]src[\\/]notfound \(from \$GOROOT\) |
| .*[\\/]testdata[\\/]src[\\/]notfound \(from \$GOPATH\)`) |
| |
| if !re.MatchString(tg.stderr.String()) { |
| t.Errorf("did not find expected search list in error text") |
| } |
| } |
| |
| // diffSortedOutput prepares a diff of the already sorted outputs haveText and wantText. |
| // The diff shows common lines prefixed by a tab, lines present only in haveText |
| // prefixed by "unexpected: ", and lines present only in wantText prefixed by "missing: ". |
| func diffSortedOutputs(haveText, wantText string) string { |
| var diff bytes.Buffer |
| have := splitLines(haveText) |
| want := splitLines(wantText) |
| for len(have) > 0 || len(want) > 0 { |
| if len(want) == 0 || len(have) > 0 && have[0] < want[0] { |
| fmt.Fprintf(&diff, "unexpected: %s\n", have[0]) |
| have = have[1:] |
| continue |
| } |
| if len(have) == 0 || len(want) > 0 && want[0] < have[0] { |
| fmt.Fprintf(&diff, "missing: %s\n", want[0]) |
| want = want[1:] |
| continue |
| } |
| fmt.Fprintf(&diff, "\t%s\n", want[0]) |
| want = want[1:] |
| have = have[1:] |
| } |
| return diff.String() |
| } |
| |
| func splitLines(s string) []string { |
| x := strings.Split(s, "\n") |
| if x[len(x)-1] == "" { |
| x = x[:len(x)-1] |
| } |
| return x |
| } |
| |
| func TestVendorGet(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.tempFile("src/v/m.go", ` |
| package main |
| import ("fmt"; "vendor.org/p") |
| func main() { |
| fmt.Println(p.C) |
| }`) |
| tg.tempFile("src/v/m_test.go", ` |
| package main |
| import ("fmt"; "testing"; "vendor.org/p") |
| func TestNothing(t *testing.T) { |
| fmt.Println(p.C) |
| }`) |
| tg.tempFile("src/v/vendor/vendor.org/p/p.go", ` |
| package p |
| const C = 1`) |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.cd(tg.path("src/v")) |
| tg.run("run", "m.go") |
| tg.run("test") |
| tg.run("list", "-f", "{{.Imports}}") |
| tg.grepStdout("v/vendor/vendor.org/p", "import not in vendor directory") |
| tg.run("list", "-f", "{{.TestImports}}") |
| tg.grepStdout("v/vendor/vendor.org/p", "test import not in vendor directory") |
| tg.run("get") |
| tg.run("get", "-t") |
| } |
| |
| func TestVendorGetUpdate(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.run("get", "github.com/rsc/go-get-issue-11864") |
| tg.run("get", "-u", "github.com/rsc/go-get-issue-11864") |
| } |
| |
| func TestVendorGetU(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.run("get", "-u", "github.com/rsc/go-get-issue-11864") |
| } |
| |
| func TestVendorGetTU(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.run("get", "-t", "-u", "github.com/rsc/go-get-issue-11864/...") |
| } |
| |
| func TestVendorGetBadVendor(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| for _, suffix := range []string{"bad/imp", "bad/imp2", "bad/imp3", "..."} { |
| t.Run(suffix, func(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.runFail("get", "-t", "-u", "github.com/rsc/go-get-issue-18219/"+suffix) |
| tg.grepStderr("must be imported as", "did not find error about vendor import") |
| tg.mustNotExist(tg.path("src/github.com/rsc/vendor")) |
| }) |
| } |
| } |
| |
| func TestGetSubmodules(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.run("get", "-d", "github.com/rsc/go-get-issue-12612") |
| tg.run("get", "-u", "-d", "github.com/rsc/go-get-issue-12612") |
| tg.mustExist(tg.path("src/github.com/rsc/go-get-issue-12612/vendor/golang.org/x/crypto/.git")) |
| } |
| |
| func TestVendorCache(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor")) |
| tg.runFail("build", "p") |
| tg.grepStderr("must be imported as x", "did not fail to build p") |
| } |
| |
| func TestVendorTest2(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.run("get", "github.com/rsc/go-get-issue-11864") |
| |
| // build -i should work |
| tg.run("build", "-i", "github.com/rsc/go-get-issue-11864") |
| tg.run("build", "-i", "github.com/rsc/go-get-issue-11864/t") |
| |
| // test -i should work like build -i (golang.org/issue/11988) |
| tg.run("test", "-i", "github.com/rsc/go-get-issue-11864") |
| tg.run("test", "-i", "github.com/rsc/go-get-issue-11864/t") |
| |
| // test should work too |
| tg.run("test", "github.com/rsc/go-get-issue-11864") |
| tg.run("test", "github.com/rsc/go-get-issue-11864/t") |
| |
| // external tests should observe internal test exports (golang.org/issue/11977) |
| tg.run("test", "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2") |
| } |
| |
| func TestVendorTest3(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.run("get", "github.com/clsung/go-vendor-issue-14613") |
| |
| tg.run("build", "-o", tg.path("a.out"), "-i", "github.com/clsung/go-vendor-issue-14613") |
| |
| // test folder should work |
| tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613") |
| tg.run("test", "github.com/clsung/go-vendor-issue-14613") |
| |
| // test with specified _test.go should work too |
| tg.cd(filepath.Join(tg.path("."), "src")) |
| tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613/vendor_test.go") |
| tg.run("test", "github.com/clsung/go-vendor-issue-14613/vendor_test.go") |
| |
| // test with imported and not used |
| tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go") |
| tg.runFail("test", "github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go") |
| tg.grepStderr("imported and not used:", `should say "imported and not used"`) |
| } |
| |
| func TestVendorList(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path(".")) |
| tg.run("get", "github.com/rsc/go-get-issue-11864") |
| |
| tg.run("list", "-f", `{{join .TestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/t") |
| tg.grepStdout("go-get-issue-11864/vendor/vendor.org/p", "did not find vendor-expanded p") |
| |
| tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/tx") |
| tg.grepStdout("go-get-issue-11864/vendor/vendor.org/p", "did not find vendor-expanded p") |
| |
| tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2") |
| tg.grepStdout("go-get-issue-11864/vendor/vendor.org/tx2", "did not find vendor-expanded tx2") |
| |
| tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3") |
| tg.grepStdout("go-get-issue-11864/vendor/vendor.org/tx3", "did not find vendor-expanded tx3") |
| } |
| |
| func TestVendor12156(t *testing.T) { |
| // Former index out of range panic. |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor2")) |
| tg.cd(filepath.Join(tg.pwd(), "testdata/testvendor2/src/p")) |
| tg.runFail("build", "p.go") |
| tg.grepStderrNot("panic", "panicked") |
| tg.grepStderr(`cannot find package "x"`, "wrong error") |
| } |
| |
| // Module legacy support does path rewriting very similar to vendoring. |
| |
| func TestModLegacy(t *testing.T) { |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy")) |
| tg.run("list", "-f", "{{.Imports}}", "old/p1") |
| tg.grepStdout("new/p1", "old/p1 should import new/p1") |
| tg.run("list", "-f", "{{.Imports}}", "new/p1") |
| tg.grepStdout("new/p2", "new/p1 should import new/p2 (not new/v2/p2)") |
| tg.grepStdoutNot("new/v2", "new/p1 should NOT import new/v2*") |
| tg.grepStdout("new/sub/x/v1/y", "new/p1 should import new/sub/x/v1/y (not new/sub/v2/x/v1/y)") |
| tg.grepStdoutNot("new/sub/v2", "new/p1 should NOT import new/sub/v2*") |
| tg.grepStdout("new/sub/inner/x", "new/p1 should import new/sub/inner/x (no rewrites)") |
| tg.run("build", "old/p1", "new/p1") |
| } |
| |
| func TestModLegacyGet(t *testing.T) { |
| testenv.MustHaveExternalNetwork(t) |
| |
| tg := testgo(t) |
| defer tg.cleanup() |
| tg.makeTempdir() |
| tg.setenv("GOPATH", tg.path("d1")) |
| tg.run("get", "vcs-test.golang.org/git/modlegacy1-old.git/p1") |
| tg.run("list", "-f", "{{.Deps}}", "vcs-test.golang.org/git/modlegacy1-old.git/p1") |
| tg.grepStdout("new.git/p2", "old/p1 should depend on new/p2") |
| tg.grepStdoutNot("new.git/v2/p2", "old/p1 should NOT depend on new/v2/p2") |
| tg.run("build", "vcs-test.golang.org/git/modlegacy1-old.git/p1", "vcs-test.golang.org/git/modlegacy1-new.git/p1") |
| |
| tg.setenv("GOPATH", tg.path("d2")) |
| |
| tg.must(os.RemoveAll(tg.path("d2"))) |
| tg.run("get", "github.com/rsc/vgotest5") |
| tg.run("get", "github.com/rsc/vgotest4") |
| tg.run("get", "github.com/myitcv/vgo_example_compat") |
| |
| if testing.Short() { |
| return |
| } |
| |
| tg.must(os.RemoveAll(tg.path("d2"))) |
| tg.run("get", "github.com/rsc/vgotest4") |
| tg.run("get", "github.com/rsc/vgotest5") |
| tg.run("get", "github.com/myitcv/vgo_example_compat") |
| |
| tg.must(os.RemoveAll(tg.path("d2"))) |
| tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5") |
| tg.run("get", "github.com/myitcv/vgo_example_compat") |
| |
| tg.must(os.RemoveAll(tg.path("d2"))) |
| tg.run("get", "github.com/rsc/vgotest5", "github.com/rsc/vgotest4") |
| tg.run("get", "github.com/myitcv/vgo_example_compat") |
| |
| tg.must(os.RemoveAll(tg.path("d2"))) |
| tg.run("get", "github.com/myitcv/vgo_example_compat") |
| tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5") |
| |
| pkgs := []string{"github.com/myitcv/vgo_example_compat", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5"} |
| for i := 0; i < 3; i++ { |
| for j := 0; j < 3; j++ { |
| for k := 0; k < 3; k++ { |
| if i == j || i == k || k == j { |
| continue |
| } |
| tg.must(os.RemoveAll(tg.path("d2"))) |
| tg.run("get", pkgs[i], pkgs[j], pkgs[k]) |
| } |
| } |
| } |
| } |