1// Copyright 2020 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 blueprint
16
17import (
18	"fmt"
19	"reflect"
20	"strings"
21	"testing"
22)
23
24type providerTestModule struct {
25	SimpleName
26	properties struct {
27		Deps []string
28	}
29
30	mutatorProviderValues              []string
31	generateBuildActionsProviderValues []string
32}
33
34func newProviderTestModule() (Module, []interface{}) {
35	m := &providerTestModule{}
36	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
37}
38
39type providerTestMutatorInfo struct {
40	Values []string
41}
42
43type providerTestGenerateBuildActionsInfo struct {
44	Value string
45}
46
47type providerTestUnsetInfo string
48
49var providerTestMutatorInfoProvider = NewMutatorProvider[*providerTestMutatorInfo]("provider_mutator")
50var providerTestGenerateBuildActionsInfoProvider = NewProvider[*providerTestGenerateBuildActionsInfo]()
51var providerTestUnsetInfoProvider = NewMutatorProvider[providerTestUnsetInfo]("provider_mutator")
52var providerTestUnusedMutatorProvider = NewMutatorProvider[*struct{ unused string }]("nonexistent_mutator")
53
54func (p *providerTestModule) GenerateBuildActions(ctx ModuleContext) {
55	unset, ok := ModuleProvider(ctx, providerTestUnsetInfoProvider)
56	if ok {
57		panic(fmt.Errorf("expected false return value for providerTestGenerateBuildActionsInfoProvider before it was set"))
58	}
59	if unset != "" {
60		panic(fmt.Errorf("expected zero value for providerTestGenerateBuildActionsInfoProvider before it was set, got %q",
61			unset))
62	}
63
64	// Verify reading providerTestUnusedMutatorProvider doesn't panic
65	_, _ = ModuleProvider(ctx, providerTestUnusedMutatorProvider)
66
67	SetProvider(ctx, providerTestGenerateBuildActionsInfoProvider, &providerTestGenerateBuildActionsInfo{
68		Value: ctx.ModuleName(),
69	})
70
71	mp, ok := ModuleProvider(ctx, providerTestMutatorInfoProvider)
72	if ok {
73		p.mutatorProviderValues = mp.Values
74	}
75
76	ctx.VisitDirectDeps(func(module Module) {
77		gbap, _ := OtherModuleProvider(ctx, module, providerTestGenerateBuildActionsInfoProvider)
78		if gbap != nil {
79			p.generateBuildActionsProviderValues = append(p.generateBuildActionsProviderValues, gbap.Value)
80		}
81	})
82}
83
84func providerTestDepsMutator(ctx BottomUpMutatorContext) {
85	if p, ok := ctx.Module().(*providerTestModule); ok {
86		ctx.AddDependency(ctx.Module(), nil, p.properties.Deps...)
87	}
88}
89
90func providerTestMutator(ctx BottomUpMutatorContext) {
91	values := []string{strings.ToLower(ctx.ModuleName())}
92
93	ctx.VisitDirectDeps(func(module Module) {
94		mp, _ := OtherModuleProvider(ctx, module, providerTestMutatorInfoProvider)
95		if mp != nil {
96			values = append(values, mp.Values...)
97		}
98	})
99
100	SetProvider(ctx, providerTestMutatorInfoProvider, &providerTestMutatorInfo{
101		Values: values,
102	})
103}
104
105func providerTestAfterMutator(ctx BottomUpMutatorContext) {
106	// Verify reading providerTestUnusedMutatorProvider doesn't panic
107	_, _ = ModuleProvider(ctx, providerTestMutatorInfoProvider)
108}
109
110func TestProviders(t *testing.T) {
111	ctx := NewContext()
112	ctx.RegisterModuleType("provider_module", newProviderTestModule)
113	ctx.RegisterBottomUpMutator("provider_deps_mutator", providerTestDepsMutator)
114	ctx.RegisterBottomUpMutator("provider_mutator", providerTestMutator)
115	ctx.RegisterBottomUpMutator("provider_after_mutator", providerTestAfterMutator)
116
117	ctx.MockFileSystem(map[string][]byte{
118		"Android.bp": []byte(`
119			provider_module {
120				name: "A",
121				deps: ["B"],
122			}
123
124			provider_module {
125				name: "B",
126				deps: ["C", "D"],
127			}
128
129			provider_module {
130				name: "C",
131				deps: ["D"],
132			}
133
134			provider_module {
135				name: "D",
136			}
137		`),
138	})
139
140	_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
141	if len(errs) == 0 {
142		_, errs = ctx.ResolveDependencies(nil)
143	}
144	if len(errs) == 0 {
145		_, errs = ctx.PrepareBuildActions(nil)
146	}
147	if len(errs) > 0 {
148		t.Errorf("unexpected errors:")
149		for _, err := range errs {
150			t.Errorf("  %s", err)
151		}
152		t.FailNow()
153	}
154
155	aModule := ctx.moduleGroupFromName("A", nil).moduleByVariantName("").logicModule.(*providerTestModule)
156	if g, w := aModule.generateBuildActionsProviderValues, []string{"B"}; !reflect.DeepEqual(g, w) {
157		t.Errorf("expected A.generateBuildActionsProviderValues %q, got %q", w, g)
158	}
159	if g, w := aModule.mutatorProviderValues, []string{"a", "b", "c", "d", "d"}; !reflect.DeepEqual(g, w) {
160		t.Errorf("expected A.mutatorProviderValues %q, got %q", w, g)
161	}
162
163	bModule := ctx.moduleGroupFromName("B", nil).moduleByVariantName("").logicModule.(*providerTestModule)
164	if g, w := bModule.generateBuildActionsProviderValues, []string{"C", "D"}; !reflect.DeepEqual(g, w) {
165		t.Errorf("expected B.generateBuildActionsProviderValues %q, got %q", w, g)
166	}
167	if g, w := bModule.mutatorProviderValues, []string{"b", "c", "d", "d"}; !reflect.DeepEqual(g, w) {
168		t.Errorf("expected B.mutatorProviderValues %q, got %q", w, g)
169	}
170}
171
172type invalidProviderUsageMutatorInfo string
173type invalidProviderUsageGenerateBuildActionsInfo string
174
175var invalidProviderUsageMutatorInfoProvider = NewMutatorProvider[invalidProviderUsageMutatorInfo]("mutator_under_test")
176var invalidProviderUsageGenerateBuildActionsInfoProvider = NewProvider[invalidProviderUsageGenerateBuildActionsInfo]()
177
178type invalidProviderUsageTestModule struct {
179	parent *invalidProviderUsageTestModule
180
181	SimpleName
182	properties struct {
183		Deps []string
184
185		Early_mutator_set_of_mutator_provider       bool
186		Late_mutator_set_of_mutator_provider        bool
187		Late_build_actions_set_of_mutator_provider  bool
188		Early_mutator_set_of_build_actions_provider bool
189
190		Early_mutator_get_of_mutator_provider       bool
191		Early_module_get_of_mutator_provider        bool
192		Early_mutator_get_of_build_actions_provider bool
193		Early_module_get_of_build_actions_provider  bool
194
195		Duplicate_set bool
196	}
197}
198
199func invalidProviderUsageDepsMutator(ctx BottomUpMutatorContext) {
200	if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
201		ctx.AddDependency(ctx.Module(), nil, i.properties.Deps...)
202	}
203}
204
205func invalidProviderUsageParentMutator(ctx TopDownMutatorContext) {
206	if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
207		ctx.VisitDirectDeps(func(module Module) {
208			module.(*invalidProviderUsageTestModule).parent = i
209		})
210	}
211}
212
213func invalidProviderUsageBeforeMutator(ctx BottomUpMutatorContext) {
214	if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
215		if i.properties.Early_mutator_set_of_mutator_provider {
216			// A mutator attempting to set the value of a provider associated with a later mutator.
217			SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
218		}
219		if i.properties.Early_mutator_get_of_mutator_provider {
220			// A mutator attempting to get the value of a provider associated with a later mutator.
221			_, _ = ModuleProvider(ctx, invalidProviderUsageMutatorInfoProvider)
222		}
223	}
224}
225
226func invalidProviderUsageMutatorUnderTest(ctx TopDownMutatorContext) {
227	if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
228		if i.properties.Early_mutator_set_of_build_actions_provider {
229			// A mutator attempting to set the value of a non-mutator provider.
230			SetProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo(""))
231		}
232		if i.properties.Early_mutator_get_of_build_actions_provider {
233			// A mutator attempting to get the value of a non-mutator provider.
234			_, _ = ModuleProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider)
235		}
236		if i.properties.Early_module_get_of_mutator_provider {
237			// A mutator attempting to get the value of a provider associated with this mutator on
238			// a module for which this mutator hasn't run.  This is a top down mutator so
239			// dependencies haven't run yet.
240			ctx.VisitDirectDeps(func(module Module) {
241				_, _ = OtherModuleProvider(ctx, module, invalidProviderUsageMutatorInfoProvider)
242			})
243		}
244	}
245}
246
247func invalidProviderUsageAfterMutator(ctx BottomUpMutatorContext) {
248	if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
249		if i.properties.Late_mutator_set_of_mutator_provider {
250			// A mutator trying to set the value of a provider associated with an earlier mutator.
251			SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
252		}
253		if i.properties.Late_mutator_set_of_mutator_provider {
254			// A mutator trying to set the value of a provider associated with an earlier mutator.
255			SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
256		}
257	}
258}
259
260func (i *invalidProviderUsageTestModule) GenerateBuildActions(ctx ModuleContext) {
261	if i.properties.Late_build_actions_set_of_mutator_provider {
262		// A GenerateBuildActions trying to set the value of a provider associated with a mutator.
263		SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
264	}
265	if i.properties.Early_module_get_of_build_actions_provider {
266		// A GenerateBuildActions trying to get the value of a provider on a module for which
267		// GenerateBuildActions hasn't run.
268		_, _ = OtherModuleProvider(ctx, i.parent, invalidProviderUsageGenerateBuildActionsInfoProvider)
269	}
270	if i.properties.Duplicate_set {
271		SetProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo(""))
272		SetProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo(""))
273	}
274}
275
276func TestInvalidProvidersUsage(t *testing.T) {
277	run := func(t *testing.T, module string, prop string, panicMsg string) {
278		t.Helper()
279		ctx := NewContext()
280		ctx.RegisterModuleType("invalid_provider_usage_test_module", func() (Module, []interface{}) {
281			m := &invalidProviderUsageTestModule{}
282			return m, []interface{}{&m.properties, &m.SimpleName.Properties}
283		})
284		ctx.RegisterBottomUpMutator("deps", invalidProviderUsageDepsMutator)
285		ctx.RegisterBottomUpMutator("before", invalidProviderUsageBeforeMutator)
286		ctx.RegisterTopDownMutator("mutator_under_test", invalidProviderUsageMutatorUnderTest)
287		ctx.RegisterBottomUpMutator("after", invalidProviderUsageAfterMutator)
288		ctx.RegisterTopDownMutator("parent", invalidProviderUsageParentMutator)
289
290		// Don't invalidate the parent pointer and before GenerateBuildActions.
291		ctx.SkipCloneModulesAfterMutators = true
292
293		var parentBP, moduleUnderTestBP, childBP string
294
295		prop += ": true,"
296
297		switch module {
298		case "parent":
299			parentBP = prop
300		case "module_under_test":
301			moduleUnderTestBP = prop
302		case "child":
303			childBP = prop
304		}
305
306		bp := fmt.Sprintf(`
307			invalid_provider_usage_test_module {
308				name: "parent",
309				deps: ["module_under_test"],
310				%s
311			}
312
313			invalid_provider_usage_test_module {
314				name: "module_under_test",
315				deps: ["child"],
316				%s
317			}
318
319			invalid_provider_usage_test_module {
320				name: "child",
321				%s
322			}
323
324		`,
325			parentBP,
326			moduleUnderTestBP,
327			childBP)
328
329		ctx.MockFileSystem(map[string][]byte{
330			"Android.bp": []byte(bp),
331		})
332
333		_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
334
335		if len(errs) == 0 {
336			_, errs = ctx.ResolveDependencies(nil)
337		}
338
339		if len(errs) == 0 {
340			_, errs = ctx.PrepareBuildActions(nil)
341		}
342
343		if len(errs) == 0 {
344			t.Fatal("expected an error")
345		}
346
347		if len(errs) > 1 {
348			t.Errorf("expected a single error, got %d:", len(errs))
349			for i, err := range errs {
350				t.Errorf("%d:  %s", i, err)
351			}
352			t.FailNow()
353		}
354
355		if panicErr, ok := errs[0].(panicError); ok {
356			if panicErr.panic != panicMsg {
357				t.Fatalf("expected panic %q, got %q", panicMsg, panicErr.panic)
358			}
359		} else {
360			t.Fatalf("expected a panicError, got %T: %s", errs[0], errs[0].Error())
361		}
362
363	}
364
365	tests := []struct {
366		prop   string
367		module string
368
369		panicMsg string
370		skip     string
371	}{
372		{
373			prop:     "early_mutator_set_of_mutator_provider",
374			module:   "module_under_test",
375			panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test started",
376		},
377		{
378			prop:     "late_mutator_set_of_mutator_provider",
379			module:   "module_under_test",
380			panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo after mutator mutator_under_test finished",
381		},
382		{
383			prop:     "late_build_actions_set_of_mutator_provider",
384			module:   "module_under_test",
385			panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo after mutator mutator_under_test finished",
386		},
387		{
388			prop:     "early_mutator_set_of_build_actions_provider",
389			module:   "module_under_test",
390			panicMsg: "Can't set value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions started",
391		},
392
393		{
394			prop:     "early_mutator_get_of_mutator_provider",
395			module:   "module_under_test",
396			panicMsg: "Can't get value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test finished",
397		},
398		{
399			prop:     "early_module_get_of_mutator_provider",
400			module:   "module_under_test",
401			panicMsg: "Can't get value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test finished",
402		},
403		{
404			prop:     "early_mutator_get_of_build_actions_provider",
405			module:   "module_under_test",
406			panicMsg: "Can't get value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions finished",
407		},
408		{
409			prop:     "early_module_get_of_build_actions_provider",
410			module:   "module_under_test",
411			panicMsg: "Can't get value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions finished",
412		},
413		{
414			prop:     "duplicate_set",
415			module:   "module_under_test",
416			panicMsg: "Value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo is already set",
417		},
418	}
419
420	for _, tt := range tests {
421		t.Run(tt.prop, func(t *testing.T) {
422			run(t, tt.module, tt.prop, tt.panicMsg)
423		})
424	}
425}
426