github.com/afking/bazel-gazelle@v0.0.0-20180301150245-c02bc0f529e8/internal/resolve/resolve_test.go (about) 1 /* Copyright 2016 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 resolve 17 18 import ( 19 "path" 20 "path/filepath" 21 "reflect" 22 "strings" 23 "testing" 24 25 "github.com/bazelbuild/bazel-gazelle/internal/config" 26 "github.com/bazelbuild/bazel-gazelle/internal/label" 27 bf "github.com/bazelbuild/buildtools/build" 28 ) 29 30 func TestResolveGoIndex(t *testing.T) { 31 c := &config.Config{ 32 GoPrefix: "example.com/repo", 33 DepMode: config.VendorMode, 34 } 35 l := label.NewLabeler(c) 36 37 type fileSpec struct { 38 rel, content string 39 } 40 type testCase struct { 41 desc string 42 buildFiles []fileSpec 43 imp string 44 from label.Label 45 wantErr string 46 want label.Label 47 } 48 for _, tc := range []testCase{ 49 { 50 desc: "no_match", 51 imp: "example.com/foo", 52 // fall back to external resolver 53 want: label.New("", "vendor/example.com/foo", config.DefaultLibName), 54 }, { 55 desc: "simple", 56 buildFiles: []fileSpec{{ 57 rel: "foo", 58 content: ` 59 go_library( 60 name = "go_default_library", 61 importpath = "example.com/foo", 62 ) 63 `}}, 64 imp: "example.com/foo", 65 want: label.New("", "foo", "go_default_library"), 66 }, { 67 desc: "test_and_library_not_indexed", 68 buildFiles: []fileSpec{{ 69 rel: "foo", 70 content: ` 71 go_test( 72 name = "go_default_test", 73 importpath = "example.com/foo", 74 ) 75 76 go_binary( 77 name = "cmd", 78 importpath = "example.com/foo", 79 ) 80 `, 81 }}, 82 imp: "example.com/foo", 83 // fall back to external resolver 84 want: label.New("", "vendor/example.com/foo", config.DefaultLibName), 85 }, { 86 desc: "multiple_rules_ambiguous", 87 buildFiles: []fileSpec{{ 88 rel: "foo", 89 content: ` 90 go_library( 91 name = "a", 92 importpath = "example.com/foo", 93 ) 94 95 go_library( 96 name = "b", 97 importpath = "example.com/foo", 98 ) 99 `, 100 }}, 101 imp: "example.com/foo", 102 wantErr: "multiple rules", 103 }, { 104 desc: "vendor_not_visible", 105 buildFiles: []fileSpec{ 106 { 107 rel: "", 108 content: ` 109 go_library( 110 name = "root", 111 importpath = "example.com/foo", 112 ) 113 `, 114 }, { 115 rel: "a/vendor/foo", 116 content: ` 117 go_library( 118 name = "vendored", 119 importpath = "example.com/foo", 120 ) 121 `, 122 }, 123 }, 124 imp: "example.com/foo", 125 from: label.New("", "b", "b"), 126 want: label.New("", "", "root"), 127 }, { 128 desc: "vendor_supercedes_nonvendor", 129 buildFiles: []fileSpec{ 130 { 131 rel: "", 132 content: ` 133 go_library( 134 name = "root", 135 importpath = "example.com/foo", 136 ) 137 `, 138 }, { 139 rel: "vendor/foo", 140 content: ` 141 go_library( 142 name = "vendored", 143 importpath = "example.com/foo", 144 ) 145 `, 146 }, 147 }, 148 imp: "example.com/foo", 149 from: label.New("", "sub", "sub"), 150 want: label.New("", "vendor/foo", "vendored"), 151 }, { 152 desc: "deep_vendor_shallow_vendor", 153 buildFiles: []fileSpec{ 154 { 155 rel: "shallow/vendor", 156 content: ` 157 go_library( 158 name = "shallow", 159 importpath = "example.com/foo", 160 ) 161 `, 162 }, { 163 rel: "shallow/deep/vendor", 164 content: ` 165 go_library( 166 name = "deep", 167 importpath = "example.com/foo", 168 ) 169 `, 170 }, 171 }, 172 imp: "example.com/foo", 173 from: label.New("", "shallow/deep", "deep"), 174 want: label.New("", "shallow/deep/vendor", "deep"), 175 }, { 176 desc: "nested_vendor", 177 buildFiles: []fileSpec{ 178 { 179 rel: "vendor/a", 180 content: ` 181 go_library( 182 name = "a", 183 importpath = "a", 184 ) 185 `, 186 }, { 187 rel: "vendor/b/vendor/a", 188 content: ` 189 go_library( 190 name = "a", 191 importpath = "a", 192 ) 193 `, 194 }, 195 }, 196 imp: "a", 197 from: label.New("", "vendor/b/c", "c"), 198 want: label.New("", "vendor/b/vendor/a", "a"), 199 }, 200 } { 201 t.Run(tc.desc, func(t *testing.T) { 202 ix := NewRuleIndex() 203 for _, fs := range tc.buildFiles { 204 f, err := bf.Parse(path.Join(fs.rel, "BUILD.bazel"), []byte(fs.content)) 205 if err != nil { 206 t.Fatal(err) 207 } 208 ix.AddRulesFromFile(c, f) 209 } 210 211 ix.Finish() 212 213 r := NewResolver(c, l, ix, nil) 214 got, err := r.resolveGo(tc.imp, tc.from) 215 if err != nil { 216 if tc.wantErr == "" { 217 t.Fatal(err) 218 } 219 if !strings.Contains(err.Error(), tc.wantErr) { 220 t.Fatalf("got %q ; want %q", err.Error(), tc.wantErr) 221 } 222 return 223 } 224 if err == nil && tc.wantErr != "" { 225 t.Fatalf("got success ; want error %q", tc.wantErr) 226 } 227 if !reflect.DeepEqual(got, tc.want) { 228 t.Fatalf("got %v ; want %v", got, tc.want) 229 } 230 }) 231 } 232 } 233 234 func TestResolveProtoIndex(t *testing.T) { 235 c := &config.Config{ 236 GoPrefix: "example.com/repo", 237 DepMode: config.VendorMode, 238 } 239 l := label.NewLabeler(c) 240 241 buildContent := []byte(` 242 proto_library( 243 name = "foo_proto", 244 srcs = ["bar.proto"], 245 ) 246 247 go_proto_library( 248 name = "foo_go_proto", 249 importpath = "example.com/foo", 250 proto = ":foo_proto", 251 ) 252 253 go_library( 254 name = "embed", 255 embed = [":foo_go_proto"], 256 importpath = "example.com/foo", 257 ) 258 `) 259 f, err := bf.Parse(filepath.Join("sub", "BUILD.bazel"), buildContent) 260 if err != nil { 261 t.Fatal(err) 262 } 263 264 ix := NewRuleIndex() 265 ix.AddRulesFromFile(c, f) 266 ix.Finish() 267 r := NewResolver(c, l, ix, nil) 268 269 wantProto := label.New("", "sub", "foo_proto") 270 if got, err := r.resolveProto("sub/bar.proto", label.New("", "baz", "baz")); err != nil { 271 t.Error(err) 272 } else if !reflect.DeepEqual(got, wantProto) { 273 t.Errorf("resolveProto: got %s ; want %s", got, wantProto) 274 } 275 _, err = r.resolveProto("sub/bar.proto", label.New("", "sub", "foo_proto")) 276 if _, ok := err.(selfImportError); !ok { 277 t.Errorf("resolveProto: got %v ; want selfImportError", err) 278 } 279 280 wantGoProto := label.New("", "sub", "embed") 281 if got, err := r.resolveGoProto("sub/bar.proto", label.New("", "baz", "baz")); err != nil { 282 t.Error(err) 283 } else if !reflect.DeepEqual(got, wantGoProto) { 284 t.Errorf("resolveGoProto: got %s ; want %s", got, wantGoProto) 285 } 286 _, err = r.resolveGoProto("sub/bar.proto", label.New("", "sub", "foo_go_proto")) 287 if _, ok := err.(selfImportError); !ok { 288 t.Errorf("resolveGoProto: got %v ; want selfImportError", err) 289 } 290 } 291 292 func TestResolveGoLocal(t *testing.T) { 293 for _, spec := range []struct { 294 importpath string 295 from, want label.Label 296 }{ 297 { 298 importpath: "example.com/repo", 299 want: label.New("", "", config.DefaultLibName), 300 }, { 301 importpath: "example.com/repo/lib", 302 want: label.New("", "lib", config.DefaultLibName), 303 }, { 304 importpath: "example.com/repo/another", 305 want: label.New("", "another", config.DefaultLibName), 306 }, { 307 importpath: "example.com/repo", 308 want: label.New("", "", config.DefaultLibName), 309 }, { 310 importpath: "example.com/repo/lib/sub", 311 want: label.New("", "lib/sub", config.DefaultLibName), 312 }, { 313 importpath: "example.com/repo/another", 314 want: label.New("", "another", config.DefaultLibName), 315 }, { 316 importpath: "../y", 317 from: label.New("", "x", "x"), 318 want: label.New("", "y", config.DefaultLibName), 319 }, 320 } { 321 c := &config.Config{GoPrefix: "example.com/repo"} 322 l := label.NewLabeler(c) 323 ix := NewRuleIndex() 324 r := NewResolver(c, l, ix, nil) 325 label, err := r.resolveGo(spec.importpath, spec.from) 326 if err != nil { 327 t.Errorf("r.resolveGo(%q) failed with %v; want success", spec.importpath, err) 328 continue 329 } 330 if got, want := label, spec.want; !reflect.DeepEqual(got, want) { 331 t.Errorf("r.resolveGo(%q) = %s; want %s", spec.importpath, got, want) 332 } 333 } 334 } 335 336 func TestResolveGoLocalError(t *testing.T) { 337 c := &config.Config{GoPrefix: "example.com/repo"} 338 l := label.NewLabeler(c) 339 ix := NewRuleIndex() 340 rc := newStubRemoteCache(nil) 341 r := NewResolver(c, l, ix, rc) 342 343 for _, importpath := range []string{ 344 "fmt", 345 "unknown.com/another", 346 "unknown.com/another/sub", 347 "unknown.com/repo_suffix", 348 } { 349 if l, err := r.resolveGo(importpath, label.NoLabel); err == nil { 350 t.Errorf("r.resolveGo(%q) = %s; want error", importpath, l) 351 } 352 } 353 354 if l, err := r.resolveGo("..", label.NoLabel); err == nil { 355 t.Errorf("r.resolveGo(%q) = %s; want error", "..", l) 356 } 357 } 358 359 func TestResolveGoEmptyPrefix(t *testing.T) { 360 c := &config.Config{} 361 l := label.NewLabeler(c) 362 ix := NewRuleIndex() 363 r := NewResolver(c, l, ix, nil) 364 365 imp := "foo" 366 want := label.New("", "foo", config.DefaultLibName) 367 if got, err := r.resolveGo(imp, label.NoLabel); err != nil { 368 t.Errorf("r.resolveGo(%q) failed with %v; want success", imp, err) 369 } else if !reflect.DeepEqual(got, want) { 370 t.Errorf("r.resolveGo(%q) = %s; want %s", imp, got, want) 371 } 372 373 imp = "fmt" 374 if _, err := r.resolveGo(imp, label.NoLabel); err == nil { 375 t.Errorf("r.resolveGo(%q) succeeded; want failure") 376 } 377 } 378 379 func TestResolveProto(t *testing.T) { 380 prefix := "example.com/repo" 381 for _, tc := range []struct { 382 desc, imp string 383 from label.Label 384 depMode config.DependencyMode 385 wantProto, wantGoProto label.Label 386 }{ 387 { 388 desc: "root", 389 imp: "foo.proto", 390 wantProto: label.New("", "", "repo_proto"), 391 wantGoProto: label.New("", "", config.DefaultLibName), 392 }, { 393 desc: "sub", 394 imp: "foo/bar/bar.proto", 395 wantProto: label.New("", "foo/bar", "bar_proto"), 396 wantGoProto: label.New("", "foo/bar", config.DefaultLibName), 397 }, { 398 desc: "vendor", 399 depMode: config.VendorMode, 400 imp: "foo/bar/bar.proto", 401 from: label.New("", "vendor", ""), 402 wantProto: label.New("", "foo/bar", "bar_proto"), 403 wantGoProto: label.New("", "vendor/foo/bar", config.DefaultLibName), 404 }, { 405 desc: "well known", 406 imp: "google/protobuf/any.proto", 407 wantProto: label.New("com_google_protobuf", "", "any_proto"), 408 wantGoProto: label.NoLabel, 409 }, { 410 desc: "well known vendor", 411 depMode: config.VendorMode, 412 imp: "google/protobuf/any.proto", 413 wantProto: label.New("com_google_protobuf", "", "any_proto"), 414 wantGoProto: label.NoLabel, 415 }, { 416 desc: "descriptor", 417 imp: "google/protobuf/descriptor.proto", 418 wantProto: label.New("com_google_protobuf", "", "descriptor_proto"), 419 wantGoProto: label.NoLabel, 420 }, { 421 desc: "descriptor vendor", 422 depMode: config.VendorMode, 423 imp: "google/protobuf/descriptor.proto", 424 wantProto: label.New("com_google_protobuf", "", "descriptor_proto"), 425 wantGoProto: label.NoLabel, 426 }, 427 } { 428 t.Run(tc.desc, func(t *testing.T) { 429 c := &config.Config{ 430 GoPrefix: prefix, 431 DepMode: tc.depMode, 432 } 433 l := label.NewLabeler(c) 434 ix := NewRuleIndex() 435 r := NewResolver(c, l, ix, nil) 436 437 got, err := r.resolveProto(tc.imp, tc.from) 438 if err != nil { 439 t.Errorf("resolveProto: got error %v; want success", err) 440 } 441 if !reflect.DeepEqual(got, tc.wantProto) { 442 t.Errorf("resolveProto: got %s; want %s", got, tc.wantProto) 443 } 444 445 got, err = r.resolveGoProto(tc.imp, tc.from) 446 if err != nil { 447 if tc.wantGoProto != label.NoLabel { 448 t.Errorf("resolveGoProto: got error %v; want %s", got, tc.wantGoProto) 449 } else if _, ok := err.(standardImportError); !ok { 450 t.Errorf("resolveGoProto: got error %v; want standardImportError", err) 451 } 452 } 453 if !got.Equal(tc.wantGoProto) { 454 t.Errorf("resolveGoProto: got %s; want %s", got, tc.wantGoProto) 455 } 456 }) 457 } 458 }