]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/go/build/build_test.go
libgo: update to Go1.14beta1
[thirdparty/gcc.git] / libgo / go / go / build / build_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 package build
6
7 import (
8 "internal/testenv"
9 "io"
10 "io/ioutil"
11 "os"
12 "path/filepath"
13 "reflect"
14 "runtime"
15 "strings"
16 "testing"
17 )
18
19 func TestMatch(t *testing.T) {
20 ctxt := Default
21 what := "default"
22 match := func(tag string, want map[string]bool) {
23 m := make(map[string]bool)
24 if !ctxt.match(tag, m) {
25 t.Errorf("%s context should match %s, does not", what, tag)
26 }
27 if !reflect.DeepEqual(m, want) {
28 t.Errorf("%s tags = %v, want %v", tag, m, want)
29 }
30 }
31 nomatch := func(tag string, want map[string]bool) {
32 m := make(map[string]bool)
33 if ctxt.match(tag, m) {
34 t.Errorf("%s context should NOT match %s, does", what, tag)
35 }
36 if !reflect.DeepEqual(m, want) {
37 t.Errorf("%s tags = %v, want %v", tag, m, want)
38 }
39 }
40
41 match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true})
42 match(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
43 nomatch(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
44
45 what = "modified"
46 ctxt.BuildTags = []string{"foo"}
47 match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true})
48 match(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
49 nomatch(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
50 match(runtime.GOOS+","+runtime.GOARCH+",!bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
51 nomatch(runtime.GOOS+","+runtime.GOARCH+",bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
52 nomatch("!", map[string]bool{})
53 }
54
55 func TestDotSlashImport(t *testing.T) {
56 p, err := ImportDir("testdata/other", 0)
57 if err != nil {
58 t.Fatal(err)
59 }
60 if len(p.Imports) != 1 || p.Imports[0] != "./file" {
61 t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports)
62 }
63
64 p1, err := Import("./file", "testdata/other", 0)
65 if err != nil {
66 t.Fatal(err)
67 }
68 if p1.Name != "file" {
69 t.Fatalf("./file: Name=%q, want %q", p1.Name, "file")
70 }
71 dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows
72 if p1.Dir != dir {
73 t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir)
74 }
75 }
76
77 func TestEmptyImport(t *testing.T) {
78 p, err := Import("", Default.GOROOT, FindOnly)
79 if err == nil {
80 t.Fatal(`Import("") returned nil error.`)
81 }
82 if p == nil {
83 t.Fatal(`Import("") returned nil package.`)
84 }
85 if p.ImportPath != "" {
86 t.Fatalf("ImportPath=%q, want %q.", p.ImportPath, "")
87 }
88 }
89
90 func TestEmptyFolderImport(t *testing.T) {
91 _, err := Import(".", "testdata/empty", 0)
92 if _, ok := err.(*NoGoError); !ok {
93 t.Fatal(`Import("testdata/empty") did not return NoGoError.`)
94 }
95 }
96
97 func TestMultiplePackageImport(t *testing.T) {
98 _, err := Import(".", "testdata/multi", 0)
99 mpe, ok := err.(*MultiplePackageError)
100 if !ok {
101 t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
102 }
103 want := &MultiplePackageError{
104 Dir: filepath.FromSlash("testdata/multi"),
105 Packages: []string{"main", "test_package"},
106 Files: []string{"file.go", "file_appengine.go"},
107 }
108 if !reflect.DeepEqual(mpe, want) {
109 t.Errorf("got %#v; want %#v", mpe, want)
110 }
111 }
112
113 func TestLocalDirectory(t *testing.T) {
114 t.Skip("does not work with gccgo")
115 if runtime.GOOS == "darwin" {
116 switch runtime.GOARCH {
117 case "arm", "arm64":
118 t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
119 }
120 }
121
122 cwd, err := os.Getwd()
123 if err != nil {
124 t.Fatal(err)
125 }
126
127 p, err := ImportDir(cwd, 0)
128 if err != nil {
129 t.Fatal(err)
130 }
131 if p.ImportPath != "go/build" {
132 t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "go/build")
133 }
134 }
135
136 func TestShouldBuild(t *testing.T) {
137 const file1 = "// +build tag1\n\n" +
138 "package main\n"
139 want1 := map[string]bool{"tag1": true}
140
141 const file2 = "// +build cgo\n\n" +
142 "// This package implements parsing of tags like\n" +
143 "// +build tag1\n" +
144 "package build"
145 want2 := map[string]bool{"cgo": true}
146
147 const file3 = "// Copyright The Go Authors.\n\n" +
148 "package build\n\n" +
149 "// shouldBuild checks tags given by lines of the form\n" +
150 "// +build tag\n" +
151 "func shouldBuild(content []byte)\n"
152 want3 := map[string]bool{}
153
154 ctx := &Context{BuildTags: []string{"tag1"}}
155 m := map[string]bool{}
156 if !ctx.shouldBuild([]byte(file1), m, nil) {
157 t.Errorf("shouldBuild(file1) = false, want true")
158 }
159 if !reflect.DeepEqual(m, want1) {
160 t.Errorf("shouldBuild(file1) tags = %v, want %v", m, want1)
161 }
162
163 m = map[string]bool{}
164 if ctx.shouldBuild([]byte(file2), m, nil) {
165 t.Errorf("shouldBuild(file2) = true, want false")
166 }
167 if !reflect.DeepEqual(m, want2) {
168 t.Errorf("shouldBuild(file2) tags = %v, want %v", m, want2)
169 }
170
171 m = map[string]bool{}
172 ctx = &Context{BuildTags: nil}
173 if !ctx.shouldBuild([]byte(file3), m, nil) {
174 t.Errorf("shouldBuild(file3) = false, want true")
175 }
176 if !reflect.DeepEqual(m, want3) {
177 t.Errorf("shouldBuild(file3) tags = %v, want %v", m, want3)
178 }
179 }
180
181 func TestGoodOSArchFile(t *testing.T) {
182 ctx := &Context{BuildTags: []string{"linux"}, GOOS: "darwin"}
183 m := map[string]bool{}
184 want := map[string]bool{"linux": true}
185 if !ctx.goodOSArchFile("hello_linux.go", m) {
186 t.Errorf("goodOSArchFile(hello_linux.go) = false, want true")
187 }
188 if !reflect.DeepEqual(m, want) {
189 t.Errorf("goodOSArchFile(hello_linux.go) tags = %v, want %v", m, want)
190 }
191 }
192
193 type readNopCloser struct {
194 io.Reader
195 }
196
197 func (r readNopCloser) Close() error {
198 return nil
199 }
200
201 var (
202 ctxtP9 = Context{GOARCH: "arm", GOOS: "plan9"}
203 ctxtAndroid = Context{GOARCH: "arm", GOOS: "android"}
204 )
205
206 var matchFileTests = []struct {
207 ctxt Context
208 name string
209 data string
210 match bool
211 }{
212 {ctxtP9, "foo_arm.go", "", true},
213 {ctxtP9, "foo1_arm.go", "// +build linux\n\npackage main\n", false},
214 {ctxtP9, "foo_darwin.go", "", false},
215 {ctxtP9, "foo.go", "", true},
216 {ctxtP9, "foo1.go", "// +build linux\n\npackage main\n", false},
217 {ctxtP9, "foo.badsuffix", "", false},
218 {ctxtAndroid, "foo_linux.go", "", true},
219 {ctxtAndroid, "foo_android.go", "", true},
220 {ctxtAndroid, "foo_plan9.go", "", false},
221 {ctxtAndroid, "android.go", "", true},
222 {ctxtAndroid, "plan9.go", "", true},
223 {ctxtAndroid, "plan9_test.go", "", true},
224 {ctxtAndroid, "arm.s", "", true},
225 {ctxtAndroid, "amd64.s", "", true},
226 }
227
228 func TestMatchFile(t *testing.T) {
229 for _, tt := range matchFileTests {
230 ctxt := tt.ctxt
231 ctxt.OpenFile = func(path string) (r io.ReadCloser, err error) {
232 if path != "x+"+tt.name {
233 t.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name)
234 }
235 return &readNopCloser{strings.NewReader(tt.data)}, nil
236 }
237 ctxt.JoinPath = func(elem ...string) string {
238 return strings.Join(elem, "+")
239 }
240 match, err := ctxt.MatchFile("x", tt.name)
241 if match != tt.match || err != nil {
242 t.Fatalf("MatchFile(%q) = %v, %v, want %v, nil", tt.name, match, err, tt.match)
243 }
244 }
245 }
246
247 func TestImportCmd(t *testing.T) {
248 t.Skip("does not work with gccgo")
249 if runtime.GOOS == "darwin" {
250 switch runtime.GOARCH {
251 case "arm", "arm64":
252 t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
253 }
254 }
255
256 p, err := Import("cmd/internal/objfile", "", 0)
257 if err != nil {
258 t.Fatal(err)
259 }
260 if !strings.HasSuffix(filepath.ToSlash(p.Dir), "src/cmd/internal/objfile") {
261 t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile")
262 }
263 }
264
265 var (
266 expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add")
267 )
268
269 var expandSrcDirTests = []struct {
270 input, expected string
271 }{
272 {"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"},
273 {"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"},
274 {"Nothing to expand here!", "Nothing to expand here!"},
275 {"$", "$"},
276 {"$$", "$$"},
277 {"${", "${"},
278 {"$}", "$}"},
279 {"$FOO ${BAR}", "$FOO ${BAR}"},
280 {"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."},
281 {"$SRCDIR is missing braces", "$SRCDIR is missing braces"},
282 }
283
284 func TestExpandSrcDir(t *testing.T) {
285 for _, test := range expandSrcDirTests {
286 output, _ := expandSrcDir(test.input, expandSrcDirPath)
287 if output != test.expected {
288 t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected)
289 } else {
290 t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath)
291 }
292 }
293 }
294
295 func TestShellSafety(t *testing.T) {
296 tests := []struct {
297 input, srcdir, expected string
298 result bool
299 }{
300 {"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
301 {"-I${SRCDIR}", "~wtf$@%^", "-I~wtf$@%^", true},
302 {"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
303 {"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", true},
304 {"-I/tmp", "/tmp/[0]", "-I/tmp", true},
305 {"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false},
306 {"-I${SRCDIR}/dir", "/tmp/go go", "-I/tmp/go go/dir", true},
307 {"-I${SRCDIR}/dir dir", "/tmp/go", "-I/tmp/go/dir dir", true},
308 }
309 for _, test := range tests {
310 output, ok := expandSrcDir(test.input, test.srcdir)
311 if ok != test.result {
312 t.Errorf("Expected %t while %q expands to %q with SRCDIR=%q; got %t", test.result, test.input, output, test.srcdir, ok)
313 }
314 if output != test.expected {
315 t.Errorf("Expected %q while %q expands with SRCDIR=%q; got %q", test.expected, test.input, test.srcdir, output)
316 }
317 }
318 }
319
320 // Want to get a "cannot find package" error when directory for package does not exist.
321 // There should be valid partial information in the returned non-nil *Package.
322 func TestImportDirNotExist(t *testing.T) {
323 testenv.MustHaveGoBuild(t) // really must just have source
324 ctxt := Default
325
326 emptyDir, err := ioutil.TempDir("", t.Name())
327 if err != nil {
328 t.Fatal(err)
329 }
330 defer os.RemoveAll(emptyDir)
331
332 ctxt.GOPATH = emptyDir
333 ctxt.Dir = emptyDir
334
335 tests := []struct {
336 label string
337 path, srcDir string
338 mode ImportMode
339 }{
340 {"Import(full, 0)", "go/build/doesnotexist", "", 0},
341 {"Import(local, 0)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), 0},
342 {"Import(full, FindOnly)", "go/build/doesnotexist", "", FindOnly},
343 {"Import(local, FindOnly)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), FindOnly},
344 }
345 for _, test := range tests {
346 p, err := ctxt.Import(test.path, test.srcDir, test.mode)
347 if err == nil || !strings.HasPrefix(err.Error(), "cannot find package") {
348 t.Errorf(`%s got error: %q, want "cannot find package" error`, test.label, err)
349 }
350 // If an error occurs, build.Import is documented to return
351 // a non-nil *Package containing partial information.
352 if p == nil {
353 t.Fatalf(`%s got nil p, want non-nil *Package`, test.label)
354 }
355 // Verify partial information in p.
356 if p.ImportPath != "go/build/doesnotexist" {
357 t.Errorf(`%s got p.ImportPath: %q, want "go/build/doesnotexist"`, test.label, p.ImportPath)
358 }
359 }
360 }
361
362 func TestImportVendor(t *testing.T) {
363 testenv.MustHaveGoBuild(t) // really must just have source
364
365 defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
366 os.Setenv("GO111MODULE", "off")
367
368 ctxt := Default
369 wd, err := os.Getwd()
370 if err != nil {
371 t.Fatal(err)
372 }
373 ctxt.GOPATH = filepath.Join(wd, "testdata/withvendor")
374 p, err := ctxt.Import("c/d", filepath.Join(ctxt.GOPATH, "src/a/b"), 0)
375 if err != nil {
376 t.Fatalf("cannot find vendored c/d from testdata src/a/b directory: %v", err)
377 }
378 want := "a/vendor/c/d"
379 if p.ImportPath != want {
380 t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want)
381 }
382 }
383
384 func TestImportVendorFailure(t *testing.T) {
385 testenv.MustHaveGoBuild(t) // really must just have source
386
387 defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
388 os.Setenv("GO111MODULE", "off")
389
390 ctxt := Default
391 wd, err := os.Getwd()
392 if err != nil {
393 t.Fatal(err)
394 }
395 ctxt.GOPATH = filepath.Join(wd, "testdata/withvendor")
396 p, err := ctxt.Import("x.com/y/z", filepath.Join(ctxt.GOPATH, "src/a/b"), 0)
397 if err == nil {
398 t.Fatalf("found made-up package x.com/y/z in %s", p.Dir)
399 }
400
401 e := err.Error()
402 if !strings.Contains(e, " (vendor tree)") {
403 t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
404 }
405 }
406
407 func TestImportVendorParentFailure(t *testing.T) {
408 testenv.MustHaveGoBuild(t) // really must just have source
409
410 defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
411 os.Setenv("GO111MODULE", "off")
412
413 ctxt := Default
414 wd, err := os.Getwd()
415 if err != nil {
416 t.Fatal(err)
417 }
418 ctxt.GOPATH = filepath.Join(wd, "testdata/withvendor")
419 // This import should fail because the vendor/c directory has no source code.
420 p, err := ctxt.Import("c", filepath.Join(ctxt.GOPATH, "src/a/b"), 0)
421 if err == nil {
422 t.Fatalf("found empty parent in %s", p.Dir)
423 }
424 if p != nil && p.Dir != "" {
425 t.Fatalf("decided to use %s", p.Dir)
426 }
427 e := err.Error()
428 if !strings.Contains(e, " (vendor tree)") {
429 t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
430 }
431 }
432
433 // Check that a package is loaded in module mode if GO111MODULE=on, even when
434 // no go.mod file is present. It should fail to resolve packages outside std.
435 // Verifies golang.org/issue/34669.
436 func TestImportPackageOutsideModule(t *testing.T) {
437 testenv.MustHaveGoBuild(t)
438
439 // Disable module fetching for this test so that 'go list' fails quickly
440 // without trying to find the latest version of a module.
441 defer os.Setenv("GOPROXY", os.Getenv("GOPROXY"))
442 os.Setenv("GOPROXY", "off")
443
444 // Create a GOPATH in a temporary directory. We don't use testdata
445 // because it's in GOROOT, which interferes with the module heuristic.
446 gopath, err := ioutil.TempDir("", "gobuild-notmodule")
447 if err != nil {
448 t.Fatal(err)
449 }
450 defer os.RemoveAll(gopath)
451 if err := os.MkdirAll(filepath.Join(gopath, "src/example.com/p"), 0777); err != nil {
452 t.Fatal(err)
453 }
454 if err := ioutil.WriteFile(filepath.Join(gopath, "src/example.com/p/p.go"), []byte("package p"), 0666); err != nil {
455 t.Fatal(err)
456 }
457
458 defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
459 os.Setenv("GO111MODULE", "on")
460 defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
461 os.Setenv("GOPATH", gopath)
462 ctxt := Default
463 ctxt.GOPATH = gopath
464 ctxt.Dir = filepath.Join(gopath, "src/example.com/p")
465
466 want := "cannot find module providing package"
467 if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil {
468 t.Fatal("importing package when no go.mod is present succeeded unexpectedly")
469 } else if errStr := err.Error(); !strings.Contains(errStr, want) {
470 t.Fatalf("error when importing package when no go.mod is present: got %q; want %q", errStr, want)
471 }
472 }
473
474 func TestImportDirTarget(t *testing.T) {
475 testenv.MustHaveGoBuild(t) // really must just have source
476 ctxt := Default
477 ctxt.GOPATH = ""
478 p, err := ctxt.ImportDir(filepath.Join(ctxt.GOROOT, "src/path"), 0)
479 if err != nil {
480 t.Fatal(err)
481 }
482 if p.PkgTargetRoot == "" || p.PkgObj == "" {
483 t.Errorf("p.PkgTargetRoot == %q, p.PkgObj == %q, want non-empty", p.PkgTargetRoot, p.PkgObj)
484 }
485 }
486
487 // TestIssue23594 prevents go/build from regressing and populating Package.Doc
488 // from comments in test files.
489 func TestIssue23594(t *testing.T) {
490 // Package testdata/doc contains regular and external test files
491 // with comments attached to their package declarations. The names of the files
492 // ensure that we see the comments from the test files first.
493 p, err := ImportDir("testdata/doc", 0)
494 if err != nil {
495 t.Fatalf("could not import testdata: %v", err)
496 }
497
498 if p.Doc != "Correct" {
499 t.Fatalf("incorrectly set .Doc to %q", p.Doc)
500 }
501 }
502
503 // TestMissingImportErrorRepetition checks that when an unknown package is
504 // imported, the package path is only shown once in the error.
505 // Verifies golang.org/issue/34752.
506 func TestMissingImportErrorRepetition(t *testing.T) {
507 testenv.MustHaveGoBuild(t) // need 'go list' internally
508 tmp, err := ioutil.TempDir("", "")
509 if err != nil {
510 t.Fatal(err)
511 }
512 defer os.RemoveAll(tmp)
513 if err := ioutil.WriteFile(filepath.Join(tmp, "go.mod"), []byte("module m"), 0666); err != nil {
514 t.Fatal(err)
515 }
516 defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
517 os.Setenv("GO111MODULE", "on")
518 defer os.Setenv("GOPROXY", os.Getenv("GOPROXY"))
519 os.Setenv("GOPROXY", "off")
520 defer os.Setenv("GONOPROXY", os.Getenv("GONOPROXY"))
521 os.Setenv("GONOPROXY", "none")
522
523 ctxt := Default
524 ctxt.Dir = tmp
525
526 pkgPath := "example.com/hello"
527 _, err = ctxt.Import(pkgPath, tmp, FindOnly)
528 if err == nil {
529 t.Fatal("unexpected success")
530 }
531 // Don't count the package path with a URL like https://...?go-get=1.
532 // See golang.org/issue/35986.
533 errStr := strings.ReplaceAll(err.Error(), "://"+pkgPath+"?go-get=1", "://...?go-get=1")
534 if n := strings.Count(errStr, pkgPath); n != 1 {
535 t.Fatalf("package path %q appears in error %d times; should appear once\nerror: %v", pkgPath, n, err)
536 }
537 }
538
539 // TestCgoImportsIgnored checks that imports in cgo files are not included
540 // in the imports list when cgo is disabled.
541 // Verifies golang.org/issue/35946.
542 func TestCgoImportsIgnored(t *testing.T) {
543 ctxt := Default
544 ctxt.CgoEnabled = false
545 p, err := ctxt.ImportDir("testdata/cgo_disabled", 0)
546 if err != nil {
547 t.Fatal(err)
548 }
549 for _, path := range p.Imports {
550 if path == "should/be/ignored" {
551 t.Errorf("found import %q in ignored cgo file", path)
552 }
553 }
554 }