Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / mod@v0.3.0 / modfile / read_test.go
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
5 package modfile
6
7 import (
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.
20 func 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.
27 func 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                 out := out
34                 name := strings.TrimSuffix(filepath.Base(out), ".golden")
35                 t.Run(name, func(t *testing.T) {
36                         t.Parallel()
37                         testPrint(t, out, out)
38                 })
39         }
40 }
41
42 // testPrint is a helper for testing the printer.
43 // It reads the file named in, reformats it, and compares
44 // the result to the file named out.
45 func testPrint(t *testing.T, in, out string) {
46         data, err := ioutil.ReadFile(in)
47         if err != nil {
48                 t.Error(err)
49                 return
50         }
51
52         golden, err := ioutil.ReadFile(out)
53         if err != nil {
54                 t.Error(err)
55                 return
56         }
57
58         base := "testdata/" + filepath.Base(in)
59         f, err := parse(in, data)
60         if err != nil {
61                 t.Error(err)
62                 return
63         }
64
65         ndata := Format(f)
66
67         if !bytes.Equal(ndata, golden) {
68                 t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
69                 tdiff(t, string(golden), string(ndata))
70                 return
71         }
72 }
73
74 // TestParsePunctuation verifies that certain ASCII punctuation characters
75 // (brackets, commas) are lexed as separate tokens, even when they're
76 // surrounded by identifier characters.
77 func TestParsePunctuation(t *testing.T) {
78         for _, test := range []struct {
79                 desc, src, want string
80         }{
81                 {"paren", "require ()", "require ( )"},
82                 {"brackets", "require []{},", "require [ ] { } ,"},
83                 {"mix", "require a[b]c{d}e,", "require a [ b ] c { d } e ,"},
84                 {"block_mix", "require (\n\ta[b]\n)", "require ( a [ b ] )"},
85                 {"interval", "require [v1.0.0, v1.1.0)", "require [ v1.0.0 , v1.1.0 )"},
86         } {
87                 t.Run(test.desc, func(t *testing.T) {
88                         f, err := parse("go.mod", []byte(test.src))
89                         if err != nil {
90                                 t.Fatalf("parsing %q: %v", test.src, err)
91                         }
92                         var tokens []string
93                         for _, stmt := range f.Stmt {
94                                 switch stmt := stmt.(type) {
95                                 case *Line:
96                                         tokens = append(tokens, stmt.Token...)
97                                 case *LineBlock:
98                                         tokens = append(tokens, stmt.Token...)
99                                         tokens = append(tokens, "(")
100                                         for _, line := range stmt.Line {
101                                                 tokens = append(tokens, line.Token...)
102                                         }
103                                         tokens = append(tokens, ")")
104                                 default:
105                                         t.Fatalf("parsing %q: unexpected statement of type %T", test.src, stmt)
106                                 }
107                         }
108                         got := strings.Join(tokens, " ")
109                         if got != test.want {
110                                 t.Errorf("parsing %q: got %q, want %q", test.src, got, test.want)
111                         }
112                 })
113         }
114 }
115
116 func TestParseLax(t *testing.T) {
117         badFile := []byte(`module m
118                 surprise attack
119                 x y (
120                         z
121                 )
122                 exclude v1.2.3
123                 replace <-!!!
124                 retract v1.2.3 v1.2.4
125                 retract (v1.2.3, v1.2.4]
126                 retract v1.2.3 (
127                         key1 value1
128                         key2 value2
129                 )
130                 require good v1.0.0
131         `)
132         f, err := ParseLax("file", badFile, nil)
133         if err != nil {
134                 t.Fatalf("ParseLax did not ignore irrelevant errors: %v", err)
135         }
136         if f.Module == nil || f.Module.Mod.Path != "m" {
137                 t.Errorf("module directive was not parsed")
138         }
139         if len(f.Require) != 1 || f.Require[0].Mod.Path != "good" {
140                 t.Errorf("require directive at end of file was not parsed")
141         }
142 }
143
144 // Test that when files in the testdata directory are parsed
145 // and printed and parsed again, we get the same parse tree
146 // both times.
147 func TestPrintParse(t *testing.T) {
148         outs, err := filepath.Glob("testdata/*")
149         if err != nil {
150                 t.Fatal(err)
151         }
152         for _, out := range outs {
153                 out := out
154                 name := filepath.Base(out)
155                 t.Run(name, func(t *testing.T) {
156                         t.Parallel()
157                         data, err := ioutil.ReadFile(out)
158                         if err != nil {
159                                 t.Fatal(err)
160                         }
161
162                         base := "testdata/" + filepath.Base(out)
163                         f, err := parse(base, data)
164                         if err != nil {
165                                 t.Fatalf("parsing original: %v", err)
166                         }
167
168                         ndata := Format(f)
169                         f2, err := parse(base, ndata)
170                         if err != nil {
171                                 t.Fatalf("parsing reformatted: %v", err)
172                         }
173
174                         eq := eqchecker{file: base}
175                         if err := eq.check(f, f2); err != nil {
176                                 t.Errorf("not equal (parse/Format/parse): %v", err)
177                         }
178
179                         pf1, err := Parse(base, data, nil)
180                         if err != nil {
181                                 switch base {
182                                 case "testdata/replace2.in", "testdata/gopkg.in.golden":
183                                         t.Errorf("should parse %v: %v", base, err)
184                                 }
185                         }
186                         if err == nil {
187                                 pf2, err := Parse(base, ndata, nil)
188                                 if err != nil {
189                                         t.Fatalf("Parsing reformatted: %v", err)
190                                 }
191                                 eq := eqchecker{file: base}
192                                 if err := eq.check(pf1, pf2); err != nil {
193                                         t.Errorf("not equal (parse/Format/Parse): %v", err)
194                                 }
195
196                                 ndata2, err := pf1.Format()
197                                 if err != nil {
198                                         t.Errorf("reformat: %v", err)
199                                 }
200                                 pf3, err := Parse(base, ndata2, nil)
201                                 if err != nil {
202                                         t.Fatalf("Parsing reformatted2: %v", err)
203                                 }
204                                 eq = eqchecker{file: base}
205                                 if err := eq.check(pf1, pf3); err != nil {
206                                         t.Errorf("not equal (Parse/Format/Parse): %v", err)
207                                 }
208                                 ndata = ndata2
209                         }
210
211                         if strings.HasSuffix(out, ".in") {
212                                 golden, err := ioutil.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
213                                 if err != nil {
214                                         t.Fatal(err)
215                                 }
216                                 if !bytes.Equal(ndata, golden) {
217                                         t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
218                                         tdiff(t, string(golden), string(ndata))
219                                         return
220                                 }
221                         }
222                 })
223         }
224 }
225
226 // An eqchecker holds state for checking the equality of two parse trees.
227 type eqchecker struct {
228         file string
229         pos  Position
230 }
231
232 // errorf returns an error described by the printf-style format and arguments,
233 // inserting the current file position before the error text.
234 func (eq *eqchecker) errorf(format string, args ...interface{}) error {
235         return fmt.Errorf("%s:%d: %s", eq.file, eq.pos.Line,
236                 fmt.Sprintf(format, args...))
237 }
238
239 // check checks that v and w represent the same parse tree.
240 // If not, it returns an error describing the first difference.
241 func (eq *eqchecker) check(v, w interface{}) error {
242         return eq.checkValue(reflect.ValueOf(v), reflect.ValueOf(w))
243 }
244
245 var (
246         posType      = reflect.TypeOf(Position{})
247         commentsType = reflect.TypeOf(Comments{})
248 )
249
250 // checkValue checks that v and w represent the same parse tree.
251 // If not, it returns an error describing the first difference.
252 func (eq *eqchecker) checkValue(v, w reflect.Value) error {
253         // inner returns the innermost expression for v.
254         // if v is a non-nil interface value, it returns the concrete
255         // value in the interface.
256         inner := func(v reflect.Value) reflect.Value {
257                 for {
258                         if v.Kind() == reflect.Interface && !v.IsNil() {
259                                 v = v.Elem()
260                                 continue
261                         }
262                         break
263                 }
264                 return v
265         }
266
267         v = inner(v)
268         w = inner(w)
269         if v.Kind() == reflect.Invalid && w.Kind() == reflect.Invalid {
270                 return nil
271         }
272         if v.Kind() == reflect.Invalid {
273                 return eq.errorf("nil interface became %s", w.Type())
274         }
275         if w.Kind() == reflect.Invalid {
276                 return eq.errorf("%s became nil interface", v.Type())
277         }
278
279         if v.Type() != w.Type() {
280                 return eq.errorf("%s became %s", v.Type(), w.Type())
281         }
282
283         if p, ok := v.Interface().(Expr); ok {
284                 eq.pos, _ = p.Span()
285         }
286
287         switch v.Kind() {
288         default:
289                 return eq.errorf("unexpected type %s", v.Type())
290
291         case reflect.Bool, reflect.Int, reflect.String:
292                 vi := v.Interface()
293                 wi := w.Interface()
294                 if vi != wi {
295                         return eq.errorf("%v became %v", vi, wi)
296                 }
297
298         case reflect.Slice:
299                 vl := v.Len()
300                 wl := w.Len()
301                 for i := 0; i < vl || i < wl; i++ {
302                         if i >= vl {
303                                 return eq.errorf("unexpected %s", w.Index(i).Type())
304                         }
305                         if i >= wl {
306                                 return eq.errorf("missing %s", v.Index(i).Type())
307                         }
308                         if err := eq.checkValue(v.Index(i), w.Index(i)); err != nil {
309                                 return err
310                         }
311                 }
312
313         case reflect.Struct:
314                 // Fields in struct must match.
315                 t := v.Type()
316                 n := t.NumField()
317                 for i := 0; i < n; i++ {
318                         tf := t.Field(i)
319                         switch {
320                         default:
321                                 if err := eq.checkValue(v.Field(i), w.Field(i)); err != nil {
322                                         return err
323                                 }
324
325                         case tf.Type == posType: // ignore positions
326                         case tf.Type == commentsType: // ignore comment assignment
327                         }
328                 }
329
330         case reflect.Ptr, reflect.Interface:
331                 if v.IsNil() != w.IsNil() {
332                         if v.IsNil() {
333                                 return eq.errorf("unexpected %s", w.Elem().Type())
334                         }
335                         return eq.errorf("missing %s", v.Elem().Type())
336                 }
337                 if err := eq.checkValue(v.Elem(), w.Elem()); err != nil {
338                         return err
339                 }
340         }
341         return nil
342 }
343
344 // diff returns the output of running diff on b1 and b2.
345 func diff(b1, b2 []byte) (data []byte, err error) {
346         f1, err := ioutil.TempFile("", "testdiff")
347         if err != nil {
348                 return nil, err
349         }
350         defer os.Remove(f1.Name())
351         defer f1.Close()
352
353         f2, err := ioutil.TempFile("", "testdiff")
354         if err != nil {
355                 return nil, err
356         }
357         defer os.Remove(f2.Name())
358         defer f2.Close()
359
360         f1.Write(b1)
361         f2.Write(b2)
362
363         data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
364         if len(data) > 0 {
365                 // diff exits with a non-zero status when the files don't match.
366                 // Ignore that failure as long as we get output.
367                 err = nil
368         }
369         return
370 }
371
372 // tdiff logs the diff output to t.Error.
373 func tdiff(t *testing.T, a, b string) {
374         data, err := diff([]byte(a), []byte(b))
375         if err != nil {
376                 t.Error(err)
377                 return
378         }
379         t.Error(string(data))
380 }
381
382 var modulePathTests = []struct {
383         input    []byte
384         expected string
385 }{
386         {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
387         {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
388         {input: []byte("module  \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
389         {input: []byte("module  github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
390         {input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"},
391         {input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"},
392         {input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"},
393         {input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"},
394         {input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"},
395         {input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"},
396         {input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""},
397         {input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"},
398         {input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"},
399         {input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"},
400         {input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"},
401         {input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"},
402         {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
403         {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
404         {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
405         {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
406         {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
407         {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
408         {input: []byte("module  \nmodule a/b/c "), expected: "a/b/c"},
409         {input: []byte("module \"   \""), expected: "   "},
410         {input: []byte("module   "), expected: ""},
411         {input: []byte("module \"  a/b/c  \""), expected: "  a/b/c  "},
412         {input: []byte("module \"github.com/rsc/vgotest1\" // with a comment"), expected: "github.com/rsc/vgotest1"},
413 }
414
415 func TestModulePath(t *testing.T) {
416         for _, test := range modulePathTests {
417                 t.Run(string(test.input), func(t *testing.T) {
418                         result := ModulePath(test.input)
419                         if result != test.expected {
420                                 t.Fatalf("ModulePath(%q): %s, want %s", string(test.input), result, test.expected)
421                         }
422                 })
423         }
424 }
425
426 func TestGoVersion(t *testing.T) {
427         for _, test := range []struct {
428                 desc, input string
429                 ok          bool
430         }{
431                 {desc: "empty", input: "module m\ngo \n", ok: false},
432                 {desc: "one", input: "module m\ngo 1\n", ok: false},
433                 {desc: "two", input: "module m\ngo 1.22\n", ok: true},
434                 {desc: "three", input: "module m\ngo 1.22.333", ok: false},
435                 {desc: "before", input: "module m\ngo v1.2\n", ok: false},
436                 {desc: "after", input: "module m\ngo 1.2rc1\n", ok: false},
437                 {desc: "space", input: "module m\ngo 1.2 3.4\n", ok: false},
438         } {
439                 t.Run(test.desc, func(t *testing.T) {
440                         if _, err := Parse("go.mod", []byte(test.input), nil); err == nil && !test.ok {
441                                 t.Error("unexpected success")
442                         } else if err != nil && test.ok {
443                                 t.Errorf("unexpected error: %v", err)
444                         }
445                 })
446         }
447 }