blob: f57fb4218e1146b8a24b47cd485d2c6fecc766dc [file] [log] [blame]
Cole Faust5a231bd2024-02-07 09:43:59 -08001// Copyright 2024 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 "testing"
21
22 "github.com/google/blueprint"
23 "github.com/google/blueprint/proptools"
24)
25
26func TestSelects(t *testing.T) {
27 testCases := []struct {
28 name string
29 bp string
30 provider selectsTestProvider
31 vendorVars map[string]map[string]string
32 expectedError string
33 }{
34 {
35 name: "basic string list",
36 bp: `
37 my_module_type {
38 name: "foo",
39 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
40 "a": ["a.cpp"],
41 "b": ["b.cpp"],
42 _: ["c.cpp"],
43 }),
44 }
45 `,
46 provider: selectsTestProvider{
47 my_string_list: &[]string{"c.cpp"},
48 },
49 },
50 {
51 name: "basic string",
52 bp: `
53 my_module_type {
54 name: "foo",
55 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
56 "a": "a.cpp",
57 "b": "b.cpp",
58 _: "c.cpp",
59 }),
60 }
61 `,
62 provider: selectsTestProvider{
63 my_string: proptools.StringPtr("c.cpp"),
64 },
65 },
66 {
67 name: "basic bool",
68 bp: `
69 my_module_type {
70 name: "foo",
71 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
72 "a": true,
73 "b": false,
74 _: true,
75 }),
76 }
77 `,
78 provider: selectsTestProvider{
79 my_bool: proptools.BoolPtr(true),
80 },
81 },
82 {
Cole Faustbdd8aee2024-03-14 14:33:02 -070083 name: "basic paths",
84 bp: `
85 my_module_type {
86 name: "foo",
87 my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
88 "a": ["foo.txt"],
89 "b": ["bar.txt"],
90 _: ["baz.txt"],
91 }),
92 }
93 `,
94 provider: selectsTestProvider{
95 my_paths: &[]string{"baz.txt"},
96 },
97 },
98 {
99 name: "paths with module references",
100 bp: `
101 my_module_type {
102 name: "foo",
103 my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
104 "a": [":a"],
105 "b": [":b"],
106 _: [":c"],
107 }),
108 }
109 `,
110 expectedError: `"foo" depends on undefined module "c"`,
111 },
112 {
Cole Faust5a231bd2024-02-07 09:43:59 -0800113 name: "Differing types",
114 bp: `
115 my_module_type {
116 name: "foo",
117 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
118 "a": "a.cpp",
119 "b": true,
120 _: "c.cpp",
121 }),
122 }
123 `,
Cole Faust12c8ed42024-03-28 16:26:59 -0700124 expectedError: `Android.bp:8:5: Found select statement with differing types "string" and "bool" in its cases`,
125 },
126 {
127 name: "Select type doesn't match property type",
128 bp: `
129 my_module_type {
130 name: "foo",
131 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
132 "a": false,
133 "b": true,
134 _: true,
135 }),
136 }
137 `,
138 expectedError: `can't assign bool value to string property "my_string\[0\]"`,
Cole Faust5a231bd2024-02-07 09:43:59 -0800139 },
140 {
141 name: "String list non-default",
142 bp: `
143 my_module_type {
144 name: "foo",
145 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
146 "a": ["a.cpp"],
147 "b": ["b.cpp"],
148 _: ["c.cpp"],
149 }),
150 }
151 `,
152 provider: selectsTestProvider{
153 my_string_list: &[]string{"a.cpp"},
154 },
155 vendorVars: map[string]map[string]string{
156 "my_namespace": {
157 "my_variable": "a",
158 },
159 },
160 },
161 {
162 name: "String list append",
163 bp: `
164 my_module_type {
165 name: "foo",
166 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
167 "a": ["a.cpp"],
168 "b": ["b.cpp"],
169 _: ["c.cpp"],
170 }) + select(soong_config_variable("my_namespace", "my_variable_2"), {
171 "a2": ["a2.cpp"],
172 "b2": ["b2.cpp"],
173 _: ["c2.cpp"],
174 }),
175 }
176 `,
177 provider: selectsTestProvider{
178 my_string_list: &[]string{"a.cpp", "c2.cpp"},
179 },
180 vendorVars: map[string]map[string]string{
181 "my_namespace": {
182 "my_variable": "a",
183 },
184 },
185 },
186 {
187 name: "String list prepend literal",
188 bp: `
189 my_module_type {
190 name: "foo",
191 my_string_list: ["literal.cpp"] + select(soong_config_variable("my_namespace", "my_variable"), {
192 "a2": ["a2.cpp"],
193 "b2": ["b2.cpp"],
194 _: ["c2.cpp"],
195 }),
196 }
197 `,
198 provider: selectsTestProvider{
199 my_string_list: &[]string{"literal.cpp", "c2.cpp"},
200 },
201 },
202 {
203 name: "String list append literal",
204 bp: `
205 my_module_type {
206 name: "foo",
207 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
208 "a2": ["a2.cpp"],
209 "b2": ["b2.cpp"],
210 _: ["c2.cpp"],
211 }) + ["literal.cpp"],
212 }
213 `,
214 provider: selectsTestProvider{
215 my_string_list: &[]string{"c2.cpp", "literal.cpp"},
216 },
217 },
218 {
Cole Faust74ef4652024-03-27 16:45:41 -0700219 name: "true + false = true",
Cole Faust5a231bd2024-02-07 09:43:59 -0800220 bp: `
221 my_module_type {
222 name: "foo",
223 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
224 "a": true,
225 "b": false,
226 _: true,
227 }) + false,
228 }
229 `,
Cole Faust74ef4652024-03-27 16:45:41 -0700230 provider: selectsTestProvider{
231 my_bool: proptools.BoolPtr(true),
232 },
233 },
234 {
235 name: "false + false = false",
236 bp: `
237 my_module_type {
238 name: "foo",
239 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
240 "a": true,
241 "b": false,
242 _: true,
243 }) + false,
244 }
245 `,
246 vendorVars: map[string]map[string]string{
247 "my_namespace": {
248 "my_variable": "b",
249 },
250 },
251 provider: selectsTestProvider{
252 my_bool: proptools.BoolPtr(false),
253 },
Cole Faust5a231bd2024-02-07 09:43:59 -0800254 },
255 {
256 name: "Append string",
257 bp: `
258 my_module_type {
259 name: "foo",
260 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
261 "a": "a",
262 "b": "b",
263 _: "c",
264 }) + ".cpp",
265 }
266 `,
267 provider: selectsTestProvider{
268 my_string: proptools.StringPtr("c.cpp"),
269 },
270 },
Cole Faust0aa21cc2024-03-20 12:28:03 -0700271 {
272 name: "Select on variant",
273 bp: `
274 my_module_type {
275 name: "foo",
276 my_string: select(variant("arch"), {
277 "x86": "my_x86",
278 "x86_64": "my_x86_64",
279 "arm": "my_arm",
280 "arm64": "my_arm64",
281 _: "my_default",
282 }),
283 }
284 `,
285 provider: selectsTestProvider{
286 my_string: proptools.StringPtr("my_arm64"),
287 },
288 },
Cole Faust12c8ed42024-03-28 16:26:59 -0700289 {
290 name: "Unset value",
291 bp: `
292 my_module_type {
293 name: "foo",
294 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
295 "a": unset,
296 "b": "b",
297 _: "c",
298 })
299 }
300 `,
301 vendorVars: map[string]map[string]string{
302 "my_namespace": {
303 "my_variable": "a",
304 },
305 },
306 provider: selectsTestProvider{},
307 },
308 {
309 name: "Unset value on different branch",
310 bp: `
311 my_module_type {
312 name: "foo",
313 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
314 "a": unset,
315 "b": "b",
316 _: "c",
317 })
318 }
319 `,
320 provider: selectsTestProvider{
321 my_string: proptools.StringPtr("c"),
322 },
323 },
324 {
325 name: "unset + unset = unset",
326 bp: `
327 my_module_type {
328 name: "foo",
329 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
330 _: unset,
331 }) + select(soong_config_variable("my_namespace", "my_variable2"), {
332 _: unset,
333 })
334 }
335 `,
336 provider: selectsTestProvider{},
337 },
338 {
339 name: "unset + string = string",
340 bp: `
341 my_module_type {
342 name: "foo",
343 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
344 _: unset,
345 }) + select(soong_config_variable("my_namespace", "my_variable2"), {
346 _: "a",
347 })
348 }
349 `,
350 provider: selectsTestProvider{
351 my_string: proptools.StringPtr("a"),
352 },
353 },
354 {
355 name: "unset + bool = bool",
356 bp: `
357 my_module_type {
358 name: "foo",
359 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
360 "a": true,
361 _: unset,
362 }) + select(soong_config_variable("my_namespace", "my_variable2"), {
363 _: true,
364 })
365 }
366 `,
367 provider: selectsTestProvider{
368 my_bool: proptools.BoolPtr(true),
369 },
370 },
Cole Faust5a231bd2024-02-07 09:43:59 -0800371 }
372
373 for _, tc := range testCases {
374 t.Run(tc.name, func(t *testing.T) {
375 fixtures := GroupFixturePreparers(
Cole Faust0aa21cc2024-03-20 12:28:03 -0700376 PrepareForTestWithArchMutator,
Cole Faust5a231bd2024-02-07 09:43:59 -0800377 FixtureRegisterWithContext(func(ctx RegistrationContext) {
378 ctx.RegisterModuleType("my_module_type", newSelectsMockModule)
379 }),
380 FixtureModifyProductVariables(func(variables FixtureProductVariables) {
381 variables.VendorVars = tc.vendorVars
382 }),
383 )
384 if tc.expectedError != "" {
385 fixtures = fixtures.ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(tc.expectedError))
386 }
387 result := fixtures.RunTestWithBp(t, tc.bp)
388
389 if tc.expectedError == "" {
Cole Faust0aa21cc2024-03-20 12:28:03 -0700390 m := result.ModuleForTests("foo", "android_arm64_armv8-a")
391 p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
Cole Faust5a231bd2024-02-07 09:43:59 -0800392 if !reflect.DeepEqual(p, tc.provider) {
393 t.Errorf("Expected:\n %q\ngot:\n %q", tc.provider.String(), p.String())
394 }
395 }
396 })
397 }
398}
399
400type selectsTestProvider struct {
401 my_bool *bool
402 my_string *string
403 my_string_list *[]string
Cole Faustbdd8aee2024-03-14 14:33:02 -0700404 my_paths *[]string
Cole Faust5a231bd2024-02-07 09:43:59 -0800405}
406
407func (p *selectsTestProvider) String() string {
408 myBoolStr := "nil"
409 if p.my_bool != nil {
410 myBoolStr = fmt.Sprintf("%t", *p.my_bool)
411 }
412 myStringStr := "nil"
413 if p.my_string != nil {
414 myStringStr = *p.my_string
415 }
416 return fmt.Sprintf(`selectsTestProvider {
417 my_bool: %v,
418 my_string: %s,
419 my_string_list: %s,
Cole Faustbdd8aee2024-03-14 14:33:02 -0700420 my_paths: %s,
421}`, myBoolStr, myStringStr, p.my_string_list, p.my_paths)
Cole Faust5a231bd2024-02-07 09:43:59 -0800422}
423
424var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]()
425
426type selectsMockModuleProperties struct {
427 My_bool proptools.Configurable[bool]
428 My_string proptools.Configurable[string]
429 My_string_list proptools.Configurable[[]string]
Cole Faustbdd8aee2024-03-14 14:33:02 -0700430 My_paths proptools.Configurable[[]string] `android:"path"`
Cole Faust5a231bd2024-02-07 09:43:59 -0800431}
432
433type selectsMockModule struct {
434 ModuleBase
435 DefaultableModuleBase
436 properties selectsMockModuleProperties
437}
438
439func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Cole Faustbdd8aee2024-03-14 14:33:02 -0700440 SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{
Cole Faust5a231bd2024-02-07 09:43:59 -0800441 my_bool: p.properties.My_bool.Evaluate(ctx),
442 my_string: p.properties.My_string.Evaluate(ctx),
443 my_string_list: p.properties.My_string_list.Evaluate(ctx),
Cole Faustbdd8aee2024-03-14 14:33:02 -0700444 my_paths: p.properties.My_paths.Evaluate(ctx),
Cole Faust5a231bd2024-02-07 09:43:59 -0800445 })
446}
447
448func newSelectsMockModule() Module {
449 m := &selectsMockModule{}
450 m.AddProperties(&m.properties)
Cole Faust0aa21cc2024-03-20 12:28:03 -0700451 InitAndroidArchModule(m, HostAndDeviceSupported, MultilibFirst)
Cole Faust5a231bd2024-02-07 09:43:59 -0800452 InitDefaultableModule(m)
453 return m
454}