1// Copyright 2017 Google Inc. 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 15package android 16 17import ( 18 "errors" 19 "path/filepath" 20 "reflect" 21 "testing" 22 23 "github.com/google/blueprint" 24) 25 26func TestDependingOnModuleInSameNamespace(t *testing.T) { 27 ctx := setupTest(t, 28 map[string]string{ 29 "dir1": ` 30 soong_namespace { 31 } 32 test_module { 33 name: "a", 34 } 35 test_module { 36 name: "b", 37 deps: ["a"], 38 } 39 `, 40 }, 41 ) 42 43 a := getModule(ctx, "a") 44 b := getModule(ctx, "b") 45 if !dependsOn(ctx, b, a) { 46 t.Errorf("module b does not depend on module a in the same namespace") 47 } 48} 49 50func TestDependingOnModuleInRootNamespace(t *testing.T) { 51 ctx := setupTest(t, 52 map[string]string{ 53 ".": ` 54 test_module { 55 name: "b", 56 deps: ["a"], 57 } 58 test_module { 59 name: "a", 60 } 61 `, 62 }, 63 ) 64 65 a := getModule(ctx, "a") 66 b := getModule(ctx, "b") 67 if !dependsOn(ctx, b, a) { 68 t.Errorf("module b in root namespace does not depend on module a in the root namespace") 69 } 70} 71 72func TestImplicitlyImportRootNamespace(t *testing.T) { 73 _ = setupTest(t, 74 map[string]string{ 75 ".": ` 76 test_module { 77 name: "a", 78 } 79 `, 80 "dir1": ` 81 soong_namespace { 82 } 83 test_module { 84 name: "b", 85 deps: ["a"], 86 } 87 `, 88 }, 89 ) 90 91 // setupTest will report any errors 92} 93 94func TestDependingOnBlueprintModuleInRootNamespace(t *testing.T) { 95 _ = setupTest(t, 96 map[string]string{ 97 ".": ` 98 blueprint_test_module { 99 name: "a", 100 } 101 `, 102 "dir1": ` 103 soong_namespace { 104 } 105 blueprint_test_module { 106 name: "b", 107 deps: ["a"], 108 } 109 `, 110 }, 111 ) 112 113 // setupTest will report any errors 114} 115 116func TestDependingOnModuleInImportedNamespace(t *testing.T) { 117 ctx := setupTest(t, 118 map[string]string{ 119 "dir1": ` 120 soong_namespace { 121 } 122 test_module { 123 name: "a", 124 } 125 `, 126 "dir2": ` 127 soong_namespace { 128 imports: ["dir1"], 129 } 130 test_module { 131 name: "b", 132 deps: ["a"], 133 } 134 `, 135 }, 136 ) 137 138 a := getModule(ctx, "a") 139 b := getModule(ctx, "b") 140 if !dependsOn(ctx, b, a) { 141 t.Errorf("module b does not depend on module a in the same namespace") 142 } 143} 144 145func TestDependingOnModuleInNonImportedNamespace(t *testing.T) { 146 _, errs := setupTestExpectErrs(t, 147 map[string]string{ 148 "dir1": ` 149 soong_namespace { 150 } 151 test_module { 152 name: "a", 153 } 154 `, 155 "dir2": ` 156 soong_namespace { 157 } 158 test_module { 159 name: "a", 160 } 161 `, 162 "dir3": ` 163 soong_namespace { 164 } 165 test_module { 166 name: "b", 167 deps: ["a"], 168 } 169 `, 170 }, 171 ) 172 173 expectedErrors := []error{ 174 errors.New( 175 `dir3/Android.bp:4:4: "b" depends on undefined module "a" 176Module "b" is defined in namespace "dir3" which can read these 2 namespaces: ["dir3" "."] 177Module "a" can be found in these namespaces: ["dir1" "dir2"]`), 178 } 179 180 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 181 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 182 } 183} 184 185func TestDependingOnModuleByFullyQualifiedReference(t *testing.T) { 186 ctx := setupTest(t, 187 map[string]string{ 188 "dir1": ` 189 soong_namespace { 190 } 191 test_module { 192 name: "a", 193 } 194 `, 195 "dir2": ` 196 soong_namespace { 197 } 198 test_module { 199 name: "b", 200 deps: ["//dir1:a"], 201 } 202 `, 203 }, 204 ) 205 a := getModule(ctx, "a") 206 b := getModule(ctx, "b") 207 if !dependsOn(ctx, b, a) { 208 t.Errorf("module b does not depend on module a") 209 } 210} 211 212func TestSameNameInTwoNamespaces(t *testing.T) { 213 ctx := setupTest(t, 214 map[string]string{ 215 "dir1": ` 216 soong_namespace { 217 } 218 test_module { 219 name: "a", 220 id: "1", 221 } 222 test_module { 223 name: "b", 224 deps: ["a"], 225 id: "2", 226 } 227 `, 228 "dir2": ` 229 soong_namespace { 230 } 231 test_module { 232 name: "a", 233 id:"3", 234 } 235 test_module { 236 name: "b", 237 deps: ["a"], 238 id:"4", 239 } 240 `, 241 }, 242 ) 243 244 one := findModuleById(ctx, "1") 245 two := findModuleById(ctx, "2") 246 three := findModuleById(ctx, "3") 247 four := findModuleById(ctx, "4") 248 if !dependsOn(ctx, two, one) { 249 t.Fatalf("Module 2 does not depend on module 1 in its namespace") 250 } 251 if dependsOn(ctx, two, three) { 252 t.Fatalf("Module 2 depends on module 3 in another namespace") 253 } 254 if !dependsOn(ctx, four, three) { 255 t.Fatalf("Module 4 does not depend on module 3 in its namespace") 256 } 257 if dependsOn(ctx, four, one) { 258 t.Fatalf("Module 4 depends on module 1 in another namespace") 259 } 260} 261 262func TestSearchOrder(t *testing.T) { 263 ctx := setupTest(t, 264 map[string]string{ 265 "dir1": ` 266 soong_namespace { 267 } 268 test_module { 269 name: "a", 270 id: "1", 271 } 272 `, 273 "dir2": ` 274 soong_namespace { 275 } 276 test_module { 277 name: "a", 278 id:"2", 279 } 280 test_module { 281 name: "b", 282 id:"3", 283 } 284 `, 285 "dir3": ` 286 soong_namespace { 287 } 288 test_module { 289 name: "a", 290 id:"4", 291 } 292 test_module { 293 name: "b", 294 id:"5", 295 } 296 test_module { 297 name: "c", 298 id:"6", 299 } 300 `, 301 ".": ` 302 test_module { 303 name: "a", 304 id: "7", 305 } 306 test_module { 307 name: "b", 308 id: "8", 309 } 310 test_module { 311 name: "c", 312 id: "9", 313 } 314 test_module { 315 name: "d", 316 id: "10", 317 } 318 `, 319 "dir4": ` 320 soong_namespace { 321 imports: ["dir1", "dir2", "dir3"] 322 } 323 test_module { 324 name: "test_me", 325 id:"0", 326 deps: ["a", "b", "c", "d"], 327 } 328 `, 329 }, 330 ) 331 332 testMe := findModuleById(ctx, "0") 333 if !dependsOn(ctx, testMe, findModuleById(ctx, "1")) { 334 t.Errorf("test_me doesn't depend on id 1") 335 } 336 if !dependsOn(ctx, testMe, findModuleById(ctx, "3")) { 337 t.Errorf("test_me doesn't depend on id 3") 338 } 339 if !dependsOn(ctx, testMe, findModuleById(ctx, "6")) { 340 t.Errorf("test_me doesn't depend on id 6") 341 } 342 if !dependsOn(ctx, testMe, findModuleById(ctx, "10")) { 343 t.Errorf("test_me doesn't depend on id 10") 344 } 345 if numDeps(ctx, testMe) != 4 { 346 t.Errorf("num dependencies of test_me = %v, not 4\n", numDeps(ctx, testMe)) 347 } 348} 349 350func TestTwoNamespacesCanImportEachOther(t *testing.T) { 351 _ = setupTest(t, 352 map[string]string{ 353 "dir1": ` 354 soong_namespace { 355 imports: ["dir2"] 356 } 357 test_module { 358 name: "a", 359 } 360 test_module { 361 name: "c", 362 deps: ["b"], 363 } 364 `, 365 "dir2": ` 366 soong_namespace { 367 imports: ["dir1"], 368 } 369 test_module { 370 name: "b", 371 deps: ["a"], 372 } 373 `, 374 }, 375 ) 376 377 // setupTest will report any errors 378} 379 380func TestImportingNonexistentNamespace(t *testing.T) { 381 _, errs := setupTestExpectErrs(t, 382 map[string]string{ 383 "dir1": ` 384 soong_namespace { 385 imports: ["a_nonexistent_namespace"] 386 } 387 test_module { 388 name: "a", 389 deps: ["a_nonexistent_module"] 390 } 391 `, 392 }, 393 ) 394 395 // should complain about the missing namespace and not complain about the unresolvable dependency 396 expectedErrors := []error{ 397 errors.New(`dir1/Android.bp:2:4: module "soong_namespace": namespace a_nonexistent_namespace does not exist`), 398 } 399 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 400 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 401 } 402} 403 404func TestNamespacesDontInheritParentNamespaces(t *testing.T) { 405 _, errs := setupTestExpectErrs(t, 406 map[string]string{ 407 "dir1": ` 408 soong_namespace { 409 } 410 test_module { 411 name: "a", 412 } 413 `, 414 "dir1/subdir1": ` 415 soong_namespace { 416 } 417 test_module { 418 name: "b", 419 deps: ["a"], 420 } 421 `, 422 }, 423 ) 424 425 expectedErrors := []error{ 426 errors.New(`dir1/subdir1/Android.bp:4:4: "b" depends on undefined module "a" 427Module "b" is defined in namespace "dir1/subdir1" which can read these 2 namespaces: ["dir1/subdir1" "."] 428Module "a" can be found in these namespaces: ["dir1"]`), 429 } 430 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 431 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 432 } 433} 434 435func TestModulesDoReceiveParentNamespace(t *testing.T) { 436 _ = setupTest(t, 437 map[string]string{ 438 "dir1": ` 439 soong_namespace { 440 } 441 test_module { 442 name: "a", 443 } 444 `, 445 "dir1/subdir": ` 446 test_module { 447 name: "b", 448 deps: ["a"], 449 } 450 `, 451 }, 452 ) 453 454 // setupTest will report any errors 455} 456 457func TestNamespaceImportsNotTransitive(t *testing.T) { 458 _, errs := setupTestExpectErrs(t, 459 map[string]string{ 460 "dir1": ` 461 soong_namespace { 462 } 463 test_module { 464 name: "a", 465 } 466 `, 467 "dir2": ` 468 soong_namespace { 469 imports: ["dir1"], 470 } 471 test_module { 472 name: "b", 473 deps: ["a"], 474 } 475 `, 476 "dir3": ` 477 soong_namespace { 478 imports: ["dir2"], 479 } 480 test_module { 481 name: "c", 482 deps: ["a"], 483 } 484 `, 485 }, 486 ) 487 488 expectedErrors := []error{ 489 errors.New(`dir3/Android.bp:5:4: "c" depends on undefined module "a" 490Module "c" is defined in namespace "dir3" which can read these 3 namespaces: ["dir3" "dir2" "."] 491Module "a" can be found in these namespaces: ["dir1"]`), 492 } 493 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 494 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 495 } 496} 497 498func TestTwoNamepacesInSameDir(t *testing.T) { 499 _, errs := setupTestExpectErrs(t, 500 map[string]string{ 501 "dir1": ` 502 soong_namespace { 503 } 504 soong_namespace { 505 } 506 `, 507 }, 508 ) 509 510 expectedErrors := []error{ 511 errors.New(`dir1/Android.bp:4:4: namespace dir1 already exists`), 512 } 513 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 514 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 515 } 516} 517 518func TestNamespaceNotAtTopOfFile(t *testing.T) { 519 _, errs := setupTestExpectErrs(t, 520 map[string]string{ 521 "dir1": ` 522 test_module { 523 name: "a" 524 } 525 soong_namespace { 526 } 527 `, 528 }, 529 ) 530 531 expectedErrors := []error{ 532 errors.New(`dir1/Android.bp:5:4: a namespace must be the first module in the file`), 533 } 534 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 535 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 536 } 537} 538 539func TestTwoModulesWithSameNameInSameNamespace(t *testing.T) { 540 _, errs := setupTestExpectErrs(t, 541 map[string]string{ 542 "dir1": ` 543 soong_namespace { 544 } 545 test_module { 546 name: "a" 547 } 548 test_module { 549 name: "a" 550 } 551 `, 552 }, 553 ) 554 555 expectedErrors := []error{ 556 errors.New(`dir1/Android.bp:7:4: module "a" already defined 557 dir1/Android.bp:4:4 <-- previous definition here`), 558 } 559 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 560 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 561 } 562} 563 564func TestDeclaringNamespaceInNonAndroidBpFile(t *testing.T) { 565 _, errs := setupTestFromFiles(t, 566 map[string][]byte{ 567 "Android.bp": []byte(` 568 build = ["include.bp"] 569 `), 570 "include.bp": []byte(` 571 soong_namespace { 572 } 573 `), 574 }, 575 ) 576 577 expectedErrors := []error{ 578 errors.New(`include.bp:2:5: A namespace may only be declared in a file named Android.bp`), 579 } 580 581 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() { 582 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs) 583 } 584} 585 586// so that the generated .ninja file will have consistent names 587func TestConsistentNamespaceNames(t *testing.T) { 588 ctx := setupTest(t, 589 map[string]string{ 590 "dir1": "soong_namespace{}", 591 "dir2": "soong_namespace{}", 592 "dir3": "soong_namespace{}", 593 }) 594 595 ns1, _ := ctx.NameResolver.namespaceAt("dir1") 596 ns2, _ := ctx.NameResolver.namespaceAt("dir2") 597 ns3, _ := ctx.NameResolver.namespaceAt("dir3") 598 actualIds := []string{ns1.id, ns2.id, ns3.id} 599 expectedIds := []string{"1", "2", "3"} 600 if !reflect.DeepEqual(actualIds, expectedIds) { 601 t.Errorf("Incorrect namespace ids.\nactual: %s\nexpected: %s\n", actualIds, expectedIds) 602 } 603} 604 605// so that the generated .ninja file will have consistent names 606func TestRename(t *testing.T) { 607 _ = setupTest(t, 608 map[string]string{ 609 "dir1": ` 610 soong_namespace { 611 } 612 test_module { 613 name: "a", 614 deps: ["c"], 615 } 616 test_module { 617 name: "b", 618 rename: "c", 619 } 620 `}) 621 // setupTest will report any errors 622} 623 624// some utils to support the tests 625 626func mockFiles(bps map[string]string) (files map[string][]byte) { 627 files = make(map[string][]byte, len(bps)) 628 files["Android.bp"] = []byte("") 629 for dir, text := range bps { 630 files[filepath.Join(dir, "Android.bp")] = []byte(text) 631 } 632 return files 633} 634 635func setupTestFromFiles(t *testing.T, bps MockFS) (ctx *TestContext, errs []error) { 636 result := GroupFixturePreparers( 637 FixtureModifyContext(func(ctx *TestContext) { 638 ctx.RegisterModuleType("test_module", newTestModule) 639 ctx.RegisterModuleType("soong_namespace", NamespaceFactory) 640 ctx.Context.RegisterModuleType("blueprint_test_module", newBlueprintTestModule) 641 ctx.PreArchMutators(RegisterNamespaceMutator) 642 ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { 643 ctx.BottomUp("rename", renameMutator) 644 }) 645 }), 646 bps.AddToFixture(), 647 ). 648 // Ignore errors for now so tests can check them later. 649 ExtendWithErrorHandler(FixtureIgnoreErrors). 650 RunTest(t) 651 652 return result.TestContext, result.Errs 653} 654 655func setupTestExpectErrs(t *testing.T, bps map[string]string) (ctx *TestContext, errs []error) { 656 files := make(map[string][]byte, len(bps)) 657 files["Android.bp"] = []byte("") 658 for dir, text := range bps { 659 files[filepath.Join(dir, "Android.bp")] = []byte(text) 660 } 661 return setupTestFromFiles(t, files) 662} 663 664func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) { 665 t.Helper() 666 ctx, errs := setupTestExpectErrs(t, bps) 667 FailIfErrored(t, errs) 668 return ctx 669} 670 671func dependsOn(ctx *TestContext, module TestingModule, possibleDependency TestingModule) bool { 672 depends := false 673 visit := func(dependency blueprint.Module) { 674 if dependency == possibleDependency.module { 675 depends = true 676 } 677 } 678 ctx.VisitDirectDeps(module.module, visit) 679 return depends 680} 681 682func numDeps(ctx *TestContext, module TestingModule) int { 683 count := 0 684 visit := func(dependency blueprint.Module) { 685 count++ 686 } 687 ctx.VisitDirectDeps(module.module, visit) 688 return count 689} 690 691func getModule(ctx *TestContext, moduleName string) TestingModule { 692 return ctx.ModuleForTests(moduleName, "") 693} 694 695func findModuleById(ctx *TestContext, id string) (module TestingModule) { 696 visit := func(candidate blueprint.Module) { 697 testModule, ok := candidate.(*testModule) 698 if ok { 699 if testModule.properties.Id == id { 700 module = newTestingModule(ctx.config, testModule) 701 } 702 } 703 } 704 ctx.VisitAllModules(visit) 705 return module 706} 707 708type testModule struct { 709 ModuleBase 710 properties struct { 711 Rename string 712 Deps []string 713 Id string 714 } 715} 716 717func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) { 718 if m.properties.Rename != "" { 719 ctx.Rename(m.properties.Rename) 720 } 721 for _, d := range m.properties.Deps { 722 ctx.AddDependency(ctx.Module(), nil, d) 723 } 724} 725 726func (m *testModule) GenerateAndroidBuildActions(ModuleContext) { 727} 728 729func renameMutator(ctx BottomUpMutatorContext) { 730 if m, ok := ctx.Module().(*testModule); ok { 731 if m.properties.Rename != "" { 732 ctx.Rename(m.properties.Rename) 733 } 734 } 735} 736 737func newTestModule() Module { 738 m := &testModule{} 739 m.AddProperties(&m.properties) 740 InitAndroidModule(m) 741 return m 742} 743 744type blueprintTestModule struct { 745 blueprint.SimpleName 746 properties struct { 747 Deps []string 748 } 749} 750 751func (b *blueprintTestModule) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string { 752 return b.properties.Deps 753} 754 755func (b *blueprintTestModule) GenerateBuildActions(blueprint.ModuleContext) { 756} 757 758func newBlueprintTestModule() (blueprint.Module, []interface{}) { 759 m := &blueprintTestModule{} 760 return m, []interface{}{&m.properties, &m.SimpleName.Properties} 761} 762