1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
22 "golang.org/x/tools/go/packages/packagestest"
23 "golang.org/x/tools/internal/gocommand"
26 var testDebug = flag.Bool("debug", false, "enable debug output")
28 var tests = []struct {
33 // Adding an import to an existing parenthesized import
35 name: "factored_imports_add",
42 fmt.Println(b.String())
54 fmt.Println(b.String())
59 // Adding an import to an existing parenthesized import,
60 // verifying it goes into the first section.
62 name: "factored_imports_add_first_sec",
67 "github.com/golang/snappy"
72 fmt.Println(b.String())
81 "github.com/golang/snappy"
87 fmt.Println(b.String())
92 // Adding an import to an existing parenthesized import,
93 // verifying it goes into the first section. (test 2)
95 name: "factored_imports_add_first_sec_2",
100 "github.com/golang/snappy"
105 _ = snappy.ErrCorrupt
114 "github.com/golang/snappy"
120 _ = snappy.ErrCorrupt
125 // Adding a new import line, without parens
127 name: "add_import_section",
143 // Adding two new imports, which should make a parenthesized import decl.
145 name: "add_import_paren_section",
148 _, _ := bytes.Buffer, zip.NewReader
159 _, _ := bytes.Buffer, zip.NewReader
164 // Make sure we don't add things twice
166 name: "no_double_add",
169 _, _ := bytes.Buffer, bytes.NewReader
177 _, _ := bytes.Buffer, bytes.NewReader
182 // Make sure we don't add packages that don't have the right exports
184 name: "no_mismatched_add",
188 _ := bytes.NonexistentSymbol
194 _ := bytes.NonexistentSymbol
199 // Remove unused imports, 1 of a factored block
201 name: "remove_unused_1_of_2",
209 _, _ := bytes.Buffer, bytes.NewReader
219 _, _ := bytes.Buffer, bytes.NewReader
224 // Remove unused imports, 2 of 2
226 name: "remove_unused_2_of_2",
243 // Remove unused imports, 1 of 1
245 name: "remove_unused_1_of_1",
260 // Don't remove empty imports.
262 name: "dont_remove_empty_imports",
278 // Don't remove dot imports.
280 name: "dont_remove_dot_imports",
296 // Skip refs the parser can resolve.
298 name: "skip_resolved_refs",
302 type t struct{ Println func(string) }
303 fmt := t{Println: func(string) {}}
310 type t struct{ Println func(string) }
311 fmt := t{Println: func(string) {}}
317 // Do not add a package we already have a resolution for.
319 name: "skip_template",
322 import "html/template"
324 func f() { t = template.New("sometemplate") }
328 import "html/template"
330 func f() { t = template.New("sometemplate") }
353 // Put some things in their own section
355 name: "make_sections",
363 _, _ = os.Args, fmt.Println
364 _, _ = snappy.ErrCorrupt, p.P
373 "github.com/golang/snappy"
378 _, _ = os.Args, fmt.Println
379 _, _ = snappy.ErrCorrupt, p.P
383 // Merge import blocks, even when no additions are required.
385 name: "merge_import_blocks_no_fix",
397 var _, _ = os.Args, fmt.Println
398 var _, _ = snappy.ErrCorrupt, p.P
406 "github.com/golang/snappy"
410 var _, _ = os.Args, fmt.Println
411 var _, _ = snappy.ErrCorrupt, p.P
414 // Delete existing empty import block
416 name: "delete_empty_import_block",
425 // Use existing empty import block
427 name: "use_empty_import_block",
446 // Blank line before adding new section.
448 name: "blank_line_before_new_group",
459 _ = snappy.ErrCorrupt
468 "github.com/golang/snappy"
474 _ = snappy.ErrCorrupt
479 // Blank line between standard library and third-party stuff.
481 name: "blank_line_separating_std_and_third_party",
485 "github.com/golang/snappy"
502 "github.com/golang/snappy"
513 // golang.org/issue/6884
515 name: "new_imports_before_comment",
520 fmt.Println("Hello, world")
529 fmt.Println("Hello, world")
534 // golang.org/issue/7132
536 name: "new_section_for_dotless_import",
543 "manypackages.com/packagea"
559 "manypackages.com/packagea"
571 name: "fragment_with_main",
572 in: `func main(){fmt.Println("Hello, world")}`,
577 func main() { fmt.Println("Hello, world") }
582 name: "fragment_without_main",
583 in: `func notmain(){fmt.Println("Hello, world")}`,
586 func notmain() { fmt.Println("Hello, world") }`,
589 // Remove first import within in a 2nd/3rd/4th/etc. section.
590 // golang.org/issue/7679
592 name: "remove_first_import_in_section",
598 "manypackages.com/packagea"
599 "manypackages.com/packageb"
613 "manypackages.com/packageb"
624 // Blank line can be added before all types of import declarations.
625 // golang.org/issue/7866
627 name: "new_section_for_all_kinds_of_imports",
632 renamed_packagea "manypackages.com/packagea"
634 . "manypackages.com/packageb"
637 _ "manypackages.com/packagec"
641 var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
648 renamed_packagea "manypackages.com/packagea"
652 . "manypackages.com/packageb"
656 _ "manypackages.com/packagec"
659 var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
663 // Non-idempotent comment formatting
664 // golang.org/issue/8035
666 name: "comments_formatted",
672 _ "manypackages.com/packagec" // C
675 func main() { _, _ = fmt.Print, ast.Walk }
683 _ "manypackages.com/packagec" // C
686 func main() { _, _ = fmt.Print, ast.Walk }
690 // Failure to delete all duplicate imports
691 // golang.org/issue/8459
693 name: "remove_duplicates",
703 func main() { fmt.Println("pi:", math.Pi) }
712 func main() { fmt.Println("pi:", math.Pi) }
716 // Too aggressive prefix matching
717 // golang.org/issue/9961
719 name: "no_extra_groups",
754 // Unused named import is mistaken for unnamed import
755 // golang.org/issue/8149
757 name: "named_import_doesnt_provide_package_name",
762 func main() { fmt.Println() }
768 func main() { fmt.Println() }
772 // Unused named import is mistaken for unnamed import
773 // golang.org/issue/8149
775 name: "unused_named_import_removed",
783 func main() { fmt.Println() }
791 func main() { fmt.Println() }
796 name: "ignore_unexported_identifier",
798 var _ = fmt.unexported`,
801 var _ = fmt.unexported
807 name: "formatonly_works",
813 "manypackages.com/packagea"
823 "manypackages.com/packagea"
831 name: "preserve_import_group",
851 name: "import_grouping_not_path_dependent_no_groups",
859 _ = snappy.ErrCorrupt
869 "github.com/golang/snappy"
874 _ = snappy.ErrCorrupt
882 name: "import_grouping_not_path_dependent_existing_group",
888 "github.com/golang/snappy"
892 _ = snappy.ErrCorrupt
902 "github.com/golang/snappy"
907 _ = snappy.ErrCorrupt
914 // golang.org/issue/12097
916 name: "package_statement_insertion_preserves_comments",
939 name: "import_comment_stays_on_import",
948 fmt.Println(strings.Join(",", []string{"hi"}), x)
960 fmt.Println(strings.Join(",", []string{"hi"}), x)
966 name: "no_blank_after_comment",
972 _ "net/http/pprof" // install the pprof http handlers
984 _ "net/http/pprof" // install the pprof http handlers
994 name: "no_blank_after_comment_reordered",
999 _ "net/http/pprof" // install the pprof http handlers
1012 _ "net/http/pprof" // install the pprof http handlers
1022 name: "no_blank_after_comment_unnamed",
1029 _ "net/http/pprof" // install the pprof http handlers
1032 "manypackages.com/packagea"
1036 _ = strings.ToUpper("hello")
1051 _ "net/http/pprof" // install the pprof http handlers
1054 "manypackages.com/packagea"
1058 _ = strings.ToUpper("hello")
1070 name: "blank_after_package_statement_with_comment",
1071 in: `package p // comment
1077 out: `package p // comment
1086 name: "blank_after_package_statement_no_comment",
1102 name: "cryptorand_preferred_easy_possible",
1109 import "crypto/rand"
1116 name: "cryptorand_preferred_easy_impossible",
1119 var _ = rand.NewZipf
1125 var _ = rand.NewZipf
1130 name: "cryptorand_preferred_complex_possible",
1133 var _, _ = rand.Read, rand.Prime
1137 import "crypto/rand"
1139 var _, _ = rand.Read, rand.Prime
1144 name: "cryptorand_preferred_complex_impossible",
1147 var _, _ = rand.Read, rand.NewZipf
1153 var _, _ = rand.Read, rand.NewZipf
1158 func TestSimpleCases(t *testing.T) {
1159 const localPrefix = "local.com,github.com/local"
1160 for _, tt := range tests {
1161 t.Run(tt.name, func(t *testing.T) {
1163 modules: []packagestest.Module{
1165 Name: "golang.org/fake",
1166 Files: fm{"x.go": tt.in},
1168 // Skeleton non-stdlib packages for use during testing.
1169 // Each includes one arbitrary symbol, e.g. the first declaration in the first file.
1170 // Try not to add more without a good reason.
1171 // DO NOT USE PACKAGES NOT LISTED HERE -- they will be downloaded!
1174 Files: fm{"p/x.go": "package p\nfunc P(){}\n"},
1177 Name: "github.com/golang/snappy",
1178 Files: fm{"x.go": "package snappy\nvar ErrCorrupt error\n"},
1181 Name: "manypackages.com",
1183 "packagea/x.go": "package packagea\nfunc A(){}\n",
1184 "packageb/x.go": "package packageb\nfunc B(){}\n",
1185 "packagec/x.go": "package packagec\nfunc C(){}\n",
1186 "packaged/x.go": "package packaged\nfunc D(){}\n",
1191 Files: fm{"foo/x.go": "package foo\nfunc Foo(){}\n"},
1194 Name: "github.com/local",
1195 Files: fm{"bar/x.go": "package bar\nfunc Bar(){}\n"},
1198 }.test(t, func(t *goimportTest) {
1199 options := &Options{
1200 LocalPrefix: localPrefix,
1205 FormatOnly: tt.formatOnly,
1207 t.assertProcessEquals("golang.org/fake", "x.go", nil, options, tt.out)
1214 func TestAppengine(t *testing.T) {
1215 const input = `package p
1217 var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
1220 const want = `package p
1226 "appengine/datastore"
1229 var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
1233 gopathOnly: true, // can't create a module named appengine, so no module tests.
1234 modules: []packagestest.Module{
1236 Name: "golang.org/fake",
1237 Files: fm{"x.go": input},
1242 "x.go": "package appengine\nfunc Main(){}\n",
1243 "datastore/x.go": "package datastore\nvar ErrInvalidEntityType error\n",
1247 }.processTest(t, "golang.org/fake", "x.go", nil, nil, want)
1250 func TestReadFromFilesystem(t *testing.T) {
1272 name: "missing_package",
1288 for _, tt := range tests {
1289 t.Run(tt.name, func(t *testing.T) {
1290 options := &Options{
1297 module: packagestest.Module{
1298 Name: "golang.org/fake",
1299 Files: fm{"x.go": tt.in},
1301 }.processTest(t, "golang.org/fake", "x.go", nil, options, tt.out)
1307 // Test support for packages in GOPATH that are actually symlinks.
1308 // Also test that a symlink loop does not block the process.
1309 func TestImportSymlinks(t *testing.T) {
1310 switch runtime.GOOS {
1311 case "windows", "plan9":
1312 t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
1315 const input = `package p
1322 const want = `package p
1327 "golang.org/fake/x/y/mypkg"
1337 module: packagestest.Module{
1338 Name: "golang.org/fake",
1340 "target/f.go": "package mypkg\nvar Foo = 123\n",
1341 "x/y/mypkg": packagestest.Symlink("../../target"), // valid symlink
1342 "x/y/apkg": packagestest.Symlink(".."), // symlink loop
1343 "myotherpackage/toformat.go": input,
1346 }.processTest(t, "golang.org/fake", "myotherpackage/toformat.go", nil, nil, want)
1349 func TestImportSymlinksWithIgnore(t *testing.T) {
1350 switch runtime.GOOS {
1351 case "windows", "plan9":
1352 t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
1355 const input = `package p
1362 const want = `package p
1374 module: packagestest.Module{
1375 Name: "golang.org/fake",
1377 "target/f.go": "package mypkg\nvar Foo = 123\n",
1378 "x/y/mypkg": packagestest.Symlink("../../target"), // valid symlink
1379 "x/y/apkg": packagestest.Symlink(".."), // symlink loop
1380 "myotherpkg/toformat.go": input,
1381 "../../.goimportsignore": "golang.org/fake/x/y/mypkg\n",
1384 }.processTest(t, "golang.org/fake", "myotherpkg/toformat.go", nil, nil, want)
1387 // Test for x/y/v2 convention for package y.
1388 func TestModuleVersion(t *testing.T) {
1389 const input = `package p
1404 modules: []packagestest.Module{
1406 Name: "mypkg.com/outpkg",
1407 Files: fm{"toformat.go": input},
1410 Name: "github.com/foo/v2",
1411 Files: fm{"x.go": "package foo\n func Foo(){}\n"},
1414 }.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, input)
1417 // Test for correctly identifying the name of a vendored package when it
1418 // differs from its directory name. In this test, the import line
1419 // "mypkg.com/mypkg_v1" would be removed if goimports wasn't able to detect
1420 // that the package name is "mypkg".
1421 func TestVendorPackage(t *testing.T) {
1422 const input = `package p
1425 "mypkg.com/mypkg_v1"
1427 var _, _ = fmt.Print, mypkg.Foo
1430 const want = `package p
1435 mypkg "mypkg.com/mypkg_v1"
1438 var _, _ = fmt.Print, mypkg.Foo
1443 module: packagestest.Module{
1444 Name: "mypkg.com/outpkg",
1446 "vendor/mypkg.com/mypkg_v1/f.go": "package mypkg\nvar Foo = 123\n",
1447 "toformat.go": input,
1450 }.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, want)
1453 func TestInternal(t *testing.T) {
1454 const input = `package bar
1456 var _ = race.Acquire
1458 const importAdded = `package bar
1460 import "foo.com/internal/race"
1462 var _ = race.Acquire
1465 // Packages under the same directory should be able to use internal packages.
1467 module: packagestest.Module{
1470 "internal/race/x.go": "package race\n func Acquire(){}\n",
1474 }.processTest(t, "foo.com", "bar/x.go", nil, nil, importAdded)
1476 // Packages outside the same directory should not.
1478 modules: []packagestest.Module{
1481 Files: fm{"internal/race/x.go": "package race\n func Acquire(){}\n"},
1485 Files: fm{"x.go": input},
1488 }.processTest(t, "bar.com", "x.go", nil, nil, input)
1491 func TestProcessVendor(t *testing.T) {
1492 const input = `package p
1494 var _ = hpack.HuffmanDecode
1496 const want = `package p
1498 import "golang.org/x/net/http2/hpack"
1500 var _ = hpack.HuffmanDecode
1504 module: packagestest.Module{
1507 "vendor/golang.org/x/net/http2/hpack/huffman.go": "package hpack\nfunc HuffmanDecode() { }\n",
1511 }.processTest(t, "foo.com", "bar/x.go", nil, nil, want)
1514 func TestFindStdlib(t *testing.T) {
1520 {"http", []string{"Get"}, "net/http"},
1521 {"http", []string{"Get", "Post"}, "net/http"},
1522 {"http", []string{"Get", "Foo"}, ""},
1523 {"bytes", []string{"Buffer"}, "bytes"},
1524 {"ioutil", []string{"Discard"}, "io/ioutil"},
1526 for _, tt := range tests {
1527 input := "package p\n"
1528 for _, sym := range tt.symbols {
1529 input += fmt.Sprintf("var _ = %s.%s\n", tt.pkg, sym)
1532 module: packagestest.Module{
1534 Files: fm{"x.go": input},
1536 }.test(t, func(t *goimportTest) {
1537 buf, err := t.process("foo.com", "x.go", nil, nil)
1541 if got := string(buf); !strings.Contains(got, tt.want) {
1542 t.Errorf("Process(%q) = %q, wanted it to contain %q", input, buf, tt.want)
1548 // https://golang.org/issue/31814
1549 func TestStdlibNotPrefixed(t *testing.T) {
1550 const input = `package p
1551 var _ = bytes.Buffer
1553 const want = `package p
1557 var _ = bytes.Buffer
1559 // Force a scan of the stdlib.
1560 savedStdlib := stdlib
1561 defer func() { stdlib = savedStdlib }()
1562 stdlib = map[string][]string{}
1565 module: packagestest.Module{
1566 Name: "ignored.com",
1567 Files: fm{"x.go": "package x"},
1569 }.test(t, func(t *goimportTest) {
1570 // Run in GOROOT/src so that the std module shows up in go list -m all.
1571 t.env.WorkingDir = filepath.Join(t.goroot, "src")
1572 got, err := t.processNonModule(filepath.Join(t.goroot, "src/x.go"), []byte(input), nil)
1574 t.Fatalf("Process() = %v", err)
1576 if string(got) != want {
1577 t.Errorf("Got:\n%s\nWant:\n%s", got, want)
1582 func TestStdlibSelfImports(t *testing.T) {
1583 const input = `package ecdsa
1585 var _ = ecdsa.GenerateKey
1589 module: packagestest.Module{
1590 Name: "ignored.com",
1591 Files: fm{"x.go": "package x"},
1593 }.test(t, func(t *goimportTest) {
1594 got, err := t.processNonModule(filepath.Join(t.goroot, "src/crypto/ecdsa/foo.go"), []byte(input), nil)
1596 t.Fatalf("Process() = %v", err)
1598 if string(got) != input {
1599 t.Errorf("Got:\n%s\nWant:\n%s", got, input)
1604 type testConfig struct {
1606 module packagestest.Module
1607 modules []packagestest.Module
1610 // fm is the type for a packagestest.Module's Files, abbreviated for shorter lines.
1611 type fm map[string]interface{}
1613 func (c testConfig) test(t *testing.T, fn func(*goimportTest)) {
1616 if c.module.Name != "" {
1617 c.modules = []packagestest.Module{c.module}
1620 for _, exporter := range packagestest.All {
1621 t.Run(exporter.Name(), func(t *testing.T) {
1623 if c.gopathOnly && exporter.Name() == "Modules" {
1624 t.Skip("test marked GOPATH-only")
1626 exported := packagestest.Export(t, exporter, c.modules)
1627 defer exported.Cleanup()
1629 env := map[string]string{}
1630 for _, kv := range exported.Config.Env {
1631 split := strings.SplitN(kv, "=", 2)
1632 env[split[0]] = split[1]
1634 it := &goimportTest{
1638 WorkingDir: exported.Config.Dir,
1639 GocmdRunner: &gocommand.Runner{},
1644 it.env.Logf = log.Printf
1646 // packagestest clears out GOROOT to work around golang/go#32849,
1647 // which isn't relevant here. Fill it back in so we can find the standard library.
1648 it.env.Env["GOROOT"] = build.Default.GOROOT
1649 it.goroot = build.Default.GOROOT
1656 func (c testConfig) processTest(t *testing.T, module, file string, contents []byte, opts *Options, want string) {
1658 c.test(t, func(t *goimportTest) {
1660 t.assertProcessEquals(module, file, contents, opts, want)
1664 type goimportTest struct {
1668 exported *packagestest.Exported
1671 func (t *goimportTest) process(module, file string, contents []byte, opts *Options) ([]byte, error) {
1673 f := t.exported.File(module, file)
1675 t.Fatalf("%v not found in exported files (typo in filename?)", file)
1677 return t.processNonModule(f, contents, opts)
1680 func (t *goimportTest) processNonModule(file string, contents []byte, opts *Options) ([]byte, error) {
1681 if contents == nil {
1683 contents, err = ioutil.ReadFile(file)
1689 opts = &Options{Comments: true, TabIndent: true, TabWidth: 8}
1691 // ProcessEnv is not safe for concurrent use. Make a copy.
1692 opts.Env = t.env.CopyConfig()
1693 return Process(file, contents, opts)
1696 func (t *goimportTest) assertProcessEquals(module, file string, contents []byte, opts *Options, want string) {
1697 buf, err := t.process(module, file, contents, opts)
1699 t.Fatalf("Process() = %v", err)
1701 if string(buf) != want {
1702 t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
1706 // Tests that added imports are renamed when the import path's base doesn't
1707 // match its package name.
1708 func TestRenameWhenPackageNameMismatch(t *testing.T) {
1709 const input = `package main
1712 const want = `package main
1714 import bar "foo.com/foo/bar/baz"
1719 module: packagestest.Module{
1722 "foo/bar/baz/x.go": "package bar \n const X = 1",
1726 }.processTest(t, "foo.com", "test/t.go", nil, nil, want)
1729 // Tests that an existing import with badly mismatched path/name has its name
1730 // correctly added. See #28645 and #29041.
1731 func TestAddNameToMismatchedImport(t *testing.T) {
1732 const input = `package main
1744 var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}`
1746 const want = `package main
1751 gow "foo.com/go-wrong"
1752 v2 "foo.com/other/v2"
1754 bar "foo.com/surprise"
1758 var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}
1762 module: packagestest.Module{
1765 "a.thing/a.go": "package a \n const A = 1",
1766 "surprise/x.go": "package bar \n const X = 1",
1767 "v1/x.go": "package v1 \n const Y = 1",
1768 "other/v2/y.go": "package v2 \n const V2 = 1",
1769 "other/v3/z.go": "package other \n const V3 = 1",
1770 "go-thing/b.go": "package thing \n const Thing = 1",
1771 "go-wrong/b.go": "package gow \n const Wrong = 1",
1775 }.processTest(t, "foo.com", "test/t.go", nil, nil, want)
1778 // Tests that the LocalPrefix option causes imports
1779 // to be added into a later group (num=3).
1780 func TestLocalPrefix(t *testing.T) {
1783 modules []packagestest.Module
1790 modules: []packagestest.Module{
1794 "bar/bar.go": "package bar \n const X = 1",
1798 localPrefix: "foo.com/",
1799 src: "package main \n const Y = bar.X \n const _ = runtime.GOOS",
1809 const _ = runtime.GOOS
1814 modules: []packagestest.Module{
1818 "foo/foo.go": "package foo \n const X = 1",
1819 "foo/bar/bar.go": "package bar \n const X = 1",
1823 localPrefix: "foo.com/foo",
1824 src: "package main \n const Y = bar.X \n const Z = foo.X \n const _ = runtime.GOOS",
1836 const _ = runtime.GOOS
1840 name: "three_prefixes",
1841 modules: []packagestest.Module{
1843 Name: "example.org/pkg",
1844 Files: fm{"pkg.go": "package pkg \n const A = 1"},
1848 Files: fm{"bar/bar.go": "package bar \n const B = 1"},
1851 Name: "code.org/r/p",
1852 Files: fm{"expproj/expproj.go": "package expproj \n const C = 1"},
1855 localPrefix: "example.org/pkg,foo.com/,code.org",
1856 src: "package main \n const X = pkg.A \n const Y = bar.B \n const Z = expproj.C \n const _ = runtime.GOOS",
1862 "code.org/r/p/expproj"
1870 const _ = runtime.GOOS
1875 for _, tt := range tests {
1876 t.Run(tt.name, func(t *testing.T) {
1878 // The module being processed has to be first so it's the primary module.
1879 modules: append([]packagestest.Module{{
1881 Files: fm{"t.go": tt.src},
1883 }.test(t, func(t *goimportTest) {
1884 options := &Options{
1885 LocalPrefix: tt.localPrefix,
1891 t.assertProcessEquals("test.com", "t.go", nil, options, tt.want)
1897 // Tests that "package documentation" files are ignored.
1898 func TestIgnoreDocumentationPackage(t *testing.T) {
1899 const input = `package x
1903 const want = `package x
1905 import "foo.com/foo"
1911 module: packagestest.Module{
1914 "foo/foo.go": "package foo\nconst X = 1\n",
1915 "foo/doc.go": "package documentation \n // just to confuse things\n",
1919 }.processTest(t, "foo.com", "x/x.go", nil, nil, want)
1922 // Tests importPathToNameGoPathParse and in particular that it stops
1923 // after finding the first non-documentation package name, not
1924 // reporting an error on inconsistent package names (since it should
1925 // never make it that far).
1926 func TestImportPathToNameGoPathParse(t *testing.T) {
1928 module: packagestest.Module{
1929 Name: "example.net/pkg",
1931 "doc.go": "package documentation\n", // ignored
1932 "gen.go": "package main\n", // also ignored
1933 "pkg.go": "package the_pkg_name_to_find\n and this syntax error is ignored because of parser.PackageClauseOnly",
1934 "z.go": "package inconsistent\n", // inconsistent but ignored
1937 }.test(t, func(t *goimportTest) {
1938 if strings.Contains(t.Name(), "GoPackages") {
1939 t.Skip("go/packages does not ignore package main")
1941 r, err := t.env.GetResolver()
1945 srcDir := filepath.Dir(t.exported.File("example.net/pkg", "z.go"))
1946 names, err := r.loadPackageNames([]string{"example.net/pkg"}, srcDir)
1950 const want = "the_pkg_name_to_find"
1951 if got := names["example.net/pkg"]; got != want {
1952 t.Errorf("loadPackageNames(..) = %q; want %q", got, want)
1957 func TestIgnoreConfiguration(t *testing.T) {
1958 const input = `package x
1962 const want = `package x
1964 import "foo.com/otherwise-longer-so-worse-example/foo/pkg"
1971 module: packagestest.Module{
1974 "../.goimportsignore": "# comment line\n\n foo.com/example", // tests comment, blank line, whitespace trimming
1975 "example/pkg/pkg.go": "package pkg\nconst X = 1",
1976 "otherwise-longer-so-worse-example/foo/pkg/pkg.go": "package pkg\nconst X = 1",
1980 }.processTest(t, "foo.com", "x/x.go", nil, nil, want)
1983 // Skip "node_modules" directory.
1984 func TestSkipNodeModules(t *testing.T) {
1985 const input = `package x
1989 const want = `package x
1991 import "foo.com/otherwise-longer/not_modules/pkg"
1998 module: packagestest.Module{
2001 "example/node_modules/pkg/a.go": "package pkg\nconst X = 1",
2002 "otherwise-longer/not_modules/pkg/a.go": "package pkg\nconst X = 1",
2006 }.processTest(t, "foo.com", "x/x.go", nil, nil, want)
2009 // Tests that package global variables with the same name and function name as
2010 // a function in a separate package do not result in an import which masks
2011 // the global variable
2012 func TestGlobalImports(t *testing.T) {
2013 const usesGlobal = `package pkg
2015 func doSomething() {
2020 const declaresGlobal = `package pkg
2024 func (t Time) Now() Time {
2032 module: packagestest.Module{
2035 "pkg/uses.go": usesGlobal,
2036 "pkg/global.go": declaresGlobal,
2039 }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, usesGlobal)
2042 // Some people put multiple packages' files in the same directory. Globals
2043 // declared in other packages should be ignored.
2044 func TestGlobalImports_DifferentPackage(t *testing.T) {
2045 const declaresGlobal = `package main
2048 const input = `package pkg
2051 const want = `package pkg
2059 module: packagestest.Module{
2062 "pkg/main.go": declaresGlobal,
2063 "pkg/uses.go": input,
2066 }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
2069 func TestGlobalImports_MultipleMains(t *testing.T) {
2070 const declaresGlobal = `package main
2073 const input = `package main
2075 var _, _ = fmt.Printf, bytes.Equal
2077 const want = `package main
2084 var _, _ = fmt.Printf, bytes.Equal
2088 module: packagestest.Module{
2091 "pkg/main.go": declaresGlobal,
2092 "pkg/uses.go": input,
2095 }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
2098 // Tests that sibling files - other files in the same package - can provide an
2099 // import that may not be the default one otherwise.
2100 func TestSiblingImports(t *testing.T) {
2102 // provide is the sibling file that provides the desired import.
2103 const provide = `package siblingimporttest
2107 import renamed "fmt"
2109 func LogSomething() {
2110 log.Print("Something")
2112 renamed.Println("Something")
2116 // need is the file being tested that needs the import.
2117 const need = `package siblingimporttest
2119 var _ = bytes.Buffer{}
2121 func LogSomethingElse() {
2122 log.Print("Something else")
2123 renamed.Println("Yet another")
2127 // want is the expected result file
2128 const want = `package siblingimporttest
2136 var _ = bytes.Buffer{}
2138 func LogSomethingElse() {
2139 log.Print("Something else")
2140 renamed.Println("Yet another")
2145 module: packagestest.Module{
2148 "p/needs_import.go": need,
2149 "p/provides_import.go": provide,
2152 }.processTest(t, "foo.com", "p/needs_import.go", nil, nil, want)
2155 // Tests #29180: a sibling import of the right package with the wrong name is used.
2156 func TestSiblingImport_Misnamed(t *testing.T) {
2157 const sibling = `package main
2158 import renamed "fmt"
2159 var _ = renamed.Printf
2161 const input = `package pkg
2164 const want = `package pkg
2172 module: packagestest.Module{
2175 "pkg/main.go": sibling,
2176 "pkg/uses.go": input,
2179 }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
2183 // Tests that an input file's own package is ignored.
2184 func TestIgnoreOwnPackage(t *testing.T) {
2185 const input = `package pkg
2189 const want = `package pkg
2195 module: packagestest.Module{
2198 "pkg/a.go": "package pkg\nconst X = 1",
2202 }.processTest(t, "foo.com", "pkg/b.go", nil, nil, want)
2205 func TestExternalTestImportsPackageUnderTest(t *testing.T) {
2206 const provide = `package pkg
2209 const input = `package pkg_test
2213 const want = `package pkg_test
2215 import "foo.com/pkg"
2221 module: packagestest.Module{
2224 "pkg/provide.go": provide,
2225 "pkg/x_test.go": input,
2228 }.processTest(t, "foo.com", "pkg/x_test.go", nil, nil, want)
2231 func TestPkgIsCandidate(t *testing.T) {
2240 name: "normal_match",
2241 filename: "/gopath/src/my/pkg/pkg.go",
2244 dir: "/gopath/src/client",
2245 importPathShort: "client",
2251 filename: "/gopath/src/my/pkg/pkg.go",
2254 dir: "/gopath/src/client",
2255 importPathShort: "client",
2260 name: "match_too_early",
2261 filename: "/gopath/src/my/pkg/pkg.go",
2264 dir: "/gopath/src/client/foo/foo/foo",
2265 importPathShort: "client/foo/foo",
2270 name: "substring_match",
2271 filename: "/gopath/src/my/pkg/pkg.go",
2274 dir: "/gopath/src/foo/go-client",
2275 importPathShort: "foo/go-client",
2280 name: "hidden_internal",
2281 filename: "/gopath/src/my/pkg/pkg.go",
2284 dir: "/gopath/src/foo/internal/client",
2285 importPathShort: "foo/internal/client",
2290 name: "visible_internal",
2291 filename: "/gopath/src/foo/bar.go",
2294 dir: "/gopath/src/foo/internal/client",
2295 importPathShort: "foo/internal/client",
2300 name: "invisible_vendor",
2301 filename: "/gopath/src/foo/bar.go",
2304 dir: "/gopath/src/other/vendor/client",
2305 importPathShort: "client",
2310 name: "visible_vendor",
2311 filename: "/gopath/src/foo/bar.go",
2314 dir: "/gopath/src/foo/vendor/client",
2315 importPathShort: "client",
2320 name: "match_with_hyphens",
2321 filename: "/gopath/src/foo/bar.go",
2322 pkgIdent: "socketio",
2324 dir: "/gopath/src/foo/socket-io",
2325 importPathShort: "foo/socket-io",
2330 name: "match_with_mixed_case",
2331 filename: "/gopath/src/foo/bar.go",
2332 pkgIdent: "fooprod",
2334 dir: "/gopath/src/foo/FooPROD",
2335 importPathShort: "foo/FooPROD",
2340 name: "matches_with_hyphen_and_caps",
2341 filename: "/gopath/src/foo/bar.go",
2342 pkgIdent: "fooprod",
2344 dir: "/gopath/src/foo/Foo-PROD",
2345 importPathShort: "foo/Foo-PROD",
2350 for i, tt := range tests {
2351 t.Run(tt.name, func(t *testing.T) {
2352 refs := references{tt.pkgIdent: nil}
2353 got := pkgIsCandidate(tt.filename, refs, tt.pkg)
2355 t.Errorf("test %d. pkgIsCandidate(%q, %q, %+v) = %v; want %v",
2356 i, tt.filename, tt.pkgIdent, *tt.pkg, got, tt.want)
2362 // Issue 20941: this used to panic on Windows.
2363 func TestProcessStdin(t *testing.T) {
2365 module: packagestest.Module{
2368 }.test(t, func(t *goimportTest) {
2369 got, err := t.processNonModule("<standard input>", []byte("package main\nfunc main() {\n\tfmt.Println(123)\n}\n"), nil)
2373 if !strings.Contains(string(got), `"fmt"`) {
2374 t.Errorf("expected fmt import; got: %s", got)
2379 // Tests LocalPackagePromotion when there is a local package that matches, it
2380 // should be the closest match.
2381 // https://golang.org/issues/17557
2382 func TestLocalPackagePromotion(t *testing.T) {
2383 const input = `package main
2384 var c = &config.SystemConfig{}
2386 const want = `package main
2388 import "mycompany.net/tool/config"
2390 var c = &config.SystemConfig{}
2394 modules: []packagestest.Module{
2396 Name: "config.net/config",
2397 Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
2400 Name: "mycompany.net/config",
2401 Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
2404 Name: "mycompany.net/tool",
2406 "config/config.go": "package config\n type SystemConfig struct {}", // Local package should be promoted over shorter package
2411 }.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
2414 // Tests FindImportInLocalGoFiles looks at the import lines for other Go files in the
2415 // local directory, since the user is likely to import the same packages in the current
2416 // Go file. If an import is found that satisfies the need, it should be used over the
2417 // standard library.
2418 // https://golang.org/issues/17557
2419 func TestFindImportInLocalGoFiles(t *testing.T) {
2420 const input = `package main
2421 var _ = &bytes.Buffer{}`
2423 const want = `package main
2425 import "bytes.net/bytes"
2427 var _ = &bytes.Buffer{}
2430 modules: []packagestest.Module{
2432 Name: "mycompany.net/tool",
2434 "io.go": "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored
2439 Name: "bytes.net/bytes",
2440 Files: fm{"bytes.go": "package bytes\n type Buffer struct {}"}, // Should be selected over standard library
2443 }.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
2446 func TestInMemoryFile(t *testing.T) {
2447 const input = `package main
2448 var _ = &bytes.Buffer{}`
2450 const want = `package main
2454 var _ = &bytes.Buffer{}
2457 module: packagestest.Module{
2459 Files: fm{"x.go": "package x\n"},
2461 }.processTest(t, "foo.com", "x.go", []byte(input), nil, want)
2464 func TestImportNoGoFiles(t *testing.T) {
2465 const input = `package main
2466 var _ = &bytes.Buffer{}`
2468 const want = `package main
2472 var _ = &bytes.Buffer{}
2475 module: packagestest.Module{
2476 Name: "mycompany.net",
2478 }.test(t, func(t *goimportTest) {
2479 buf, err := t.processNonModule("mycompany.net/tool/main.go", []byte(input), nil)
2481 t.Fatalf("Process() = %v", err)
2483 if string(buf) != want {
2484 t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
2490 // Ensures a token as large as 500000 bytes can be handled
2491 // https://golang.org/issues/18201
2492 func TestProcessLargeToken(t *testing.T) {
2493 largeString := strings.Repeat("x", 500000)
2495 input := `package testimports
2501 const s = fmt.Sprintf("%s", "` + largeString + `")
2502 var _ = bytes.Buffer{}
2507 want := `package testimports
2514 const s = fmt.Sprintf("%s", "` + largeString + `")
2516 var _ = bytes.Buffer{}
2522 module: packagestest.Module{
2524 Files: fm{"foo.go": input},
2526 }.processTest(t, "foo.com", "foo.go", nil, nil, want)
2529 // Tests that an external test package will import the package under test if it
2530 // also uses symbols exported only in test files.
2531 // https://golang.org/issues/29979
2532 func TestExternalTest(t *testing.T) {
2533 const input = `package a_test
2539 const want = `package a_test
2550 modules: []packagestest.Module{
2554 "a.go": "package a\n func X() {}",
2555 "export_test.go": "package a\n func Y() {}",
2560 }.processTest(t, "foo.com/a", "a_test.go", nil, nil, want)
2563 // TestGetCandidates tests that get packages finds packages
2564 // with correct priorities.
2565 func TestGetCandidates(t *testing.T) {
2571 {0, "bytes", "bytes"},
2572 {0, "http", "net/http"},
2573 {0, "rand", "crypto/rand"},
2574 {0, "bar", "bar.com/bar"},
2575 {0, "foo", "foo.com/foo"},
2579 modules: []packagestest.Module{
2582 Files: fm{"bar/bar.go": "package bar\n"},
2586 Files: fm{"foo/foo.go": "package foo\n"},
2589 }.test(t, func(t *goimportTest) {
2592 add := func(c ImportFix) {
2595 for _, w := range want {
2596 if c.StmtInfo.ImportPath == w.path {
2597 got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
2601 if err := GetAllCandidates(context.Background(), add, "", "x.go", "x", t.env); err != nil {
2602 t.Fatalf("GetAllCandidates() = %v", err)
2604 // Sort, then clear out relevance so it doesn't mess up the DeepEqual.
2605 sort.Slice(got, func(i, j int) bool {
2606 ri, rj := got[i], got[j]
2607 if ri.relevance != rj.relevance {
2608 return ri.relevance > rj.relevance // Highest first.
2610 return ri.name < rj.name
2612 for i := range got {
2613 got[i].relevance = 0
2615 if !reflect.DeepEqual(want, got) {
2616 t.Errorf("wanted results in order %v, got %v", want, got)
2621 func TestGetImportPaths(t *testing.T) {
2627 {0, "http", "net/http"},
2629 {0, "neta", "neta.com/neta"},
2633 modules: []packagestest.Module{
2636 Files: fm{"neta/neta.go": "package neta\n"},
2639 }.test(t, func(t *goimportTest) {
2642 add := func(c ImportFix) {
2645 for _, w := range want {
2646 if c.StmtInfo.ImportPath == w.path {
2647 got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
2651 if err := GetImportPaths(context.Background(), add, "ne", "x.go", "x", t.env); err != nil {
2652 t.Fatalf("GetImportPaths() = %v", err)
2654 // Sort, then clear out relevance so it doesn't mess up the DeepEqual.
2655 sort.Slice(got, func(i, j int) bool {
2656 ri, rj := got[i], got[j]
2657 if ri.relevance != rj.relevance {
2658 return ri.relevance > rj.relevance // Highest first.
2660 return ri.name < rj.name
2662 for i := range got {
2663 got[i].relevance = 0
2665 if !reflect.DeepEqual(want, got) {
2666 t.Errorf("wanted results in order %v, got %v", want, got)
2671 func TestGetPackageCompletions(t *testing.T) {
2674 name, path, symbol string
2677 {0, "rand", "math/rand", "Seed"},
2678 {0, "rand", "bar.com/rand", "Bar"},
2682 modules: []packagestest.Module{
2685 Files: fm{"rand/bar.go": "package rand\nvar Bar int\n"},
2688 }.test(t, func(t *goimportTest) {
2691 add := func(c PackageExport) {
2694 for _, csym := range c.Exports {
2695 for _, w := range want {
2696 if c.Fix.StmtInfo.ImportPath == w.path && csym == w.symbol {
2697 got = append(got, res{c.Fix.Relevance, c.Fix.IdentName, c.Fix.StmtInfo.ImportPath, csym})
2702 if err := GetPackageExports(context.Background(), add, "rand", "x.go", "x", t.env); err != nil {
2703 t.Fatalf("getPackageCompletions() = %v", err)
2705 // Sort, then clear out relevance so it doesn't mess up the DeepEqual.
2706 sort.Slice(got, func(i, j int) bool {
2707 ri, rj := got[i], got[j]
2708 if ri.relevance != rj.relevance {
2709 return ri.relevance > rj.relevance // Highest first.
2711 return ri.name < rj.name
2713 for i := range got {
2714 got[i].relevance = 0
2716 if !reflect.DeepEqual(want, got) {
2717 t.Errorf("wanted results in order %v, got %v", want, got)
2722 // Tests #34895: process should not panic on concurrent calls.
2723 func TestConcurrentProcess(t *testing.T) {
2725 module: packagestest.Module{
2728 "p/first.go": `package foo
2734 "p/second.go": `package foo
2740 imports.Bar() // not imported.
2745 }.test(t, func(t *goimportTest) {
2751 for i := 0; i < n; i++ {
2754 _, err := t.process("foo.com", "p/first.go", nil, nil)
2764 func TestNonlocalDot(t *testing.T) {
2765 const input = `package main
2769 var _, _ = fmt.Sprintf, dot.Dot
2771 const want = `package main
2775 "noninternet/dot.v1/dot"
2778 var _, _ = fmt.Sprintf, dot.Dot
2781 modules: []packagestest.Module{
2783 Name: "golang.org/fake",
2784 Files: fm{"x.go": input},
2787 Name: "noninternet/dot.v1",
2789 "dot/dot.go": "package dot\nfunc Dot(){}\n",
2793 gopathOnly: true, // our modules testing setup doesn't allow modules without dots.
2794 }.processTest(t, "golang.org/fake", "x.go", nil, nil, want)