mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
136 lines
4.1 KiB
Go
136 lines
4.1 KiB
Go
|
|
// Copyright 2025 The Go Authors. All rights reserved.
|
||
|
|
// Use of this source code is governed by a BSD-style
|
||
|
|
// license that can be found in the LICENSE file.
|
||
|
|
|
||
|
|
package ssa
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"fmt"
|
||
|
|
"internal/testenv"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
const expectedHeader = "// Code generated from _gen/" // this is the common part
|
||
|
|
|
||
|
|
// TestGeneratedFilesUpToDate regenerates all the rewrite and rewrite-related
|
||
|
|
// files defined in _gen into a temporary directory,
|
||
|
|
// checks that they match what appears in the source tree,
|
||
|
|
// verifies that they start with the prefix of a generated header,
|
||
|
|
// and checks that the only source files with that header were actually generated.
|
||
|
|
func TestGeneratedFilesUpToDate(t *testing.T) {
|
||
|
|
testenv.MustHaveGoRun(t)
|
||
|
|
wd, err := os.Getwd()
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("Failed to get current working directory: %v", err)
|
||
|
|
}
|
||
|
|
genDir := filepath.Join(wd, "_gen")
|
||
|
|
if _, err := os.Stat(genDir); os.IsNotExist(err) {
|
||
|
|
t.Fatalf("_gen directory not found")
|
||
|
|
}
|
||
|
|
|
||
|
|
tmpdir := t.TempDir()
|
||
|
|
|
||
|
|
// Accumulate a list of all existing files that look generated.
|
||
|
|
// It's an error if this set does not match the set that are
|
||
|
|
// generated into tmpdir.
|
||
|
|
genFiles := make(map[string]bool)
|
||
|
|
genPrefix := []byte(expectedHeader)
|
||
|
|
ssaFiles, err := filepath.Glob(filepath.Join(wd, "*.go"))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("could not glob for .go files in ssa directory: %v", err)
|
||
|
|
}
|
||
|
|
for _, f := range ssaFiles {
|
||
|
|
contents, err := os.ReadFile(f)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("could not read source file from ssa directory: %v", err)
|
||
|
|
}
|
||
|
|
// verify that the generated file has the expected header
|
||
|
|
// (this should cause other failures later, but if this is
|
||
|
|
// the problem, diagnose it here to shorten the treasure hunt.)
|
||
|
|
if bytes.HasPrefix(contents, genPrefix) {
|
||
|
|
genFiles[filepath.Base(f)] = true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
goFiles, err := filepath.Glob(filepath.Join(genDir, "*.go"))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("could not glob for .go files in _gen: %v", err)
|
||
|
|
}
|
||
|
|
if len(goFiles) == 0 {
|
||
|
|
t.Fatal("no .go files found in _gen")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Construct the command line for "go run".
|
||
|
|
// Explicitly list the files, just to make it
|
||
|
|
// clear what is included (if the test is logging).
|
||
|
|
args := []string{"run", "-C", genDir}
|
||
|
|
for _, f := range goFiles {
|
||
|
|
args = append(args, filepath.Base(f))
|
||
|
|
}
|
||
|
|
args = append(args, "-outdir", tmpdir)
|
||
|
|
|
||
|
|
logArgs := fmt.Sprintf("%v", args)
|
||
|
|
logArgs = logArgs[1 : len(logArgs)-2] // strip '[' and ']'
|
||
|
|
t.Logf("%s %v", testenv.GoToolPath(t), logArgs)
|
||
|
|
output, err := testenv.Command(t, testenv.GoToolPath(t), args...).CombinedOutput()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("go run in _gen failed: %v\n%s", err, output)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Compare generated files with existing files in the parent directory.
|
||
|
|
files, err := os.ReadDir(tmpdir)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("could not read tmpdir %s: %v", tmpdir, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, file := range files {
|
||
|
|
if file.IsDir() {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
filename := file.Name()
|
||
|
|
|
||
|
|
// filename must be in the generated set,
|
||
|
|
if !genFiles[filename] {
|
||
|
|
t.Errorf("%s does not start with the expected header '%s' (if the header was changed the test needs to be updated)",
|
||
|
|
filename, expectedHeader)
|
||
|
|
}
|
||
|
|
genFiles[filename] = false // remove from set
|
||
|
|
|
||
|
|
generatedPath := filepath.Join(tmpdir, filename)
|
||
|
|
originalPath := filepath.Join(wd, filename)
|
||
|
|
|
||
|
|
generatedData, err := os.ReadFile(generatedPath)
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("could not read generated file %s: %v", generatedPath, err)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
// there should be a corresponding file in the ssa directory,
|
||
|
|
originalData, err := os.ReadFile(originalPath)
|
||
|
|
if err != nil {
|
||
|
|
if os.IsNotExist(err) {
|
||
|
|
t.Errorf("generated file %s was created, but does not exist in the ssa directory. It may need to be added to the repository.", filename)
|
||
|
|
} else {
|
||
|
|
t.Errorf("could not read original file %s: %v", originalPath, err)
|
||
|
|
}
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
// and the contents of that file should match.
|
||
|
|
if !bytes.Equal(originalData, generatedData) {
|
||
|
|
t.Errorf("%s is out of date. Please run 'go generate'.", filename)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// the generated set should be empty now.
|
||
|
|
for file, notGenerated := range genFiles {
|
||
|
|
if notGenerated {
|
||
|
|
t.Errorf("%s has the header of a generated file but was not generated", file)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|