• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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