Skip to content

Commit 2debfbe

Browse files
committed
internal/testfiles: add a helper package for test files
Adds a new package testfiles to help write tests around go files and directories. These are especially helpful when dealing with go.mod files. Adds a new CopyTestFiles function that copies a directory and removes the ".test" file extension, e.g. "go.mod.test" becomes "go.mod". This allows for easily creating analysistests with go.mod files. This change also adds a new TestDir helper to extract to a temporary directory. Consolidates txtar usage around ExtractTxtar, which writes a txtar archive to a directory, and adds a convenience helper TestTxtar that extracts a txtar at a path to a temporary directory. Updates golang/go#61336 Updates golang/go#53063 Updates golang/go#46041 Updates golang/go#37054 Change-Id: I09210f751bbc6ac3f01c34fba22b7e8fa1ddf93f Reviewed-on: https://go-review.googlesource.com/c/tools/+/577995 Reviewed-by: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent c17402c commit 2debfbe

File tree

14 files changed

+253
-142
lines changed

14 files changed

+253
-142
lines changed

go/analysis/analysistest/analysistest_test.go

+2-6
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,8 @@ import (
2020
)
2121

2222
func init() {
23-
// This test currently requires GOPATH mode.
24-
// Explicitly disabling module mode should suffice, but
25-
// we'll also turn off GOPROXY just for good measure.
26-
if err := os.Setenv("GO111MODULE", "off"); err != nil {
27-
log.Fatal(err)
28-
}
23+
// Run() decides when tests use GOPATH mode or modules.
24+
// We turn off GOPROXY just for good measure.
2925
if err := os.Setenv("GOPROXY", "off"); err != nil {
3026
log.Fatal(err)
3127
}

go/analysis/passes/loopclosure/loopclosure_test.go

+7-33
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
package loopclosure_test
66

77
import (
8-
"os"
98
"path/filepath"
109
"testing"
1110

12-
"golang.org/x/tools/go/analysis"
1311
"golang.org/x/tools/go/analysis/analysistest"
1412
"golang.org/x/tools/go/analysis/passes/loopclosure"
1513
"golang.org/x/tools/internal/testenv"
16-
"golang.org/x/tools/txtar"
14+
"golang.org/x/tools/internal/testfiles"
1715
)
1816

1917
func Test(t *testing.T) {
@@ -28,37 +26,13 @@ func Test(t *testing.T) {
2826
func TestVersions22(t *testing.T) {
2927
testenv.NeedsGo1Point(t, 22)
3028

31-
testfile := filepath.Join(analysistest.TestData(), "src", "versions", "go22.txtar")
32-
runTxtarFile(t, testfile, loopclosure.Analyzer, "golang.org/fake/versions")
29+
txtar := filepath.Join(analysistest.TestData(), "src", "versions", "go22.txtar")
30+
dir := testfiles.ExtractTxtarToTmp(t, txtar)
31+
analysistest.Run(t, dir, loopclosure.Analyzer, "golang.org/fake/versions")
3332
}
3433

3534
func TestVersions18(t *testing.T) {
36-
testfile := filepath.Join(analysistest.TestData(), "src", "versions", "go18.txtar")
37-
runTxtarFile(t, testfile, loopclosure.Analyzer, "golang.org/fake/versions")
38-
}
39-
40-
// runTxtarFile unpacks a txtar archive to a directory, and runs
41-
// analyzer on the given patterns.
42-
//
43-
// This is compatible with a go.mod file.
44-
//
45-
// TODO(taking): Consider unifying with analysistest.
46-
func runTxtarFile(t *testing.T, path string, analyzer *analysis.Analyzer, patterns ...string) {
47-
ar, err := txtar.ParseFile(path)
48-
if err != nil {
49-
t.Fatal(err)
50-
}
51-
52-
dir := t.TempDir()
53-
for _, file := range ar.Files {
54-
name, content := file.Name, file.Data
55-
56-
filename := filepath.Join(dir, name)
57-
os.MkdirAll(filepath.Dir(filename), 0777) // ignore error
58-
if err := os.WriteFile(filename, content, 0666); err != nil {
59-
t.Fatal(err)
60-
}
61-
}
62-
63-
analysistest.Run(t, dir, analyzer, patterns...)
35+
txtar := filepath.Join(analysistest.TestData(), "src", "versions", "go18.txtar")
36+
dir := testfiles.ExtractTxtarToTmp(t, txtar)
37+
analysistest.Run(t, dir, loopclosure.Analyzer, "golang.org/fake/versions")
6438
}

go/analysis/passes/stdversion/stdversion_test.go

+3-32
Original file line numberDiff line numberDiff line change
@@ -5,52 +5,23 @@
55
package stdversion_test
66

77
import (
8-
"os"
98
"path/filepath"
109
"testing"
1110

12-
"golang.org/x/tools/go/analysis"
1311
"golang.org/x/tools/go/analysis/analysistest"
1412
"golang.org/x/tools/go/analysis/passes/stdversion"
1513
"golang.org/x/tools/internal/testenv"
16-
"golang.org/x/tools/txtar"
14+
"golang.org/x/tools/internal/testfiles"
1715
)
1816

1917
func Test(t *testing.T) {
2018
// The test relies on go1.21 std symbols, but the analyzer
2119
// itself requires the go1.22 implementation of versions.FileVersions.
2220
testenv.NeedsGo1Point(t, 22)
2321

24-
testfile := filepath.Join(analysistest.TestData(), "test.txtar")
25-
runTxtarFile(t, testfile, stdversion.Analyzer,
22+
dir := testfiles.ExtractTxtarToTmp(t, filepath.Join(analysistest.TestData(), "test.txtar"))
23+
analysistest.Run(t, dir, stdversion.Analyzer,
2624
"example.com/a",
2725
"example.com/sub",
2826
"example.com/old")
2927
}
30-
31-
// runTxtarFile unpacks a txtar archive to a directory, and runs
32-
// analyzer on the given patterns.
33-
//
34-
// This is compatible with a go.mod file.
35-
//
36-
// Plundered from loopclosure_test.go.
37-
// TODO(golang/go#46136): add module support to analysistest.
38-
func runTxtarFile(t *testing.T, path string, analyzer *analysis.Analyzer, patterns ...string) {
39-
ar, err := txtar.ParseFile(path)
40-
if err != nil {
41-
t.Fatal(err)
42-
}
43-
44-
dir := t.TempDir()
45-
for _, file := range ar.Files {
46-
name, content := file.Name, file.Data
47-
48-
filename := filepath.Join(dir, name)
49-
os.MkdirAll(filepath.Dir(filename), 0777) // ignore error
50-
if err := os.WriteFile(filename, content, 0666); err != nil {
51-
t.Fatal(err)
52-
}
53-
}
54-
55-
analysistest.Run(t, dir, analyzer, patterns...)
56-
}

go/analysis/unitchecker/separate_test.go

+2-17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"golang.org/x/tools/go/gcexportdata"
2525
"golang.org/x/tools/go/packages"
2626
"golang.org/x/tools/internal/testenv"
27+
"golang.org/x/tools/internal/testfiles"
2728
"golang.org/x/tools/txtar"
2829
)
2930

@@ -82,7 +83,7 @@ func MyPrintf(format string, args ...any) {
8283

8384
// Expand archive into tmp tree.
8485
tmpdir := t.TempDir()
85-
if err := extractTxtar(txtar.Parse([]byte(src)), tmpdir); err != nil {
86+
if err := testfiles.ExtractTxtar(tmpdir, txtar.Parse([]byte(src))); err != nil {
8687
t.Fatal(err)
8788
}
8889

@@ -291,19 +292,3 @@ func exportTypes(cfg *unitchecker.Config, fset *token.FileSet, pkg *types.Packag
291292
type importerFunc func(path string) (*types.Package, error)
292293

293294
func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
294-
295-
// extractTxtar writes each archive file to the corresponding location beneath dir.
296-
//
297-
// TODO(adonovan): move this to txtar package, we need it all the time (#61386).
298-
func extractTxtar(ar *txtar.Archive, dir string) error {
299-
for _, file := range ar.Files {
300-
name := filepath.Join(dir, file.Name)
301-
if err := os.MkdirAll(filepath.Dir(name), 0777); err != nil {
302-
return err
303-
}
304-
if err := os.WriteFile(name, file.Data, 0666); err != nil {
305-
return err
306-
}
307-
}
308-
return nil
309-
}

go/ssa/builder_test.go

+3-54
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ import (
2020
"strings"
2121
"testing"
2222

23+
"golang.org/x/tools/go/analysis/analysistest"
2324
"golang.org/x/tools/go/buildutil"
2425
"golang.org/x/tools/go/loader"
2526
"golang.org/x/tools/go/packages"
2627
"golang.org/x/tools/go/ssa"
2728
"golang.org/x/tools/go/ssa/ssautil"
2829
"golang.org/x/tools/internal/aliases"
2930
"golang.org/x/tools/internal/testenv"
30-
"golang.org/x/tools/txtar"
31+
"golang.org/x/tools/internal/testfiles"
3132
)
3233

3334
func isEmpty(f *ssa.Function) bool { return f.Blocks == nil }
@@ -172,38 +173,7 @@ func main() {
172173
func TestNoIndirectCreatePackage(t *testing.T) {
173174
testenv.NeedsGoBuild(t) // for go/packages
174175

175-
src := `
176-
-- go.mod --
177-
module testdata
178-
go 1.18
179-
180-
-- a/a.go --
181-
package a
182-
183-
import "testdata/b"
184-
185-
func A() {
186-
var x b.B
187-
x.F()
188-
}
189-
190-
-- b/b.go --
191-
package b
192-
193-
import "testdata/c"
194-
195-
type B struct { c.C }
196-
197-
-- c/c.go --
198-
package c
199-
200-
type C int
201-
func (C) F() {}
202-
`
203-
dir := t.TempDir()
204-
if err := extractArchive(dir, src); err != nil {
205-
t.Fatal(err)
206-
}
176+
dir := testfiles.ExtractTxtarToTmp(t, filepath.Join(analysistest.TestData(), "indirect.txtar"))
207177
pkgs, err := loadPackages(dir, "testdata/a")
208178
if err != nil {
209179
t.Fatal(err)
@@ -235,27 +205,6 @@ func (C) F() {}
235205
}
236206
}
237207

238-
// extractArchive extracts the txtar archive into the specified directory.
239-
func extractArchive(dir, arch string) error {
240-
// TODO(adonovan): publish this a helper (#61386).
241-
extractTxtar := func(ar *txtar.Archive, dir string) error {
242-
for _, file := range ar.Files {
243-
name := filepath.Join(dir, file.Name)
244-
if err := os.MkdirAll(filepath.Dir(name), 0777); err != nil {
245-
return err
246-
}
247-
if err := os.WriteFile(name, file.Data, 0666); err != nil {
248-
return err
249-
}
250-
}
251-
return nil
252-
}
253-
254-
// Extract archive to temporary tree.
255-
ar := txtar.Parse([]byte(arch))
256-
return extractTxtar(ar, dir)
257-
}
258-
259208
// loadPackages loads packages from the specified directory, using LoadSyntax.
260209
func loadPackages(dir string, patterns ...string) ([]*packages.Package, error) {
261210
cfg := &packages.Config{

go/ssa/testdata/indirect.txtar

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
-- go.mod --
2+
module testdata
3+
go 1.18
4+
5+
-- a/a.go --
6+
package a
7+
8+
import "testdata/b"
9+
10+
func A() {
11+
var x b.B
12+
x.F()
13+
}
14+
15+
-- b/b.go --
16+
package b
17+
18+
import "testdata/c"
19+
20+
type B struct { c.C }
21+
22+
-- c/c.go --
23+
package c
24+
25+
type C int
26+
func (C) F() {}
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
A file to try to load.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// File is versions/go.mod after expansion with TestDir()
2+
3+
module golang.org/fake/versions
4+
5+
go 1.21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// The file will be go1.21 from the go.mod.
2+
3+
package versions // want "[email protected]"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//go:build go1.22
2+
3+
package versions // want "[email protected]"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//go:build go1.20
2+
3+
package versions // want "[email protected]"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package sub // want "[email protected]"

0 commit comments

Comments
 (0)