| |
| |
| |
|
|
| |
| |
| |
|
|
| package main |
|
|
| import ( |
| "bytes" |
| "flag" |
| "fmt" |
| "go/ast" |
| "go/printer" |
| "go/token" |
| "internal/testenv" |
| "io" |
| "io/fs" |
| "os" |
| "path/filepath" |
| "runtime" |
| "strings" |
| "testing" |
| ) |
|
|
| var ( |
| root = flag.String("root", runtime.GOROOT(), "test root directory") |
| files = flag.String("files", "", "comma-separated list of files to test") |
| ngo = flag.Int("n", runtime.NumCPU(), "number of goroutines used") |
| verbose = flag.Bool("verbose", false, "verbose mode") |
| nfiles int |
| ) |
|
|
| func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error { |
| f, _, _, err := parse(fset, filename, src.Bytes(), false) |
| if err != nil { |
| return err |
| } |
| ast.SortImports(fset, f) |
| src.Reset() |
| return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f) |
| } |
|
|
| func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) { |
| |
| f, err := os.Open(filename) |
| if err != nil { |
| t.Error(err) |
| return |
| } |
|
|
| |
| b1.Reset() |
| _, err = io.Copy(b1, f) |
| f.Close() |
| if err != nil { |
| t.Error(err) |
| return |
| } |
|
|
| |
| fset := token.NewFileSet() |
| if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil { |
| if *verbose { |
| fmt.Fprintf(os.Stderr, "ignoring %s\n", err) |
| } |
| return |
| } |
|
|
| |
| if err = gofmt(fset, filename, b1); err != nil { |
| t.Errorf("1st gofmt failed: %v", err) |
| return |
| } |
|
|
| |
| b2.Reset() |
| b2.Write(b1.Bytes()) |
|
|
| |
| if err = gofmt(fset, filename, b2); err != nil { |
| t.Errorf("2nd gofmt failed: %v", err) |
| return |
| } |
|
|
| |
| if !bytes.Equal(b1.Bytes(), b2.Bytes()) { |
| |
| |
| if strings.HasSuffix(filename, "issue22662.go") { |
| t.Log("known gofmt idempotency bug (Issue #24472)") |
| return |
| } |
| t.Errorf("gofmt %s not idempotent", filename) |
| } |
| } |
|
|
| func testFiles(t *testing.T, filenames <-chan string, done chan<- int) { |
| b1 := new(bytes.Buffer) |
| b2 := new(bytes.Buffer) |
| for filename := range filenames { |
| testFile(t, b1, b2, filename) |
| } |
| done <- 0 |
| } |
|
|
| func genFilenames(t *testing.T, filenames chan<- string) { |
| defer close(filenames) |
|
|
| handleFile := func(filename string, d fs.DirEntry, err error) error { |
| if err != nil { |
| t.Error(err) |
| return nil |
| } |
| |
| if !d.IsDir() && isGoFilename(d.Name()) && !strings.Contains(filepath.ToSlash(filename), "/testdata/") { |
| filenames <- filename |
| nfiles++ |
| } |
| return nil |
| } |
|
|
| |
| if *files != "" { |
| for _, filename := range strings.Split(*files, ",") { |
| fi, err := os.Stat(filename) |
| handleFile(filename, fs.FileInfoToDirEntry(fi), err) |
| } |
| return |
| } |
|
|
| |
| goroot := *root |
| if goroot == "" { |
| goroot = testenv.GOROOT(t) |
| } |
| filepath.WalkDir(goroot, handleFile) |
| } |
|
|
| func TestAll(t *testing.T) { |
| if testing.Short() { |
| return |
| } |
|
|
| if *ngo < 1 { |
| *ngo = 1 |
| } |
| if *verbose { |
| fmt.Printf("running test using %d goroutines\n", *ngo) |
| } |
|
|
| |
| filenames := make(chan string, 32) |
| go genFilenames(t, filenames) |
|
|
| |
| done := make(chan int) |
| for i := 0; i < *ngo; i++ { |
| go testFiles(t, filenames, done) |
| } |
|
|
| |
| for i := 0; i < *ngo; i++ { |
| <-done |
| } |
|
|
| if *verbose { |
| fmt.Printf("processed %d files\n", nfiles) |
| } |
| } |
|
|