Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / internal / gcimporter / gcimporter_test.go
1 // Copyright 2011 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 // This file is a copy of $GOROOT/src/go/internal/gcimporter/gcimporter_test.go,
6 // adjusted to make it build with code from (std lib) internal/testenv copied.
7
8 package gcimporter
9
10 import (
11         "bytes"
12         "fmt"
13         "go/types"
14         "io/ioutil"
15         "os"
16         "os/exec"
17         "path/filepath"
18         "runtime"
19         "strings"
20         "testing"
21         "time"
22
23         "golang.org/x/tools/internal/testenv"
24 )
25
26 func TestMain(m *testing.M) {
27         testenv.ExitIfSmallMachine()
28         os.Exit(m.Run())
29 }
30
31 // ----------------------------------------------------------------------------
32 // The following three functions (Builder, HasGoBuild, MustHaveGoBuild) were
33 // copied from $GOROOT/src/internal/testenv since that package is not available
34 // in x/tools.
35
36 // Builder reports the name of the builder running this test
37 // (for example, "linux-amd64" or "windows-386-gce").
38 // If the test is not running on the build infrastructure,
39 // Builder returns the empty string.
40 func Builder() string {
41         return os.Getenv("GO_BUILDER_NAME")
42 }
43
44 // HasGoBuild reports whether the current system can build programs with ``go build''
45 // and then run them with os.StartProcess or exec.Command.
46 func HasGoBuild() bool {
47         switch runtime.GOOS {
48         case "android", "nacl":
49                 return false
50         case "darwin":
51                 if strings.HasPrefix(runtime.GOARCH, "arm") {
52                         return false
53                 }
54         }
55         return true
56 }
57
58 // MustHaveGoBuild checks that the current system can build programs with ``go build''
59 // and then run them with os.StartProcess or exec.Command.
60 // If not, MustHaveGoBuild calls t.Skip with an explanation.
61 func MustHaveGoBuild(t *testing.T) {
62         testenv.NeedsTool(t, "go")
63         if !HasGoBuild() {
64                 t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
65         }
66 }
67
68 // ----------------------------------------------------------------------------
69
70 // skipSpecialPlatforms causes the test to be skipped for platforms where
71 // builders (build.golang.org) don't have access to compiled packages for
72 // import.
73 func skipSpecialPlatforms(t *testing.T) {
74         switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
75         case "nacl-amd64p32",
76                 "nacl-386",
77                 "nacl-arm",
78                 "darwin-arm",
79                 "darwin-arm64":
80                 t.Skipf("no compiled packages available for import on %s", platform)
81         }
82 }
83
84 // compile runs the compiler on filename, with dirname as the working directory,
85 // and writes the output file to outdirname.
86 func compile(t *testing.T, dirname, filename, outdirname string) string {
87         /* testenv. */ MustHaveGoBuild(t)
88         // filename must end with ".go"
89         if !strings.HasSuffix(filename, ".go") {
90                 t.Fatalf("filename doesn't end in .go: %s", filename)
91         }
92         basename := filepath.Base(filename)
93         outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o")
94         cmd := exec.Command("go", "tool", "compile", "-o", outname, filename)
95         cmd.Dir = dirname
96         out, err := cmd.CombinedOutput()
97         if err != nil {
98                 t.Logf("%s", out)
99                 t.Fatalf("go tool compile %s failed: %s", filename, err)
100         }
101         return outname
102 }
103
104 func testPath(t *testing.T, path, srcDir string) *types.Package {
105         t0 := time.Now()
106         pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil)
107         if err != nil {
108                 t.Errorf("testPath(%s): %s", path, err)
109                 return nil
110         }
111         t.Logf("testPath(%s): %v", path, time.Since(t0))
112         return pkg
113 }
114
115 const maxTime = 30 * time.Second
116
117 func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
118         dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
119         list, err := ioutil.ReadDir(dirname)
120         if err != nil {
121                 t.Fatalf("testDir(%s): %s", dirname, err)
122         }
123         for _, f := range list {
124                 if time.Now().After(endTime) {
125                         t.Log("testing time used up")
126                         return
127                 }
128                 switch {
129                 case !f.IsDir():
130                         // try extensions
131                         for _, ext := range pkgExts {
132                                 if strings.HasSuffix(f.Name(), ext) {
133                                         name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
134                                         if testPath(t, filepath.Join(dir, name), dir) != nil {
135                                                 nimports++
136                                         }
137                                 }
138                         }
139                 case f.IsDir():
140                         nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
141                 }
142         }
143         return
144 }
145
146 func mktmpdir(t *testing.T) string {
147         tmpdir, err := ioutil.TempDir("", "gcimporter_test")
148         if err != nil {
149                 t.Fatal("mktmpdir:", err)
150         }
151         if err := os.Mkdir(filepath.Join(tmpdir, "testdata"), 0700); err != nil {
152                 os.RemoveAll(tmpdir)
153                 t.Fatal("mktmpdir:", err)
154         }
155         return tmpdir
156 }
157
158 const testfile = "exports.go"
159
160 func TestImportTestdata(t *testing.T) {
161         // This package only handles gc export data.
162         if runtime.Compiler != "gc" {
163                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
164         }
165
166         tmpdir := mktmpdir(t)
167         defer os.RemoveAll(tmpdir)
168
169         compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"))
170
171         // filename should end with ".go"
172         filename := testfile[:len(testfile)-3]
173         if pkg := testPath(t, "./testdata/"+filename, tmpdir); pkg != nil {
174                 // The package's Imports list must include all packages
175                 // explicitly imported by testfile, plus all packages
176                 // referenced indirectly via exported objects in testfile.
177                 // With the textual export format (when run against Go1.6),
178                 // the list may also include additional packages that are
179                 // not strictly required for import processing alone (they
180                 // are exported to err "on the safe side").
181                 // For now, we just test the presence of a few packages
182                 // that we know are there for sure.
183                 got := fmt.Sprint(pkg.Imports())
184                 for _, want := range []string{"go/ast", "go/token"} {
185                         if !strings.Contains(got, want) {
186                                 t.Errorf(`Package("exports").Imports() = %s, does not contain %s`, got, want)
187                         }
188                 }
189         }
190 }
191
192 func TestVersionHandling(t *testing.T) {
193         skipSpecialPlatforms(t) // we really only need to exclude nacl platforms, but this is fine
194
195         // This package only handles gc export data.
196         if runtime.Compiler != "gc" {
197                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
198         }
199
200         const dir = "./testdata/versions"
201         list, err := ioutil.ReadDir(dir)
202         if err != nil {
203                 t.Fatal(err)
204         }
205
206         tmpdir := mktmpdir(t)
207         defer os.RemoveAll(tmpdir)
208         corruptdir := filepath.Join(tmpdir, "testdata", "versions")
209         if err := os.Mkdir(corruptdir, 0700); err != nil {
210                 t.Fatal(err)
211         }
212
213         for _, f := range list {
214                 name := f.Name()
215                 if !strings.HasSuffix(name, ".a") {
216                         continue // not a package file
217                 }
218                 if strings.Contains(name, "corrupted") {
219                         continue // don't process a leftover corrupted file
220                 }
221                 pkgpath := "./" + name[:len(name)-2]
222
223                 if testing.Verbose() {
224                         t.Logf("importing %s", name)
225                 }
226
227                 // test that export data can be imported
228                 _, err := Import(make(map[string]*types.Package), pkgpath, dir, nil)
229                 if err != nil {
230                         // ok to fail if it fails with a newer version error for select files
231                         if strings.Contains(err.Error(), "newer version") {
232                                 switch name {
233                                 case "test_go1.11_999b.a", "test_go1.11_999i.a":
234                                         continue
235                                 }
236                                 // fall through
237                         }
238                         t.Errorf("import %q failed: %v", pkgpath, err)
239                         continue
240                 }
241
242                 // create file with corrupted export data
243                 // 1) read file
244                 data, err := ioutil.ReadFile(filepath.Join(dir, name))
245                 if err != nil {
246                         t.Fatal(err)
247                 }
248                 // 2) find export data
249                 i := bytes.Index(data, []byte("\n$$B\n")) + 5
250                 j := bytes.Index(data[i:], []byte("\n$$\n")) + i
251                 if i < 0 || j < 0 || i > j {
252                         t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
253                 }
254                 // 3) corrupt the data (increment every 7th byte)
255                 for k := j - 13; k >= i; k -= 7 {
256                         data[k]++
257                 }
258                 // 4) write the file
259                 pkgpath += "_corrupted"
260                 filename := filepath.Join(corruptdir, pkgpath) + ".a"
261                 ioutil.WriteFile(filename, data, 0666)
262
263                 // test that importing the corrupted file results in an error
264                 _, err = Import(make(map[string]*types.Package), pkgpath, corruptdir, nil)
265                 if err == nil {
266                         t.Errorf("import corrupted %q succeeded", pkgpath)
267                 } else if msg := err.Error(); !strings.Contains(msg, "version skew") {
268                         t.Errorf("import %q error incorrect (%s)", pkgpath, msg)
269                 }
270         }
271 }
272
273 func TestImportStdLib(t *testing.T) {
274         skipSpecialPlatforms(t)
275
276         // This package only handles gc export data.
277         if runtime.Compiler != "gc" {
278                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
279         }
280
281         dt := maxTime
282         if testing.Short() && /* testenv. */ Builder() == "" {
283                 dt = 10 * time.Millisecond
284         }
285         nimports := testDir(t, "", time.Now().Add(dt)) // installed packages
286         t.Logf("tested %d imports", nimports)
287 }
288
289 func TestIssue5815(t *testing.T) {
290         skipSpecialPlatforms(t)
291
292         // This package only handles gc export data.
293         if runtime.Compiler != "gc" {
294                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
295         }
296
297         pkg := importPkg(t, "strings", ".")
298
299         scope := pkg.Scope()
300         for _, name := range scope.Names() {
301                 obj := scope.Lookup(name)
302                 if obj.Pkg() == nil {
303                         t.Errorf("no pkg for %s", obj)
304                 }
305                 if tname, _ := obj.(*types.TypeName); tname != nil {
306                         named := tname.Type().(*types.Named)
307                         for i := 0; i < named.NumMethods(); i++ {
308                                 m := named.Method(i)
309                                 if m.Pkg() == nil {
310                                         t.Errorf("no pkg for %s", m)
311                                 }
312                         }
313                 }
314         }
315 }
316
317 // Smoke test to ensure that imported methods get the correct package.
318 func TestCorrectMethodPackage(t *testing.T) {
319         skipSpecialPlatforms(t)
320
321         // This package only handles gc export data.
322         if runtime.Compiler != "gc" {
323                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
324         }
325
326         imports := make(map[string]*types.Package)
327         _, err := Import(imports, "net/http", ".", nil)
328         if err != nil {
329                 t.Fatal(err)
330         }
331
332         mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
333         mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
334         sel := mset.Lookup(nil, "Lock")
335         lock := sel.Obj().(*types.Func)
336         if got, want := lock.Pkg().Path(), "sync"; got != want {
337                 t.Errorf("got package path %q; want %q", got, want)
338         }
339 }
340
341 func TestIssue13566(t *testing.T) {
342         skipSpecialPlatforms(t)
343
344         // This package only handles gc export data.
345         if runtime.Compiler != "gc" {
346                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
347         }
348
349         // On windows, we have to set the -D option for the compiler to avoid having a drive
350         // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
351         if runtime.GOOS == "windows" {
352                 t.Skip("avoid dealing with relative paths/drive letters on windows")
353         }
354
355         tmpdir := mktmpdir(t)
356         defer os.RemoveAll(tmpdir)
357         testoutdir := filepath.Join(tmpdir, "testdata")
358
359         // b.go needs to be compiled from the output directory so that the compiler can
360         // find the compiled package a. We pass the full path to compile() so that we
361         // don't have to copy the file to that directory.
362         bpath, err := filepath.Abs(filepath.Join("testdata", "b.go"))
363         if err != nil {
364                 t.Fatal(err)
365         }
366         compile(t, "testdata", "a.go", testoutdir)
367         compile(t, testoutdir, bpath, testoutdir)
368
369         // import must succeed (test for issue at hand)
370         pkg := importPkg(t, "./testdata/b", tmpdir)
371
372         // make sure all indirectly imported packages have names
373         for _, imp := range pkg.Imports() {
374                 if imp.Name() == "" {
375                         t.Errorf("no name for %s package", imp.Path())
376                 }
377         }
378 }
379
380 func TestIssue13898(t *testing.T) {
381         skipSpecialPlatforms(t)
382
383         // This package only handles gc export data.
384         if runtime.Compiler != "gc" {
385                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
386         }
387
388         // import go/internal/gcimporter which imports go/types partially
389         imports := make(map[string]*types.Package)
390         _, err := Import(imports, "go/internal/gcimporter", ".", nil)
391         if err != nil {
392                 t.Fatal(err)
393         }
394
395         // look for go/types package
396         var goTypesPkg *types.Package
397         for path, pkg := range imports {
398                 if path == "go/types" {
399                         goTypesPkg = pkg
400                         break
401                 }
402         }
403         if goTypesPkg == nil {
404                 t.Fatal("go/types not found")
405         }
406
407         // look for go/types.Object type
408         obj := lookupObj(t, goTypesPkg.Scope(), "Object")
409         typ, ok := obj.Type().(*types.Named)
410         if !ok {
411                 t.Fatalf("go/types.Object type is %v; wanted named type", typ)
412         }
413
414         // lookup go/types.Object.Pkg method
415         m, index, indirect := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
416         if m == nil {
417                 t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
418         }
419
420         // the method must belong to go/types
421         if m.Pkg().Path() != "go/types" {
422                 t.Fatalf("found %v; want go/types", m.Pkg())
423         }
424 }
425
426 func TestIssue15517(t *testing.T) {
427         skipSpecialPlatforms(t)
428
429         // This package only handles gc export data.
430         if runtime.Compiler != "gc" {
431                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
432         }
433
434         // On windows, we have to set the -D option for the compiler to avoid having a drive
435         // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
436         if runtime.GOOS == "windows" {
437                 t.Skip("avoid dealing with relative paths/drive letters on windows")
438         }
439
440         tmpdir := mktmpdir(t)
441         defer os.RemoveAll(tmpdir)
442
443         compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"))
444
445         // Multiple imports of p must succeed without redeclaration errors.
446         // We use an import path that's not cleaned up so that the eventual
447         // file path for the package is different from the package path; this
448         // will expose the error if it is present.
449         //
450         // (Issue: Both the textual and the binary importer used the file path
451         // of the package to be imported as key into the shared packages map.
452         // However, the binary importer then used the package path to identify
453         // the imported package to mark it as complete; effectively marking the
454         // wrong package as complete. By using an "unclean" package path, the
455         // file and package path are different, exposing the problem if present.
456         // The same issue occurs with vendoring.)
457         imports := make(map[string]*types.Package)
458         for i := 0; i < 3; i++ {
459                 if _, err := Import(imports, "./././testdata/p", tmpdir, nil); err != nil {
460                         t.Fatal(err)
461                 }
462         }
463 }
464
465 func TestIssue15920(t *testing.T) {
466         skipSpecialPlatforms(t)
467
468         // This package only handles gc export data.
469         if runtime.Compiler != "gc" {
470                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
471         }
472
473         // On windows, we have to set the -D option for the compiler to avoid having a drive
474         // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
475         if runtime.GOOS == "windows" {
476                 t.Skip("avoid dealing with relative paths/drive letters on windows")
477         }
478
479         compileAndImportPkg(t, "issue15920")
480 }
481
482 func TestIssue20046(t *testing.T) {
483         skipSpecialPlatforms(t)
484
485         // This package only handles gc export data.
486         if runtime.Compiler != "gc" {
487                 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
488         }
489
490         // On windows, we have to set the -D option for the compiler to avoid having a drive
491         // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
492         if runtime.GOOS == "windows" {
493                 t.Skip("avoid dealing with relative paths/drive letters on windows")
494         }
495
496         // "./issue20046".V.M must exist
497         pkg := compileAndImportPkg(t, "issue20046")
498         obj := lookupObj(t, pkg.Scope(), "V")
499         if m, index, indirect := types.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
500                 t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
501         }
502 }
503
504 func importPkg(t *testing.T, path, srcDir string) *types.Package {
505         pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil)
506         if err != nil {
507                 t.Fatal(err)
508         }
509         return pkg
510 }
511
512 func compileAndImportPkg(t *testing.T, name string) *types.Package {
513         tmpdir := mktmpdir(t)
514         defer os.RemoveAll(tmpdir)
515         compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"))
516         return importPkg(t, "./testdata/"+name, tmpdir)
517 }
518
519 func lookupObj(t *testing.T, scope *types.Scope, name string) types.Object {
520         if obj := scope.Lookup(name); obj != nil {
521                 return obj
522         }
523         t.Fatalf("%s not found", name)
524         return nil
525 }