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(
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(
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(
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(
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(
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(
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(
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(
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(bps map[string][]byte) (ctx *TestContext, errs []error) {
636	config := TestConfig(buildDir, nil, "", bps)
637
638	ctx = NewTestContext()
639	ctx.RegisterModuleType("test_module", newTestModule)
640	ctx.RegisterModuleType("soong_namespace", NamespaceFactory)
641	ctx.Context.RegisterModuleType("blueprint_test_module", newBlueprintTestModule)
642	ctx.PreArchMutators(RegisterNamespaceMutator)
643	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
644		ctx.BottomUp("rename", renameMutator)
645	})
646	ctx.Register(config)
647
648	_, errs = ctx.ParseBlueprintsFiles("Android.bp")
649	if len(errs) > 0 {
650		return ctx, errs
651	}
652	_, errs = ctx.PrepareBuildActions(config)
653	return ctx, errs
654}
655
656func setupTestExpectErrs(bps map[string]string) (ctx *TestContext, errs []error) {
657	files := make(map[string][]byte, 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 setupTestFromFiles(files)
663}
664
665func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) {
666	t.Helper()
667	ctx, errs := setupTestExpectErrs(bps)
668	FailIfErrored(t, errs)
669	return ctx
670}
671
672func dependsOn(ctx *TestContext, module TestingModule, possibleDependency TestingModule) bool {
673	depends := false
674	visit := func(dependency blueprint.Module) {
675		if dependency == possibleDependency.module {
676			depends = true
677		}
678	}
679	ctx.VisitDirectDeps(module.module, visit)
680	return depends
681}
682
683func numDeps(ctx *TestContext, module TestingModule) int {
684	count := 0
685	visit := func(dependency blueprint.Module) {
686		count++
687	}
688	ctx.VisitDirectDeps(module.module, visit)
689	return count
690}
691
692func getModule(ctx *TestContext, moduleName string) TestingModule {
693	return ctx.ModuleForTests(moduleName, "")
694}
695
696func findModuleById(ctx *TestContext, id string) (module TestingModule) {
697	visit := func(candidate blueprint.Module) {
698		testModule, ok := candidate.(*testModule)
699		if ok {
700			if testModule.properties.Id == id {
701				module = TestingModule{testModule}
702			}
703		}
704	}
705	ctx.VisitAllModules(visit)
706	return module
707}
708
709type testModule struct {
710	ModuleBase
711	properties struct {
712		Rename string
713		Deps   []string
714		Id     string
715	}
716}
717
718func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
719	if m.properties.Rename != "" {
720		ctx.Rename(m.properties.Rename)
721	}
722	for _, d := range m.properties.Deps {
723		ctx.AddDependency(ctx.Module(), nil, d)
724	}
725}
726
727func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
728}
729
730func renameMutator(ctx BottomUpMutatorContext) {
731	if m, ok := ctx.Module().(*testModule); ok {
732		if m.properties.Rename != "" {
733			ctx.Rename(m.properties.Rename)
734		}
735	}
736}
737
738func newTestModule() Module {
739	m := &testModule{}
740	m.AddProperties(&m.properties)
741	InitAndroidModule(m)
742	return m
743}
744
745type blueprintTestModule struct {
746	blueprint.SimpleName
747	properties struct {
748		Deps []string
749	}
750}
751
752func (b *blueprintTestModule) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
753	return b.properties.Deps
754}
755
756func (b *blueprintTestModule) GenerateBuildActions(blueprint.ModuleContext) {
757}
758
759func newBlueprintTestModule() (blueprint.Module, []interface{}) {
760	m := &blueprintTestModule{}
761	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
762}
763