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