зеркало из https://github.com/golang/tools.git
internal/testfiles: consolidate to CopyToTmp
Use the new txtar.FS function to consolidate API around fs.FS. This has been simplified to two functions: ExtractTxtarFileToTmp, and CopyToTmp. CopyToTmp is a combination replacement for CopyFS and CopyDirToTmp. The main distinction is that it now takes an explicit renaming map instead of implicitly removing ".test" extensions. Updates golang/go#68408 Change-Id: I9558044ec4613835327c0b0a5e8d1cc8fe847d59 Reviewed-on: https://go-review.googlesource.com/c/tools/+/598996 Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Tim King <taking@google.com>
This commit is contained in:
Родитель
444aadd6e6
Коммит
12d2c3421a
|
@ -299,10 +299,11 @@ hello from other
|
||||||
`
|
`
|
||||||
|
|
||||||
// Expand archive into tmp tree.
|
// Expand archive into tmp tree.
|
||||||
tmpdir := t.TempDir()
|
fs, err := txtar.FS(txtar.Parse([]byte(src)))
|
||||||
if err := testfiles.ExtractTxtar(tmpdir, txtar.Parse([]byte(src))); err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
tmpdir := testfiles.CopyToTmp(t, fs)
|
||||||
|
|
||||||
ran := false
|
ran := false
|
||||||
a := &analysis.Analyzer{
|
a := &analysis.Analyzer{
|
||||||
|
|
|
@ -26,13 +26,11 @@ func Test(t *testing.T) {
|
||||||
func TestVersions22(t *testing.T) {
|
func TestVersions22(t *testing.T) {
|
||||||
testenv.NeedsGo1Point(t, 22)
|
testenv.NeedsGo1Point(t, 22)
|
||||||
|
|
||||||
txtar := filepath.Join(analysistest.TestData(), "src", "versions", "go22.txtar")
|
dir := testfiles.ExtractTxtarFileToTmp(t, filepath.Join(analysistest.TestData(), "src", "versions", "go22.txtar"))
|
||||||
dir := testfiles.ExtractTxtarFileToTmp(t, txtar)
|
|
||||||
analysistest.Run(t, dir, loopclosure.Analyzer, "golang.org/fake/versions")
|
analysistest.Run(t, dir, loopclosure.Analyzer, "golang.org/fake/versions")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVersions18(t *testing.T) {
|
func TestVersions18(t *testing.T) {
|
||||||
txtar := filepath.Join(analysistest.TestData(), "src", "versions", "go18.txtar")
|
dir := testfiles.ExtractTxtarFileToTmp(t, filepath.Join(analysistest.TestData(), "src", "versions", "go18.txtar"))
|
||||||
dir := testfiles.ExtractTxtarFileToTmp(t, txtar)
|
|
||||||
analysistest.Run(t, dir, loopclosure.Analyzer, "golang.org/fake/versions")
|
analysistest.Run(t, dir, loopclosure.Analyzer, "golang.org/fake/versions")
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,10 +82,11 @@ func MyPrintf(format string, args ...any) {
|
||||||
`
|
`
|
||||||
|
|
||||||
// Expand archive into tmp tree.
|
// Expand archive into tmp tree.
|
||||||
tmpdir := t.TempDir()
|
fs, err := txtar.FS(txtar.Parse([]byte(src)))
|
||||||
if err := testfiles.ExtractTxtar(tmpdir, txtar.Parse([]byte(src))); err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
tmpdir := testfiles.CopyToTmp(t, fs)
|
||||||
|
|
||||||
// Load metadata for the main package and all its dependencies.
|
// Load metadata for the main package and all its dependencies.
|
||||||
cfg := &packages.Config{
|
cfg := &packages.Config{
|
||||||
|
|
|
@ -44,11 +44,15 @@ package m
|
||||||
package lib
|
package lib
|
||||||
`
|
`
|
||||||
|
|
||||||
dir := testfiles.ExtractTxtarToTmp(t, txtar.Parse([]byte(workspace)))
|
fs, err := txtar.FS(txtar.Parse([]byte(workspace)))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
dir := testfiles.CopyToTmp(t, fs)
|
||||||
|
|
||||||
// TODO(rfindley): on mac, this is required to fix symlink path mismatches.
|
// TODO(rfindley): on mac, this is required to fix symlink path mismatches.
|
||||||
// But why? Where is the symlink being evaluated in go/packages?
|
// But why? Where is the symlink being evaluated in go/packages?
|
||||||
dir, err := filepath.EvalSymlinks(dir)
|
dir, err = filepath.EvalSymlinks(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,20 +17,14 @@ import (
|
||||||
"golang.org/x/tools/txtar"
|
"golang.org/x/tools/txtar"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CopyDirToTmp copies dir to a temporary test directory using
|
// CopyToTmp copies the files and directories in src to a new temporary testing
|
||||||
// CopyTestFiles and returns the path to the test directory.
|
// directory dst, and returns dst on success.
|
||||||
func CopyDirToTmp(t testing.TB, srcdir string) string {
|
//
|
||||||
dst := t.TempDir()
|
// After copying the files, it processes each of the 'old,new,' rename
|
||||||
if err := CopyFS(dst, os.DirFS(srcdir)); err != nil {
|
// directives in order. Each rename directive moves the relative path "old"
|
||||||
t.Fatal(err)
|
// to the relative path "new" within the directory.
|
||||||
}
|
//
|
||||||
return dst
|
// Renaming allows tests to hide files whose names have
|
||||||
}
|
|
||||||
|
|
||||||
// CopyFS copies the files and directories in src to a
|
|
||||||
// destination directory dst. Paths to files and directories
|
|
||||||
// ending in a ".test" extension have the ".test" extension
|
|
||||||
// removed. This allows tests to hide files whose names have
|
|
||||||
// special meaning, such as "go.mod" files or "testdata" directories
|
// special meaning, such as "go.mod" files or "testdata" directories
|
||||||
// from the go command, or ill-formed Go source files from gofmt.
|
// from the go command, or ill-formed Go source files from gofmt.
|
||||||
//
|
//
|
||||||
|
@ -41,42 +35,31 @@ func CopyDirToTmp(t testing.TB, srcdir string) string {
|
||||||
// a/a.go
|
// a/a.go
|
||||||
// b/b.go
|
// b/b.go
|
||||||
//
|
//
|
||||||
// The resulting files will be:
|
// with the rename "go.mod.test,go.mod", the resulting files will be:
|
||||||
//
|
//
|
||||||
// dst/
|
// dst/
|
||||||
// go.mod
|
// go.mod
|
||||||
// a/a.go
|
// a/a.go
|
||||||
// b/b.go
|
// b/b.go
|
||||||
func CopyFS(dstdir string, src fs.FS) error {
|
func CopyToTmp(t testing.TB, src fs.FS, rename ...string) string {
|
||||||
|
dstdir := t.TempDir()
|
||||||
|
|
||||||
if err := copyFS(dstdir, src); err != nil {
|
if err := copyFS(dstdir, src); err != nil {
|
||||||
return err
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, r := range rename {
|
||||||
|
old, new, found := strings.Cut(r, ",")
|
||||||
|
if !found {
|
||||||
|
t.Fatalf("rename directive %q does not contain delimiter %q", r, ",")
|
||||||
|
}
|
||||||
|
oldpath := filepath.Join(dstdir, old)
|
||||||
|
newpath := filepath.Join(dstdir, new)
|
||||||
|
if err := os.Rename(oldpath, newpath); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect ".test" paths in lexical order.
|
return dstdir
|
||||||
var rename []string
|
|
||||||
err := fs.WalkDir(os.DirFS(dstdir), ".", func(path string, d fs.DirEntry, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(path, ".test") {
|
|
||||||
rename = append(rename, path)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rename the .test paths in reverse lexical order, e.g.
|
|
||||||
// in d.test/a.test renames a.test to d.test/a then d.test to d.
|
|
||||||
for i := len(rename) - 1; i >= 0; i-- {
|
|
||||||
oldpath := filepath.Join(dstdir, rename[i])
|
|
||||||
newpath := strings.TrimSuffix(oldpath, ".test")
|
|
||||||
if err != os.Rename(oldpath, newpath) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the files in src to dst.
|
// Copy the files in src to dst.
|
||||||
|
@ -106,46 +89,18 @@ func copyFS(dstdir string, src fs.FS) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractTxtar writes each archive file to the corresponding location beneath dir.
|
|
||||||
//
|
|
||||||
// TODO(adonovan): move this to txtar package, we need it all the time (#61386).
|
|
||||||
func ExtractTxtar(dstdir string, ar *txtar.Archive) error {
|
|
||||||
for _, file := range ar.Files {
|
|
||||||
name := filepath.Join(dstdir, file.Name)
|
|
||||||
if err := os.MkdirAll(filepath.Dir(name), 0777); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := os.WriteFile(name, file.Data, 0666); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractTxtarFileToTmp read a txtar archive on a given path,
|
// ExtractTxtarFileToTmp read a txtar archive on a given path,
|
||||||
// extracts it to a temporary directory, and returns the
|
// extracts it to a temporary directory, and returns the
|
||||||
// temporary directory.
|
// temporary directory.
|
||||||
func ExtractTxtarFileToTmp(t testing.TB, archiveFile string) string {
|
func ExtractTxtarFileToTmp(t testing.TB, file string) string {
|
||||||
ar, err := txtar.ParseFile(archiveFile)
|
ar, err := txtar.ParseFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := t.TempDir()
|
fs, err := txtar.FS(ar)
|
||||||
err = ExtractTxtar(dir, ar)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return dir
|
return CopyToTmp(t, fs)
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractTxtarToTmp extracts the given archive to a temp directory, and
|
|
||||||
// returns that temporary directory.
|
|
||||||
func ExtractTxtarToTmp(t testing.TB, ar *txtar.Archive) string {
|
|
||||||
dir := t.TempDir()
|
|
||||||
err := ExtractTxtar(dir, ar)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return dir
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package testfiles_test
|
package testfiles_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -14,16 +15,20 @@ import (
|
||||||
"golang.org/x/tools/internal/testenv"
|
"golang.org/x/tools/internal/testenv"
|
||||||
"golang.org/x/tools/internal/testfiles"
|
"golang.org/x/tools/internal/testfiles"
|
||||||
"golang.org/x/tools/internal/versions"
|
"golang.org/x/tools/internal/versions"
|
||||||
|
"golang.org/x/tools/txtar"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTestDir(t *testing.T) {
|
func TestTestDir(t *testing.T) {
|
||||||
testenv.NeedsGo1Point(t, 22)
|
testenv.NeedsGo1Point(t, 22)
|
||||||
|
|
||||||
// TODO(taking): Expose a helper for this pattern?
|
// Files are initially {go.mod.test,sub.test/sub.go.test}.
|
||||||
// dir must contain a go.mod file to be picked up by Run().
|
fs := os.DirFS(filepath.Join(analysistest.TestData(), "versions"))
|
||||||
// So this pattern or Join(TestDir(t, TestData()), "versions") are
|
tmpdir := testfiles.CopyToTmp(t, fs,
|
||||||
// probably what everyone will want.
|
"go.mod.test,go.mod", // After: {go.mod,sub.test/sub.go.test}
|
||||||
dir := testfiles.CopyDirToTmp(t, filepath.Join(analysistest.TestData(), "versions"))
|
"sub.test/sub.go.test,sub.test/abc", // After: {go.mod,sub.test/abc}
|
||||||
|
"sub.test,sub", // After: {go.mod,sub/abc}
|
||||||
|
"sub/abc,sub/sub.go", // After: {go.mod,sub/sub.go}
|
||||||
|
)
|
||||||
|
|
||||||
filever := &analysis.Analyzer{
|
filever := &analysis.Analyzer{
|
||||||
Name: "filever",
|
Name: "filever",
|
||||||
|
@ -37,18 +42,54 @@ func TestTestDir(t *testing.T) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
analysistest.Run(t, dir, filever, "golang.org/fake/versions", "golang.org/fake/versions/sub")
|
res := analysistest.Run(t, tmpdir, filever, "golang.org/fake/versions", "golang.org/fake/versions/sub")
|
||||||
}
|
got := 0
|
||||||
|
for _, r := range res {
|
||||||
|
got += len(r.Diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCopyTestFilesErrors(t *testing.T) {
|
if want := 4; got != want {
|
||||||
tmp := t.TempDir() // a real tmp dir
|
t.Errorf("Got %d diagnostics. wanted %d", got, want)
|
||||||
for _, dir := range []string{
|
|
||||||
filepath.Join(analysistest.TestData(), "not_there"), // dir does not exist
|
|
||||||
filepath.Join(analysistest.TestData(), "somefile.txt"), // not a dir
|
|
||||||
} {
|
|
||||||
err := testfiles.CopyFS(tmp, os.DirFS(dir))
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Expected an error from CopyTestFiles")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTestDirErrors(t *testing.T) {
|
||||||
|
const input = `
|
||||||
|
-- one.txt --
|
||||||
|
one
|
||||||
|
`
|
||||||
|
// Files are initially {go.mod.test,sub.test/sub.go.test}.
|
||||||
|
fs, err := txtar.FS(txtar.Parse([]byte(input)))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
directive := "no comma to split on"
|
||||||
|
intercept := &fatalIntercept{t, nil}
|
||||||
|
func() {
|
||||||
|
defer func() { // swallow panics from fatalIntercept.Fatal
|
||||||
|
if r := recover(); r != intercept {
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
testfiles.CopyToTmp(intercept, fs, directive)
|
||||||
|
}()
|
||||||
|
|
||||||
|
got := fmt.Sprint(intercept.fatalfs)
|
||||||
|
want := `[rename directive "no comma to split on" does not contain delimiter ","]`
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("CopyToTmp(%q) had the Fatal messages %q. wanted %q", directive, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for TestTestDirErrors
|
||||||
|
type fatalIntercept struct {
|
||||||
|
testing.TB
|
||||||
|
fatalfs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *fatalIntercept) Fatalf(format string, args ...any) {
|
||||||
|
i.fatalfs = append(i.fatalfs, fmt.Sprintf(format, args...))
|
||||||
|
// Do not mark the test as failing, but fail early.
|
||||||
|
panic(i)
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче