cmd/go: add -testsum flag to update go.sum in script tests

-testsum may be set to "tidy", "listm", or "listall". When set,
TestScript runs 'go mod tidy', 'go list -m -mod=mod all', or
'go list -mod=mod all' at the beginning of each test that has a go.mod
file in its root directory. If the test passes and go.mod or go.sum
was updated, TestScript will rewrite the test file with the initial
content of go.mod and go.sum (after the above command).

This is useful for writing tests that need a working go.sum and for
fixing tests that rely on -mod=mod.

For golang/go#41302

Change-Id: I63a5667621a5082ccedfc1bff33c3969c29e8b3d
Reviewed-on: https://go-review.googlesource.com/c/go/+/336150
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Jay Conrod <jayconrod@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341932
Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
Jay Conrod 2021-07-20 14:37:53 -07:00
parent 0d01934094
commit 1fffeddfe9

View file

@ -11,6 +11,7 @@ import (
"bytes"
"context"
"errors"
"flag"
"fmt"
"go/build"
"internal/testenv"
@ -35,6 +36,8 @@ import (
"cmd/internal/sys"
)
var testSum = flag.String("testsum", "", `may be tidy, listm, or listall. If set, TestScript generates a go.sum file at the beginning of each test and updates test files if they pass.`)
// TestScript runs the tests in testdata/script/*.txt.
func TestScript(t *testing.T) {
testenv.MustHaveGoBuild(t)
@ -269,6 +272,22 @@ func (ts *testScript) run() {
ts.mark = ts.log.Len()
}
// With -testsum, if a go.mod file is present in the test's initial
// working directory, run 'go mod tidy'.
if *testSum != "" {
if ts.updateSum(a) {
defer func() {
if ts.t.Failed() {
return
}
data := txtar.Format(a)
if err := os.WriteFile(ts.file, data, 0666); err != nil {
ts.t.Errorf("rewriting test file: %v", err)
}
}()
}
}
// Run script.
// See testdata/script/README for documentation of script form.
script := string(a.Comment)
@ -1341,6 +1360,68 @@ func (ts *testScript) parse(line string) command {
return cmd
}
// updateSum runs 'go mod tidy', 'go list -mod=mod -m all', or
// 'go list -mod=mod all' in the test's current directory if a file named
// "go.mod" is present after the archive has been extracted. updateSum modifies
// archive and returns true if go.mod or go.sum were changed.
func (ts *testScript) updateSum(archive *txtar.Archive) (rewrite bool) {
gomodIdx, gosumIdx := -1, -1
for i := range archive.Files {
switch archive.Files[i].Name {
case "go.mod":
gomodIdx = i
case "go.sum":
gosumIdx = i
}
}
if gomodIdx < 0 {
return false
}
switch *testSum {
case "tidy":
ts.cmdGo(success, []string{"mod", "tidy"})
case "listm":
ts.cmdGo(success, []string{"list", "-m", "-mod=mod", "all"})
case "listall":
ts.cmdGo(success, []string{"list", "-mod=mod", "all"})
default:
ts.t.Fatalf(`unknown value for -testsum %q; may be "tidy", "listm", or "listall"`, *testSum)
}
newGomodData, err := os.ReadFile(filepath.Join(ts.cd, "go.mod"))
if err != nil {
ts.t.Fatalf("reading go.mod after -testsum: %v", err)
}
if !bytes.Equal(newGomodData, archive.Files[gomodIdx].Data) {
archive.Files[gomodIdx].Data = newGomodData
rewrite = true
}
newGosumData, err := os.ReadFile(filepath.Join(ts.cd, "go.sum"))
if err != nil && !os.IsNotExist(err) {
ts.t.Fatalf("reading go.sum after -testsum: %v", err)
}
switch {
case os.IsNotExist(err) && gosumIdx >= 0:
// go.sum was deleted.
rewrite = true
archive.Files = append(archive.Files[:gosumIdx], archive.Files[gosumIdx+1:]...)
case err == nil && gosumIdx < 0:
// go.sum was created.
rewrite = true
gosumIdx = gomodIdx + 1
archive.Files = append(archive.Files, txtar.File{})
copy(archive.Files[gosumIdx+1:], archive.Files[gosumIdx:])
archive.Files[gosumIdx] = txtar.File{Name: "go.sum", Data: newGosumData}
case err == nil && gosumIdx >= 0 && !bytes.Equal(newGosumData, archive.Files[gosumIdx].Data):
// go.sum was changed.
rewrite = true
archive.Files[gosumIdx].Data = newGosumData
}
return rewrite
}
// diff returns a formatted diff of the two texts,
// showing the entire text and the minimum line-level
// additions and removals to turn text1 into text2.