github.com/wolfd/bazel-gazelle@v0.14.0/internal/language/go/fileinfo_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  	"testing"
    24  )
    25  
    26  func TestOtherFileInfo(t *testing.T) {
    27  	dir := "."
    28  	for _, tc := range []struct {
    29  		desc, name, source string
    30  		wantTags           []tagLine
    31  	}{
    32  		{
    33  			"empty file",
    34  			"foo.c",
    35  			"",
    36  			nil,
    37  		},
    38  		{
    39  			"tags file",
    40  			"foo.c",
    41  			`// +build foo bar
    42  // +build baz,!ignore
    43  
    44  `,
    45  			[]tagLine{{{"foo"}, {"bar"}}, {{"baz", "!ignore"}}},
    46  		},
    47  	} {
    48  		t.Run(tc.desc, func(t *testing.T) {
    49  			if err := ioutil.WriteFile(tc.name, []byte(tc.source), 0600); err != nil {
    50  				t.Fatal(err)
    51  			}
    52  			defer os.Remove(tc.name)
    53  
    54  			got := otherFileInfo(filepath.Join(dir, tc.name))
    55  
    56  			// Only check that we can extract tags. Everything else is covered
    57  			// by other tests.
    58  			if !reflect.DeepEqual(got.tags, tc.wantTags) {
    59  				t.Errorf("got %#v; want %#v", got.tags, tc.wantTags)
    60  			}
    61  		})
    62  	}
    63  }
    64  
    65  func TestFileNameInfo(t *testing.T) {
    66  	for _, tc := range []struct {
    67  		desc, name string
    68  		want       fileInfo
    69  	}{
    70  		{
    71  			"simple go file",
    72  			"simple.go",
    73  			fileInfo{
    74  				ext: goExt,
    75  			},
    76  		},
    77  		{
    78  			"simple go test",
    79  			"foo_test.go",
    80  			fileInfo{
    81  				ext:    goExt,
    82  				isTest: true,
    83  			},
    84  		},
    85  		{
    86  			"test source",
    87  			"test.go",
    88  			fileInfo{
    89  				ext:    goExt,
    90  				isTest: false,
    91  			},
    92  		},
    93  		{
    94  			"_test source",
    95  			"_test.go",
    96  			fileInfo{
    97  				ext:    goExt,
    98  				isTest: true,
    99  			},
   100  		},
   101  		{
   102  			"source with goos",
   103  			"foo_linux.go",
   104  			fileInfo{
   105  				ext:  goExt,
   106  				goos: "linux",
   107  			},
   108  		},
   109  		{
   110  			"source with goarch",
   111  			"foo_amd64.go",
   112  			fileInfo{
   113  				ext:    goExt,
   114  				goarch: "amd64",
   115  			},
   116  		},
   117  		{
   118  			"source with goos then goarch",
   119  			"foo_linux_amd64.go",
   120  			fileInfo{
   121  				ext:    goExt,
   122  				goos:   "linux",
   123  				goarch: "amd64",
   124  			},
   125  		},
   126  		{
   127  			"source with goarch then goos",
   128  			"foo_amd64_linux.go",
   129  			fileInfo{
   130  				ext:  goExt,
   131  				goos: "linux",
   132  			},
   133  		},
   134  		{
   135  			"test with goos and goarch",
   136  			"foo_linux_amd64_test.go",
   137  			fileInfo{
   138  				ext:    goExt,
   139  				goos:   "linux",
   140  				goarch: "amd64",
   141  				isTest: true,
   142  			},
   143  		},
   144  		{
   145  			"test then goos",
   146  			"foo_test_linux.go",
   147  			fileInfo{
   148  				ext:  goExt,
   149  				goos: "linux",
   150  			},
   151  		},
   152  		{
   153  			"goos source",
   154  			"linux.go",
   155  			fileInfo{
   156  				ext:  goExt,
   157  				goos: "",
   158  			},
   159  		},
   160  		{
   161  			"goarch source",
   162  			"amd64.go",
   163  			fileInfo{
   164  				ext:    goExt,
   165  				goarch: "",
   166  			},
   167  		},
   168  		{
   169  			"goos test",
   170  			"linux_test.go",
   171  			fileInfo{
   172  				ext:    goExt,
   173  				goos:   "",
   174  				isTest: true,
   175  			},
   176  		},
   177  		{
   178  			"c file",
   179  			"foo_test.cxx",
   180  			fileInfo{
   181  				ext:    cExt,
   182  				isTest: false,
   183  			},
   184  		},
   185  		{
   186  			"c os test file",
   187  			"foo_linux_test.c",
   188  			fileInfo{
   189  				ext:    cExt,
   190  				isTest: false,
   191  				goos:   "linux",
   192  			},
   193  		},
   194  		{
   195  			"h file",
   196  			"foo_linux.h",
   197  			fileInfo{
   198  				ext:  hExt,
   199  				goos: "linux",
   200  			},
   201  		},
   202  		{
   203  			"go asm file",
   204  			"foo_amd64.s",
   205  			fileInfo{
   206  				ext:    sExt,
   207  				goarch: "amd64",
   208  			},
   209  		},
   210  		{
   211  			"c asm file",
   212  			"foo.S",
   213  			fileInfo{
   214  				ext: csExt,
   215  			},
   216  		},
   217  		{
   218  			"unsupported file",
   219  			"foo.m",
   220  			fileInfo{
   221  				ext: cExt,
   222  			},
   223  		},
   224  		{
   225  			"ignored test file",
   226  			"foo_test.py",
   227  			fileInfo{
   228  				isTest: false,
   229  			},
   230  		},
   231  		{
   232  			"ignored xtest file",
   233  			"foo_xtest.py",
   234  			fileInfo{
   235  				isTest: false,
   236  			},
   237  		},
   238  		{
   239  			"ignored file",
   240  			"foo.txt",
   241  			fileInfo{
   242  				ext: unknownExt,
   243  			},
   244  		},
   245  	} {
   246  		tc.want.name = tc.name
   247  		tc.want.path = filepath.Join("dir", tc.name)
   248  
   249  		if got := fileNameInfo(tc.want.path); !reflect.DeepEqual(got, tc.want) {
   250  			t.Errorf("case %q: got %#v; want %#v", tc.desc, got, tc.want)
   251  		}
   252  	}
   253  }
   254  
   255  func TestReadTags(t *testing.T) {
   256  	for _, tc := range []struct {
   257  		desc, source string
   258  		want         []tagLine
   259  	}{
   260  		{
   261  			"empty file",
   262  			"",
   263  			nil,
   264  		},
   265  		{
   266  			"single comment without blank line",
   267  			"// +build foo\npackage main",
   268  			nil,
   269  		},
   270  		{
   271  			"multiple comments without blank link",
   272  			`// +build foo
   273  
   274  // +build bar
   275  package main
   276  
   277  `,
   278  			[]tagLine{{{"foo"}}},
   279  		},
   280  		{
   281  			"single comment",
   282  			"// +build foo\n\n",
   283  			[]tagLine{{{"foo"}}},
   284  		},
   285  		{
   286  			"multiple comments",
   287  			`// +build foo
   288  // +build bar
   289  
   290  package main`,
   291  			[]tagLine{{{"foo"}}, {{"bar"}}},
   292  		},
   293  		{
   294  			"multiple comments with blank",
   295  			`// +build foo
   296  
   297  // +build bar
   298  
   299  package main`,
   300  			[]tagLine{{{"foo"}}, {{"bar"}}},
   301  		},
   302  		{
   303  			"comment with space",
   304  			"  //   +build   foo   bar  \n\n",
   305  			[]tagLine{{{"foo"}, {"bar"}}},
   306  		},
   307  		{
   308  			"slash star comment",
   309  			"/* +build foo */\n\n",
   310  			nil,
   311  		},
   312  	} {
   313  		f, err := ioutil.TempFile(".", "TestReadTags")
   314  		if err != nil {
   315  			t.Fatal(err)
   316  		}
   317  		path := f.Name()
   318  		defer os.Remove(path)
   319  		if err = f.Close(); err != nil {
   320  			t.Fatal(err)
   321  		}
   322  		if err = ioutil.WriteFile(path, []byte(tc.source), 0600); err != nil {
   323  			t.Fatal(err)
   324  		}
   325  
   326  		if got, err := readTags(path); err != nil {
   327  			t.Fatal(err)
   328  		} else if !reflect.DeepEqual(got, tc.want) {
   329  			t.Errorf("case %q: got %#v; want %#v", tc.desc, got, tc.want)
   330  		}
   331  	}
   332  }
   333  
   334  func TestCheckConstraints(t *testing.T) {
   335  	dir, err := ioutil.TempDir(os.Getenv("TEST_TEMPDIR"), "TestCheckConstraints")
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  	defer os.RemoveAll(dir)
   340  	for _, tc := range []struct {
   341  		desc                        string
   342  		genericTags                 map[string]bool
   343  		os, arch, filename, content string
   344  		want                        bool
   345  	}{
   346  		{
   347  			desc: "unconstrained",
   348  			want: true,
   349  		}, {
   350  			desc:     "goos satisfied",
   351  			filename: "foo_linux.go",
   352  			os:       "linux",
   353  			want:     true,
   354  		}, {
   355  			desc:     "goos unsatisfied",
   356  			filename: "foo_linux.go",
   357  			os:       "darwin",
   358  			want:     false,
   359  		}, {
   360  			desc:     "goarch satisfied",
   361  			filename: "foo_amd64.go",
   362  			arch:     "amd64",
   363  			want:     true,
   364  		}, {
   365  			desc:     "goarch unsatisfied",
   366  			filename: "foo_amd64.go",
   367  			arch:     "arm",
   368  			want:     false,
   369  		}, {
   370  			desc:     "goos goarch satisfied",
   371  			filename: "foo_linux_amd64.go",
   372  			os:       "linux",
   373  			arch:     "amd64",
   374  			want:     true,
   375  		}, {
   376  			desc:     "goos goarch unsatisfied",
   377  			filename: "foo_linux_amd64.go",
   378  			os:       "darwin",
   379  			arch:     "amd64",
   380  			want:     false,
   381  		}, {
   382  			desc:     "goos unsatisfied tags satisfied",
   383  			filename: "foo_linux.go",
   384  			content:  "// +build foo\n\npackage foo",
   385  			want:     false,
   386  		}, {
   387  			desc:        "tags all satisfied",
   388  			genericTags: map[string]bool{"a": true, "b": true},
   389  			content:     "// +build a,b\n\npackage foo",
   390  			want:        true,
   391  		}, {
   392  			desc:        "tags some satisfied",
   393  			genericTags: map[string]bool{"a": true},
   394  			content:     "// +build a,b\n\npackage foo",
   395  			want:        false,
   396  		}, {
   397  			desc:    "tag unsatisfied negated",
   398  			content: "// +build !a\n\npackage foo",
   399  			want:    true,
   400  		}, {
   401  			desc:        "tag satisfied negated",
   402  			genericTags: map[string]bool{"a": true},
   403  			content:     "// +build !a\n\npackage foo",
   404  			want:        false,
   405  		}, {
   406  			desc:    "tag double negative",
   407  			content: "// +build !!a\n\npackage foo",
   408  			want:    false,
   409  		}, {
   410  			desc:        "tag group and satisfied",
   411  			genericTags: map[string]bool{"foo": true, "bar": true},
   412  			content:     "// +build foo,bar\n\npackage foo",
   413  			want:        true,
   414  		}, {
   415  			desc:        "tag group and unsatisfied",
   416  			genericTags: map[string]bool{"foo": true},
   417  			content:     "// +build foo,bar\n\npackage foo",
   418  			want:        false,
   419  		}, {
   420  			desc:        "tag line or satisfied",
   421  			genericTags: map[string]bool{"foo": true},
   422  			content:     "// +build foo bar\n\npackage foo",
   423  			want:        true,
   424  		}, {
   425  			desc:        "tag line or unsatisfied",
   426  			genericTags: map[string]bool{"foo": true},
   427  			content:     "// +build !foo bar\n\npackage foo",
   428  			want:        false,
   429  		}, {
   430  			desc:        "tag lines and satisfied",
   431  			genericTags: map[string]bool{"foo": true, "bar": true},
   432  			content: `
   433  // +build foo
   434  // +build bar
   435  
   436  package foo`,
   437  			want: true,
   438  		}, {
   439  			desc:        "tag lines and unsatisfied",
   440  			genericTags: map[string]bool{"foo": true},
   441  			content: `
   442  // +build foo
   443  // +build bar
   444  
   445  package foo`,
   446  			want: false,
   447  		}, {
   448  			desc:        "cgo tags satisfied",
   449  			os:          "linux",
   450  			genericTags: map[string]bool{"foo": true},
   451  			content: `
   452  // +build foo
   453  
   454  package foo
   455  
   456  /*
   457  #cgo linux CFLAGS: -Ilinux
   458  */
   459  import "C"
   460  `,
   461  			want: true,
   462  		}, {
   463  			desc: "cgo tags unsatisfied",
   464  			os:   "linux",
   465  			content: `
   466  package foo
   467  
   468  /*
   469  #cgo !linux CFLAGS: -Inotlinux
   470  */
   471  import "C"
   472  `,
   473  			want: false,
   474  		}, {
   475  			desc:    "release tags",
   476  			content: "// +build go1.7,go1.8,go1.9,go1.91,go2.0\n\npackage foo",
   477  			want:    true,
   478  		}, {
   479  			desc:    "release tag negated",
   480  			content: "// +build !go1.8\n\npackage foo",
   481  			want:    true,
   482  		}, {
   483  			desc:    "cgo tag",
   484  			content: "// +build cgo",
   485  			want:    true,
   486  		}, {
   487  			desc:    "cgo tag negated",
   488  			content: "// +build !cgo",
   489  			want:    true,
   490  		}, {
   491  			desc:    "race msan tags",
   492  			content: "// +build msan race",
   493  			want:    true,
   494  		}, {
   495  			desc:    "race msan tags negated",
   496  			content: "//+ build !msan,!race",
   497  			want:    true,
   498  		},
   499  	} {
   500  		t.Run(tc.desc, func(t *testing.T) {
   501  			c, _, _ := testConfig()
   502  			gc := getGoConfig(c)
   503  			gc.genericTags = tc.genericTags
   504  			if gc.genericTags == nil {
   505  				gc.genericTags = map[string]bool{"gc": true}
   506  			}
   507  			filename := tc.filename
   508  			if filename == "" {
   509  				filename = tc.desc + ".go"
   510  			}
   511  			content := []byte(tc.content)
   512  			if len(content) == 0 {
   513  				content = []byte(`package foo`)
   514  			}
   515  
   516  			path := filepath.Join(dir, filename)
   517  			if err := ioutil.WriteFile(path, []byte(content), 0666); err != nil {
   518  				t.Fatal(err)
   519  			}
   520  
   521  			fi := goFileInfo(path, "")
   522  			var cgoTags tagLine
   523  			if len(fi.copts) > 0 {
   524  				cgoTags = fi.copts[0].tags
   525  			}
   526  
   527  			got := checkConstraints(c, tc.os, tc.arch, fi.goos, fi.goarch, fi.tags, cgoTags)
   528  			if got != tc.want {
   529  				t.Errorf("got %v ; want %v", got, tc.want)
   530  			}
   531  		})
   532  	}
   533  }