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