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