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