1// Copyright 2016 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	"testing"
20
21	"github.com/google/blueprint"
22)
23
24var prebuiltsTests = []struct {
25	name      string
26	replaceBp bool // modules is added to default bp boilerplate if false.
27	modules   string
28	prebuilt  []OsType
29}{
30	{
31		name: "no prebuilt",
32		modules: `
33			source {
34				name: "bar",
35			}`,
36		prebuilt: nil,
37	},
38	{
39		name: "no source prebuilt not preferred",
40		modules: `
41			prebuilt {
42				name: "bar",
43				prefer: false,
44				srcs: ["prebuilt_file"],
45			}`,
46		prebuilt: []OsType{Android, BuildOs},
47	},
48	{
49		name: "no source prebuilt preferred",
50		modules: `
51			prebuilt {
52				name: "bar",
53				prefer: true,
54				srcs: ["prebuilt_file"],
55			}`,
56		prebuilt: []OsType{Android, BuildOs},
57	},
58	{
59		name: "prebuilt not preferred",
60		modules: `
61			source {
62				name: "bar",
63			}
64
65			prebuilt {
66				name: "bar",
67				prefer: false,
68				srcs: ["prebuilt_file"],
69			}`,
70		prebuilt: nil,
71	},
72	{
73		name: "prebuilt preferred",
74		modules: `
75			source {
76				name: "bar",
77			}
78
79			prebuilt {
80				name: "bar",
81				prefer: true,
82				srcs: ["prebuilt_file"],
83			}`,
84		prebuilt: []OsType{Android, BuildOs},
85	},
86	{
87		name: "prebuilt no file not preferred",
88		modules: `
89			source {
90				name: "bar",
91			}
92
93			prebuilt {
94				name: "bar",
95				prefer: false,
96			}`,
97		prebuilt: nil,
98	},
99	{
100		name: "prebuilt no file preferred",
101		modules: `
102			source {
103				name: "bar",
104			}
105
106			prebuilt {
107				name: "bar",
108				prefer: true,
109			}`,
110		prebuilt: nil,
111	},
112	{
113		name: "prebuilt file from filegroup preferred",
114		modules: `
115			filegroup {
116				name: "fg",
117				srcs: ["prebuilt_file"],
118			}
119			prebuilt {
120				name: "bar",
121				prefer: true,
122				srcs: [":fg"],
123			}`,
124		prebuilt: []OsType{Android, BuildOs},
125	},
126	{
127		name: "prebuilt module for device only",
128		modules: `
129			source {
130				name: "bar",
131			}
132
133			prebuilt {
134				name: "bar",
135				host_supported: false,
136				prefer: true,
137				srcs: ["prebuilt_file"],
138			}`,
139		prebuilt: []OsType{Android},
140	},
141	{
142		name: "prebuilt file for host only",
143		modules: `
144			source {
145				name: "bar",
146			}
147
148			prebuilt {
149				name: "bar",
150				prefer: true,
151				target: {
152					host: {
153						srcs: ["prebuilt_file"],
154					},
155				},
156			}`,
157		prebuilt: []OsType{BuildOs},
158	},
159	{
160		name: "prebuilt override not preferred",
161		modules: `
162			source {
163				name: "baz",
164			}
165
166			override_source {
167				name: "bar",
168				base: "baz",
169			}
170
171			prebuilt {
172				name: "bar",
173				prefer: false,
174				srcs: ["prebuilt_file"],
175			}`,
176		prebuilt: nil,
177	},
178	{
179		name: "prebuilt override preferred",
180		modules: `
181			source {
182				name: "baz",
183			}
184
185			override_source {
186				name: "bar",
187				base: "baz",
188			}
189
190			prebuilt {
191				name: "bar",
192				prefer: true,
193				srcs: ["prebuilt_file"],
194			}`,
195		prebuilt: []OsType{Android, BuildOs},
196	},
197	{
198		name:      "prebuilt including default-disabled OS",
199		replaceBp: true,
200		modules: `
201			source {
202				name: "foo",
203				deps: [":bar"],
204				target: {
205					windows: {
206						enabled: true,
207					},
208				},
209			}
210
211			source {
212				name: "bar",
213				target: {
214					windows: {
215						enabled: true,
216					},
217				},
218			}
219
220			prebuilt {
221				name: "bar",
222				prefer: true,
223				srcs: ["prebuilt_file"],
224				target: {
225					windows: {
226						enabled: true,
227					},
228				},
229			}`,
230		prebuilt: []OsType{Android, BuildOs, Windows},
231	},
232	{
233		name:      "fall back to source for default-disabled OS",
234		replaceBp: true,
235		modules: `
236			source {
237				name: "foo",
238				deps: [":bar"],
239				target: {
240					windows: {
241						enabled: true,
242					},
243				},
244			}
245
246			source {
247				name: "bar",
248				target: {
249					windows: {
250						enabled: true,
251					},
252				},
253			}
254
255			prebuilt {
256				name: "bar",
257				prefer: true,
258				srcs: ["prebuilt_file"],
259			}`,
260		prebuilt: []OsType{Android, BuildOs},
261	},
262}
263
264func TestPrebuilts(t *testing.T) {
265	fs := map[string][]byte{
266		"prebuilt_file": nil,
267		"source_file":   nil,
268	}
269
270	for _, test := range prebuiltsTests {
271		t.Run(test.name, func(t *testing.T) {
272			bp := test.modules
273			if !test.replaceBp {
274				bp = bp + `
275					source {
276						name: "foo",
277						deps: [":bar"],
278					}`
279			}
280			config := TestArchConfig(buildDir, nil, bp, fs)
281
282			// Add windows to the target list to test the logic when a variant is
283			// disabled by default.
284			if !Windows.DefaultDisabled {
285				t.Errorf("windows is assumed to be disabled by default")
286			}
287			config.config.Targets[Windows] = []Target{
288				{Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
289			}
290
291			ctx := NewTestArchContext()
292			registerTestPrebuiltBuildComponents(ctx)
293			ctx.RegisterModuleType("filegroup", FileGroupFactory)
294			ctx.Register(config)
295
296			_, errs := ctx.ParseBlueprintsFiles("Android.bp")
297			FailIfErrored(t, errs)
298			_, errs = ctx.PrepareBuildActions(config)
299			FailIfErrored(t, errs)
300
301			for _, variant := range ctx.ModuleVariantsForTests("foo") {
302				foo := ctx.ModuleForTests("foo", variant)
303				t.Run(foo.Module().Target().Os.String(), func(t *testing.T) {
304					var dependsOnSourceModule, dependsOnPrebuiltModule bool
305					ctx.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
306						if _, ok := m.(*sourceModule); ok {
307							dependsOnSourceModule = true
308						}
309						if p, ok := m.(*prebuiltModule); ok {
310							dependsOnPrebuiltModule = true
311							if !p.Prebuilt().properties.UsePrebuilt {
312								t.Errorf("dependency on prebuilt module not marked used")
313							}
314						}
315					})
316
317					moduleIsDisabled := !foo.Module().Enabled()
318					deps := foo.Module().(*sourceModule).deps
319					if moduleIsDisabled {
320						if len(deps) > 0 {
321							t.Errorf("disabled module got deps: %v", deps)
322						}
323					} else {
324						if len(deps) != 1 {
325							t.Errorf("deps does not have single path, but is %v", deps)
326						}
327					}
328
329					var usingSourceFile, usingPrebuiltFile bool
330					if len(deps) > 0 && deps[0].String() == "source_file" {
331						usingSourceFile = true
332					}
333					if len(deps) > 0 && deps[0].String() == "prebuilt_file" {
334						usingPrebuiltFile = true
335					}
336
337					prebuilt := false
338					for _, os := range test.prebuilt {
339						if os == foo.Module().Target().Os {
340							prebuilt = true
341						}
342					}
343
344					if prebuilt {
345						if moduleIsDisabled {
346							t.Errorf("dependent module for prebuilt is disabled")
347						}
348
349						if !dependsOnPrebuiltModule {
350							t.Errorf("doesn't depend on prebuilt module")
351						}
352						if !usingPrebuiltFile {
353							t.Errorf("doesn't use prebuilt_file")
354						}
355
356						if dependsOnSourceModule {
357							t.Errorf("depends on source module")
358						}
359						if usingSourceFile {
360							t.Errorf("using source_file")
361						}
362					} else if !moduleIsDisabled {
363						if dependsOnPrebuiltModule {
364							t.Errorf("depends on prebuilt module")
365						}
366						if usingPrebuiltFile {
367							t.Errorf("using prebuilt_file")
368						}
369
370						if !dependsOnSourceModule {
371							t.Errorf("doesn't depend on source module")
372						}
373						if !usingSourceFile {
374							t.Errorf("doesn't use source_file")
375						}
376					}
377				})
378			}
379		})
380	}
381}
382
383func registerTestPrebuiltBuildComponents(ctx RegistrationContext) {
384	ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
385	ctx.RegisterModuleType("source", newSourceModule)
386	ctx.RegisterModuleType("override_source", newOverrideSourceModule)
387
388	RegisterPrebuiltMutators(ctx)
389	ctx.PostDepsMutators(RegisterOverridePostDepsMutators)
390}
391
392type prebuiltModule struct {
393	ModuleBase
394	prebuilt   Prebuilt
395	properties struct {
396		Srcs []string `android:"path,arch_variant"`
397	}
398	src Path
399}
400
401func newPrebuiltModule() Module {
402	m := &prebuiltModule{}
403	m.AddProperties(&m.properties)
404	InitPrebuiltModule(m, &m.properties.Srcs)
405	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
406	return m
407}
408
409func (p *prebuiltModule) Name() string {
410	return p.prebuilt.Name(p.ModuleBase.Name())
411}
412
413func (p *prebuiltModule) GenerateAndroidBuildActions(ctx ModuleContext) {
414	if len(p.properties.Srcs) >= 1 {
415		p.src = p.prebuilt.SingleSourcePath(ctx)
416	}
417}
418
419func (p *prebuiltModule) Prebuilt() *Prebuilt {
420	return &p.prebuilt
421}
422
423func (p *prebuiltModule) OutputFiles(tag string) (Paths, error) {
424	switch tag {
425	case "":
426		return Paths{p.src}, nil
427	default:
428		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
429	}
430}
431
432type sourceModuleProperties struct {
433	Deps []string `android:"path,arch_variant"`
434}
435
436type sourceModule struct {
437	ModuleBase
438	OverridableModuleBase
439
440	properties                                     sourceModuleProperties
441	dependsOnSourceModule, dependsOnPrebuiltModule bool
442	deps                                           Paths
443	src                                            Path
444}
445
446func newSourceModule() Module {
447	m := &sourceModule{}
448	m.AddProperties(&m.properties)
449	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
450	InitOverridableModule(m, nil)
451	return m
452}
453
454func (s *sourceModule) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
455	// s.properties.Deps are annotated with android:path, so they are
456	// automatically added to the dependency by pathDeps mutator
457}
458
459func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
460	s.deps = PathsForModuleSrc(ctx, s.properties.Deps)
461	s.src = PathForModuleSrc(ctx, "source_file")
462}
463
464func (s *sourceModule) Srcs() Paths {
465	return Paths{s.src}
466}
467
468type overrideSourceModule struct {
469	ModuleBase
470	OverrideModuleBase
471}
472
473func (o *overrideSourceModule) GenerateAndroidBuildActions(_ ModuleContext) {
474}
475
476func newOverrideSourceModule() Module {
477	m := &overrideSourceModule{}
478	m.AddProperties(&sourceModuleProperties{})
479
480	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
481	InitOverrideModule(m)
482	return m
483}
484