]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/go/cmd/go/internal/modfile/read_test.go
Add error check on return value of build_co_await
[thirdparty/gcc.git] / libgo / go / cmd / go / internal / modfile / read_test.go
CommitLineData
dd931d9b
ILT
1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package modfile
6
7import (
8 "bytes"
9 "fmt"
10 "io/ioutil"
11 "os"
12 "os/exec"
13 "path/filepath"
14 "reflect"
15 "strings"
16 "testing"
17)
18
19// exists reports whether the named file exists.
20func exists(name string) bool {
21 _, err := os.Stat(name)
22 return err == nil
23}
24
25// Test that reading and then writing the golden files
26// does not change their output.
27func TestPrintGolden(t *testing.T) {
28 outs, err := filepath.Glob("testdata/*.golden")
29 if err != nil {
30 t.Fatal(err)
31 }
32 for _, out := range outs {
33 testPrint(t, out, out)
34 }
35}
36
37// testPrint is a helper for testing the printer.
38// It reads the file named in, reformats it, and compares
39// the result to the file named out.
40func testPrint(t *testing.T, in, out string) {
41 data, err := ioutil.ReadFile(in)
42 if err != nil {
43 t.Error(err)
44 return
45 }
46
47 golden, err := ioutil.ReadFile(out)
48 if err != nil {
49 t.Error(err)
50 return
51 }
52
53 base := "testdata/" + filepath.Base(in)
54 f, err := parse(in, data)
55 if err != nil {
56 t.Error(err)
57 return
58 }
59
60 ndata := Format(f)
61
62 if !bytes.Equal(ndata, golden) {
63 t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
64 tdiff(t, string(golden), string(ndata))
65 return
66 }
67}
68
69func TestParseLax(t *testing.T) {
70 badFile := []byte(`module m
71 surprise attack
72 x y (
73 z
74 )
75 exclude v1.2.3
76 replace <-!!!
77 `)
78 _, err := ParseLax("file", badFile, nil)
79 if err != nil {
80 t.Fatalf("ParseLax did not ignore irrelevant errors: %v", err)
81 }
82}
83
84// Test that when files in the testdata directory are parsed
85// and printed and parsed again, we get the same parse tree
86// both times.
87func TestPrintParse(t *testing.T) {
88 outs, err := filepath.Glob("testdata/*")
89 if err != nil {
90 t.Fatal(err)
91 }
92 for _, out := range outs {
93 data, err := ioutil.ReadFile(out)
94 if err != nil {
95 t.Error(err)
96 continue
97 }
98
99 base := "testdata/" + filepath.Base(out)
100 f, err := parse(base, data)
101 if err != nil {
102 t.Errorf("parsing original: %v", err)
103 continue
104 }
105
106 ndata := Format(f)
107 f2, err := parse(base, ndata)
108 if err != nil {
109 t.Errorf("parsing reformatted: %v", err)
110 continue
111 }
112
113 eq := eqchecker{file: base}
114 if err := eq.check(f, f2); err != nil {
115 t.Errorf("not equal (parse/Format/parse): %v", err)
116 }
117
118 pf1, err := Parse(base, data, nil)
119 if err != nil {
120 switch base {
121 case "testdata/replace2.in", "testdata/gopkg.in.golden":
122 t.Errorf("should parse %v: %v", base, err)
123 }
124 }
125 if err == nil {
126 pf2, err := Parse(base, ndata, nil)
127 if err != nil {
128 t.Errorf("Parsing reformatted: %v", err)
129 continue
130 }
131 eq := eqchecker{file: base}
132 if err := eq.check(pf1, pf2); err != nil {
133 t.Errorf("not equal (parse/Format/Parse): %v", err)
134 }
135
136 ndata2, err := pf1.Format()
137 if err != nil {
138 t.Errorf("reformat: %v", err)
139 }
140 pf3, err := Parse(base, ndata2, nil)
141 if err != nil {
142 t.Errorf("Parsing reformatted2: %v", err)
143 continue
144 }
145 eq = eqchecker{file: base}
146 if err := eq.check(pf1, pf3); err != nil {
147 t.Errorf("not equal (Parse/Format/Parse): %v", err)
148 }
149 ndata = ndata2
150 }
151
152 if strings.HasSuffix(out, ".in") {
153 golden, err := ioutil.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
154 if err != nil {
155 t.Error(err)
156 continue
157 }
158 if !bytes.Equal(ndata, golden) {
159 t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
160 tdiff(t, string(golden), string(ndata))
161 return
162 }
163 }
164 }
165}
166
167// An eqchecker holds state for checking the equality of two parse trees.
168type eqchecker struct {
169 file string
170 pos Position
171}
172
173// errorf returns an error described by the printf-style format and arguments,
174// inserting the current file position before the error text.
175func (eq *eqchecker) errorf(format string, args ...interface{}) error {
176 return fmt.Errorf("%s:%d: %s", eq.file, eq.pos.Line,
177 fmt.Sprintf(format, args...))
178}
179
180// check checks that v and w represent the same parse tree.
181// If not, it returns an error describing the first difference.
182func (eq *eqchecker) check(v, w interface{}) error {
183 return eq.checkValue(reflect.ValueOf(v), reflect.ValueOf(w))
184}
185
186var (
187 posType = reflect.TypeOf(Position{})
188 commentsType = reflect.TypeOf(Comments{})
189)
190
191// checkValue checks that v and w represent the same parse tree.
192// If not, it returns an error describing the first difference.
193func (eq *eqchecker) checkValue(v, w reflect.Value) error {
194 // inner returns the innermost expression for v.
195 // if v is a non-nil interface value, it returns the concrete
196 // value in the interface.
197 inner := func(v reflect.Value) reflect.Value {
198 for {
199 if v.Kind() == reflect.Interface && !v.IsNil() {
200 v = v.Elem()
201 continue
202 }
203 break
204 }
205 return v
206 }
207
208 v = inner(v)
209 w = inner(w)
210 if v.Kind() == reflect.Invalid && w.Kind() == reflect.Invalid {
211 return nil
212 }
213 if v.Kind() == reflect.Invalid {
214 return eq.errorf("nil interface became %s", w.Type())
215 }
216 if w.Kind() == reflect.Invalid {
217 return eq.errorf("%s became nil interface", v.Type())
218 }
219
220 if v.Type() != w.Type() {
221 return eq.errorf("%s became %s", v.Type(), w.Type())
222 }
223
224 if p, ok := v.Interface().(Expr); ok {
225 eq.pos, _ = p.Span()
226 }
227
228 switch v.Kind() {
229 default:
230 return eq.errorf("unexpected type %s", v.Type())
231
232 case reflect.Bool, reflect.Int, reflect.String:
233 vi := v.Interface()
234 wi := w.Interface()
235 if vi != wi {
236 return eq.errorf("%v became %v", vi, wi)
237 }
238
239 case reflect.Slice:
240 vl := v.Len()
241 wl := w.Len()
242 for i := 0; i < vl || i < wl; i++ {
243 if i >= vl {
244 return eq.errorf("unexpected %s", w.Index(i).Type())
245 }
246 if i >= wl {
247 return eq.errorf("missing %s", v.Index(i).Type())
248 }
249 if err := eq.checkValue(v.Index(i), w.Index(i)); err != nil {
250 return err
251 }
252 }
253
254 case reflect.Struct:
255 // Fields in struct must match.
256 t := v.Type()
257 n := t.NumField()
258 for i := 0; i < n; i++ {
259 tf := t.Field(i)
260 switch {
261 default:
262 if err := eq.checkValue(v.Field(i), w.Field(i)); err != nil {
263 return err
264 }
265
266 case tf.Type == posType: // ignore positions
267 case tf.Type == commentsType: // ignore comment assignment
268 }
269 }
270
271 case reflect.Ptr, reflect.Interface:
272 if v.IsNil() != w.IsNil() {
273 if v.IsNil() {
274 return eq.errorf("unexpected %s", w.Elem().Type())
275 }
276 return eq.errorf("missing %s", v.Elem().Type())
277 }
278 if err := eq.checkValue(v.Elem(), w.Elem()); err != nil {
279 return err
280 }
281 }
282 return nil
283}
284
285// diff returns the output of running diff on b1 and b2.
286func diff(b1, b2 []byte) (data []byte, err error) {
287 f1, err := ioutil.TempFile("", "testdiff")
288 if err != nil {
289 return nil, err
290 }
291 defer os.Remove(f1.Name())
292 defer f1.Close()
293
294 f2, err := ioutil.TempFile("", "testdiff")
295 if err != nil {
296 return nil, err
297 }
298 defer os.Remove(f2.Name())
299 defer f2.Close()
300
301 f1.Write(b1)
302 f2.Write(b2)
303
304 data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
305 if len(data) > 0 {
306 // diff exits with a non-zero status when the files don't match.
307 // Ignore that failure as long as we get output.
308 err = nil
309 }
310 return
311}
312
313// tdiff logs the diff output to t.Error.
314func tdiff(t *testing.T, a, b string) {
315 data, err := diff([]byte(a), []byte(b))
316 if err != nil {
317 t.Error(err)
318 return
319 }
320 t.Error(string(data))
321}
322
323var modulePathTests = []struct {
324 input []byte
325 expected string
326}{
327 {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
328 {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
329 {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
330 {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
331 {input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"},
332 {input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"},
333 {input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"},
334 {input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"},
335 {input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"},
336 {input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"},
337 {input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""},
338 {input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"},
339 {input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"},
340 {input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"},
341 {input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"},
342 {input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"},
343 {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
344 {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
345 {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
346 {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
347 {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
348 {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
349 {input: []byte("module \nmodule a/b/c "), expected: "a/b/c"},
350 {input: []byte("module \" \""), expected: " "},
351 {input: []byte("module "), expected: ""},
352 {input: []byte("module \" a/b/c \""), expected: " a/b/c "},
353 {input: []byte("module \"github.com/rsc/vgotest1\" // with a comment"), expected: "github.com/rsc/vgotest1"},
354}
355
356func TestModulePath(t *testing.T) {
357 for _, test := range modulePathTests {
358 t.Run(string(test.input), func(t *testing.T) {
359 result := ModulePath(test.input)
360 if result != test.expected {
361 t.Fatalf("ModulePath(%q): %s, want %s", string(test.input), result, test.expected)
362 }
363 })
364 }
365}