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