github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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  	"internal/testenv"
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"reflect"
    13  	"runtime"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  func TestMatch(t *testing.T) {
    19  	ctxt := Default
    20  	what := "default"
    21  	match := func(tag string, want map[string]bool) {
    22  		m := make(map[string]bool)
    23  		if !ctxt.match(tag, m) {
    24  			t.Errorf("%s context should match %s, does not", what, tag)
    25  		}
    26  		if !reflect.DeepEqual(m, want) {
    27  			t.Errorf("%s tags = %v, want %v", tag, m, want)
    28  		}
    29  	}
    30  	nomatch := func(tag string, want map[string]bool) {
    31  		m := make(map[string]bool)
    32  		if ctxt.match(tag, m) {
    33  			t.Errorf("%s context should NOT match %s, does", what, tag)
    34  		}
    35  		if !reflect.DeepEqual(m, want) {
    36  			t.Errorf("%s tags = %v, want %v", tag, m, want)
    37  		}
    38  	}
    39  
    40  	match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true})
    41  	match(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
    42  	nomatch(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
    43  
    44  	what = "modified"
    45  	ctxt.BuildTags = []string{"foo"}
    46  	match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true})
    47  	match(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
    48  	nomatch(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
    49  	match(runtime.GOOS+","+runtime.GOARCH+",!bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
    50  	nomatch(runtime.GOOS+","+runtime.GOARCH+",bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
    51  	nomatch("!", map[string]bool{})
    52  }
    53  
    54  func TestDotSlashImport(t *testing.T) {
    55  	p, err := ImportDir("testdata/other", 0)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	if len(p.Imports) != 1 || p.Imports[0] != "./file" {
    60  		t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports)
    61  	}
    62  
    63  	p1, err := Import("./file", "testdata/other", 0)
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	if p1.Name != "file" {
    68  		t.Fatalf("./file: Name=%q, want %q", p1.Name, "file")
    69  	}
    70  	dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows
    71  	if p1.Dir != dir {
    72  		t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir)
    73  	}
    74  }
    75  
    76  func TestEmptyImport(t *testing.T) {
    77  	p, err := Import("", Default.GOROOT, FindOnly)
    78  	if err == nil {
    79  		t.Fatal(`Import("") returned nil error.`)
    80  	}
    81  	if p == nil {
    82  		t.Fatal(`Import("") returned nil package.`)
    83  	}
    84  	if p.ImportPath != "" {
    85  		t.Fatalf("ImportPath=%q, want %q.", p.ImportPath, "")
    86  	}
    87  }
    88  
    89  func TestEmptyFolderImport(t *testing.T) {
    90  	_, err := Import(".", "testdata/empty", 0)
    91  	if _, ok := err.(*NoGoError); !ok {
    92  		t.Fatal(`Import("testdata/empty") did not return NoGoError.`)
    93  	}
    94  }
    95  
    96  func TestIgnoredGoFilesImport(t *testing.T) {
    97  	_, err := Import(".", "testdata/ignored", 0)
    98  	e, ok := err.(*NoGoError)
    99  	if !ok {
   100  		t.Fatal(`Import("testdata/ignored") did not return NoGoError.`)
   101  	}
   102  	if !e.Ignored {
   103  		t.Fatal(`Import("testdata/ignored") should have ignored Go files.`)
   104  	}
   105  }
   106  
   107  func TestMultiplePackageImport(t *testing.T) {
   108  	_, err := Import(".", "testdata/multi", 0)
   109  	mpe, ok := err.(*MultiplePackageError)
   110  	if !ok {
   111  		t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
   112  	}
   113  	want := &MultiplePackageError{
   114  		Dir:      filepath.FromSlash("testdata/multi"),
   115  		Packages: []string{"main", "test_package"},
   116  		Files:    []string{"file.go", "file_appengine.go"},
   117  	}
   118  	if !reflect.DeepEqual(mpe, want) {
   119  		t.Errorf("got %#v; want %#v", mpe, want)
   120  	}
   121  }
   122  
   123  func TestLocalDirectory(t *testing.T) {
   124  	if runtime.GOOS == "darwin" {
   125  		switch runtime.GOARCH {
   126  		case "arm", "arm64":
   127  			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
   128  		}
   129  	}
   130  
   131  	cwd, err := os.Getwd()
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  
   136  	p, err := ImportDir(cwd, 0)
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  	if p.ImportPath != "go/build" {
   141  		t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "go/build")
   142  	}
   143  }
   144  
   145  func TestShouldBuild(t *testing.T) {
   146  	const file1 = "// +build tag1\n\n" +
   147  		"package main\n"
   148  	want1 := map[string]bool{"tag1": true}
   149  
   150  	const file2 = "// +build cgo\n\n" +
   151  		"// This package implements parsing of tags like\n" +
   152  		"// +build tag1\n" +
   153  		"package build"
   154  	want2 := map[string]bool{"cgo": true}
   155  
   156  	const file3 = "// Copyright The Go Authors.\n\n" +
   157  		"package build\n\n" +
   158  		"// shouldBuild checks tags given by lines of the form\n" +
   159  		"// +build tag\n" +
   160  		"func shouldBuild(content []byte)\n"
   161  	want3 := map[string]bool{}
   162  
   163  	ctx := &Context{BuildTags: []string{"tag1"}}
   164  	m := map[string]bool{}
   165  	if !ctx.shouldBuild([]byte(file1), m, nil) {
   166  		t.Errorf("shouldBuild(file1) = false, want true")
   167  	}
   168  	if !reflect.DeepEqual(m, want1) {
   169  		t.Errorf("shouldBuild(file1) tags = %v, want %v", m, want1)
   170  	}
   171  
   172  	m = map[string]bool{}
   173  	if ctx.shouldBuild([]byte(file2), m, nil) {
   174  		t.Errorf("shouldBuild(file2) = true, want false")
   175  	}
   176  	if !reflect.DeepEqual(m, want2) {
   177  		t.Errorf("shouldBuild(file2) tags = %v, want %v", m, want2)
   178  	}
   179  
   180  	m = map[string]bool{}
   181  	ctx = &Context{BuildTags: nil}
   182  	if !ctx.shouldBuild([]byte(file3), m, nil) {
   183  		t.Errorf("shouldBuild(file3) = false, want true")
   184  	}
   185  	if !reflect.DeepEqual(m, want3) {
   186  		t.Errorf("shouldBuild(file3) tags = %v, want %v", m, want3)
   187  	}
   188  }
   189  
   190  type readNopCloser struct {
   191  	io.Reader
   192  }
   193  
   194  func (r readNopCloser) Close() error {
   195  	return nil
   196  }
   197  
   198  var (
   199  	ctxtP9      = Context{GOARCH: "arm", GOOS: "plan9"}
   200  	ctxtAndroid = Context{GOARCH: "arm", GOOS: "android"}
   201  )
   202  
   203  var matchFileTests = []struct {
   204  	ctxt  Context
   205  	name  string
   206  	data  string
   207  	match bool
   208  }{
   209  	{ctxtP9, "foo_arm.go", "", true},
   210  	{ctxtP9, "foo1_arm.go", "// +build linux\n\npackage main\n", false},
   211  	{ctxtP9, "foo_darwin.go", "", false},
   212  	{ctxtP9, "foo.go", "", true},
   213  	{ctxtP9, "foo1.go", "// +build linux\n\npackage main\n", false},
   214  	{ctxtP9, "foo.badsuffix", "", false},
   215  	{ctxtAndroid, "foo_linux.go", "", true},
   216  	{ctxtAndroid, "foo_android.go", "", true},
   217  	{ctxtAndroid, "foo_plan9.go", "", false},
   218  	{ctxtAndroid, "android.go", "", true},
   219  	{ctxtAndroid, "plan9.go", "", true},
   220  	{ctxtAndroid, "plan9_test.go", "", true},
   221  	{ctxtAndroid, "arm.s", "", true},
   222  	{ctxtAndroid, "amd64.s", "", true},
   223  }
   224  
   225  func TestMatchFile(t *testing.T) {
   226  	for _, tt := range matchFileTests {
   227  		ctxt := tt.ctxt
   228  		ctxt.OpenFile = func(path string) (r io.ReadCloser, err error) {
   229  			if path != "x+"+tt.name {
   230  				t.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name)
   231  			}
   232  			return &readNopCloser{strings.NewReader(tt.data)}, nil
   233  		}
   234  		ctxt.JoinPath = func(elem ...string) string {
   235  			return strings.Join(elem, "+")
   236  		}
   237  		match, err := ctxt.MatchFile("x", tt.name)
   238  		if match != tt.match || err != nil {
   239  			t.Fatalf("MatchFile(%q) = %v, %v, want %v, nil", tt.name, match, err, tt.match)
   240  		}
   241  	}
   242  }
   243  
   244  func TestImportCmd(t *testing.T) {
   245  	if runtime.GOOS == "darwin" {
   246  		switch runtime.GOARCH {
   247  		case "arm", "arm64":
   248  			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
   249  		}
   250  	}
   251  
   252  	p, err := Import("cmd/internal/objfile", "", 0)
   253  	if err != nil {
   254  		t.Fatal(err)
   255  	}
   256  	if !strings.HasSuffix(filepath.ToSlash(p.Dir), "src/cmd/internal/objfile") {
   257  		t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile")
   258  	}
   259  }
   260  
   261  var (
   262  	expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add")
   263  )
   264  
   265  var expandSrcDirTests = []struct {
   266  	input, expected string
   267  }{
   268  	{"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"},
   269  	{"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"},
   270  	{"Nothing to expand here!", "Nothing to expand here!"},
   271  	{"$", "$"},
   272  	{"$$", "$$"},
   273  	{"${", "${"},
   274  	{"$}", "$}"},
   275  	{"$FOO ${BAR}", "$FOO ${BAR}"},
   276  	{"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."},
   277  	{"$SRCDIR is missing braces", "$SRCDIR is missing braces"},
   278  }
   279  
   280  func TestExpandSrcDir(t *testing.T) {
   281  	for _, test := range expandSrcDirTests {
   282  		output, _ := expandSrcDir(test.input, expandSrcDirPath)
   283  		if output != test.expected {
   284  			t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected)
   285  		} else {
   286  			t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath)
   287  		}
   288  	}
   289  }
   290  
   291  func TestShellSafety(t *testing.T) {
   292  	tests := []struct {
   293  		input, srcdir, expected string
   294  		result                  bool
   295  	}{
   296  		{"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
   297  		{"-I${SRCDIR}", "wtf$@%", "-Iwtf$@%", true},
   298  		{"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
   299  		{"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", false},
   300  		{"-I/tmp", "/tmp/[0]", "-I/tmp", true},
   301  		{"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false},
   302  	}
   303  	for _, test := range tests {
   304  		output, ok := expandSrcDir(test.input, test.srcdir)
   305  		if ok != test.result {
   306  			t.Errorf("Expected %t while %q expands to %q with SRCDIR=%q; got %t", test.result, test.input, output, test.srcdir, ok)
   307  		}
   308  		if output != test.expected {
   309  			t.Errorf("Expected %q while %q expands with SRCDIR=%q; got %q", test.expected, test.input, test.srcdir, output)
   310  		}
   311  	}
   312  }
   313  
   314  func TestImportVendor(t *testing.T) {
   315  	testenv.MustHaveGoBuild(t) // really must just have source
   316  	ctxt := Default
   317  	ctxt.GOPATH = ""
   318  	p, err := ctxt.Import("golang_org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
   319  	if err != nil {
   320  		t.Fatalf("cannot find vendored golang_org/x/net/http2/hpack from net/http directory: %v", err)
   321  	}
   322  	want := "vendor/golang_org/x/net/http2/hpack"
   323  	if p.ImportPath != want {
   324  		t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want)
   325  	}
   326  }
   327  
   328  func TestImportVendorFailure(t *testing.T) {
   329  	testenv.MustHaveGoBuild(t) // really must just have source
   330  	ctxt := Default
   331  	ctxt.GOPATH = ""
   332  	p, err := ctxt.Import("x.com/y/z", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
   333  	if err == nil {
   334  		t.Fatalf("found made-up package x.com/y/z in %s", p.Dir)
   335  	}
   336  
   337  	e := err.Error()
   338  	if !strings.Contains(e, " (vendor tree)") {
   339  		t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
   340  	}
   341  }
   342  
   343  func TestImportVendorParentFailure(t *testing.T) {
   344  	testenv.MustHaveGoBuild(t) // really must just have source
   345  	ctxt := Default
   346  	ctxt.GOPATH = ""
   347  	// This import should fail because the vendor/golang.org/x/net/http2 directory has no source code.
   348  	p, err := ctxt.Import("golang_org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
   349  	if err == nil {
   350  		t.Fatalf("found empty parent in %s", p.Dir)
   351  	}
   352  	if p != nil && p.Dir != "" {
   353  		t.Fatalf("decided to use %s", p.Dir)
   354  	}
   355  	e := err.Error()
   356  	if !strings.Contains(e, " (vendor tree)") {
   357  		t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
   358  	}
   359  }