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	ctx := NewTestContext()
161	// A module type that has a srcs property but not a cflags property.
162	ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(&struct {
163		Srcs []string
164	}{}))
165	// A module type that has a cflags property but not a srcs property.
166	ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(&struct {
167		Cflags []string
168	}{}))
169	// A module type that does not have any properties that match product_variables.
170	ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct {
171		Foo []string
172	}{}))
173	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
174		ctx.BottomUp("variable", VariableMutator).Parallel()
175	})
176
177	// Test that a module can use one product variable even if it doesn't have all the properties
178	// supported by that product variable.
179	bp := `
180		module1 {
181			name: "foo",
182			product_variables: {
183				eng: {
184					srcs: ["foo.c"],
185				},
186			},
187		}
188		module2 {
189			name: "bar",
190			product_variables: {
191				eng: {
192					cflags: ["-DBAR"],
193				},
194			},
195		}
196
197		module3 {
198			name: "baz",
199		}
200	`
201	config := TestConfig(buildDir, nil, bp, nil)
202	config.TestProductVariables.Eng = proptools.BoolPtr(true)
203
204	ctx.Register(config)
205
206	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
207	FailIfErrored(t, errs)
208	_, errs = ctx.PrepareBuildActions(config)
209	FailIfErrored(t, errs)
210}
211
212var testProductVariableDefaultsProperties = struct {
213	Product_variables struct {
214		Eng struct {
215			Foo []string
216			Bar []string
217		}
218	}
219}{}
220
221type productVariablesDefaultsTestProperties struct {
222	Foo []string
223}
224
225type productVariablesDefaultsTestProperties2 struct {
226	Foo []string
227	Bar []string
228}
229
230type productVariablesDefaultsTestModule struct {
231	ModuleBase
232	DefaultableModuleBase
233	properties productVariablesDefaultsTestProperties
234}
235
236func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
237	ctx.Build(pctx, BuildParams{
238		Rule:   Touch,
239		Output: PathForModuleOut(ctx, "out"),
240	})
241}
242
243func productVariablesDefaultsTestModuleFactory() Module {
244	module := &productVariablesDefaultsTestModule{}
245	module.AddProperties(&module.properties)
246	module.variableProperties = testProductVariableDefaultsProperties
247	InitAndroidModule(module)
248	InitDefaultableModule(module)
249	return module
250}
251
252type productVariablesDefaultsTestDefaults struct {
253	ModuleBase
254	DefaultsModuleBase
255}
256
257func productVariablesDefaultsTestDefaultsFactory() Module {
258	defaults := &productVariablesDefaultsTestDefaults{}
259	defaults.AddProperties(&productVariablesDefaultsTestProperties{})
260	defaults.AddProperties(&productVariablesDefaultsTestProperties2{})
261	defaults.variableProperties = testProductVariableDefaultsProperties
262	InitDefaultsModule(defaults)
263	return defaults
264}
265
266// Test a defaults module that supports more product variable properties than the target module.
267func TestProductVariablesDefaults(t *testing.T) {
268	bp := `
269		defaults {
270			name: "defaults",
271			product_variables: {
272				eng: {
273					foo: ["product_variable_defaults"],
274					bar: ["product_variable_defaults"],
275				},
276			},
277			foo: ["defaults"],
278			bar: ["defaults"],
279		}
280
281		test {
282			name: "foo",
283			defaults: ["defaults"],
284			foo: ["module"],
285			product_variables: {
286				eng: {
287					foo: ["product_variable_module"],
288				},
289			},
290		}
291	`
292
293	config := TestConfig(buildDir, nil, bp, nil)
294	config.TestProductVariables.Eng = boolPtr(true)
295
296	ctx := NewTestContext()
297
298	ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
299	ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory)
300
301	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
302	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
303		ctx.BottomUp("variable", VariableMutator).Parallel()
304	})
305
306	ctx.Register(config)
307
308	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
309	FailIfErrored(t, errs)
310	_, errs = ctx.PrepareBuildActions(config)
311	FailIfErrored(t, errs)
312
313	foo := ctx.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule)
314
315	want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"}
316	if g, w := foo.properties.Foo, want; !reflect.DeepEqual(g, w) {
317		t.Errorf("expected foo %q, got %q", w, g)
318	}
319}
320
321func BenchmarkSliceToTypeArray(b *testing.B) {
322	for _, n := range []int{1, 2, 4, 8, 100} {
323		var propStructs []interface{}
324		for i := 0; i < n; i++ {
325			propStructs = append(propStructs, &struct {
326				A *string
327				B string
328			}{})
329
330		}
331		b.Run(strconv.Itoa(n), func(b *testing.B) {
332			for i := 0; i < b.N; i++ {
333				_ = sliceToTypeArray(propStructs)
334			}
335		})
336	}
337}
338