blob: ec392dfcfd582faee013cca3f63a39e19c39db0d [file] [log] [blame]
Jeff Gaston088e29e2017-11-29 16:47:17 -08001// 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"
Jeff Gastonb274ed32017-12-01 17:10:33 -080022 "reflect"
Jeff Gaston088e29e2017-11-29 16:47:17 -080023 "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
Colin Crossd602c382019-06-14 11:26:09 -070096func TestDependingOnBlueprintModuleInRootNamespace(t *testing.T) {
97 _ = setupTest(t,
98 map[string]string{
99 ".": `
100 blueprint_test_module {
101 name: "a",
102 }
103 `,
104 "dir1": `
105 soong_namespace {
106 }
107 blueprint_test_module {
108 name: "b",
109 deps: ["a"],
110 }
111 `,
112 },
113 )
114
115 // setupTest will report any errors
116}
117
Jeff Gaston088e29e2017-11-29 16:47:17 -0800118func TestDependingOnModuleInImportedNamespace(t *testing.T) {
119 ctx := setupTest(t,
120 map[string]string{
121 "dir1": `
122 soong_namespace {
123 }
124 test_module {
125 name: "a",
126 }
127 `,
128 "dir2": `
129 soong_namespace {
130 imports: ["dir1"],
131 }
132 test_module {
133 name: "b",
134 deps: ["a"],
135 }
136 `,
137 },
138 )
139
140 a := getModule(ctx, "a")
141 b := getModule(ctx, "b")
142 if !dependsOn(ctx, b, a) {
143 t.Errorf("module b does not depend on module a in the same namespace")
144 }
145}
146
147func TestDependingOnModuleInNonImportedNamespace(t *testing.T) {
148 _, errs := setupTestExpectErrs(
149 map[string]string{
150 "dir1": `
151 soong_namespace {
152 }
153 test_module {
154 name: "a",
155 }
156 `,
157 "dir2": `
158 soong_namespace {
159 }
160 test_module {
161 name: "a",
162 }
163 `,
164 "dir3": `
165 soong_namespace {
166 }
167 test_module {
168 name: "b",
169 deps: ["a"],
170 }
171 `,
172 },
173 )
174
175 expectedErrors := []error{
176 errors.New(
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800177 `dir3/Android.bp:4:4: "b" depends on undefined module "a"
Jeff Gaston088e29e2017-11-29 16:47:17 -0800178Module "b" is defined in namespace "dir3" which can read these 2 namespaces: ["dir3" "."]
179Module "a" can be found in these namespaces: ["dir1" "dir2"]`),
180 }
181
182 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
183 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
184 }
185}
186
187func TestDependingOnModuleByFullyQualifiedReference(t *testing.T) {
188 ctx := setupTest(t,
189 map[string]string{
190 "dir1": `
191 soong_namespace {
192 }
193 test_module {
194 name: "a",
195 }
196 `,
197 "dir2": `
198 soong_namespace {
199 }
200 test_module {
201 name: "b",
202 deps: ["//dir1:a"],
203 }
204 `,
205 },
206 )
207 a := getModule(ctx, "a")
208 b := getModule(ctx, "b")
209 if !dependsOn(ctx, b, a) {
210 t.Errorf("module b does not depend on module a")
211 }
212}
213
214func TestSameNameInTwoNamespaces(t *testing.T) {
215 ctx := setupTest(t,
216 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 )
245
246 one := findModuleById(ctx, "1")
247 two := findModuleById(ctx, "2")
248 three := findModuleById(ctx, "3")
249 four := findModuleById(ctx, "4")
250 if !dependsOn(ctx, two, one) {
251 t.Fatalf("Module 2 does not depend on module 1 in its namespace")
252 }
253 if dependsOn(ctx, two, three) {
254 t.Fatalf("Module 2 depends on module 3 in another namespace")
255 }
256 if !dependsOn(ctx, four, three) {
257 t.Fatalf("Module 4 does not depend on module 3 in its namespace")
258 }
259 if dependsOn(ctx, four, one) {
260 t.Fatalf("Module 4 depends on module 1 in another namespace")
261 }
262}
263
264func TestSearchOrder(t *testing.T) {
265 ctx := setupTest(t,
266 map[string]string{
267 "dir1": `
268 soong_namespace {
269 }
270 test_module {
271 name: "a",
272 id: "1",
273 }
274 `,
275 "dir2": `
276 soong_namespace {
277 }
278 test_module {
279 name: "a",
280 id:"2",
281 }
282 test_module {
283 name: "b",
284 id:"3",
285 }
286 `,
287 "dir3": `
288 soong_namespace {
289 }
290 test_module {
291 name: "a",
292 id:"4",
293 }
294 test_module {
295 name: "b",
296 id:"5",
297 }
298 test_module {
299 name: "c",
300 id:"6",
301 }
302 `,
303 ".": `
304 test_module {
305 name: "a",
306 id: "7",
307 }
308 test_module {
309 name: "b",
310 id: "8",
311 }
312 test_module {
313 name: "c",
314 id: "9",
315 }
316 test_module {
317 name: "d",
318 id: "10",
319 }
320 `,
321 "dir4": `
322 soong_namespace {
323 imports: ["dir1", "dir2", "dir3"]
324 }
325 test_module {
326 name: "test_me",
327 id:"0",
328 deps: ["a", "b", "c", "d"],
329 }
330 `,
331 },
332 )
333
334 testMe := findModuleById(ctx, "0")
335 if !dependsOn(ctx, testMe, findModuleById(ctx, "1")) {
336 t.Errorf("test_me doesn't depend on id 1")
337 }
338 if !dependsOn(ctx, testMe, findModuleById(ctx, "3")) {
339 t.Errorf("test_me doesn't depend on id 3")
340 }
341 if !dependsOn(ctx, testMe, findModuleById(ctx, "6")) {
342 t.Errorf("test_me doesn't depend on id 6")
343 }
344 if !dependsOn(ctx, testMe, findModuleById(ctx, "10")) {
345 t.Errorf("test_me doesn't depend on id 10")
346 }
347 if numDeps(ctx, testMe) != 4 {
348 t.Errorf("num dependencies of test_me = %v, not 4\n", numDeps(ctx, testMe))
349 }
350}
351
352func TestTwoNamespacesCanImportEachOther(t *testing.T) {
353 _ = setupTest(t,
354 map[string]string{
355 "dir1": `
356 soong_namespace {
357 imports: ["dir2"]
358 }
359 test_module {
360 name: "a",
361 }
362 test_module {
363 name: "c",
364 deps: ["b"],
365 }
366 `,
367 "dir2": `
368 soong_namespace {
369 imports: ["dir1"],
370 }
371 test_module {
372 name: "b",
373 deps: ["a"],
374 }
375 `,
376 },
377 )
378
379 // setupTest will report any errors
380}
381
382func TestImportingNonexistentNamespace(t *testing.T) {
383 _, errs := setupTestExpectErrs(
384 map[string]string{
385 "dir1": `
386 soong_namespace {
387 imports: ["a_nonexistent_namespace"]
388 }
389 test_module {
390 name: "a",
391 deps: ["a_nonexistent_module"]
392 }
393 `,
394 },
395 )
396
397 // should complain about the missing namespace and not complain about the unresolvable dependency
398 expectedErrors := []error{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800399 errors.New(`dir1/Android.bp:2:4: module "soong_namespace": namespace a_nonexistent_namespace does not exist`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800400 }
401 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
402 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
403 }
404}
405
406func TestNamespacesDontInheritParentNamespaces(t *testing.T) {
407 _, errs := setupTestExpectErrs(
408 map[string]string{
409 "dir1": `
410 soong_namespace {
411 }
412 test_module {
413 name: "a",
414 }
415 `,
416 "dir1/subdir1": `
417 soong_namespace {
418 }
419 test_module {
420 name: "b",
421 deps: ["a"],
422 }
423 `,
424 },
425 )
426
427 expectedErrors := []error{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800428 errors.New(`dir1/subdir1/Android.bp:4:4: "b" depends on undefined module "a"
Jeff Gaston088e29e2017-11-29 16:47:17 -0800429Module "b" is defined in namespace "dir1/subdir1" which can read these 2 namespaces: ["dir1/subdir1" "."]
430Module "a" can be found in these namespaces: ["dir1"]`),
431 }
432 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
433 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
434 }
435}
436
437func TestModulesDoReceiveParentNamespace(t *testing.T) {
438 _ = setupTest(t,
439 map[string]string{
440 "dir1": `
441 soong_namespace {
442 }
443 test_module {
444 name: "a",
445 }
446 `,
447 "dir1/subdir": `
448 test_module {
449 name: "b",
450 deps: ["a"],
451 }
452 `,
453 },
454 )
455
456 // setupTest will report any errors
457}
458
459func TestNamespaceImportsNotTransitive(t *testing.T) {
460 _, errs := setupTestExpectErrs(
461 map[string]string{
462 "dir1": `
463 soong_namespace {
464 }
465 test_module {
466 name: "a",
467 }
468 `,
469 "dir2": `
470 soong_namespace {
471 imports: ["dir1"],
472 }
473 test_module {
474 name: "b",
475 deps: ["a"],
476 }
477 `,
478 "dir3": `
479 soong_namespace {
480 imports: ["dir2"],
481 }
482 test_module {
483 name: "c",
484 deps: ["a"],
485 }
486 `,
487 },
488 )
489
490 expectedErrors := []error{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800491 errors.New(`dir3/Android.bp:5:4: "c" depends on undefined module "a"
Jeff Gaston088e29e2017-11-29 16:47:17 -0800492Module "c" is defined in namespace "dir3" which can read these 3 namespaces: ["dir3" "dir2" "."]
493Module "a" can be found in these namespaces: ["dir1"]`),
494 }
495 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
496 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
497 }
498}
499
500func TestTwoNamepacesInSameDir(t *testing.T) {
501 _, errs := setupTestExpectErrs(
502 map[string]string{
503 "dir1": `
504 soong_namespace {
505 }
506 soong_namespace {
507 }
508 `,
509 },
510 )
511
512 expectedErrors := []error{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800513 errors.New(`dir1/Android.bp:4:4: namespace dir1 already exists`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800514 }
515 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
516 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
517 }
518}
519
520func TestNamespaceNotAtTopOfFile(t *testing.T) {
521 _, errs := setupTestExpectErrs(
522 map[string]string{
523 "dir1": `
524 test_module {
525 name: "a"
526 }
527 soong_namespace {
528 }
529 `,
530 },
531 )
532
533 expectedErrors := []error{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800534 errors.New(`dir1/Android.bp:5:4: a namespace must be the first module in the file`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800535 }
536 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
537 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
538 }
539}
540
541func TestTwoModulesWithSameNameInSameNamespace(t *testing.T) {
542 _, errs := setupTestExpectErrs(
543 map[string]string{
544 "dir1": `
545 soong_namespace {
546 }
547 test_module {
548 name: "a"
549 }
550 test_module {
551 name: "a"
552 }
553 `,
554 },
555 )
556
557 expectedErrors := []error{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800558 errors.New(`dir1/Android.bp:7:4: module "a" already defined
559 dir1/Android.bp:4:4 <-- previous definition here`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800560 }
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
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800566func TestDeclaringNamespaceInNonAndroidBpFile(t *testing.T) {
567 _, errs := setupTestFromFiles(
568 map[string][]byte{
569 "Android.bp": []byte(`
570 build = ["include.bp"]
571 `),
572 "include.bp": []byte(`
573 soong_namespace {
574 }
575 `),
576 },
577 )
578
579 expectedErrors := []error{
580 errors.New(`include.bp:2:5: A namespace may only be declared in a file named Android.bp`),
581 }
582
583 if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
584 t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
585 }
586}
587
Jeff Gastonb274ed32017-12-01 17:10:33 -0800588// so that the generated .ninja file will have consistent names
589func TestConsistentNamespaceNames(t *testing.T) {
590 ctx := setupTest(t,
591 map[string]string{
592 "dir1": "soong_namespace{}",
593 "dir2": "soong_namespace{}",
594 "dir3": "soong_namespace{}",
595 })
596
597 ns1, _ := ctx.NameResolver.namespaceAt("dir1")
598 ns2, _ := ctx.NameResolver.namespaceAt("dir2")
599 ns3, _ := ctx.NameResolver.namespaceAt("dir3")
600 actualIds := []string{ns1.id, ns2.id, ns3.id}
601 expectedIds := []string{"1", "2", "3"}
602 if !reflect.DeepEqual(actualIds, expectedIds) {
603 t.Errorf("Incorrect namespace ids.\nactual: %s\nexpected: %s\n", actualIds, expectedIds)
604 }
605}
606
Colin Crosseafb10c2018-04-16 13:58:10 -0700607// so that the generated .ninja file will have consistent names
608func TestRename(t *testing.T) {
609 _ = setupTest(t,
610 map[string]string{
611 "dir1": `
612 soong_namespace {
613 }
614 test_module {
615 name: "a",
616 deps: ["c"],
617 }
618 test_module {
619 name: "b",
620 rename: "c",
621 }
622 `})
623 // setupTest will report any errors
624}
625
Jeff Gaston088e29e2017-11-29 16:47:17 -0800626// some utils to support the tests
627
628func mockFiles(bps map[string]string) (files map[string][]byte) {
629 files = make(map[string][]byte, len(bps))
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800630 files["Android.bp"] = []byte("")
Jeff Gaston088e29e2017-11-29 16:47:17 -0800631 for dir, text := range bps {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800632 files[filepath.Join(dir, "Android.bp")] = []byte(text)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800633 }
634 return files
635}
636
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800637func setupTestFromFiles(bps map[string][]byte) (ctx *TestContext, errs []error) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800638 buildDir, err := ioutil.TempDir("", "soong_namespace_test")
639 if err != nil {
640 return nil, []error{err}
641 }
642 defer os.RemoveAll(buildDir)
643
644 config := TestConfig(buildDir, nil)
645
646 ctx = NewTestContext()
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800647 ctx.MockFileSystem(bps)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800648 ctx.RegisterModuleType("test_module", ModuleFactoryAdaptor(newTestModule))
649 ctx.RegisterModuleType("soong_namespace", ModuleFactoryAdaptor(NamespaceFactory))
Colin Crossd602c382019-06-14 11:26:09 -0700650 ctx.RegisterModuleType("blueprint_test_module", newBlueprintTestModule)
Dan Willemsen6e72ef72018-01-26 18:27:02 -0800651 ctx.PreArchMutators(RegisterNamespaceMutator)
Colin Crosseafb10c2018-04-16 13:58:10 -0700652 ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
653 ctx.BottomUp("rename", renameMutator)
654 })
Jeff Gaston088e29e2017-11-29 16:47:17 -0800655 ctx.Register()
656
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800657 _, errs = ctx.ParseBlueprintsFiles("Android.bp")
Jeff Gaston088e29e2017-11-29 16:47:17 -0800658 if len(errs) > 0 {
659 return ctx, errs
660 }
661 _, errs = ctx.PrepareBuildActions(config)
662 return ctx, errs
663}
664
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800665func setupTestExpectErrs(bps map[string]string) (ctx *TestContext, errs []error) {
666 files := make(map[string][]byte, len(bps))
667 files["Android.bp"] = []byte("")
668 for dir, text := range bps {
669 files[filepath.Join(dir, "Android.bp")] = []byte(text)
670 }
671 return setupTestFromFiles(files)
672}
673
Jeff Gaston088e29e2017-11-29 16:47:17 -0800674func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) {
Colin Crossd602c382019-06-14 11:26:09 -0700675 t.Helper()
Jeff Gaston088e29e2017-11-29 16:47:17 -0800676 ctx, errs := setupTestExpectErrs(bps)
Logan Chien42039712018-03-12 16:29:17 +0800677 FailIfErrored(t, errs)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800678 return ctx
679}
680
681func dependsOn(ctx *TestContext, module TestingModule, possibleDependency TestingModule) bool {
682 depends := false
683 visit := func(dependency blueprint.Module) {
684 if dependency == possibleDependency.module {
685 depends = true
686 }
687 }
688 ctx.VisitDirectDeps(module.module, visit)
689 return depends
690}
691
692func numDeps(ctx *TestContext, module TestingModule) int {
693 count := 0
694 visit := func(dependency blueprint.Module) {
695 count++
696 }
697 ctx.VisitDirectDeps(module.module, visit)
698 return count
699}
700
701func getModule(ctx *TestContext, moduleName string) TestingModule {
702 return ctx.ModuleForTests(moduleName, "")
703}
704
705func findModuleById(ctx *TestContext, id string) (module TestingModule) {
706 visit := func(candidate blueprint.Module) {
707 testModule, ok := candidate.(*testModule)
708 if ok {
709 if testModule.properties.Id == id {
710 module = TestingModule{testModule}
711 }
712 }
713 }
714 ctx.VisitAllModules(visit)
715 return module
716}
717
718type testModule struct {
719 ModuleBase
720 properties struct {
Colin Crosseafb10c2018-04-16 13:58:10 -0700721 Rename string
722 Deps []string
723 Id string
Jeff Gaston088e29e2017-11-29 16:47:17 -0800724 }
725}
726
727func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
Colin Crosseafb10c2018-04-16 13:58:10 -0700728 if m.properties.Rename != "" {
729 ctx.Rename(m.properties.Rename)
730 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800731 for _, d := range m.properties.Deps {
732 ctx.AddDependency(ctx.Module(), nil, d)
733 }
734}
735
736func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
737}
738
Colin Crosseafb10c2018-04-16 13:58:10 -0700739func renameMutator(ctx BottomUpMutatorContext) {
740 if m, ok := ctx.Module().(*testModule); ok {
741 if m.properties.Rename != "" {
742 ctx.Rename(m.properties.Rename)
743 }
744 }
745}
746
Jeff Gaston088e29e2017-11-29 16:47:17 -0800747func newTestModule() Module {
748 m := &testModule{}
749 m.AddProperties(&m.properties)
750 InitAndroidModule(m)
751 return m
752}
Colin Crossd602c382019-06-14 11:26:09 -0700753
754type blueprintTestModule struct {
755 blueprint.SimpleName
756 properties struct {
757 Deps []string
758 }
759}
760
761func (b *blueprintTestModule) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
762 return b.properties.Deps
763}
764
765func (b *blueprintTestModule) GenerateBuildActions(blueprint.ModuleContext) {
766}
767
768func newBlueprintTestModule() (blueprint.Module, []interface{}) {
769 m := &blueprintTestModule{}
770 return m, []interface{}{&m.properties, &m.SimpleName.Properties}
771}