github.com/AndrienkoAleksandr/go@v0.0.19/src/go/build/build_test.go (about) 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 "fmt" 9 "internal/testenv" 10 "io" 11 "os" 12 "path/filepath" 13 "reflect" 14 "runtime" 15 "strings" 16 "testing" 17 ) 18 19 func TestMain(m *testing.M) { 20 Default.GOROOT = testenv.GOROOT(nil) 21 os.Exit(m.Run()) 22 } 23 24 func TestMatch(t *testing.T) { 25 ctxt := Default 26 what := "default" 27 match := func(tag string, want map[string]bool) { 28 t.Helper() 29 m := make(map[string]bool) 30 if !ctxt.matchAuto(tag, m) { 31 t.Errorf("%s context should match %s, does not", what, tag) 32 } 33 if !reflect.DeepEqual(m, want) { 34 t.Errorf("%s tags = %v, want %v", tag, m, want) 35 } 36 } 37 nomatch := func(tag string, want map[string]bool) { 38 t.Helper() 39 m := make(map[string]bool) 40 if ctxt.matchAuto(tag, m) { 41 t.Errorf("%s context should NOT match %s, does", what, tag) 42 } 43 if !reflect.DeepEqual(m, want) { 44 t.Errorf("%s tags = %v, want %v", tag, m, want) 45 } 46 } 47 48 match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true}) 49 match(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) 50 nomatch(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) 51 52 what = "modified" 53 ctxt.BuildTags = []string{"foo"} 54 match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true}) 55 match(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) 56 nomatch(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) 57 match(runtime.GOOS+","+runtime.GOARCH+",!bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true}) 58 nomatch(runtime.GOOS+","+runtime.GOARCH+",bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true}) 59 } 60 61 func TestDotSlashImport(t *testing.T) { 62 p, err := ImportDir("testdata/other", 0) 63 if err != nil { 64 t.Fatal(err) 65 } 66 if len(p.Imports) != 1 || p.Imports[0] != "./file" { 67 t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports) 68 } 69 70 p1, err := Import("./file", "testdata/other", 0) 71 if err != nil { 72 t.Fatal(err) 73 } 74 if p1.Name != "file" { 75 t.Fatalf("./file: Name=%q, want %q", p1.Name, "file") 76 } 77 dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows 78 if p1.Dir != dir { 79 t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir) 80 } 81 } 82 83 func TestEmptyImport(t *testing.T) { 84 p, err := Import("", testenv.GOROOT(t), FindOnly) 85 if err == nil { 86 t.Fatal(`Import("") returned nil error.`) 87 } 88 if p == nil { 89 t.Fatal(`Import("") returned nil package.`) 90 } 91 if p.ImportPath != "" { 92 t.Fatalf("ImportPath=%q, want %q.", p.ImportPath, "") 93 } 94 } 95 96 func TestEmptyFolderImport(t *testing.T) { 97 _, err := Import(".", "testdata/empty", 0) 98 if _, ok := err.(*NoGoError); !ok { 99 t.Fatal(`Import("testdata/empty") did not return NoGoError.`) 100 } 101 } 102 103 func TestMultiplePackageImport(t *testing.T) { 104 pkg, err := Import(".", "testdata/multi", 0) 105 106 mpe, ok := err.(*MultiplePackageError) 107 if !ok { 108 t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`) 109 } 110 want := &MultiplePackageError{ 111 Dir: filepath.FromSlash("testdata/multi"), 112 Packages: []string{"main", "test_package"}, 113 Files: []string{"file.go", "file_appengine.go"}, 114 } 115 if !reflect.DeepEqual(mpe, want) { 116 t.Errorf("err = %#v; want %#v", mpe, want) 117 } 118 119 // TODO(#45999): Since the name is ambiguous, pkg.Name should be left empty. 120 if wantName := "main"; pkg.Name != wantName { 121 t.Errorf("pkg.Name = %q; want %q", pkg.Name, wantName) 122 } 123 124 if wantGoFiles := []string{"file.go", "file_appengine.go"}; !reflect.DeepEqual(pkg.GoFiles, wantGoFiles) { 125 t.Errorf("pkg.GoFiles = %q; want %q", pkg.GoFiles, wantGoFiles) 126 } 127 128 if wantInvalidFiles := []string{"file_appengine.go"}; !reflect.DeepEqual(pkg.InvalidGoFiles, wantInvalidFiles) { 129 t.Errorf("pkg.InvalidGoFiles = %q; want %q", pkg.InvalidGoFiles, wantInvalidFiles) 130 } 131 } 132 133 func TestLocalDirectory(t *testing.T) { 134 if runtime.GOOS == "ios" { 135 t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH) 136 } 137 138 cwd, err := os.Getwd() 139 if err != nil { 140 t.Fatal(err) 141 } 142 143 p, err := ImportDir(cwd, 0) 144 if err != nil { 145 t.Fatal(err) 146 } 147 if p.ImportPath != "go/build" { 148 t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "go/build") 149 } 150 } 151 152 var shouldBuildTests = []struct { 153 name string 154 content string 155 tags map[string]bool 156 binaryOnly bool 157 shouldBuild bool 158 err error 159 }{ 160 { 161 name: "Yes", 162 content: "// +build yes\n\n" + 163 "package main\n", 164 tags: map[string]bool{"yes": true}, 165 shouldBuild: true, 166 }, 167 { 168 name: "Yes2", 169 content: "//go:build yes\n" + 170 "package main\n", 171 tags: map[string]bool{"yes": true}, 172 shouldBuild: true, 173 }, 174 { 175 name: "Or", 176 content: "// +build no yes\n\n" + 177 "package main\n", 178 tags: map[string]bool{"yes": true, "no": true}, 179 shouldBuild: true, 180 }, 181 { 182 name: "Or2", 183 content: "//go:build no || yes\n" + 184 "package main\n", 185 tags: map[string]bool{"yes": true, "no": true}, 186 shouldBuild: true, 187 }, 188 { 189 name: "And", 190 content: "// +build no,yes\n\n" + 191 "package main\n", 192 tags: map[string]bool{"yes": true, "no": true}, 193 shouldBuild: false, 194 }, 195 { 196 name: "And2", 197 content: "//go:build no && yes\n" + 198 "package main\n", 199 tags: map[string]bool{"yes": true, "no": true}, 200 shouldBuild: false, 201 }, 202 { 203 name: "Cgo", 204 content: "// +build cgo\n\n" + 205 "// Copyright The Go Authors.\n\n" + 206 "// This package implements parsing of tags like\n" + 207 "// +build tag1\n" + 208 "package build", 209 tags: map[string]bool{"cgo": true}, 210 shouldBuild: false, 211 }, 212 { 213 name: "Cgo2", 214 content: "//go:build cgo\n" + 215 "// Copyright The Go Authors.\n\n" + 216 "// This package implements parsing of tags like\n" + 217 "// +build tag1\n" + 218 "package build", 219 tags: map[string]bool{"cgo": true}, 220 shouldBuild: false, 221 }, 222 { 223 name: "AfterPackage", 224 content: "// Copyright The Go Authors.\n\n" + 225 "package build\n\n" + 226 "// shouldBuild checks tags given by lines of the form\n" + 227 "// +build tag\n" + 228 "//go:build tag\n" + 229 "func shouldBuild(content []byte)\n", 230 tags: map[string]bool{}, 231 shouldBuild: true, 232 }, 233 { 234 name: "TooClose", 235 content: "// +build yes\n" + 236 "package main\n", 237 tags: map[string]bool{}, 238 shouldBuild: true, 239 }, 240 { 241 name: "TooClose2", 242 content: "//go:build yes\n" + 243 "package main\n", 244 tags: map[string]bool{"yes": true}, 245 shouldBuild: true, 246 }, 247 { 248 name: "TooCloseNo", 249 content: "// +build no\n" + 250 "package main\n", 251 tags: map[string]bool{}, 252 shouldBuild: true, 253 }, 254 { 255 name: "TooCloseNo2", 256 content: "//go:build no\n" + 257 "package main\n", 258 tags: map[string]bool{"no": true}, 259 shouldBuild: false, 260 }, 261 { 262 name: "BinaryOnly", 263 content: "//go:binary-only-package\n" + 264 "// +build yes\n" + 265 "package main\n", 266 tags: map[string]bool{}, 267 binaryOnly: true, 268 shouldBuild: true, 269 }, 270 { 271 name: "BinaryOnly2", 272 content: "//go:binary-only-package\n" + 273 "//go:build no\n" + 274 "package main\n", 275 tags: map[string]bool{"no": true}, 276 binaryOnly: true, 277 shouldBuild: false, 278 }, 279 { 280 name: "ValidGoBuild", 281 content: "// +build yes\n\n" + 282 "//go:build no\n" + 283 "package main\n", 284 tags: map[string]bool{"no": true}, 285 shouldBuild: false, 286 }, 287 { 288 name: "MissingBuild2", 289 content: "/* */\n" + 290 "// +build yes\n\n" + 291 "//go:build no\n" + 292 "package main\n", 293 tags: map[string]bool{"no": true}, 294 shouldBuild: false, 295 }, 296 { 297 name: "Comment1", 298 content: "/*\n" + 299 "//go:build no\n" + 300 "*/\n\n" + 301 "package main\n", 302 tags: map[string]bool{}, 303 shouldBuild: true, 304 }, 305 { 306 name: "Comment2", 307 content: "/*\n" + 308 "text\n" + 309 "*/\n\n" + 310 "//go:build no\n" + 311 "package main\n", 312 tags: map[string]bool{"no": true}, 313 shouldBuild: false, 314 }, 315 { 316 name: "Comment3", 317 content: "/*/*/ /* hi *//* \n" + 318 "text\n" + 319 "*/\n\n" + 320 "//go:build no\n" + 321 "package main\n", 322 tags: map[string]bool{"no": true}, 323 shouldBuild: false, 324 }, 325 { 326 name: "Comment4", 327 content: "/**///go:build no\n" + 328 "package main\n", 329 tags: map[string]bool{}, 330 shouldBuild: true, 331 }, 332 { 333 name: "Comment5", 334 content: "/**/\n" + 335 "//go:build no\n" + 336 "package main\n", 337 tags: map[string]bool{"no": true}, 338 shouldBuild: false, 339 }, 340 } 341 342 func TestShouldBuild(t *testing.T) { 343 for _, tt := range shouldBuildTests { 344 t.Run(tt.name, func(t *testing.T) { 345 ctx := &Context{BuildTags: []string{"yes"}} 346 tags := map[string]bool{} 347 shouldBuild, binaryOnly, err := ctx.shouldBuild([]byte(tt.content), tags) 348 if shouldBuild != tt.shouldBuild || binaryOnly != tt.binaryOnly || !reflect.DeepEqual(tags, tt.tags) || err != tt.err { 349 t.Errorf("mismatch:\n"+ 350 "have shouldBuild=%v, binaryOnly=%v, tags=%v, err=%v\n"+ 351 "want shouldBuild=%v, binaryOnly=%v, tags=%v, err=%v", 352 shouldBuild, binaryOnly, tags, err, 353 tt.shouldBuild, tt.binaryOnly, tt.tags, tt.err) 354 } 355 }) 356 } 357 } 358 359 func TestGoodOSArchFile(t *testing.T) { 360 ctx := &Context{BuildTags: []string{"linux"}, GOOS: "darwin"} 361 m := map[string]bool{} 362 want := map[string]bool{"linux": true} 363 if !ctx.goodOSArchFile("hello_linux.go", m) { 364 t.Errorf("goodOSArchFile(hello_linux.go) = false, want true") 365 } 366 if !reflect.DeepEqual(m, want) { 367 t.Errorf("goodOSArchFile(hello_linux.go) tags = %v, want %v", m, want) 368 } 369 } 370 371 type readNopCloser struct { 372 io.Reader 373 } 374 375 func (r readNopCloser) Close() error { 376 return nil 377 } 378 379 var ( 380 ctxtP9 = Context{GOARCH: "arm", GOOS: "plan9"} 381 ctxtAndroid = Context{GOARCH: "arm", GOOS: "android"} 382 ) 383 384 var matchFileTests = []struct { 385 ctxt Context 386 name string 387 data string 388 match bool 389 }{ 390 {ctxtP9, "foo_arm.go", "", true}, 391 {ctxtP9, "foo1_arm.go", "// +build linux\n\npackage main\n", false}, 392 {ctxtP9, "foo_darwin.go", "", false}, 393 {ctxtP9, "foo.go", "", true}, 394 {ctxtP9, "foo1.go", "// +build linux\n\npackage main\n", false}, 395 {ctxtP9, "foo.badsuffix", "", false}, 396 {ctxtAndroid, "foo_linux.go", "", true}, 397 {ctxtAndroid, "foo_android.go", "", true}, 398 {ctxtAndroid, "foo_plan9.go", "", false}, 399 {ctxtAndroid, "android.go", "", true}, 400 {ctxtAndroid, "plan9.go", "", true}, 401 {ctxtAndroid, "plan9_test.go", "", true}, 402 {ctxtAndroid, "arm.s", "", true}, 403 {ctxtAndroid, "amd64.s", "", true}, 404 } 405 406 func TestMatchFile(t *testing.T) { 407 for _, tt := range matchFileTests { 408 ctxt := tt.ctxt 409 ctxt.OpenFile = func(path string) (r io.ReadCloser, err error) { 410 if path != "x+"+tt.name { 411 t.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name) 412 } 413 return &readNopCloser{strings.NewReader(tt.data)}, nil 414 } 415 ctxt.JoinPath = func(elem ...string) string { 416 return strings.Join(elem, "+") 417 } 418 match, err := ctxt.MatchFile("x", tt.name) 419 if match != tt.match || err != nil { 420 t.Fatalf("MatchFile(%q) = %v, %v, want %v, nil", tt.name, match, err, tt.match) 421 } 422 } 423 } 424 425 func TestImportCmd(t *testing.T) { 426 if runtime.GOOS == "ios" { 427 t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH) 428 } 429 430 p, err := Import("cmd/internal/objfile", "", 0) 431 if err != nil { 432 t.Fatal(err) 433 } 434 if !strings.HasSuffix(filepath.ToSlash(p.Dir), "src/cmd/internal/objfile") { 435 t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile") 436 } 437 } 438 439 var ( 440 expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add") 441 ) 442 443 var expandSrcDirTests = []struct { 444 input, expected string 445 }{ 446 {"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"}, 447 {"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"}, 448 {"Nothing to expand here!", "Nothing to expand here!"}, 449 {"$", "$"}, 450 {"$$", "$$"}, 451 {"${", "${"}, 452 {"$}", "$}"}, 453 {"$FOO ${BAR}", "$FOO ${BAR}"}, 454 {"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."}, 455 {"$SRCDIR is missing braces", "$SRCDIR is missing braces"}, 456 } 457 458 func TestExpandSrcDir(t *testing.T) { 459 for _, test := range expandSrcDirTests { 460 output, _ := expandSrcDir(test.input, expandSrcDirPath) 461 if output != test.expected { 462 t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected) 463 } else { 464 t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath) 465 } 466 } 467 } 468 469 func TestShellSafety(t *testing.T) { 470 tests := []struct { 471 input, srcdir, expected string 472 result bool 473 }{ 474 {"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true}, 475 {"-I${SRCDIR}", "~wtf$@%^", "-I~wtf$@%^", true}, 476 {"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true}, 477 {"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", true}, 478 {"-I/tmp", "/tmp/[0]", "-I/tmp", true}, 479 {"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false}, 480 {"-I${SRCDIR}/dir", "/tmp/go go", "-I/tmp/go go/dir", true}, 481 {"-I${SRCDIR}/dir dir", "/tmp/go", "-I/tmp/go/dir dir", true}, 482 } 483 for _, test := range tests { 484 output, ok := expandSrcDir(test.input, test.srcdir) 485 if ok != test.result { 486 t.Errorf("Expected %t while %q expands to %q with SRCDIR=%q; got %t", test.result, test.input, output, test.srcdir, ok) 487 } 488 if output != test.expected { 489 t.Errorf("Expected %q while %q expands with SRCDIR=%q; got %q", test.expected, test.input, test.srcdir, output) 490 } 491 } 492 } 493 494 // Want to get a "cannot find package" error when directory for package does not exist. 495 // There should be valid partial information in the returned non-nil *Package. 496 func TestImportDirNotExist(t *testing.T) { 497 testenv.MustHaveGoBuild(t) // really must just have source 498 ctxt := Default 499 500 emptyDir := t.TempDir() 501 502 ctxt.GOPATH = emptyDir 503 ctxt.Dir = emptyDir 504 505 tests := []struct { 506 label string 507 path, srcDir string 508 mode ImportMode 509 }{ 510 {"Import(full, 0)", "go/build/doesnotexist", "", 0}, 511 {"Import(local, 0)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), 0}, 512 {"Import(full, FindOnly)", "go/build/doesnotexist", "", FindOnly}, 513 {"Import(local, FindOnly)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), FindOnly}, 514 } 515 516 defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE")) 517 518 for _, GO111MODULE := range []string{"off", "on"} { 519 t.Run("GO111MODULE="+GO111MODULE, func(t *testing.T) { 520 os.Setenv("GO111MODULE", GO111MODULE) 521 522 for _, test := range tests { 523 p, err := ctxt.Import(test.path, test.srcDir, test.mode) 524 525 errOk := (err != nil && strings.HasPrefix(err.Error(), "cannot find package")) 526 wantErr := `"cannot find package" error` 527 if test.srcDir == "" { 528 if err != nil && strings.Contains(err.Error(), "is not in std") { 529 errOk = true 530 } 531 wantErr = `"cannot find package" or "is not in std" error` 532 } 533 if !errOk { 534 t.Errorf("%s got error: %q, want %s", test.label, err, wantErr) 535 } 536 // If an error occurs, build.Import is documented to return 537 // a non-nil *Package containing partial information. 538 if p == nil { 539 t.Fatalf(`%s got nil p, want non-nil *Package`, test.label) 540 } 541 // Verify partial information in p. 542 if p.ImportPath != "go/build/doesnotexist" { 543 t.Errorf(`%s got p.ImportPath: %q, want "go/build/doesnotexist"`, test.label, p.ImportPath) 544 } 545 } 546 }) 547 } 548 } 549 550 func TestImportVendor(t *testing.T) { 551 testenv.MustHaveGoBuild(t) // really must just have source 552 553 t.Setenv("GO111MODULE", "off") 554 555 ctxt := Default 556 wd, err := os.Getwd() 557 if err != nil { 558 t.Fatal(err) 559 } 560 ctxt.GOPATH = filepath.Join(wd, "testdata/withvendor") 561 p, err := ctxt.Import("c/d", filepath.Join(ctxt.GOPATH, "src/a/b"), 0) 562 if err != nil { 563 t.Fatalf("cannot find vendored c/d from testdata src/a/b directory: %v", err) 564 } 565 want := "a/vendor/c/d" 566 if p.ImportPath != want { 567 t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want) 568 } 569 } 570 571 func BenchmarkImportVendor(b *testing.B) { 572 testenv.MustHaveGoBuild(b) // really must just have source 573 574 b.Setenv("GO111MODULE", "off") 575 576 ctxt := Default 577 wd, err := os.Getwd() 578 if err != nil { 579 b.Fatal(err) 580 } 581 ctxt.GOPATH = filepath.Join(wd, "testdata/withvendor") 582 dir := filepath.Join(ctxt.GOPATH, "src/a/b") 583 b.ResetTimer() 584 for i := 0; i < b.N; i++ { 585 _, err := ctxt.Import("c/d", dir, 0) 586 if err != nil { 587 b.Fatalf("cannot find vendored c/d from testdata src/a/b directory: %v", err) 588 } 589 } 590 } 591 592 func TestImportVendorFailure(t *testing.T) { 593 testenv.MustHaveGoBuild(t) // really must just have source 594 595 t.Setenv("GO111MODULE", "off") 596 597 ctxt := Default 598 wd, err := os.Getwd() 599 if err != nil { 600 t.Fatal(err) 601 } 602 ctxt.GOPATH = filepath.Join(wd, "testdata/withvendor") 603 p, err := ctxt.Import("x.com/y/z", filepath.Join(ctxt.GOPATH, "src/a/b"), 0) 604 if err == nil { 605 t.Fatalf("found made-up package x.com/y/z in %s", p.Dir) 606 } 607 608 e := err.Error() 609 if !strings.Contains(e, " (vendor tree)") { 610 t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e) 611 } 612 } 613 614 func TestImportVendorParentFailure(t *testing.T) { 615 testenv.MustHaveGoBuild(t) // really must just have source 616 617 t.Setenv("GO111MODULE", "off") 618 619 ctxt := Default 620 wd, err := os.Getwd() 621 if err != nil { 622 t.Fatal(err) 623 } 624 ctxt.GOPATH = filepath.Join(wd, "testdata/withvendor") 625 // This import should fail because the vendor/c directory has no source code. 626 p, err := ctxt.Import("c", filepath.Join(ctxt.GOPATH, "src/a/b"), 0) 627 if err == nil { 628 t.Fatalf("found empty parent in %s", p.Dir) 629 } 630 if p != nil && p.Dir != "" { 631 t.Fatalf("decided to use %s", p.Dir) 632 } 633 e := err.Error() 634 if !strings.Contains(e, " (vendor tree)") { 635 t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e) 636 } 637 } 638 639 // Check that a package is loaded in module mode if GO111MODULE=on, even when 640 // no go.mod file is present. It should fail to resolve packages outside std. 641 // Verifies golang.org/issue/34669. 642 func TestImportPackageOutsideModule(t *testing.T) { 643 testenv.MustHaveGoBuild(t) 644 645 // Disable module fetching for this test so that 'go list' fails quickly 646 // without trying to find the latest version of a module. 647 t.Setenv("GOPROXY", "off") 648 649 // Create a GOPATH in a temporary directory. We don't use testdata 650 // because it's in GOROOT, which interferes with the module heuristic. 651 gopath := t.TempDir() 652 if err := os.MkdirAll(filepath.Join(gopath, "src/example.com/p"), 0777); err != nil { 653 t.Fatal(err) 654 } 655 if err := os.WriteFile(filepath.Join(gopath, "src/example.com/p/p.go"), []byte("package p"), 0666); err != nil { 656 t.Fatal(err) 657 } 658 659 t.Setenv("GO111MODULE", "on") 660 t.Setenv("GOPATH", gopath) 661 ctxt := Default 662 ctxt.GOPATH = gopath 663 ctxt.Dir = filepath.Join(gopath, "src/example.com/p") 664 665 want := "go.mod file not found in current directory or any parent directory" 666 if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil { 667 t.Fatal("importing package when no go.mod is present succeeded unexpectedly") 668 } else if errStr := err.Error(); !strings.Contains(errStr, want) { 669 t.Fatalf("error when importing package when no go.mod is present: got %q; want %q", errStr, want) 670 } else { 671 t.Logf(`ctxt.Import("example.com/p", _, FindOnly): %v`, err) 672 } 673 } 674 675 // TestIssue23594 prevents go/build from regressing and populating Package.Doc 676 // from comments in test files. 677 func TestIssue23594(t *testing.T) { 678 // Package testdata/doc contains regular and external test files 679 // with comments attached to their package declarations. The names of the files 680 // ensure that we see the comments from the test files first. 681 p, err := ImportDir("testdata/doc", 0) 682 if err != nil { 683 t.Fatalf("could not import testdata: %v", err) 684 } 685 686 if p.Doc != "Correct" { 687 t.Fatalf("incorrectly set .Doc to %q", p.Doc) 688 } 689 } 690 691 // TestIssue56509 tests that go/build does not add non-go files to InvalidGoFiles 692 // when they have unparsable comments. 693 func TestIssue56509(t *testing.T) { 694 // The directory testdata/bads contains a .s file that has an unparsable 695 // comment. (go/build parses initial comments in non-go files looking for 696 // //go:build or //+go build comments). 697 p, err := ImportDir("testdata/bads", 0) 698 if err == nil { 699 t.Fatalf("could not import testdata/bads: %v", err) 700 } 701 702 if len(p.InvalidGoFiles) != 0 { 703 t.Fatalf("incorrectly added non-go file to InvalidGoFiles") 704 } 705 } 706 707 // TestMissingImportErrorRepetition checks that when an unknown package is 708 // imported, the package path is only shown once in the error. 709 // Verifies golang.org/issue/34752. 710 func TestMissingImportErrorRepetition(t *testing.T) { 711 testenv.MustHaveGoBuild(t) // need 'go list' internally 712 tmp := t.TempDir() 713 if err := os.WriteFile(filepath.Join(tmp, "go.mod"), []byte("module m"), 0666); err != nil { 714 t.Fatal(err) 715 } 716 t.Setenv("GO111MODULE", "on") 717 t.Setenv("GOPROXY", "off") 718 t.Setenv("GONOPROXY", "none") 719 720 ctxt := Default 721 ctxt.Dir = tmp 722 723 pkgPath := "example.com/hello" 724 _, err := ctxt.Import(pkgPath, tmp, FindOnly) 725 if err == nil { 726 t.Fatal("unexpected success") 727 } 728 729 // Don't count the package path with a URL like https://...?go-get=1. 730 // See golang.org/issue/35986. 731 errStr := strings.ReplaceAll(err.Error(), "://"+pkgPath+"?go-get=1", "://...?go-get=1") 732 733 // Also don't count instances in suggested "go get" or similar commands 734 // (see https://golang.org/issue/41576). The suggested command typically 735 // follows a semicolon. 736 errStr, _, _ = strings.Cut(errStr, ";") 737 738 if n := strings.Count(errStr, pkgPath); n != 1 { 739 t.Fatalf("package path %q appears in error %d times; should appear once\nerror: %v", pkgPath, n, err) 740 } 741 } 742 743 // TestCgoImportsIgnored checks that imports in cgo files are not included 744 // in the imports list when cgo is disabled. 745 // Verifies golang.org/issue/35946. 746 func TestCgoImportsIgnored(t *testing.T) { 747 ctxt := Default 748 ctxt.CgoEnabled = false 749 p, err := ctxt.ImportDir("testdata/cgo_disabled", 0) 750 if err != nil { 751 t.Fatal(err) 752 } 753 for _, path := range p.Imports { 754 if path == "should/be/ignored" { 755 t.Errorf("found import %q in ignored cgo file", path) 756 } 757 } 758 } 759 760 // Issue #52053. Check that if there is a file x_GOOS_GOARCH.go that both 761 // GOOS and GOARCH show up in the Package.AllTags field. We test both the 762 // case where the file matches and where the file does not match. 763 // The latter case used to fail, incorrectly omitting GOOS. 764 func TestAllTags(t *testing.T) { 765 ctxt := Default 766 ctxt.GOARCH = "arm" 767 ctxt.GOOS = "netbsd" 768 p, err := ctxt.ImportDir("testdata/alltags", 0) 769 if err != nil { 770 t.Fatal(err) 771 } 772 want := []string{"arm", "netbsd"} 773 if !reflect.DeepEqual(p.AllTags, want) { 774 t.Errorf("AllTags = %v, want %v", p.AllTags, want) 775 } 776 wantFiles := []string{"alltags.go", "x_netbsd_arm.go"} 777 if !reflect.DeepEqual(p.GoFiles, wantFiles) { 778 t.Errorf("GoFiles = %v, want %v", p.GoFiles, wantFiles) 779 } 780 781 ctxt.GOARCH = "amd64" 782 ctxt.GOOS = "linux" 783 p, err = ctxt.ImportDir("testdata/alltags", 0) 784 if err != nil { 785 t.Fatal(err) 786 } 787 if !reflect.DeepEqual(p.AllTags, want) { 788 t.Errorf("AllTags = %v, want %v", p.AllTags, want) 789 } 790 wantFiles = []string{"alltags.go"} 791 if !reflect.DeepEqual(p.GoFiles, wantFiles) { 792 t.Errorf("GoFiles = %v, want %v", p.GoFiles, wantFiles) 793 } 794 } 795 796 func TestAllTagsNonSourceFile(t *testing.T) { 797 p, err := Default.ImportDir("testdata/non_source_tags", 0) 798 if err != nil { 799 t.Fatal(err) 800 } 801 if len(p.AllTags) > 0 { 802 t.Errorf("AllTags = %v, want empty", p.AllTags) 803 } 804 } 805 806 func TestDirectives(t *testing.T) { 807 p, err := ImportDir("testdata/directives", 0) 808 if err != nil { 809 t.Fatalf("could not import testdata: %v", err) 810 } 811 812 check := func(name string, list []Directive, want string) { 813 if runtime.GOOS == "windows" { 814 want = strings.ReplaceAll(want, "testdata/directives/", `testdata\\directives\\`) 815 } 816 t.Helper() 817 s := fmt.Sprintf("%q", list) 818 if s != want { 819 t.Errorf("%s = %s, want %s", name, s, want) 820 } 821 } 822 check("Directives", p.Directives, 823 `[{"//go:main1" "testdata/directives/a.go:1:1"} {"//go:plant" "testdata/directives/eve.go:1:1"}]`) 824 check("TestDirectives", p.TestDirectives, 825 `[{"//go:test1" "testdata/directives/a_test.go:1:1"} {"//go:test2" "testdata/directives/b_test.go:1:1"}]`) 826 check("XTestDirectives", p.XTestDirectives, 827 `[{"//go:xtest1" "testdata/directives/c_test.go:1:1"} {"//go:xtest2" "testdata/directives/d_test.go:1:1"} {"//go:xtest3" "testdata/directives/d_test.go:2:1"}]`) 828 }