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