imports: make tests compatible with modules

Tweak the goimports tests to be more module-compatible. This should be
the last big change to the tests; they all pass with the new
implementation.

The primary change is to avoid using packages not provided by the test's
modules. Other modules will be downloaded at test time, which is
nonhermetic and quite slow.

Other miscellanea:

- The appengine grouping tests have to be split out so
they can be GOPATH-only, because modules have to have dots in their
names.
- The tests for .goimportsignore and node_modules are GOPATH-only
because we decided not to include those behaviors in go/packages in
module mode.
- Some vendoring tests are GOPATH-only because vendoring is not a thing
in module mode.
- TestFindImportInLocalGoFiles changes content, because the existing
test was incorrect: bogus.net/bytes was a viable candidate even though
it isn't on disk. I'm not sure why it wasn't flaky.

Change-Id: I35a3aac92d3fb7f70a1a8f027f0b423282420a4d
Reviewed-on: https://go-review.googlesource.com/c/145138
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Heschi Kreinick 2018-10-26 14:54:05 -04:00
parent 00c5fa5868
commit a0a13e073c

View File

@ -55,11 +55,11 @@ func bar() {
import ( import (
"fmt" "fmt"
"appengine" "github.com/golang/snappy"
) )
func bar() { func bar() {
var b bytes.Buffer var b bytes.Buffer
_ = appengine.IsDevServer _ = snappy.ErrCorrupt
fmt.Println(b.String()) fmt.Println(b.String())
} }
`, `,
@ -69,12 +69,12 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"appengine" "github.com/golang/snappy"
) )
func bar() { func bar() {
var b bytes.Buffer var b bytes.Buffer
_ = appengine.IsDevServer _ = snappy.ErrCorrupt
fmt.Println(b.String()) fmt.Println(b.String())
} }
`, `,
@ -88,12 +88,12 @@ func bar() {
import ( import (
"fmt" "fmt"
"appengine" "github.com/golang/snappy"
) )
func bar() { func bar() {
_ = math.NaN _ = math.NaN
_ = fmt.Sprintf _ = fmt.Sprintf
_ = appengine.IsDevServer _ = snappy.ErrCorrupt
} }
`, `,
out: `package foo out: `package foo
@ -102,13 +102,13 @@ import (
"fmt" "fmt"
"math" "math"
"appengine" "github.com/golang/snappy"
) )
func bar() { func bar() {
_ = math.NaN _ = math.NaN
_ = fmt.Sprintf _ = fmt.Sprintf
_ = appengine.IsDevServer _ = snappy.ErrCorrupt
} }
`, `,
}, },
@ -352,7 +352,7 @@ import (
func foo () { func foo () {
_, _ = os.Args, fmt.Println _, _ = os.Args, fmt.Println
_, _ = appengine.Main, datastore.ErrInvalidEntityType _, _ = snappy.ErrCorrupt, p.P
} }
`, `,
out: `package foo out: `package foo
@ -361,13 +361,13 @@ import (
"fmt" "fmt"
"os" "os"
"appengine" "github.com/golang/snappy"
"appengine/datastore" "rsc.io/p"
) )
func foo() { func foo() {
_, _ = os.Args, fmt.Println _, _ = os.Args, fmt.Println
_, _ = appengine.Main, datastore.ErrInvalidEntityType _, _ = snappy.ErrCorrupt, p.P
} }
`, `,
}, },
@ -426,7 +426,7 @@ import (
"fmt" "fmt"
"net" "net"
"code.google.com/p/snappy-go/snappy" "github.com/golang/snappy"
) )
func f() { func f() {
@ -443,7 +443,7 @@ func f() {
in: `package foo in: `package foo
import ( import (
"code.google.com/p/snappy-go/snappy" "github.com/golang/snappy"
"fmt" "fmt"
"net" "net"
) )
@ -460,7 +460,7 @@ import (
"fmt" "fmt"
"net" "net"
"code.google.com/p/snappy-go/snappy" "github.com/golang/snappy"
) )
func f() { func f() {
@ -501,12 +501,12 @@ import (
"fmt" "fmt"
"gu" "gu"
"github.com/foo/bar" "manypackages.com/packagea"
) )
var ( var (
a = bar.a a = packagea.A
b = gu.a b = gu.A
c = fmt.Printf c = fmt.Printf
) )
`, `,
@ -517,12 +517,12 @@ import (
"gu" "gu"
"github.com/foo/bar" "manypackages.com/packagea"
) )
var ( var (
a = bar.a a = packagea.A
b = gu.a b = gu.A
c = fmt.Printf c = fmt.Printf
) )
`, `,
@ -556,14 +556,14 @@ func notmain() { fmt.Println("Hello, world") }`,
import ( import (
"fmt" "fmt"
"github.com/foo/bar" "manypackages.com/packagea"
"github.com/foo/qux" "manypackages.com/packageb"
) )
func main() { func main() {
var _ = fmt.Println var _ = fmt.Println
//var _ = bar.A //var _ = packagea.A
var _ = qux.B var _ = packageb.B
} }
`, `,
out: `package main out: `package main
@ -571,13 +571,13 @@ func main() {
import ( import (
"fmt" "fmt"
"github.com/foo/qux" "manypackages.com/packageb"
) )
func main() { func main() {
var _ = fmt.Println var _ = fmt.Println
//var _ = bar.A //var _ = packagea.A
var _ = qux.B var _ = packageb.B
} }
`, `,
}, },
@ -590,34 +590,34 @@ func main() {
import ( import (
"fmt" "fmt"
renamed_bar "github.com/foo/bar" renamed_packagea "manypackages.com/packagea"
. "github.com/foo/baz" . "manypackages.com/packageb"
"io" "io"
_ "github.com/foo/qux" _ "manypackages.com/packagec"
"strings" "strings"
) )
var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
`, `,
out: `package main out: `package main
import ( import (
"fmt" "fmt"
renamed_bar "github.com/foo/bar" renamed_packagea "manypackages.com/packagea"
"io" "io"
. "github.com/foo/baz" . "manypackages.com/packageb"
"strings" "strings"
_ "github.com/foo/qux" _ "manypackages.com/packagec"
) )
var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
`, `,
}, },
@ -630,7 +630,7 @@ var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B
import ( import (
"fmt" // A "fmt" // A
"go/ast" // B "go/ast" // B
_ "launchpad.net/gocheck" // C _ "manypackages.com/packagec" // C
) )
func main() { _, _ = fmt.Print, ast.Walk } func main() { _, _ = fmt.Print, ast.Walk }
@ -641,7 +641,7 @@ import (
"fmt" // A "fmt" // A
"go/ast" // B "go/ast" // B
_ "launchpad.net/gocheck" // C _ "manypackages.com/packagec" // C
) )
func main() { _, _ = fmt.Print, ast.Walk } func main() { _, _ = fmt.Print, ast.Walk }
@ -761,7 +761,7 @@ func main() { fmt.Println() }
import ( import (
"fmt" "fmt"
"golang.org/x/foo" "manypackages.com/packagea"
) )
func main() {} func main() {}
@ -771,7 +771,7 @@ func main() {}
import ( import (
"fmt" "fmt"
"golang.org/x/foo" "manypackages.com/packagea"
) )
func main() {} func main() {}
@ -818,7 +818,7 @@ func main() {
import ( import (
"time" "time"
"code.google.com/p/snappy-go/snappy" "github.com/golang/snappy"
"rsc.io/p" "rsc.io/p"
) )
@ -837,7 +837,7 @@ func main() {
import ( import (
"time" "time"
"code.google.com/p/snappy-go/snappy" "github.com/golang/snappy"
) )
func main() { func main() {
@ -851,7 +851,7 @@ func main() {
import ( import (
"time" "time"
"code.google.com/p/snappy-go/snappy" "github.com/golang/snappy"
"rsc.io/p" "rsc.io/p"
) )
@ -863,8 +863,9 @@ func main() {
`, `,
}, },
// golang.org/issue/12097
{ {
name: "issue #12097", name: "package_statement_insertion_preserves_comments",
in: `// a in: `// a
// b // b
// c // c
@ -980,7 +981,7 @@ import (
_ "net/http/pprof" // install the pprof http handlers _ "net/http/pprof" // install the pprof http handlers
"strings" "strings"
"github.com/pkg/errors" "manypackages.com/packagea"
) )
func main() { func main() {
@ -989,7 +990,7 @@ func main() {
var ( var (
_ json.Number _ json.Number
_ *http.Request _ *http.Request
_ errors.Frame _ packagea.A
) )
} }
`, `,
@ -1002,7 +1003,7 @@ import (
_ "net/http/pprof" // install the pprof http handlers _ "net/http/pprof" // install the pprof http handlers
"strings" "strings"
"github.com/pkg/errors" "manypackages.com/packagea"
) )
func main() { func main() {
@ -1011,7 +1012,7 @@ func main() {
var ( var (
_ json.Number _ json.Number
_ *http.Request _ *http.Request
_ errors.Frame _ packagea.A
) )
} }
`, `,
@ -1108,7 +1109,7 @@ var _, _ = rand.Read, rand.NewZipf
func TestSimpleCases(t *testing.T) { func TestSimpleCases(t *testing.T) {
defer func(lp string) { LocalPrefix = lp }(LocalPrefix) defer func(lp string) { LocalPrefix = lp }(LocalPrefix)
LocalPrefix = "local,github.com/local" LocalPrefix = "local.com,github.com/local"
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
options := &Options{ options := &Options{
@ -1119,28 +1120,39 @@ func TestSimpleCases(t *testing.T) {
FormatOnly: tt.formatOnly, FormatOnly: tt.formatOnly,
} }
testConfig{ testConfig{
// Skeleton non-stdlib packages for use during testing.
// Each includes one arbitrary symbol, e.g. the first declaration in the first file.
// Try not to add more without a good reason.
modules: []packagestest.Module{ modules: []packagestest.Module{
{ {
Name: "appengine", Name: "golang.org/fake",
Files: fm{ Files: fm{"x.go": tt.in},
"x.go": "package appengine\nfunc Main(){}\n",
"datastore/x.go": "package datastore\nvar ErrInvalidEntityType error\n",
},
}, },
// Skeleton non-stdlib packages for use during testing.
// Each includes one arbitrary symbol, e.g. the first declaration in the first file.
// Try not to add more without a good reason.
// DO NOT USE PACKAGES NOT LISTED HERE -- they will be downloaded!
{ {
Name: "rsc.io", Name: "rsc.io",
Files: fm{"p/x.go": "package p\nfunc P(){}\n"}, Files: fm{"p/x.go": "package p\nfunc P(){}\n"},
}, },
{ {
Name: "code.google.com/p/snappy-go", Name: "github.com/golang/snappy",
Files: fm{"snappy/x.go": "package snappy\nvar ErrCorrupt error\n"}, Files: fm{"x.go": "package snappy\nvar ErrCorrupt error\n"},
}, },
{ {
Name: "golang.org/fake", Name: "manypackages.com",
Files: fm{"x.go": tt.in}, Files: fm{
"packagea/x.go": "package packagea\nfunc A(){}\n",
"packageb/x.go": "package packageb\nfunc B(){}\n",
"packagec/x.go": "package packagec\nfunc C(){}\n",
"packaged/x.go": "package packaged\nfunc D(){}\n",
},
},
{
Name: "local.com",
Files: fm{"foo/x.go": "package foo\nfunc Foo(){}\n"},
},
{
Name: "github.com/local",
Files: fm{"bar/x.go": "package bar\nfunc Bar(){}\n"},
}, },
}, },
}.processTest(t, "golang.org/fake", "x.go", nil, options, tt.out) }.processTest(t, "golang.org/fake", "x.go", nil, options, tt.out)
@ -1148,6 +1160,42 @@ func TestSimpleCases(t *testing.T) {
} }
} }
func TestAppengine(t *testing.T) {
const input = `package p
var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
`
const want = `package p
import (
"fmt"
"appengine"
"appengine/datastore"
)
var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
`
testConfig{
gopathOnly: true, // can't create a module named appengine, so no module tests.
modules: []packagestest.Module{
{
Name: "golang.org/fake",
Files: fm{"x.go": input},
},
{
Name: "appengine",
Files: fm{
"x.go": "package appengine\nfunc Main(){}\n",
"datastore/x.go": "package datastore\nvar ErrInvalidEntityType error\n",
},
},
},
}.processTest(t, "golang.org/fake", "x.go", nil, nil, want)
}
func TestReadFromFilesystem(t *testing.T) { func TestReadFromFilesystem(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
@ -1271,6 +1319,7 @@ var (
` `
testConfig{ testConfig{
gopathOnly: true,
module: packagestest.Module{ module: packagestest.Module{
Name: "golang.org/fake", Name: "golang.org/fake",
Files: fm{ Files: fm{
@ -1327,6 +1376,7 @@ var (
) )
` `
testConfig{ testConfig{
gopathOnly: true,
module: packagestest.Module{ module: packagestest.Module{
Name: "mypkg.com/outpkg", Name: "mypkg.com/outpkg",
Files: fm{ Files: fm{
@ -1425,8 +1475,9 @@ func TestFindStdlib(t *testing.T) {
} }
type testConfig struct { type testConfig struct {
module packagestest.Module gopathOnly bool
modules []packagestest.Module module packagestest.Module
modules []packagestest.Module
} }
// fm is the type for a packagestest.Module's Files, abbreviated for shorter lines. // fm is the type for a packagestest.Module's Files, abbreviated for shorter lines.
@ -1440,72 +1491,68 @@ func (c testConfig) test(t *testing.T, fn func(*goimportTest)) {
c.modules = []packagestest.Module{c.module} c.modules = []packagestest.Module{c.module}
} }
exported = packagestest.Export(t, packagestest.GOPATH, c.modules) for _, exporter := range []packagestest.Exporter{packagestest.GOPATH} {
defer exported.Cleanup() t.Run(exporter.Name(), func(t *testing.T) {
t.Helper()
exported = packagestest.Export(t, exporter, c.modules)
defer exported.Cleanup()
env := make(map[string]string) env := make(map[string]string)
for _, kv := range exported.Config.Env { for _, kv := range exported.Config.Env {
split := strings.Split(kv, "=") split := strings.Split(kv, "=")
k, v := split[0], split[1] k, v := split[0], split[1]
env[k] = v env[k] = v
}
goroot := env["GOROOT"]
gopath := env["GOPATH"]
scanOnce = sync.Once{}
oldGOPATH := build.Default.GOPATH
oldGOROOT := build.Default.GOROOT
oldCompiler := build.Default.Compiler
build.Default.GOROOT = goroot
build.Default.GOPATH = gopath
build.Default.Compiler = "gc"
defer func() {
build.Default.GOPATH = oldGOPATH
build.Default.GOROOT = oldGOROOT
build.Default.Compiler = oldCompiler
}()
it := &goimportTest{
T: t,
gopath: gopath,
exported: exported,
}
fn(it)
})
} }
goroot := env["GOROOT"]
gopath := env["GOPATH"]
scanOnce = sync.Once{}
oldGOPATH := build.Default.GOPATH
oldGOROOT := build.Default.GOROOT
oldCompiler := build.Default.Compiler
build.Default.GOPATH = ""
build.Default.Compiler = "gc"
defer func() {
build.Default.GOPATH = oldGOPATH
build.Default.GOROOT = oldGOROOT
build.Default.Compiler = oldCompiler
}()
build.Default.GOROOT = goroot
build.Default.GOPATH = gopath
it := &goimportTest{
T: t,
goroot: build.Default.GOROOT,
gopath: gopath,
ctx: &build.Default,
exported: exported,
}
fn(it)
} }
func (c testConfig) processTest(t *testing.T, module, file string, contents []byte, opts *Options, want string) { func (c testConfig) processTest(t *testing.T, module, file string, contents []byte, opts *Options, want string) {
t.Helper() t.Helper()
c.test(t, func(t *goimportTest) { c.test(t, func(t *goimportTest) {
t.Helper() t.Helper()
f := t.exported.File(module, file) t.process(module, file, contents, opts, want)
if f == "" {
t.Fatalf("%v not found in exported files (typo in filename?)", file)
}
t.process(f, contents, opts, want)
}) })
} }
type goimportTest struct { type goimportTest struct {
*testing.T *testing.T
ctx *build.Context
goroot string
gopath string gopath string
exported *packagestest.Exported exported *packagestest.Exported
} }
func (t *goimportTest) process(file string, contents []byte, opts *Options, want string) { func (t *goimportTest) process(module, file string, contents []byte, opts *Options, want string) {
t.Helper() t.Helper()
if !filepath.IsAbs(file) { f := t.exported.File(module, file)
file = filepath.Join(t.gopath, "src", file) if f == "" {
t.Fatalf("%v not found in exported files (typo in filename?)", file)
} }
buf, err := Process(file, contents, opts) buf, err := Process(f, contents, opts)
if err != nil { if err != nil {
t.Fatalf("Process() = %v", err) t.Fatalf("Process() = %v", err)
} }
@ -1543,12 +1590,14 @@ const Y = bar.X
// to be added into a later group (num=3). // to be added into a later group (num=3).
func TestLocalPrefix(t *testing.T) { func TestLocalPrefix(t *testing.T) {
tests := []struct { tests := []struct {
name string
modules []packagestest.Module modules []packagestest.Module
localPrefix string localPrefix string
src string src string
want string want string
}{ }{
{ {
name: "one_local",
modules: []packagestest.Module{ modules: []packagestest.Module{
{ {
Name: "foo.com", Name: "foo.com",
@ -1572,6 +1621,7 @@ const _ = runtime.GOOS
`, `,
}, },
{ {
name: "two_local",
modules: []packagestest.Module{ modules: []packagestest.Module{
{ {
Name: "foo.com", Name: "foo.com",
@ -1598,6 +1648,7 @@ const _ = runtime.GOOS
`, `,
}, },
{ {
name: "three_prefixes",
modules: []packagestest.Module{ modules: []packagestest.Module{
{ {
Name: "example.org/pkg", Name: "example.org/pkg",
@ -1633,12 +1684,18 @@ const _ = runtime.GOOS
} }
for _, tt := range tests { for _, tt := range tests {
testConfig{ t.Run(tt.name, func(t *testing.T) {
modules: tt.modules, testConfig{
}.test(t, func(t *goimportTest) { // The module being processed has to be first so it's the primary module.
defer func(s string) { LocalPrefix = s }(LocalPrefix) modules: append([]packagestest.Module{{
LocalPrefix = tt.localPrefix Name: "test.com",
t.process("test/t.go", []byte(tt.src), nil, tt.want) Files: fm{"t.go": tt.src},
}}, tt.modules...),
}.test(t, func(t *goimportTest) {
defer func(s string) { LocalPrefix = s }(LocalPrefix)
LocalPrefix = tt.localPrefix
t.process("test.com", "t.go", nil, nil, tt.want)
})
}) })
} }
} }
@ -1674,6 +1731,7 @@ const Y = foo.X
// never make it that far). // never make it that far).
func TestImportPathToNameGoPathParse(t *testing.T) { func TestImportPathToNameGoPathParse(t *testing.T) {
testConfig{ testConfig{
gopathOnly: true,
module: packagestest.Module{ module: packagestest.Module{
Name: "example.net/pkg", Name: "example.net/pkg",
Files: fm{ Files: fm{
@ -1708,6 +1766,7 @@ const _ = pkg.X
` `
testConfig{ testConfig{
gopathOnly: true,
module: packagestest.Module{ module: packagestest.Module{
Name: "foo.com", Name: "foo.com",
Files: fm{ Files: fm{
@ -1734,6 +1793,7 @@ const _ = pkg.X
` `
testConfig{ testConfig{
gopathOnly: true,
module: packagestest.Module{ module: packagestest.Module{
Name: "foo.com", Name: "foo.com",
Files: fm{ Files: fm{
@ -2034,22 +2094,39 @@ var _ = &bytes.Buffer{}
` `
testConfig{ testConfig{
modules: []packagestest.Module{ modules: []packagestest.Module{
{
Name: "bytes.net/bytes",
Files: fm{"bytes.go": "package bytes\n type Buffer struct {}"}, // Should be selected over standard library
},
{ {
Name: "mycompany.net/tool", Name: "mycompany.net/tool",
Files: fm{ Files: fm{
"io.go": "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored "io.go": "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored
"err.go": "package main\n import \"bogus.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains import which is not resolved, so it is ignored
"main.go": input, "main.go": input,
}, },
}, },
{
Name: "bytes.net/bytes",
Files: fm{"bytes.go": "package bytes\n type Buffer struct {}"}, // Should be selected over standard library
},
}, },
}.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want) }.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
} }
func TestInMemoryFile(t *testing.T) {
const input = `package main
var _ = &bytes.Buffer{}`
const want = `package main
import "bytes"
var _ = &bytes.Buffer{}
`
testConfig{
module: packagestest.Module{
Name: "foo.com",
Files: fm{"x.go": "package x\n"},
},
}.processTest(t, "foo.com", "x.go", []byte(input), nil, want)
}
func TestImportNoGoFiles(t *testing.T) { func TestImportNoGoFiles(t *testing.T) {
const input = `package main const input = `package main
var _ = &bytes.Buffer{}` var _ = &bytes.Buffer{}`
@ -2078,12 +2155,11 @@ func TestProcessLargeToken(t *testing.T) {
input := `package testimports input := `package testimports
import ( import (
"fmt" "bytes"
"mydomain.mystuff/mypkg"
) )
const s = fmt.Sprintf("%s", "` + largeString + `") const s = fmt.Sprintf("%s", "` + largeString + `")
const x = mypkg.Sprintf("%s", "my package") var _ = bytes.Buffer{}
// end // end
` `
@ -2091,13 +2167,13 @@ const x = mypkg.Sprintf("%s", "my package")
want := `package testimports want := `package testimports
import ( import (
"bytes"
"fmt" "fmt"
"mydomain.mystuff/mypkg"
) )
const s = fmt.Sprintf("%s", "` + largeString + `") const s = fmt.Sprintf("%s", "` + largeString + `")
const x = mypkg.Sprintf("%s", "my package")
var _ = bytes.Buffer{}
// end // end
` `