blob: 9a791a534c0ac0955067a6bfc92213694419bc5d [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
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(
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800155 `dir3/Android.bp:4:4: "b" depends on undefined module "a"
Jeff Gaston088e29e2017-11-29 16:47:17 -0800156Module "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{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800377 errors.New(`dir1/Android.bp:2:4: module "soong_namespace": namespace a_nonexistent_namespace does not exist`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800378 }
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{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800406 errors.New(`dir1/subdir1/Android.bp:4:4: "b" depends on undefined module "a"
Jeff Gaston088e29e2017-11-29 16:47:17 -0800407Module "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{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800469 errors.New(`dir3/Android.bp:5:4: "c" depends on undefined module "a"
Jeff Gaston088e29e2017-11-29 16:47:17 -0800470Module "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{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800491 errors.New(`dir1/Android.bp:4:4: namespace dir1 already exists`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800492 }
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{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800512 errors.New(`dir1/Android.bp:5:4: a namespace must be the first module in the file`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800513 }
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{
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800536 errors.New(`dir1/Android.bp:7:4: module "a" already defined
537 dir1/Android.bp:4:4 <-- previous definition here`),
Jeff Gaston088e29e2017-11-29 16:47:17 -0800538 }
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
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800544func 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
Jeff Gastonb274ed32017-12-01 17:10:33 -0800566// 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
Colin Crosseafb10c2018-04-16 13:58:10 -0700585// 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
Jeff Gaston088e29e2017-11-29 16:47:17 -0800604// 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))
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800608 files["Android.bp"] = []byte("")
Jeff Gaston088e29e2017-11-29 16:47:17 -0800609 for dir, text := range bps {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800610 files[filepath.Join(dir, "Android.bp")] = []byte(text)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800611 }
612 return files
613}
614
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800615func setupTestFromFiles(bps map[string][]byte) (ctx *TestContext, errs []error) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800616 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()
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800625 ctx.MockFileSystem(bps)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800626 ctx.RegisterModuleType("test_module", ModuleFactoryAdaptor(newTestModule))
627 ctx.RegisterModuleType("soong_namespace", ModuleFactoryAdaptor(NamespaceFactory))
Dan Willemsen6e72ef72018-01-26 18:27:02 -0800628 ctx.PreArchMutators(RegisterNamespaceMutator)
Colin Crosseafb10c2018-04-16 13:58:10 -0700629 ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
630 ctx.BottomUp("rename", renameMutator)
631 })
Jeff Gaston088e29e2017-11-29 16:47:17 -0800632 ctx.Register()
633
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800634 _, errs = ctx.ParseBlueprintsFiles("Android.bp")
Jeff Gaston088e29e2017-11-29 16:47:17 -0800635 if len(errs) > 0 {
636 return ctx, errs
637 }
638 _, errs = ctx.PrepareBuildActions(config)
639 return ctx, errs
640}
641
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800642func 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
Jeff Gaston088e29e2017-11-29 16:47:17 -0800651func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) {
652 ctx, errs := setupTestExpectErrs(bps)
Logan Chien42039712018-03-12 16:29:17 +0800653 FailIfErrored(t, errs)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800654 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 {
Colin Crosseafb10c2018-04-16 13:58:10 -0700697 Rename string
698 Deps []string
699 Id string
Jeff Gaston088e29e2017-11-29 16:47:17 -0800700 }
701}
702
703func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
Colin Crosseafb10c2018-04-16 13:58:10 -0700704 if m.properties.Rename != "" {
705 ctx.Rename(m.properties.Rename)
706 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800707 for _, d := range m.properties.Deps {
708 ctx.AddDependency(ctx.Module(), nil, d)
709 }
710}
711
712func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
713}
714
Colin Crosseafb10c2018-04-16 13:58:10 -0700715func 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
Jeff Gaston088e29e2017-11-29 16:47:17 -0800723func newTestModule() Module {
724 m := &testModule{}
725 m.AddProperties(&m.properties)
726 InitAndroidModule(m)
727 return m
728}