xref: /aosp_15_r20/build/soong/android/variable_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"reflect"
19	"strconv"
20	"testing"
21
22	"github.com/google/blueprint/proptools"
23)
24
25type printfIntoPropertyTestCase struct {
26	in  string
27	val interface{}
28	out string
29	err bool
30}
31
32var printfIntoPropertyTestCases = []printfIntoPropertyTestCase{
33	{
34		in:  "%d",
35		val: 0,
36		out: "0",
37	},
38	{
39		in:  "%d",
40		val: 1,
41		out: "1",
42	},
43	{
44		in:  "%d",
45		val: 2,
46		out: "2",
47	},
48	{
49		in:  "%d",
50		val: false,
51		out: "0",
52	},
53	{
54		in:  "%d",
55		val: true,
56		out: "1",
57	},
58	{
59		in:  "%d",
60		val: -1,
61		out: "-1",
62	},
63
64	{
65		in:  "-DA=%d",
66		val: 1,
67		out: "-DA=1",
68	},
69	{
70		in:  "-DA=%du",
71		val: 1,
72		out: "-DA=1u",
73	},
74	{
75		in:  "-DA=%s",
76		val: "abc",
77		out: "-DA=abc",
78	},
79	{
80		in:  `-DA="%s"`,
81		val: "abc",
82		out: `-DA="abc"`,
83	},
84
85	{
86		in:  "%%",
87		err: true,
88	},
89	{
90		in:  "%d%s",
91		err: true,
92	},
93	{
94		in:  "%d,%s",
95		err: true,
96	},
97	{
98		in:  "%d",
99		val: "",
100		err: true,
101	},
102	{
103		in:  "%d",
104		val: 1.5,
105		err: true,
106	},
107	{
108		in:  "%f",
109		val: 1.5,
110		err: true,
111	},
112}
113
114func TestPrintfIntoProperty(t *testing.T) {
115	for _, testCase := range printfIntoPropertyTestCases {
116		s := testCase.in
117		v := reflect.ValueOf(&s).Elem()
118		err := printfIntoProperty(v, testCase.val)
119		if err != nil && !testCase.err {
120			t.Errorf("unexpected error %s", err)
121		} else if err == nil && testCase.err {
122			t.Errorf("expected error")
123		} else if err == nil && v.String() != testCase.out {
124			t.Errorf("expected %q got %q", testCase.out, v.String())
125		}
126	}
127}
128
129type testProductVariableModule struct {
130	ModuleBase
131}
132
133func (m *testProductVariableModule) GenerateAndroidBuildActions(ctx ModuleContext) {
134}
135
136var testProductVariableProperties = struct {
137	Product_variables struct {
138		Eng struct {
139			Srcs   []string
140			Cflags []string
141		}
142	}
143}{}
144
145func testProductVariableModuleFactoryFactory(props interface{}) func() Module {
146	return func() Module {
147		m := &testProductVariableModule{}
148		clonedProps := proptools.CloneProperties(reflect.ValueOf(props)).Interface()
149		m.AddProperties(clonedProps)
150
151		// Set a default soongConfigVariableProperties, this will be used as the input to the property struct filter
152		// for this test module.
153		m.variableProperties = testProductVariableProperties
154		InitAndroidModule(m)
155		return m
156	}
157}
158
159func TestProductVariables(t *testing.T) {
160	// Test that a module can use one product variable even if it doesn't have all the properties
161	// supported by that product variable.
162	bp := `
163		module1 {
164			name: "foo",
165			product_variables: {
166				eng: {
167					srcs: ["foo.c"],
168				},
169			},
170		}
171		module2 {
172			name: "bar",
173			product_variables: {
174				eng: {
175					cflags: ["-DBAR"],
176				},
177			},
178		}
179
180		module3 {
181			name: "baz",
182		}
183	`
184
185	GroupFixturePreparers(
186		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
187			variables.Eng = proptools.BoolPtr(true)
188		}),
189		FixtureRegisterWithContext(func(ctx RegistrationContext) {
190			// A module type that has a srcs property but not a cflags property.
191			ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(&struct {
192				Srcs []string
193			}{}))
194			// A module type that has a cflags property but not a srcs property.
195			ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(&struct {
196				Cflags []string
197			}{}))
198			// A module type that does not have any properties that match product_variables.
199			ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct {
200				Foo []string
201			}{}))
202			registerVariableBuildComponents(ctx)
203		}),
204		FixtureWithRootAndroidBp(bp),
205	).RunTest(t)
206}
207
208var testProductVariableDefaultsProperties = struct {
209	Product_variables struct {
210		Eng struct {
211			Foo []string `android:"arch_variant"`
212			Bar []string
213		} `android:"arch_variant"`
214	} `android:"arch_variant"`
215}{}
216
217type productVariablesDefaultsTestProperties struct {
218	Foo []string `android:"arch_variant"`
219}
220
221type productVariablesDefaultsTestProperties2 struct {
222	Foo []string
223	Bar []string
224}
225
226type productVariablesDefaultsTestModule struct {
227	ModuleBase
228	DefaultableModuleBase
229	properties productVariablesDefaultsTestProperties
230}
231
232func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
233	ctx.Build(pctx, BuildParams{
234		Rule:   Touch,
235		Output: PathForModuleOut(ctx, "out"),
236	})
237}
238
239func productVariablesDefaultsTestModuleFactory() Module {
240	module := &productVariablesDefaultsTestModule{}
241	module.AddProperties(&module.properties)
242	module.variableProperties = testProductVariableDefaultsProperties
243	InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
244	InitDefaultableModule(module)
245	return module
246}
247
248type productVariablesDefaultsTestDefaults struct {
249	ModuleBase
250	DefaultsModuleBase
251}
252
253func productVariablesDefaultsTestDefaultsFactory() Module {
254	defaults := &productVariablesDefaultsTestDefaults{}
255	defaults.AddProperties(&productVariablesDefaultsTestProperties{})
256	defaults.AddProperties(&productVariablesDefaultsTestProperties2{})
257	defaults.variableProperties = testProductVariableDefaultsProperties
258	InitDefaultsModule(defaults)
259	return defaults
260}
261
262// Test a defaults module that supports more product variable properties than the target module.
263func TestProductVariablesDefaults(t *testing.T) {
264	bp := `
265		defaults {
266			name: "defaults",
267			product_variables: {
268				eng: {
269					foo: ["product_variable_defaults"],
270					bar: ["product_variable_defaults"],
271				},
272			},
273			foo: ["defaults"],
274			bar: ["defaults"],
275		}
276
277		test {
278			name: "foo",
279			defaults: ["defaults"],
280			foo: ["module"],
281			product_variables: {
282				eng: {
283					foo: ["product_variable_module"],
284				},
285			},
286		}
287	`
288
289	result := GroupFixturePreparers(
290		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
291			variables.Eng = boolPtr(true)
292		}),
293		PrepareForTestWithDefaults,
294		PrepareForTestWithVariables,
295		FixtureRegisterWithContext(func(ctx RegistrationContext) {
296			ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
297			ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory)
298		}),
299		FixtureWithRootAndroidBp(bp),
300	).RunTest(t)
301
302	foo := result.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule)
303
304	want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"}
305	AssertDeepEquals(t, "foo", want, foo.properties.Foo)
306}
307
308func BenchmarkSliceToTypeArray(b *testing.B) {
309	for _, n := range []int{1, 2, 4, 8, 100} {
310		var propStructs []interface{}
311		for i := 0; i < n; i++ {
312			propStructs = append(propStructs, &struct {
313				A *string
314				B string
315			}{})
316
317		}
318		b.Run(strconv.Itoa(n), func(b *testing.B) {
319			for i := 0; i < b.N; i++ {
320				_ = sliceToTypeArray(propStructs)
321			}
322		})
323	}
324}
325
326// Test a defaults module that supports more product variable properties than the target module.
327func TestProductVariablesArch(t *testing.T) {
328	bp := `
329		test {
330			name: "foo",
331			arch: {
332				arm: {
333					product_variables: {
334						eng: {
335							foo: ["arm"],
336						},
337					},
338				},
339				arm64: {
340					product_variables: {
341						eng: {
342							foo: ["arm64"],
343						},
344					},
345				},
346			},
347			foo: ["module"],
348		}
349	`
350
351	result := GroupFixturePreparers(
352		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
353			variables.Eng = boolPtr(true)
354		}),
355		PrepareForTestWithArchMutator,
356		PrepareForTestWithVariables,
357		FixtureRegisterWithContext(func(ctx RegistrationContext) {
358			ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
359		}),
360		FixtureWithRootAndroidBp(bp),
361	).RunTest(t)
362
363	foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*productVariablesDefaultsTestModule)
364
365	want := []string{"module", "arm64"}
366	AssertDeepEquals(t, "foo", want, foo.properties.Foo)
367}
368