1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package types2_test
24
25 import (
26 "cmd/compile/internal/syntax"
27 "flag"
28 "internal/buildcfg"
29 "internal/testenv"
30 "os"
31 "path/filepath"
32 "regexp"
33 "sort"
34 "strings"
35 "testing"
36
37 . "cmd/compile/internal/types2"
38 )
39
40 var (
41 haltOnError = flag.Bool("halt", false, "halt on error")
42 verifyErrors = flag.Bool("verify", false, "verify errors (rather than list them) in TestManual")
43 goVersion = flag.String("lang", "", "Go language version (e.g. \"go1.12\")")
44 )
45
46 func parseFiles(t *testing.T, filenames []string, mode syntax.Mode) ([]*syntax.File, []error) {
47 var files []*syntax.File
48 var errlist []error
49 errh := func(err error) { errlist = append(errlist, err) }
50 for _, filename := range filenames {
51 file, err := syntax.ParseFile(filename, errh, nil, mode)
52 if file == nil {
53 t.Fatalf("%s: %s", filename, err)
54 }
55 files = append(files, file)
56 }
57 return files, errlist
58 }
59
60 func unpackError(err error) syntax.Error {
61 switch err := err.(type) {
62 case syntax.Error:
63 return err
64 case Error:
65 return syntax.Error{Pos: err.Pos, Msg: err.Msg}
66 default:
67 return syntax.Error{Msg: err.Error()}
68 }
69 }
70
71
72 func delta(x, y uint) uint {
73 switch {
74 case x < y:
75 return y - x
76 case x > y:
77 return x - y
78 default:
79 return 0
80 }
81 }
82
83
84 var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*_(0|[1-9][0-9]*)$`)
85
86
87
88
89
90 func asGoVersion(s string) string {
91 if goVersionRx.MatchString(s) {
92 return strings.Replace(s, "_", ".", 1)
93 }
94 return ""
95 }
96
97
98
99
100 var excludedForUnifiedBuild = map[string]bool{
101 "issue47818.go2": true,
102 "issue49705.go2": true,
103 }
104
105 func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) {
106 if len(filenames) == 0 {
107 t.Fatal("no source files")
108 }
109
110 if buildcfg.Experiment.Unified {
111 for _, f := range filenames {
112 if excludedForUnifiedBuild[filepath.Base(f)] {
113 t.Logf("%s cannot be tested with unified build - skipped", f)
114 return
115 }
116 }
117 }
118
119 var mode syntax.Mode
120 if strings.HasSuffix(filenames[0], ".go2") || manual {
121 mode |= syntax.AllowGenerics | syntax.AllowMethodTypeParams
122 }
123
124 files, errlist := parseFiles(t, filenames, mode)
125
126 pkgName := "<no package>"
127 if len(files) > 0 {
128 pkgName = files[0].PkgName.Value
129 }
130
131
132 goVersion := *goVersion
133 if goVersion == "" {
134 goVersion = asGoVersion(pkgName)
135 }
136
137 listErrors := manual && !*verifyErrors
138 if listErrors && len(errlist) > 0 {
139 t.Errorf("--- %s:", pkgName)
140 for _, err := range errlist {
141 t.Error(err)
142 }
143 }
144
145
146 var conf Config
147 conf.GoVersion = goVersion
148
149 if len(filenames) == 1 && strings.HasSuffix(filenames[0], "importC.src") {
150 conf.FakeImportC = true
151 }
152 conf.Trace = manual && testing.Verbose()
153 conf.Importer = defaultImporter()
154 conf.Error = func(err error) {
155 if *haltOnError {
156 defer panic(err)
157 }
158 if listErrors {
159 t.Error(err)
160 return
161 }
162 errlist = append(errlist, err)
163 }
164 conf.Check(pkgName, files, nil)
165
166 if listErrors {
167 return
168 }
169
170
171 sort.Slice(errlist, func(i, j int) bool {
172 pi := unpackError(errlist[i]).Pos
173 pj := unpackError(errlist[j]).Pos
174 return pi.Cmp(pj) < 0
175 })
176
177
178 errmap := make(map[string]map[uint][]syntax.Error)
179 for _, filename := range filenames {
180 f, err := os.Open(filename)
181 if err != nil {
182 t.Error(err)
183 continue
184 }
185 if m := syntax.ErrorMap(f); len(m) > 0 {
186 errmap[filename] = m
187 }
188 f.Close()
189 }
190
191
192 for _, err := range errlist {
193 got := unpackError(err)
194
195
196 filename := got.Pos.Base().Filename()
197 filemap := errmap[filename]
198 line := got.Pos.Line()
199 var list []syntax.Error
200 if filemap != nil {
201 list = filemap[line]
202 }
203
204
205
206 index := -1
207 for i, want := range list {
208 rx, err := regexp.Compile(want.Msg)
209 if err != nil {
210 t.Errorf("%s:%d:%d: %v", filename, line, want.Pos.Col(), err)
211 continue
212 }
213 if rx.MatchString(got.Msg) {
214 index = i
215 break
216 }
217 }
218 if index < 0 {
219 t.Errorf("%s: no error expected: %q", got.Pos, got.Msg)
220 continue
221 }
222
223
224 want := list[index]
225 if delta(got.Pos.Col(), want.Pos.Col()) > colDelta {
226 t.Errorf("%s: got col = %d; want %d", got.Pos, got.Pos.Col(), want.Pos.Col())
227 }
228
229
230 if n := len(list) - 1; n > 0 {
231
232 copy(list[index:], list[index+1:])
233 filemap[line] = list[:n]
234 } else {
235
236 delete(filemap, line)
237 }
238
239
240 if len(filemap) == 0 {
241 delete(errmap, filename)
242 }
243 }
244
245
246 if len(errmap) > 0 {
247 t.Errorf("--- %s: unreported errors:", pkgName)
248 for filename, filemap := range errmap {
249 for line, list := range filemap {
250 for _, err := range list {
251 t.Errorf("%s:%d:%d: %s", filename, line, err.Pos.Col(), err.Msg)
252 }
253 }
254 }
255 }
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 func TestManual(t *testing.T) {
273 testenv.MustHaveGoBuild(t)
274
275 filenames := flag.Args()
276 if len(filenames) == 0 {
277 filenames = []string{filepath.FromSlash("testdata/manual.go2")}
278 }
279
280 info, err := os.Stat(filenames[0])
281 if err != nil {
282 t.Fatalf("TestManual: %v", err)
283 }
284
285 DefPredeclaredTestFuncs()
286 if info.IsDir() {
287 if len(filenames) > 1 {
288 t.Fatal("TestManual: must have only one directory argument")
289 }
290 testDir(t, filenames[0], 0, true)
291 } else {
292 testFiles(t, filenames, 0, true)
293 }
294 }
295
296
297
298 func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", 55, false) }
299 func TestSpec(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/spec", 0, false) }
300 func TestExamples(t *testing.T) { testDirFiles(t, "testdata/examples", 0, false) }
301 func TestFixedbugs(t *testing.T) {
302 DefPredeclaredTestFuncs()
303 testDirFiles(t, "testdata/fixedbugs", 0, false)
304 }
305
306 func testDirFiles(t *testing.T, dir string, colDelta uint, manual bool) {
307 testenv.MustHaveGoBuild(t)
308 dir = filepath.FromSlash(dir)
309
310 fis, err := os.ReadDir(dir)
311 if err != nil {
312 t.Error(err)
313 return
314 }
315
316 for _, fi := range fis {
317 path := filepath.Join(dir, fi.Name())
318
319
320 if fi.IsDir() {
321 testDir(t, path, colDelta, manual)
322 } else {
323 t.Run(filepath.Base(path), func(t *testing.T) {
324 testFiles(t, []string{path}, colDelta, manual)
325 })
326 }
327 }
328 }
329
330 func testDir(t *testing.T, dir string, colDelta uint, manual bool) {
331 fis, err := os.ReadDir(dir)
332 if err != nil {
333 t.Error(err)
334 return
335 }
336
337 var filenames []string
338 for _, fi := range fis {
339 filenames = append(filenames, filepath.Join(dir, fi.Name()))
340 }
341
342 t.Run(filepath.Base(dir), func(t *testing.T) {
343 testFiles(t, filenames, colDelta, manual)
344 })
345 }
346
View as plain text