github.com/afking/bazel-gazelle@v0.0.0-20180301150245-c02bc0f529e8/internal/packages/fileinfo_go_test.go (about)

     1  /* Copyright 2017 The Bazel Authors. All rights reserved.
     2  
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7     http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package packages
    17  
    18  import (
    19  	"io/ioutil"
    20  	"os"
    21  	"path/filepath"
    22  	"reflect"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/bazelbuild/bazel-gazelle/internal/config"
    27  )
    28  
    29  func TestGoFileInfo(t *testing.T) {
    30  	c := &config.Config{}
    31  	dir := "."
    32  	rel := ""
    33  	for _, tc := range []struct {
    34  		desc, name, source string
    35  		want               fileInfo
    36  	}{
    37  		{
    38  			"empty file",
    39  			"foo.go",
    40  			"package foo\n",
    41  			fileInfo{
    42  				packageName: "foo",
    43  			},
    44  		},
    45  		{
    46  			"xtest file",
    47  			"foo_test.go",
    48  			"package foo_test\n",
    49  			fileInfo{
    50  				packageName: "foo",
    51  				isTest:      true,
    52  				isXTest:     true,
    53  			},
    54  		},
    55  		{
    56  			"xtest suffix on non-test",
    57  			"foo_xtest.go",
    58  			"package foo_test\n",
    59  			fileInfo{
    60  				packageName: "foo_test",
    61  				isTest:      false,
    62  				isXTest:     false,
    63  			},
    64  		},
    65  		{
    66  			"single import",
    67  			"foo.go",
    68  			`package foo
    69  
    70  import "github.com/foo/bar"
    71  `,
    72  			fileInfo{
    73  				packageName: "foo",
    74  				imports:     []string{"github.com/foo/bar"},
    75  			},
    76  		},
    77  		{
    78  			"multiple imports",
    79  			"foo.go",
    80  			`package foo
    81  
    82  import (
    83  	"github.com/foo/bar"
    84  	x "github.com/local/project/y"
    85  )
    86  `,
    87  			fileInfo{
    88  				packageName: "foo",
    89  				imports:     []string{"github.com/foo/bar", "github.com/local/project/y"},
    90  			},
    91  		},
    92  		{
    93  			"standard imports included",
    94  			"foo.go",
    95  			`package foo
    96  
    97  import "fmt"
    98  `,
    99  			fileInfo{
   100  				packageName: "foo",
   101  				imports:     []string{"fmt"},
   102  			},
   103  		},
   104  		{
   105  			"cgo",
   106  			"foo.go",
   107  			`package foo
   108  
   109  import "C"
   110  `,
   111  			fileInfo{
   112  				packageName: "foo",
   113  				isCgo:       true,
   114  			},
   115  		},
   116  		{
   117  			"build tags",
   118  			"foo.go",
   119  			`// +build linux darwin
   120  
   121  // +build !ignore
   122  
   123  package foo
   124  `,
   125  			fileInfo{
   126  				packageName: "foo",
   127  				tags:        []tagLine{{{"linux"}, {"darwin"}}, {{"!ignore"}}},
   128  			},
   129  		},
   130  		{
   131  			"build tags without blank line",
   132  			"route.go",
   133  			`// Copyright 2017
   134  
   135  // +build darwin dragonfly freebsd netbsd openbsd
   136  
   137  // Package route provides basic functions for the manipulation of
   138  // packet routing facilities on BSD variants.
   139  package route
   140  `,
   141  			fileInfo{
   142  				packageName: "route",
   143  				tags:        []tagLine{{{"darwin"}, {"dragonfly"}, {"freebsd"}, {"netbsd"}, {"openbsd"}}},
   144  			},
   145  		},
   146  	} {
   147  		if err := ioutil.WriteFile(tc.name, []byte(tc.source), 0600); err != nil {
   148  			t.Fatal(err)
   149  		}
   150  		defer os.Remove(tc.name)
   151  
   152  		got := goFileInfo(c, dir, rel, tc.name)
   153  
   154  		// Clear fields we don't care about for testing.
   155  		got = fileInfo{
   156  			packageName: got.packageName,
   157  			isTest:      got.isTest,
   158  			isXTest:     got.isXTest,
   159  			imports:     got.imports,
   160  			isCgo:       got.isCgo,
   161  			tags:        got.tags,
   162  		}
   163  
   164  		if !reflect.DeepEqual(got, tc.want) {
   165  			t.Errorf("case %q: got %#v; want %#v", tc.desc, got, tc.want)
   166  		}
   167  	}
   168  }
   169  
   170  func TestGoFileInfoFailure(t *testing.T) {
   171  	dir := "."
   172  	name := "foo_linux_amd64.go"
   173  	if err := ioutil.WriteFile(name, []byte("pakcage foo"), 0600); err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	defer os.Remove(name)
   177  
   178  	c := &config.Config{}
   179  	got := goFileInfo(c, dir, "", name)
   180  	want := fileInfo{
   181  		path:     filepath.Join(dir, name),
   182  		name:     name,
   183  		ext:      ".go",
   184  		category: goExt,
   185  		goos:     "linux",
   186  		goarch:   "amd64",
   187  	}
   188  	if !reflect.DeepEqual(got, want) {
   189  		t.Errorf("got %#v ; want %#v", got, want)
   190  	}
   191  }
   192  
   193  func TestCgo(t *testing.T) {
   194  	c := &config.Config{}
   195  	dir := "."
   196  	rel := ""
   197  	for _, tc := range []struct {
   198  		desc, source string
   199  		want         fileInfo
   200  	}{
   201  		{
   202  			"not cgo",
   203  			"package foo\n",
   204  			fileInfo{isCgo: false},
   205  		},
   206  		{
   207  			"empty cgo",
   208  			`package foo
   209  
   210  import "C"
   211  `,
   212  			fileInfo{isCgo: true},
   213  		},
   214  		{
   215  			"simple flags",
   216  			`package foo
   217  
   218  /*
   219  #cgo CFLAGS: -O0
   220  	#cgo CPPFLAGS: -O1
   221  #cgo   CXXFLAGS:   -O2
   222  #cgo LDFLAGS: -O3 -O4
   223  */
   224  import "C"
   225  `,
   226  			fileInfo{
   227  				isCgo: true,
   228  				copts: []taggedOpts{
   229  					{opts: "-O0"},
   230  					{opts: "-O1"},
   231  					{opts: "-O2"},
   232  				},
   233  				clinkopts: []taggedOpts{
   234  					{opts: strings.Join([]string{"-O3", "-O4"}, OptSeparator)},
   235  				},
   236  			},
   237  		},
   238  		{
   239  			"cflags with conditions",
   240  			`package foo
   241  
   242  /*
   243  #cgo foo bar,!baz CFLAGS: -O0
   244  */
   245  import "C"
   246  `,
   247  			fileInfo{
   248  				isCgo: true,
   249  				copts: []taggedOpts{
   250  					{
   251  						tags: tagLine{{"foo"}, {"bar", "!baz"}},
   252  						opts: "-O0",
   253  					},
   254  				},
   255  			},
   256  		},
   257  		{
   258  			"slashslash comments",
   259  			`package foo
   260  
   261  // #cgo CFLAGS: -O0
   262  // #cgo CFLAGS: -O1
   263  import "C"
   264  `,
   265  			fileInfo{
   266  				isCgo: true,
   267  				copts: []taggedOpts{
   268  					{opts: "-O0"},
   269  					{opts: "-O1"},
   270  				},
   271  			},
   272  		},
   273  		{
   274  			"comment above single import group",
   275  			`package foo
   276  
   277  /*
   278  #cgo CFLAGS: -O0
   279  */
   280  import ("C")
   281  `,
   282  			fileInfo{
   283  				isCgo: true,
   284  				copts: []taggedOpts{
   285  					{opts: "-O0"},
   286  				},
   287  			},
   288  		},
   289  	} {
   290  		path := "TestCgo.go"
   291  		if err := ioutil.WriteFile(path, []byte(tc.source), 0600); err != nil {
   292  			t.Fatal(err)
   293  		}
   294  		defer os.Remove(path)
   295  
   296  		got := goFileInfo(c, dir, rel, path)
   297  
   298  		// Clear fields we don't care about for testing.
   299  		got = fileInfo{isCgo: got.isCgo, copts: got.copts, clinkopts: got.clinkopts}
   300  
   301  		if !reflect.DeepEqual(got, tc.want) {
   302  			t.Errorf("case %q: got %#v; want %#v", tc.desc, got, tc.want)
   303  		}
   304  	}
   305  }
   306  
   307  // Copied from go/build build_test.go
   308  var (
   309  	expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add")
   310  )
   311  
   312  // Copied from go/build build_test.go
   313  var expandSrcDirTests = []struct {
   314  	input, expected string
   315  }{
   316  	{"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"},
   317  	{"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"},
   318  	{"Nothing to expand here!", "Nothing to expand here!"},
   319  	{"$", "$"},
   320  	{"$$", "$$"},
   321  	{"${", "${"},
   322  	{"$}", "$}"},
   323  	{"$FOO ${BAR}", "$FOO ${BAR}"},
   324  	{"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."},
   325  	{"$SRCDIR is missing braces", "$SRCDIR is missing braces"},
   326  }
   327  
   328  // Copied from go/build build_test.go
   329  func TestExpandSrcDir(t *testing.T) {
   330  	for _, test := range expandSrcDirTests {
   331  		output, _ := expandSrcDir(test.input, expandSrcDirPath)
   332  		if output != test.expected {
   333  			t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected)
   334  		} else {
   335  			t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath)
   336  		}
   337  	}
   338  }
   339  
   340  func TestExpandSrcDirRepoRelative(t *testing.T) {
   341  	repo, err := ioutil.TempDir(os.Getenv("TEST_TEMPDIR"), "repo")
   342  	if err != nil {
   343  		t.Fatal(err)
   344  	}
   345  	sub := filepath.Join(repo, "sub")
   346  	if err := os.Mkdir(sub, 0755); err != nil {
   347  		t.Fatal(err)
   348  	}
   349  	goFile := filepath.Join(sub, "sub.go")
   350  	content := []byte(`package sub
   351  
   352  /*
   353  #cgo CFLAGS: -I${SRCDIR}/..
   354  */
   355  import "C"
   356  `)
   357  	if err := ioutil.WriteFile(goFile, content, 0644); err != nil {
   358  		t.Fatal(err)
   359  	}
   360  	c := &config.Config{
   361  		RepoRoot: repo,
   362  		GoPrefix: "example.com/repo",
   363  	}
   364  	got := buildPackage(c, sub, "sub", []string{"sub.go"}, nil, nil, false)
   365  	want := &Package{
   366  		Name:       "sub",
   367  		Dir:        sub,
   368  		Rel:        "sub",
   369  		ImportPath: "example.com/repo/sub",
   370  		Library: GoTarget{
   371  			Sources: PlatformStrings{
   372  				Generic: []string{"sub.go"},
   373  			},
   374  			COpts: PlatformStrings{
   375  				Generic: []string{"-Isub/.."},
   376  			},
   377  			Cgo: true,
   378  		},
   379  	}
   380  	if !reflect.DeepEqual(got, want) {
   381  		t.Errorf("got %#v ; want %#v", got, want)
   382  	}
   383  }
   384  
   385  // Copied from go/build build_test.go
   386  func TestShellSafety(t *testing.T) {
   387  	tests := []struct {
   388  		input, srcdir, expected string
   389  		result                  bool
   390  	}{
   391  		{"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
   392  		{"-I${SRCDIR}", "wtf$@%", "-Iwtf$@%", true},
   393  		{"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
   394  		{"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", false},
   395  		{"-I/tmp", "/tmp/[0]", "-I/tmp", true},
   396  		{"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false},
   397  	}
   398  	for _, test := range tests {
   399  		output, ok := expandSrcDir(test.input, test.srcdir)
   400  		if ok != test.result {
   401  			t.Errorf("Expected %t while %q expands to %q with SRCDIR=%q; got %t", test.result, test.input, output, test.srcdir, ok)
   402  		}
   403  		if output != test.expected {
   404  			t.Errorf("Expected %q while %q expands with SRCDIR=%q; got %q", test.expected, test.input, test.srcdir, output)
   405  		}
   406  	}
   407  }