1// Copyright 2015 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	"fmt"
19	"reflect"
20	"strings"
21	"testing"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/proptools"
25)
26
27type mutatorTestModule struct {
28	ModuleBase
29	props struct {
30		Deps_missing_deps    []string
31		Mutator_missing_deps []string
32	}
33
34	missingDeps []string
35}
36
37func mutatorTestModuleFactory() Module {
38	module := &mutatorTestModule{}
39	module.AddProperties(&module.props)
40	InitAndroidModule(module)
41	return module
42}
43
44func (m *mutatorTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
45	ctx.Build(pctx, BuildParams{
46		Rule:   Touch,
47		Output: PathForModuleOut(ctx, "output"),
48	})
49
50	m.missingDeps = ctx.GetMissingDependencies()
51}
52
53func (m *mutatorTestModule) DepsMutator(ctx BottomUpMutatorContext) {
54	ctx.AddDependency(ctx.Module(), nil, m.props.Deps_missing_deps...)
55}
56
57func addMissingDependenciesMutator(ctx TopDownMutatorContext) {
58	ctx.AddMissingDependencies(ctx.Module().(*mutatorTestModule).props.Mutator_missing_deps)
59}
60
61func TestMutatorAddMissingDependencies(t *testing.T) {
62	bp := `
63		test {
64			name: "foo",
65			deps_missing_deps: ["regular_missing_dep"],
66			mutator_missing_deps: ["added_missing_dep"],
67		}
68	`
69
70	config := TestConfig(buildDir, nil, bp, nil)
71	config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
72
73	ctx := NewTestContext()
74	ctx.SetAllowMissingDependencies(true)
75
76	ctx.RegisterModuleType("test", mutatorTestModuleFactory)
77	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
78		ctx.TopDown("add_missing_dependencies", addMissingDependenciesMutator)
79	})
80
81	ctx.Register(config)
82	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
83	FailIfErrored(t, errs)
84	_, errs = ctx.PrepareBuildActions(config)
85	FailIfErrored(t, errs)
86
87	foo := ctx.ModuleForTests("foo", "").Module().(*mutatorTestModule)
88
89	if g, w := foo.missingDeps, []string{"added_missing_dep", "regular_missing_dep"}; !reflect.DeepEqual(g, w) {
90		t.Errorf("want foo missing deps %q, got %q", w, g)
91	}
92}
93
94func TestModuleString(t *testing.T) {
95	ctx := NewTestContext()
96
97	var moduleStrings []string
98
99	ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
100		ctx.BottomUp("pre_arch", func(ctx BottomUpMutatorContext) {
101			moduleStrings = append(moduleStrings, ctx.Module().String())
102			ctx.CreateVariations("a", "b")
103		})
104		ctx.TopDown("rename_top_down", func(ctx TopDownMutatorContext) {
105			moduleStrings = append(moduleStrings, ctx.Module().String())
106			ctx.Rename(ctx.Module().base().Name() + "_renamed1")
107		})
108	})
109
110	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
111		ctx.BottomUp("pre_deps", func(ctx BottomUpMutatorContext) {
112			moduleStrings = append(moduleStrings, ctx.Module().String())
113			ctx.CreateVariations("c", "d")
114		})
115	})
116
117	ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
118		ctx.BottomUp("post_deps", func(ctx BottomUpMutatorContext) {
119			moduleStrings = append(moduleStrings, ctx.Module().String())
120			ctx.CreateLocalVariations("e", "f")
121		})
122		ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
123			moduleStrings = append(moduleStrings, ctx.Module().String())
124			ctx.Rename(ctx.Module().base().Name() + "_renamed2")
125		})
126		ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
127			moduleStrings = append(moduleStrings, ctx.Module().String())
128		})
129	})
130
131	ctx.RegisterModuleType("test", mutatorTestModuleFactory)
132
133	bp := `
134		test {
135			name: "foo",
136		}
137	`
138
139	config := TestConfig(buildDir, nil, bp, nil)
140
141	ctx.Register(config)
142
143	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
144	FailIfErrored(t, errs)
145	_, errs = ctx.PrepareBuildActions(config)
146	FailIfErrored(t, errs)
147
148	want := []string{
149		// Initial name.
150		"foo{}",
151
152		// After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order).
153		"foo{pre_arch:b}",
154		"foo{pre_arch:a}",
155
156		// After rename_top_down.
157		"foo_renamed1{pre_arch:a}",
158		"foo_renamed1{pre_arch:b}",
159
160		// After pre_deps.
161		"foo_renamed1{pre_arch:a,pre_deps:c}",
162		"foo_renamed1{pre_arch:a,pre_deps:d}",
163		"foo_renamed1{pre_arch:b,pre_deps:c}",
164		"foo_renamed1{pre_arch:b,pre_deps:d}",
165
166		// After post_deps.
167		"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
168		"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}",
169		"foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}",
170		"foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}",
171		"foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}",
172		"foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}",
173		"foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}",
174		"foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}",
175
176		// After rename_bottom_up.
177		"foo_renamed2{pre_arch:a,pre_deps:c,post_deps:e}",
178		"foo_renamed2{pre_arch:a,pre_deps:c,post_deps:f}",
179		"foo_renamed2{pre_arch:a,pre_deps:d,post_deps:e}",
180		"foo_renamed2{pre_arch:a,pre_deps:d,post_deps:f}",
181		"foo_renamed2{pre_arch:b,pre_deps:c,post_deps:e}",
182		"foo_renamed2{pre_arch:b,pre_deps:c,post_deps:f}",
183		"foo_renamed2{pre_arch:b,pre_deps:d,post_deps:e}",
184		"foo_renamed2{pre_arch:b,pre_deps:d,post_deps:f}",
185	}
186
187	if !reflect.DeepEqual(moduleStrings, want) {
188		t.Errorf("want module String() values:\n%q\ngot:\n%q", want, moduleStrings)
189	}
190}
191
192func TestFinalDepsPhase(t *testing.T) {
193	ctx := NewTestContext()
194
195	finalGot := map[string]int{}
196
197	dep1Tag := struct {
198		blueprint.BaseDependencyTag
199	}{}
200	dep2Tag := struct {
201		blueprint.BaseDependencyTag
202	}{}
203
204	ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
205		ctx.BottomUp("far_deps_1", func(ctx BottomUpMutatorContext) {
206			if !strings.HasPrefix(ctx.ModuleName(), "common_dep") {
207				ctx.AddFarVariationDependencies([]blueprint.Variation{}, dep1Tag, "common_dep_1")
208			}
209		})
210		ctx.BottomUp("variant", func(ctx BottomUpMutatorContext) {
211			ctx.CreateLocalVariations("a", "b")
212		})
213	})
214
215	ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
216		ctx.BottomUp("far_deps_2", func(ctx BottomUpMutatorContext) {
217			if !strings.HasPrefix(ctx.ModuleName(), "common_dep") {
218				ctx.AddFarVariationDependencies([]blueprint.Variation{}, dep2Tag, "common_dep_2")
219			}
220		})
221		ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
222			finalGot[ctx.Module().String()] += 1
223			ctx.VisitDirectDeps(func(mod Module) {
224				finalGot[fmt.Sprintf("%s -> %s", ctx.Module().String(), mod)] += 1
225			})
226		})
227	})
228
229	ctx.RegisterModuleType("test", mutatorTestModuleFactory)
230
231	bp := `
232		test {
233			name: "common_dep_1",
234		}
235		test {
236			name: "common_dep_2",
237		}
238		test {
239			name: "foo",
240		}
241	`
242
243	config := TestConfig(buildDir, nil, bp, nil)
244	ctx.Register(config)
245
246	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
247	FailIfErrored(t, errs)
248	_, errs = ctx.PrepareBuildActions(config)
249	FailIfErrored(t, errs)
250
251	finalWant := map[string]int{
252		"common_dep_1{variant:a}":                   1,
253		"common_dep_1{variant:b}":                   1,
254		"common_dep_2{variant:a}":                   1,
255		"common_dep_2{variant:b}":                   1,
256		"foo{variant:a}":                            1,
257		"foo{variant:a} -> common_dep_1{variant:a}": 1,
258		"foo{variant:a} -> common_dep_2{variant:a}": 1,
259		"foo{variant:b}":                            1,
260		"foo{variant:b} -> common_dep_1{variant:b}": 1,
261		"foo{variant:b} -> common_dep_2{variant:a}": 1,
262	}
263
264	if !reflect.DeepEqual(finalWant, finalGot) {
265		t.Errorf("want:\n%q\ngot:\n%q", finalWant, finalGot)
266	}
267}
268
269func TestNoCreateVariationsInFinalDeps(t *testing.T) {
270	ctx := NewTestContext()
271
272	checkErr := func() {
273		if err := recover(); err == nil || !strings.Contains(fmt.Sprintf("%s", err), "not allowed in FinalDepsMutators") {
274			panic("Expected FinalDepsMutators consistency check to fail")
275		}
276	}
277
278	ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
279		ctx.BottomUp("vars", func(ctx BottomUpMutatorContext) {
280			defer checkErr()
281			ctx.CreateVariations("a", "b")
282		})
283		ctx.BottomUp("local_vars", func(ctx BottomUpMutatorContext) {
284			defer checkErr()
285			ctx.CreateLocalVariations("a", "b")
286		})
287	})
288
289	ctx.RegisterModuleType("test", mutatorTestModuleFactory)
290	config := TestConfig(buildDir, nil, `test {name: "foo"}`, nil)
291	ctx.Register(config)
292
293	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
294	FailIfErrored(t, errs)
295	_, errs = ctx.PrepareBuildActions(config)
296	FailIfErrored(t, errs)
297}
298