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