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( 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( 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( 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( 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( 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( 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( 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( 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(bps map[string][]byte) (ctx *TestContext, errs []error) { 636 config := TestConfig(buildDir, nil, "", bps) 637 638 ctx = NewTestContext() 639 ctx.RegisterModuleType("test_module", newTestModule) 640 ctx.RegisterModuleType("soong_namespace", NamespaceFactory) 641 ctx.Context.RegisterModuleType("blueprint_test_module", newBlueprintTestModule) 642 ctx.PreArchMutators(RegisterNamespaceMutator) 643 ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { 644 ctx.BottomUp("rename", renameMutator) 645 }) 646 ctx.Register(config) 647 648 _, errs = ctx.ParseBlueprintsFiles("Android.bp") 649 if len(errs) > 0 { 650 return ctx, errs 651 } 652 _, errs = ctx.PrepareBuildActions(config) 653 return ctx, errs 654} 655 656func setupTestExpectErrs(bps map[string]string) (ctx *TestContext, errs []error) { 657 files := make(map[string][]byte, 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 setupTestFromFiles(files) 663} 664 665func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) { 666 t.Helper() 667 ctx, errs := setupTestExpectErrs(bps) 668 FailIfErrored(t, errs) 669 return ctx 670} 671 672func dependsOn(ctx *TestContext, module TestingModule, possibleDependency TestingModule) bool { 673 depends := false 674 visit := func(dependency blueprint.Module) { 675 if dependency == possibleDependency.module { 676 depends = true 677 } 678 } 679 ctx.VisitDirectDeps(module.module, visit) 680 return depends 681} 682 683func numDeps(ctx *TestContext, module TestingModule) int { 684 count := 0 685 visit := func(dependency blueprint.Module) { 686 count++ 687 } 688 ctx.VisitDirectDeps(module.module, visit) 689 return count 690} 691 692func getModule(ctx *TestContext, moduleName string) TestingModule { 693 return ctx.ModuleForTests(moduleName, "") 694} 695 696func findModuleById(ctx *TestContext, id string) (module TestingModule) { 697 visit := func(candidate blueprint.Module) { 698 testModule, ok := candidate.(*testModule) 699 if ok { 700 if testModule.properties.Id == id { 701 module = TestingModule{testModule} 702 } 703 } 704 } 705 ctx.VisitAllModules(visit) 706 return module 707} 708 709type testModule struct { 710 ModuleBase 711 properties struct { 712 Rename string 713 Deps []string 714 Id string 715 } 716} 717 718func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) { 719 if m.properties.Rename != "" { 720 ctx.Rename(m.properties.Rename) 721 } 722 for _, d := range m.properties.Deps { 723 ctx.AddDependency(ctx.Module(), nil, d) 724 } 725} 726 727func (m *testModule) GenerateAndroidBuildActions(ModuleContext) { 728} 729 730func renameMutator(ctx BottomUpMutatorContext) { 731 if m, ok := ctx.Module().(*testModule); ok { 732 if m.properties.Rename != "" { 733 ctx.Rename(m.properties.Rename) 734 } 735 } 736} 737 738func newTestModule() Module { 739 m := &testModule{} 740 m.AddProperties(&m.properties) 741 InitAndroidModule(m) 742 return m 743} 744 745type blueprintTestModule struct { 746 blueprint.SimpleName 747 properties struct { 748 Deps []string 749 } 750} 751 752func (b *blueprintTestModule) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string { 753 return b.properties.Deps 754} 755 756func (b *blueprintTestModule) GenerateBuildActions(blueprint.ModuleContext) { 757} 758 759func newBlueprintTestModule() (blueprint.Module, []interface{}) { 760 m := &blueprintTestModule{} 761 return m, []interface{}{&m.properties, &m.SimpleName.Properties} 762} 763