Source file
src/cmd/gofmt/long_test.go
1
2
3
4
5
6
7
8
9 package main
10
11 import (
12 "bytes"
13 "flag"
14 "fmt"
15 "go/ast"
16 "go/printer"
17 "go/token"
18 "io"
19 "io/fs"
20 "os"
21 "path/filepath"
22 "runtime"
23 "strings"
24 "testing"
25 )
26
27 var (
28 root = flag.String("root", runtime.GOROOT(), "test root directory")
29 files = flag.String("files", "", "comma-separated list of files to test")
30 ngo = flag.Int("n", runtime.NumCPU(), "number of goroutines used")
31 verbose = flag.Bool("verbose", false, "verbose mode")
32 nfiles int
33 )
34
35 func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
36 f, _, _, err := parse(fset, filename, src.Bytes(), false)
37 if err != nil {
38 return err
39 }
40 ast.SortImports(fset, f)
41 src.Reset()
42 return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f)
43 }
44
45 func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
46
47 f, err := os.Open(filename)
48 if err != nil {
49 t.Error(err)
50 return
51 }
52
53
54 b1.Reset()
55 _, err = io.Copy(b1, f)
56 f.Close()
57 if err != nil {
58 t.Error(err)
59 return
60 }
61
62
63 fset := token.NewFileSet()
64 if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
65 if *verbose {
66 fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
67 }
68 return
69 }
70
71
72 if err = gofmt(fset, filename, b1); err != nil {
73 t.Errorf("1st gofmt failed: %v", err)
74 return
75 }
76
77
78 b2.Reset()
79 b2.Write(b1.Bytes())
80
81
82 if err = gofmt(fset, filename, b2); err != nil {
83 t.Errorf("2nd gofmt failed: %v", err)
84 return
85 }
86
87
88 if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
89
90
91 if strings.HasSuffix(filename, "issue22662.go") {
92 t.Log("known gofmt idempotency bug (Issue #24472)")
93 return
94 }
95 t.Errorf("gofmt %s not idempotent", filename)
96 }
97 }
98
99 func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
100 b1 := new(bytes.Buffer)
101 b2 := new(bytes.Buffer)
102 for filename := range filenames {
103 testFile(t, b1, b2, filename)
104 }
105 done <- 0
106 }
107
108 func genFilenames(t *testing.T, filenames chan<- string) {
109 defer close(filenames)
110
111 handleFile := func(filename string, d fs.DirEntry, err error) error {
112 if err != nil {
113 t.Error(err)
114 return nil
115 }
116 if isGoFile(d) {
117 filenames <- filename
118 nfiles++
119 }
120 return nil
121 }
122
123
124 if *files != "" {
125 for _, filename := range strings.Split(*files, ",") {
126 fi, err := os.Stat(filename)
127 handleFile(filename, &statDirEntry{fi}, err)
128 }
129 return
130 }
131
132
133 filepath.WalkDir(*root, handleFile)
134 }
135
136 func TestAll(t *testing.T) {
137 if testing.Short() {
138 return
139 }
140
141 if *ngo < 1 {
142 *ngo = 1
143 }
144 if *verbose {
145 fmt.Printf("running test using %d goroutines\n", *ngo)
146 }
147
148
149 filenames := make(chan string, 32)
150 go genFilenames(t, filenames)
151
152
153 done := make(chan int)
154 for i := 0; i < *ngo; i++ {
155 go testFiles(t, filenames, done)
156 }
157
158
159 for i := 0; i < *ngo; i++ {
160 <-done
161 }
162
163 if *verbose {
164 fmt.Printf("processed %d files\n", nfiles)
165 }
166 }
167
168 type statDirEntry struct {
169 info fs.FileInfo
170 }
171
172 func (d *statDirEntry) Name() string { return d.info.Name() }
173 func (d *statDirEntry) IsDir() bool { return d.info.IsDir() }
174 func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() }
175 func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil }
176
View as plain text