Source file
src/go/parser/error_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package parser
24
25 import (
26 "go/internal/typeparams"
27 "go/scanner"
28 "go/token"
29 "os"
30 "path/filepath"
31 "regexp"
32 "strings"
33 "testing"
34 )
35
36 const testdata = "testdata"
37
38
39 func getFile(fset *token.FileSet, filename string) (file *token.File) {
40 fset.Iterate(func(f *token.File) bool {
41 if f.Name() == filename {
42 if file != nil {
43 panic(filename + " used multiple times")
44 }
45 file = f
46 }
47 return true
48 })
49 return file
50 }
51
52 func getPos(fset *token.FileSet, filename string, offset int) token.Pos {
53 if f := getFile(fset, filename); f != nil {
54 return f.Pos(offset)
55 }
56 return token.NoPos
57 }
58
59
60
61
62
63
64
65 var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`)
66
67
68
69
70 func expectedErrors(fset *token.FileSet, filename string, src []byte) map[token.Pos]string {
71 errors := make(map[token.Pos]string)
72
73 var s scanner.Scanner
74
75
76
77 s.Init(getFile(fset, filename), src, nil, scanner.ScanComments)
78 var prev token.Pos
79 var here token.Pos
80
81 for {
82 pos, tok, lit := s.Scan()
83 switch tok {
84 case token.EOF:
85 return errors
86 case token.COMMENT:
87 s := errRx.FindStringSubmatch(lit)
88 if len(s) == 3 {
89 pos := prev
90 if s[1] == "HERE" {
91 pos = here
92 }
93 errors[pos] = s[2]
94 }
95 case token.SEMICOLON:
96
97 if lit != ";" {
98 break
99 }
100 fallthrough
101 default:
102 prev = pos
103 var l int
104 if tok.IsLiteral() {
105 l = len(lit)
106 } else {
107 l = len(tok.String())
108 }
109 here = prev + token.Pos(l)
110 }
111 }
112 }
113
114
115
116
117 func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) {
118 t.Helper()
119 for _, error := range found {
120
121
122 pos := getPos(fset, error.Pos.Filename, error.Pos.Offset)
123 if msg, found := expected[pos]; found {
124
125 rx, err := regexp.Compile(msg)
126 if err != nil {
127 t.Errorf("%s: %v", error.Pos, err)
128 continue
129 }
130 if match := rx.MatchString(error.Msg); !match {
131 t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg)
132 continue
133 }
134
135 delete(expected, pos)
136 } else {
137
138
139
140
141 t.Errorf("%s: unexpected error: %s", error.Pos, error.Msg)
142 }
143 }
144
145
146 if len(expected) > 0 {
147 t.Errorf("%d errors not reported:", len(expected))
148 for pos, msg := range expected {
149 t.Errorf("%s: %s\n", fset.Position(pos), msg)
150 }
151 }
152 }
153
154 func checkErrors(t *testing.T, filename string, input interface{}, mode Mode, expectErrors bool) {
155 t.Helper()
156 src, err := readSource(filename, input)
157 if err != nil {
158 t.Error(err)
159 return
160 }
161
162 fset := token.NewFileSet()
163 _, err = ParseFile(fset, filename, src, mode)
164 found, ok := err.(scanner.ErrorList)
165 if err != nil && !ok {
166 t.Error(err)
167 return
168 }
169 found.RemoveMultiples()
170
171 expected := map[token.Pos]string{}
172 if expectErrors {
173
174
175 expected = expectedErrors(fset, filename, src)
176 }
177
178
179 compareErrors(t, fset, expected, found)
180 }
181
182 func TestErrors(t *testing.T) {
183 list, err := os.ReadDir(testdata)
184 if err != nil {
185 t.Fatal(err)
186 }
187 for _, d := range list {
188 name := d.Name()
189 if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) {
190 mode := DeclarationErrors | AllErrors
191 if strings.HasSuffix(name, ".go2") {
192 if !typeparams.Enabled {
193 continue
194 }
195 } else {
196 mode |= typeparams.DisallowParsing
197 }
198 checkErrors(t, filepath.Join(testdata, name), nil, mode, true)
199 }
200 }
201 }
202
View as plain text