1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package syntax
30
31 import (
32 "flag"
33 "fmt"
34 "internal/testenv"
35 "os"
36 "path/filepath"
37 "regexp"
38 "sort"
39 "strings"
40 "testing"
41 )
42
43 const testdata = "testdata"
44
45 var print = flag.Bool("print", false, "only print errors")
46
47
48 type position struct {
49 line, col uint
50 }
51
52 func (pos position) String() string {
53 return fmt.Sprintf("%d:%d", pos.line, pos.col)
54 }
55
56 func sortedPositions(m map[position]string) []position {
57 list := make([]position, len(m))
58 i := 0
59 for pos := range m {
60 list[i] = pos
61 i++
62 }
63 sort.Slice(list, func(i, j int) bool {
64 a, b := list[i], list[j]
65 return a.line < b.line || a.line == b.line && a.col < b.col
66 })
67 return list
68 }
69
70
71
72
73
74 func declaredErrors(t *testing.T, filename string) map[position]string {
75 f, err := os.Open(filename)
76 if err != nil {
77 t.Fatal(err)
78 }
79 defer f.Close()
80
81 declared := make(map[position]string)
82
83 var s scanner
84 var pattern string
85 s.init(f, func(line, col uint, msg string) {
86
87 switch {
88 case strings.HasPrefix(msg, "// ERROR "):
89
90 declared[position{s.line, 0}] = strings.TrimSpace(msg[9:])
91 case strings.HasPrefix(msg, "/* ERROR "):
92
93 pattern = strings.TrimSpace(msg[9 : len(msg)-2])
94 }
95 }, comments)
96
97
98 for {
99 s.next()
100 if pattern != "" {
101 declared[position{s.line, s.col}] = pattern
102 pattern = ""
103 }
104 if s.tok == _EOF {
105 break
106 }
107 }
108
109 return declared
110 }
111
112 func testSyntaxErrors(t *testing.T, filename string) {
113 declared := declaredErrors(t, filename)
114 if *print {
115 fmt.Println("Declared errors:")
116 for _, pos := range sortedPositions(declared) {
117 fmt.Printf("%s:%s: %s\n", filename, pos, declared[pos])
118 }
119
120 fmt.Println()
121 fmt.Println("Reported errors:")
122 }
123
124 f, err := os.Open(filename)
125 if err != nil {
126 t.Fatal(err)
127 }
128 defer f.Close()
129
130 ParseFile(filename, func(err error) {
131 e, ok := err.(Error)
132 if !ok {
133 return
134 }
135
136 if *print {
137 fmt.Println(err)
138 return
139 }
140
141 orig := position{e.Pos.Line(), e.Pos.Col()}
142 pos := orig
143 pattern, found := declared[pos]
144 if !found {
145
146 pos = position{e.Pos.Line(), 0}
147 pattern, found = declared[pos]
148 }
149 if found {
150 rx, err := regexp.Compile(pattern)
151 if err != nil {
152 t.Errorf("%s:%s: %v", filename, pos, err)
153 return
154 }
155 if match := rx.MatchString(e.Msg); !match {
156 t.Errorf("%s:%s: %q does not match %q", filename, pos, e.Msg, pattern)
157 return
158 }
159
160 delete(declared, pos)
161 } else {
162 t.Errorf("%s:%s: unexpected error: %s", filename, orig, e.Msg)
163 }
164 }, nil, CheckBranches)
165
166 if *print {
167 fmt.Println()
168 return
169 }
170
171
172 for pos, pattern := range declared {
173 t.Errorf("%s:%s: missing error: %s", filename, pos, pattern)
174 }
175 }
176
177 func TestSyntaxErrors(t *testing.T) {
178 testenv.MustHaveGoBuild(t)
179
180 list, err := os.ReadDir(testdata)
181 if err != nil {
182 t.Fatal(err)
183 }
184 for _, fi := range list {
185 name := fi.Name()
186 if !fi.IsDir() && !strings.HasPrefix(name, ".") {
187 testSyntaxErrors(t, filepath.Join(testdata, name))
188 }
189 }
190 }
191
View as plain text