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