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 }