blob: fc020a47d1a12ade679711b2dfdd231fa75116b1 [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 {
Cole Faust46f6e2f2024-06-20 12:57:43 -070028 name string
29 bp string
Cole Faust165a05b2024-06-20 18:17:04 -070030 fs MockFS
Cole Faust46f6e2f2024-06-20 12:57:43 -070031 provider selectsTestProvider
32 providers map[string]selectsTestProvider
33 vendorVars map[string]map[string]string
34 vendorVarTypes map[string]map[string]string
35 expectedError string
Cole Faust5a231bd2024-02-07 09:43:59 -080036 }{
37 {
38 name: "basic string list",
39 bp: `
40 my_module_type {
41 name: "foo",
42 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
43 "a": ["a.cpp"],
44 "b": ["b.cpp"],
Cole Faust683316a2024-04-02 16:45:54 -070045 default: ["c.cpp"],
Cole Faust5a231bd2024-02-07 09:43:59 -080046 }),
47 }
48 `,
49 provider: selectsTestProvider{
50 my_string_list: &[]string{"c.cpp"},
51 },
52 },
53 {
54 name: "basic string",
55 bp: `
56 my_module_type {
57 name: "foo",
58 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
59 "a": "a.cpp",
60 "b": "b.cpp",
Cole Faust683316a2024-04-02 16:45:54 -070061 default: "c.cpp",
Cole Faust5a231bd2024-02-07 09:43:59 -080062 }),
63 }
64 `,
65 provider: selectsTestProvider{
66 my_string: proptools.StringPtr("c.cpp"),
67 },
68 },
69 {
70 name: "basic bool",
71 bp: `
72 my_module_type {
73 name: "foo",
74 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
75 "a": true,
76 "b": false,
Cole Faust683316a2024-04-02 16:45:54 -070077 default: true,
Cole Faust5a231bd2024-02-07 09:43:59 -080078 }),
79 }
80 `,
81 provider: selectsTestProvider{
82 my_bool: proptools.BoolPtr(true),
83 },
84 },
85 {
Cole Faustbdd8aee2024-03-14 14:33:02 -070086 name: "basic paths",
87 bp: `
88 my_module_type {
89 name: "foo",
90 my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
91 "a": ["foo.txt"],
92 "b": ["bar.txt"],
Cole Faust683316a2024-04-02 16:45:54 -070093 default: ["baz.txt"],
Cole Faustbdd8aee2024-03-14 14:33:02 -070094 }),
95 }
96 `,
97 provider: selectsTestProvider{
98 my_paths: &[]string{"baz.txt"},
99 },
100 },
101 {
Cole Faustba483662024-06-17 15:03:33 -0700102 name: "Expression in select",
103 bp: `
104 my_module_type {
105 name: "foo",
106 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
107 "a": "foo" + "bar",
108 default: "baz",
109 }),
110 }
111 `,
112 provider: selectsTestProvider{
113 my_string: proptools.StringPtr("foobar"),
114 },
115 vendorVars: map[string]map[string]string{
116 "my_namespace": {
117 "my_variable": "a",
118 },
119 },
120 },
121 {
Cole Faustbdd8aee2024-03-14 14:33:02 -0700122 name: "paths with module references",
123 bp: `
124 my_module_type {
125 name: "foo",
126 my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
127 "a": [":a"],
128 "b": [":b"],
Cole Faust683316a2024-04-02 16:45:54 -0700129 default: [":c"],
Cole Faustbdd8aee2024-03-14 14:33:02 -0700130 }),
131 }
132 `,
133 expectedError: `"foo" depends on undefined module "c"`,
134 },
135 {
Cole Faust12c8ed42024-03-28 16:26:59 -0700136 name: "Select type doesn't match property type",
137 bp: `
138 my_module_type {
139 name: "foo",
140 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
141 "a": false,
142 "b": true,
Cole Faust683316a2024-04-02 16:45:54 -0700143 default: true,
Cole Faust12c8ed42024-03-28 16:26:59 -0700144 }),
145 }
146 `,
Cole Faustba483662024-06-17 15:03:33 -0700147 expectedError: `can't assign bool value to string property`,
Cole Faust5a231bd2024-02-07 09:43:59 -0800148 },
149 {
150 name: "String list non-default",
151 bp: `
152 my_module_type {
153 name: "foo",
154 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
155 "a": ["a.cpp"],
156 "b": ["b.cpp"],
Cole Faust683316a2024-04-02 16:45:54 -0700157 default: ["c.cpp"],
Cole Faust5a231bd2024-02-07 09:43:59 -0800158 }),
159 }
160 `,
161 provider: selectsTestProvider{
162 my_string_list: &[]string{"a.cpp"},
163 },
164 vendorVars: map[string]map[string]string{
165 "my_namespace": {
166 "my_variable": "a",
167 },
168 },
169 },
170 {
171 name: "String list append",
172 bp: `
173 my_module_type {
174 name: "foo",
175 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
176 "a": ["a.cpp"],
177 "b": ["b.cpp"],
Cole Faust683316a2024-04-02 16:45:54 -0700178 default: ["c.cpp"],
Cole Faust5a231bd2024-02-07 09:43:59 -0800179 }) + select(soong_config_variable("my_namespace", "my_variable_2"), {
180 "a2": ["a2.cpp"],
181 "b2": ["b2.cpp"],
Cole Faust683316a2024-04-02 16:45:54 -0700182 default: ["c2.cpp"],
Cole Faust5a231bd2024-02-07 09:43:59 -0800183 }),
184 }
185 `,
186 provider: selectsTestProvider{
187 my_string_list: &[]string{"a.cpp", "c2.cpp"},
188 },
189 vendorVars: map[string]map[string]string{
190 "my_namespace": {
191 "my_variable": "a",
192 },
193 },
194 },
195 {
196 name: "String list prepend literal",
197 bp: `
198 my_module_type {
199 name: "foo",
200 my_string_list: ["literal.cpp"] + select(soong_config_variable("my_namespace", "my_variable"), {
201 "a2": ["a2.cpp"],
202 "b2": ["b2.cpp"],
Cole Faust683316a2024-04-02 16:45:54 -0700203 default: ["c2.cpp"],
Cole Faust5a231bd2024-02-07 09:43:59 -0800204 }),
205 }
206 `,
207 provider: selectsTestProvider{
208 my_string_list: &[]string{"literal.cpp", "c2.cpp"},
209 },
210 },
211 {
212 name: "String list append literal",
213 bp: `
214 my_module_type {
215 name: "foo",
216 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
217 "a2": ["a2.cpp"],
218 "b2": ["b2.cpp"],
Cole Faust683316a2024-04-02 16:45:54 -0700219 default: ["c2.cpp"],
Cole Faust5a231bd2024-02-07 09:43:59 -0800220 }) + ["literal.cpp"],
221 }
222 `,
223 provider: selectsTestProvider{
224 my_string_list: &[]string{"c2.cpp", "literal.cpp"},
225 },
226 },
227 {
Cole Faust74ef4652024-03-27 16:45:41 -0700228 name: "true + false = true",
Cole Faust5a231bd2024-02-07 09:43:59 -0800229 bp: `
230 my_module_type {
231 name: "foo",
232 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
233 "a": true,
234 "b": false,
Cole Faust683316a2024-04-02 16:45:54 -0700235 default: true,
Cole Faust5a231bd2024-02-07 09:43:59 -0800236 }) + false,
237 }
238 `,
Cole Faust74ef4652024-03-27 16:45:41 -0700239 provider: selectsTestProvider{
240 my_bool: proptools.BoolPtr(true),
241 },
242 },
243 {
244 name: "false + false = false",
245 bp: `
246 my_module_type {
247 name: "foo",
248 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
249 "a": true,
250 "b": false,
Cole Faust683316a2024-04-02 16:45:54 -0700251 default: true,
Cole Faust74ef4652024-03-27 16:45:41 -0700252 }) + false,
253 }
254 `,
255 vendorVars: map[string]map[string]string{
256 "my_namespace": {
257 "my_variable": "b",
258 },
259 },
260 provider: selectsTestProvider{
261 my_bool: proptools.BoolPtr(false),
262 },
Cole Faust5a231bd2024-02-07 09:43:59 -0800263 },
264 {
265 name: "Append string",
266 bp: `
267 my_module_type {
268 name: "foo",
269 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
270 "a": "a",
271 "b": "b",
Cole Faust683316a2024-04-02 16:45:54 -0700272 default: "c",
Cole Faust5a231bd2024-02-07 09:43:59 -0800273 }) + ".cpp",
274 }
275 `,
276 provider: selectsTestProvider{
277 my_string: proptools.StringPtr("c.cpp"),
278 },
279 },
Cole Faust0aa21cc2024-03-20 12:28:03 -0700280 {
Cole Faustfc57d402024-04-11 12:09:44 -0700281 name: "Select on arch",
Cole Faust0aa21cc2024-03-20 12:28:03 -0700282 bp: `
283 my_module_type {
284 name: "foo",
Cole Faustfc57d402024-04-11 12:09:44 -0700285 my_string: select(arch(), {
Cole Faust0aa21cc2024-03-20 12:28:03 -0700286 "x86": "my_x86",
287 "x86_64": "my_x86_64",
288 "arm": "my_arm",
289 "arm64": "my_arm64",
Cole Faust683316a2024-04-02 16:45:54 -0700290 default: "my_default",
Cole Faust0aa21cc2024-03-20 12:28:03 -0700291 }),
292 }
293 `,
294 provider: selectsTestProvider{
295 my_string: proptools.StringPtr("my_arm64"),
296 },
297 },
Cole Faust12c8ed42024-03-28 16:26:59 -0700298 {
Cole Faustfc57d402024-04-11 12:09:44 -0700299 name: "Select on os",
300 bp: `
301 my_module_type {
302 name: "foo",
303 my_string: select(os(), {
304 "android": "my_android",
305 "linux": "my_linux",
306 default: "my_default",
307 }),
308 }
309 `,
310 provider: selectsTestProvider{
311 my_string: proptools.StringPtr("my_android"),
312 },
313 },
314 {
Cole Faust12c8ed42024-03-28 16:26:59 -0700315 name: "Unset value",
316 bp: `
317 my_module_type {
318 name: "foo",
319 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
320 "a": unset,
321 "b": "b",
Cole Faust683316a2024-04-02 16:45:54 -0700322 default: "c",
Cole Faust12c8ed42024-03-28 16:26:59 -0700323 })
324 }
325 `,
326 vendorVars: map[string]map[string]string{
327 "my_namespace": {
328 "my_variable": "a",
329 },
330 },
331 provider: selectsTestProvider{},
332 },
333 {
334 name: "Unset value on different branch",
335 bp: `
336 my_module_type {
337 name: "foo",
338 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
339 "a": unset,
340 "b": "b",
Cole Faust683316a2024-04-02 16:45:54 -0700341 default: "c",
Cole Faust12c8ed42024-03-28 16:26:59 -0700342 })
343 }
344 `,
345 provider: selectsTestProvider{
346 my_string: proptools.StringPtr("c"),
347 },
348 },
349 {
350 name: "unset + unset = unset",
351 bp: `
352 my_module_type {
353 name: "foo",
354 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
Cole Faustfdbf5d42024-04-10 15:01:23 -0700355 "foo": "bar",
Cole Faust683316a2024-04-02 16:45:54 -0700356 default: unset,
Cole Faust12c8ed42024-03-28 16:26:59 -0700357 }) + select(soong_config_variable("my_namespace", "my_variable2"), {
Cole Faustfdbf5d42024-04-10 15:01:23 -0700358 "baz": "qux",
Cole Faust683316a2024-04-02 16:45:54 -0700359 default: unset,
Cole Faust12c8ed42024-03-28 16:26:59 -0700360 })
361 }
362 `,
363 provider: selectsTestProvider{},
364 },
365 {
366 name: "unset + string = string",
367 bp: `
368 my_module_type {
369 name: "foo",
370 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
Cole Faustfdbf5d42024-04-10 15:01:23 -0700371 "foo": "bar",
Cole Faust683316a2024-04-02 16:45:54 -0700372 default: unset,
Cole Faust12c8ed42024-03-28 16:26:59 -0700373 }) + select(soong_config_variable("my_namespace", "my_variable2"), {
Cole Faust683316a2024-04-02 16:45:54 -0700374 default: "a",
Cole Faust12c8ed42024-03-28 16:26:59 -0700375 })
376 }
377 `,
378 provider: selectsTestProvider{
379 my_string: proptools.StringPtr("a"),
380 },
381 },
382 {
383 name: "unset + bool = bool",
384 bp: `
385 my_module_type {
386 name: "foo",
387 my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
388 "a": true,
Cole Faust683316a2024-04-02 16:45:54 -0700389 default: unset,
Cole Faust12c8ed42024-03-28 16:26:59 -0700390 }) + select(soong_config_variable("my_namespace", "my_variable2"), {
Cole Faust683316a2024-04-02 16:45:54 -0700391 default: true,
Cole Faust12c8ed42024-03-28 16:26:59 -0700392 })
393 }
394 `,
395 provider: selectsTestProvider{
396 my_bool: proptools.BoolPtr(true),
397 },
398 },
Cole Faust02dd6e52024-04-03 17:04:57 -0700399 {
400 name: "defaults with lists are appended",
401 bp: `
402 my_module_type {
403 name: "foo",
404 defaults: ["bar"],
405 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
406 "a": ["a1"],
407 default: ["b1"],
408 }),
409 }
410 my_defaults {
411 name: "bar",
412 my_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
413 "a": ["a2"],
414 default: ["b2"],
415 }),
416 }
417 `,
418 provider: selectsTestProvider{
419 my_string_list: &[]string{"b2", "b1"},
420 },
421 },
422 {
Cole Faust69349462024-04-25 16:02:15 -0700423 name: "defaults applied to multiple modules",
424 bp: `
425 my_module_type {
426 name: "foo2",
427 defaults: ["bar"],
428 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
429 "a": ["a1"],
430 default: ["b1"],
431 }),
432 }
433 my_module_type {
434 name: "foo",
435 defaults: ["bar"],
436 my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
437 "a": ["a1"],
438 default: ["b1"],
439 }),
440 }
441 my_defaults {
442 name: "bar",
443 my_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
444 "a": ["a2"],
445 default: ["b2"],
446 }),
447 }
448 `,
449 providers: map[string]selectsTestProvider{
450 "foo": {
451 my_string_list: &[]string{"b2", "b1"},
452 },
453 "foo2": {
454 my_string_list: &[]string{"b2", "b1"},
455 },
456 },
457 },
458 {
Cole Faust02dd6e52024-04-03 17:04:57 -0700459 name: "Replacing string list",
460 bp: `
461 my_module_type {
462 name: "foo",
463 defaults: ["bar"],
464 replacing_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
465 "a": ["a1"],
466 default: ["b1"],
467 }),
468 }
469 my_defaults {
470 name: "bar",
471 replacing_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
472 "a": ["a2"],
473 default: ["b2"],
474 }),
475 }
476 `,
477 provider: selectsTestProvider{
478 replacing_string_list: &[]string{"b1"},
479 },
480 },
Cole Faustfdbf5d42024-04-10 15:01:23 -0700481 {
482 name: "Multi-condition string 1",
483 bp: `
484 my_module_type {
485 name: "foo",
486 my_string: select((
487 soong_config_variable("my_namespace", "my_variable"),
488 soong_config_variable("my_namespace", "my_variable2"),
489 ), {
490 ("a", "b"): "a+b",
491 ("a", default): "a+default",
492 (default, default): "default",
493 }),
494 }
495 `,
496 vendorVars: map[string]map[string]string{
497 "my_namespace": {
498 "my_variable": "a",
499 "my_variable2": "b",
500 },
501 },
502 provider: selectsTestProvider{
503 my_string: proptools.StringPtr("a+b"),
504 },
505 },
506 {
507 name: "Multi-condition string 2",
508 bp: `
509 my_module_type {
510 name: "foo",
511 my_string: select((
512 soong_config_variable("my_namespace", "my_variable"),
513 soong_config_variable("my_namespace", "my_variable2"),
514 ), {
515 ("a", "b"): "a+b",
516 ("a", default): "a+default",
517 (default, default): "default",
518 }),
519 }
520 `,
521 vendorVars: map[string]map[string]string{
522 "my_namespace": {
523 "my_variable": "a",
524 "my_variable2": "c",
525 },
526 },
527 provider: selectsTestProvider{
528 my_string: proptools.StringPtr("a+default"),
529 },
530 },
531 {
532 name: "Multi-condition string 3",
533 bp: `
534 my_module_type {
535 name: "foo",
536 my_string: select((
537 soong_config_variable("my_namespace", "my_variable"),
538 soong_config_variable("my_namespace", "my_variable2"),
539 ), {
540 ("a", "b"): "a+b",
541 ("a", default): "a+default",
542 (default, default): "default",
543 }),
544 }
545 `,
546 vendorVars: map[string]map[string]string{
547 "my_namespace": {
548 "my_variable": "c",
549 "my_variable2": "b",
550 },
551 },
552 provider: selectsTestProvider{
553 my_string: proptools.StringPtr("default"),
554 },
555 },
556 {
Cole Faustb81dc0e2024-05-09 15:51:52 -0700557 name: "Unhandled string value",
558 bp: `
559 my_module_type {
560 name: "foo",
561 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
562 "foo": "a",
563 "bar": "b",
564 }),
565 }
566 `,
567 vendorVars: map[string]map[string]string{
568 "my_namespace": {
569 "my_variable": "baz",
570 },
571 },
572 expectedError: `my_string: soong_config_variable\("my_namespace", "my_variable"\) had value "baz", which was not handled by the select statement`,
573 },
574 {
Cole Faustfdbf5d42024-04-10 15:01:23 -0700575 name: "Select on boolean",
576 bp: `
577 my_module_type {
578 name: "foo",
579 my_string: select(boolean_var_for_testing(), {
580 true: "t",
581 false: "f",
582 }),
583 }
584 `,
585 vendorVars: map[string]map[string]string{
586 "boolean_var": {
587 "for_testing": "true",
588 },
589 },
590 provider: selectsTestProvider{
591 my_string: proptools.StringPtr("t"),
592 },
593 },
594 {
Cole Faust46f6e2f2024-06-20 12:57:43 -0700595 name: "Select on boolean soong config variable",
596 bp: `
597 my_module_type {
598 name: "foo",
599 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
600 true: "t",
601 false: "f",
602 }),
603 }
604 `,
605 vendorVars: map[string]map[string]string{
606 "my_namespace": {
607 "my_variable": "true",
608 },
609 },
610 vendorVarTypes: map[string]map[string]string{
611 "my_namespace": {
612 "my_variable": "bool",
613 },
614 },
615 provider: selectsTestProvider{
616 my_string: proptools.StringPtr("t"),
617 },
618 },
619 {
Cole Faustfdbf5d42024-04-10 15:01:23 -0700620 name: "Select on boolean false",
621 bp: `
622 my_module_type {
623 name: "foo",
624 my_string: select(boolean_var_for_testing(), {
625 true: "t",
626 false: "f",
627 }),
628 }
629 `,
630 vendorVars: map[string]map[string]string{
631 "boolean_var": {
632 "for_testing": "false",
633 },
634 },
635 provider: selectsTestProvider{
636 my_string: proptools.StringPtr("f"),
637 },
638 },
639 {
640 name: "Select on boolean undefined",
641 bp: `
642 my_module_type {
643 name: "foo",
644 my_string: select(boolean_var_for_testing(), {
645 true: "t",
646 false: "f",
647 }),
648 }
649 `,
Cole Faustb81dc0e2024-05-09 15:51:52 -0700650 expectedError: `my_string: boolean_var_for_testing\(\) had value undefined, which was not handled by the select statement`,
Cole Faustfdbf5d42024-04-10 15:01:23 -0700651 },
652 {
653 name: "Select on boolean undefined with default",
654 bp: `
655 my_module_type {
656 name: "foo",
657 my_string: select(boolean_var_for_testing(), {
658 true: "t",
659 false: "f",
660 default: "default",
661 }),
662 }
663 `,
664 provider: selectsTestProvider{
665 my_string: proptools.StringPtr("default"),
666 },
667 },
668 {
669 name: "Mismatched condition types",
670 bp: `
671 my_module_type {
672 name: "foo",
673 my_string: select(boolean_var_for_testing(), {
674 "true": "t",
675 "false": "f",
676 default: "default",
677 }),
678 }
679 `,
680 vendorVars: map[string]map[string]string{
681 "boolean_var": {
682 "for_testing": "false",
683 },
684 },
685 expectedError: "Expected all branches of a select on condition boolean_var_for_testing\\(\\) to have type bool, found string",
686 },
Cole Faust60f6bb22024-04-30 13:58:55 -0700687 {
688 name: "Assigning select to nonconfigurable bool",
689 bp: `
690 my_module_type {
691 name: "foo",
692 my_nonconfigurable_bool: select(arch(), {
693 "x86_64": true,
694 default: false,
695 }),
696 }
697 `,
698 expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_bool"`,
699 },
700 {
701 name: "Assigning select to nonconfigurable string",
702 bp: `
703 my_module_type {
704 name: "foo",
705 my_nonconfigurable_string: select(arch(), {
706 "x86_64": "x86!",
707 default: "unknown!",
708 }),
709 }
710 `,
711 expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`,
712 },
713 {
714 name: "Assigning appended selects to nonconfigurable string",
715 bp: `
716 my_module_type {
717 name: "foo",
718 my_nonconfigurable_string: select(arch(), {
719 "x86_64": "x86!",
720 default: "unknown!",
721 }) + select(os(), {
722 "darwin": "_darwin!",
723 default: "unknown!",
724 }),
725 }
726 `,
727 expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`,
728 },
729 {
730 name: "Assigning select to nonconfigurable string list",
731 bp: `
732 my_module_type {
733 name: "foo",
734 my_nonconfigurable_string_list: select(arch(), {
735 "x86_64": ["foo", "bar"],
736 default: ["baz", "qux"],
737 }),
738 }
739 `,
740 expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string_list"`,
741 },
Cole Faustb9519092024-05-21 11:20:15 -0700742 {
743 name: "Select in variable",
744 bp: `
745 my_second_variable = ["after.cpp"]
746 my_variable = select(soong_config_variable("my_namespace", "my_variable"), {
747 "a": ["a.cpp"],
748 "b": ["b.cpp"],
749 default: ["c.cpp"],
750 }) + my_second_variable
751 my_module_type {
752 name: "foo",
753 my_string_list: ["before.cpp"] + my_variable,
754 }
755 `,
756 provider: selectsTestProvider{
757 my_string_list: &[]string{"before.cpp", "a.cpp", "after.cpp"},
758 },
759 vendorVars: map[string]map[string]string{
760 "my_namespace": {
761 "my_variable": "a",
762 },
763 },
764 },
Cole Faust5f297062024-05-22 14:30:16 -0700765 {
766 name: "Soong config value variable on configurable property",
767 bp: `
768 soong_config_module_type {
769 name: "soong_config_my_module_type",
770 module_type: "my_module_type",
771 config_namespace: "my_namespace",
772 value_variables: ["my_variable"],
773 properties: ["my_string", "my_string_list"],
774 }
775
776 soong_config_my_module_type {
777 name: "foo",
778 my_string_list: ["before.cpp"],
779 soong_config_variables: {
780 my_variable: {
781 my_string_list: ["after_%s.cpp"],
782 my_string: "%s.cpp",
783 },
784 },
785 }
786 `,
787 provider: selectsTestProvider{
788 my_string: proptools.StringPtr("foo.cpp"),
789 my_string_list: &[]string{"before.cpp", "after_foo.cpp"},
790 },
791 vendorVars: map[string]map[string]string{
792 "my_namespace": {
793 "my_variable": "foo",
794 },
795 },
796 },
Cole Faustaeecb752024-05-22 13:41:35 -0700797 {
798 name: "Property appending with variable",
799 bp: `
800 my_variable = ["b.cpp"]
801 my_module_type {
802 name: "foo",
803 my_string_list: ["a.cpp"] + my_variable + select(soong_config_variable("my_namespace", "my_variable"), {
804 "a": ["a.cpp"],
805 "b": ["b.cpp"],
806 default: ["c.cpp"],
807 }),
808 }
809 `,
810 provider: selectsTestProvider{
811 my_string_list: &[]string{"a.cpp", "b.cpp", "c.cpp"},
812 },
813 },
Cole Faustfee6fde2024-06-13 15:35:17 -0700814 {
815 name: "Test AppendSimpleValue",
816 bp: `
817 my_module_type {
818 name: "foo",
819 my_string_list: ["a.cpp"] + select(soong_config_variable("my_namespace", "my_variable"), {
820 "a": ["a.cpp"],
821 "b": ["b.cpp"],
822 default: ["c.cpp"],
823 }),
824 }
825 `,
826 vendorVars: map[string]map[string]string{
827 "selects_test": {
828 "append_to_string_list": "foo.cpp",
829 },
830 },
831 provider: selectsTestProvider{
832 my_string_list: &[]string{"a.cpp", "c.cpp", "foo.cpp"},
833 },
834 },
Cole Faustba483662024-06-17 15:03:33 -0700835 {
836 name: "Arch variant bool",
837 bp: `
838 my_variable = ["b.cpp"]
839 my_module_type {
840 name: "foo",
841 arch_variant_configurable_bool: false,
842 target: {
843 bionic_arm64: {
844 enabled: true,
845 },
846 },
847 }
848 `,
849 provider: selectsTestProvider{
850 arch_variant_configurable_bool: proptools.BoolPtr(false),
851 },
852 },
Cole Faust165a05b2024-06-20 18:17:04 -0700853 {
854 name: "Simple string binding",
855 bp: `
856 my_module_type {
857 name: "foo",
858 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
859 any @ my_binding: "hello " + my_binding,
860 default: "goodbye",
861 })
862 }
863 `,
864 vendorVars: map[string]map[string]string{
865 "my_namespace": {
866 "my_variable": "world!",
867 },
868 },
869 provider: selectsTestProvider{
870 my_string: proptools.StringPtr("hello world!"),
871 },
872 },
873 {
874 name: "Any branch with binding not taken",
875 bp: `
876 my_module_type {
877 name: "foo",
878 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
879 any @ my_binding: "hello " + my_binding,
880 default: "goodbye",
881 })
882 }
883 `,
884 provider: selectsTestProvider{
885 my_string: proptools.StringPtr("goodbye"),
886 },
887 },
888 {
889 name: "Any branch without binding",
890 bp: `
891 my_module_type {
892 name: "foo",
893 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
894 any: "hello",
895 default: "goodbye",
896 })
897 }
898 `,
899 vendorVars: map[string]map[string]string{
900 "my_namespace": {
901 "my_variable": "world!",
902 },
903 },
904 provider: selectsTestProvider{
905 my_string: proptools.StringPtr("hello"),
906 },
907 },
908 {
909 name: "Binding conflicts with file-level variable",
910 bp: `
911 my_binding = "asdf"
912 my_module_type {
913 name: "foo",
914 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
915 any @ my_binding: "hello",
916 default: "goodbye",
917 })
918 }
919 `,
920 vendorVars: map[string]map[string]string{
921 "my_namespace": {
922 "my_variable": "world!",
923 },
924 },
925 expectedError: "variable already set in inherited scope, previous assignment",
926 },
927 {
928 name: "Binding in combination with file-level variable",
929 bp: `
930 my_var = " there "
931 my_module_type {
932 name: "foo",
933 my_string: select(soong_config_variable("my_namespace", "my_variable"), {
934 any @ my_binding: "hello" + my_var + my_binding,
935 default: "goodbye",
936 })
937 }
938 `,
939 vendorVars: map[string]map[string]string{
940 "my_namespace": {
941 "my_variable": "world!",
942 },
943 },
944 provider: selectsTestProvider{
945 my_string: proptools.StringPtr("hello there world!"),
946 },
947 },
948 {
949 name: "Bindings in subdirectory inherits variable",
950 fs: map[string][]byte{
951 "Android.bp": []byte(`
952my_var = "abcd"
953`),
954 "directoryB/Android.bp": []byte(`
955my_module_type {
956 name: "foo",
957 my_string: select(soong_config_variable("my_namespace", "variable_a"), {
958 any @ my_binding: my_var + my_binding,
959 default: "",
960 }),
961}
962`),
963 },
964 vendorVars: map[string]map[string]string{
965 "my_namespace": {
966 "variable_a": "e",
967 },
968 },
969 provider: selectsTestProvider{
970 my_string: proptools.StringPtr("abcde"),
971 },
972 },
973 {
974 name: "Cannot modify variable after referenced by select",
975 bp: `
976my_var = "foo"
977my_module_type {
978 name: "foo",
979 my_string: select(soong_config_variable("my_namespace", "variable_a"), {
980 "a": my_var,
981 default: "",
982 }),
983}
984my_var += "bar"
985`,
986 vendorVars: map[string]map[string]string{
987 "my_namespace": {
988 "variable_a": "b", // notably not the value that causes my_var to be referenced
989 },
990 },
991 expectedError: `modified variable "my_var" with \+= after referencing`,
992 },
993 {
994 name: "Cannot shadow variable with binding",
995 bp: `
996my_var = "foo"
997my_module_type {
998 name: "foo",
999 my_string: select(soong_config_variable("my_namespace", "variable_a"), {
1000 any @ my_var: my_var,
1001 default: "",
1002 }),
1003}
1004`,
1005 vendorVars: map[string]map[string]string{
1006 "my_namespace": {
1007 "variable_a": "a",
1008 },
1009 },
1010 expectedError: `variable already set in inherited scope, previous assignment:`,
1011 },
Cole Faust5a231bd2024-02-07 09:43:59 -08001012 }
1013
1014 for _, tc := range testCases {
1015 t.Run(tc.name, func(t *testing.T) {
Cole Faust165a05b2024-06-20 18:17:04 -07001016 fs := tc.fs
1017 if fs == nil {
1018 fs = make(MockFS)
1019 }
1020 if tc.bp != "" {
1021 fs["Android.bp"] = []byte(tc.bp)
1022 }
Cole Faust5a231bd2024-02-07 09:43:59 -08001023 fixtures := GroupFixturePreparers(
Cole Faust02dd6e52024-04-03 17:04:57 -07001024 PrepareForTestWithDefaults,
Cole Faust0aa21cc2024-03-20 12:28:03 -07001025 PrepareForTestWithArchMutator,
Cole Faust5f297062024-05-22 14:30:16 -07001026 PrepareForTestWithSoongConfigModuleBuildComponents,
Cole Faust5a231bd2024-02-07 09:43:59 -08001027 FixtureRegisterWithContext(func(ctx RegistrationContext) {
1028 ctx.RegisterModuleType("my_module_type", newSelectsMockModule)
Cole Faust02dd6e52024-04-03 17:04:57 -07001029 ctx.RegisterModuleType("my_defaults", newSelectsMockModuleDefaults)
Cole Faust5a231bd2024-02-07 09:43:59 -08001030 }),
1031 FixtureModifyProductVariables(func(variables FixtureProductVariables) {
1032 variables.VendorVars = tc.vendorVars
Cole Faust46f6e2f2024-06-20 12:57:43 -07001033 variables.VendorVarTypes = tc.vendorVarTypes
Cole Faust5a231bd2024-02-07 09:43:59 -08001034 }),
Cole Faust165a05b2024-06-20 18:17:04 -07001035 FixtureMergeMockFs(fs),
Cole Faust5a231bd2024-02-07 09:43:59 -08001036 )
1037 if tc.expectedError != "" {
1038 fixtures = fixtures.ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(tc.expectedError))
1039 }
Cole Faust165a05b2024-06-20 18:17:04 -07001040 result := fixtures.RunTest(t)
Cole Faust5a231bd2024-02-07 09:43:59 -08001041
1042 if tc.expectedError == "" {
Cole Faust69349462024-04-25 16:02:15 -07001043 if len(tc.providers) == 0 {
1044 tc.providers = map[string]selectsTestProvider{
1045 "foo": tc.provider,
1046 }
1047 }
1048
1049 for moduleName := range tc.providers {
1050 expected := tc.providers[moduleName]
1051 m := result.ModuleForTests(moduleName, "android_arm64_armv8-a")
1052 p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
1053 if !reflect.DeepEqual(p, expected) {
1054 t.Errorf("Expected:\n %q\ngot:\n %q", expected.String(), p.String())
1055 }
Cole Faust5a231bd2024-02-07 09:43:59 -08001056 }
1057 }
1058 })
1059 }
1060}
1061
1062type selectsTestProvider struct {
Cole Faust60f6bb22024-04-30 13:58:55 -07001063 my_bool *bool
1064 my_string *string
1065 my_string_list *[]string
1066 my_paths *[]string
1067 replacing_string_list *[]string
Cole Faustba483662024-06-17 15:03:33 -07001068 arch_variant_configurable_bool *bool
Cole Faust60f6bb22024-04-30 13:58:55 -07001069 my_nonconfigurable_bool *bool
1070 my_nonconfigurable_string *string
1071 my_nonconfigurable_string_list []string
Cole Faust5a231bd2024-02-07 09:43:59 -08001072}
1073
1074func (p *selectsTestProvider) String() string {
1075 myBoolStr := "nil"
1076 if p.my_bool != nil {
1077 myBoolStr = fmt.Sprintf("%t", *p.my_bool)
1078 }
1079 myStringStr := "nil"
1080 if p.my_string != nil {
1081 myStringStr = *p.my_string
1082 }
Cole Faust60f6bb22024-04-30 13:58:55 -07001083 myNonconfigurableStringStr := "nil"
Cole Faust5f297062024-05-22 14:30:16 -07001084 if p.my_nonconfigurable_string != nil {
Cole Faust60f6bb22024-04-30 13:58:55 -07001085 myNonconfigurableStringStr = *p.my_nonconfigurable_string
1086 }
Cole Faust5a231bd2024-02-07 09:43:59 -08001087 return fmt.Sprintf(`selectsTestProvider {
1088 my_bool: %v,
1089 my_string: %s,
1090 my_string_list: %s,
Cole Faustbdd8aee2024-03-14 14:33:02 -07001091 my_paths: %s,
Cole Faust02dd6e52024-04-03 17:04:57 -07001092 replacing_string_list %s,
Cole Faustba483662024-06-17 15:03:33 -07001093 arch_variant_configurable_bool %v
Cole Faust60f6bb22024-04-30 13:58:55 -07001094 my_nonconfigurable_bool: %v,
1095 my_nonconfigurable_string: %s,
1096 my_nonconfigurable_string_list: %s,
1097}`,
1098 myBoolStr,
1099 myStringStr,
1100 p.my_string_list,
1101 p.my_paths,
1102 p.replacing_string_list,
Cole Faustba483662024-06-17 15:03:33 -07001103 p.arch_variant_configurable_bool,
Cole Faust60f6bb22024-04-30 13:58:55 -07001104 p.my_nonconfigurable_bool,
1105 myNonconfigurableStringStr,
1106 p.my_nonconfigurable_string_list,
1107 )
Cole Faust5a231bd2024-02-07 09:43:59 -08001108}
1109
1110var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]()
1111
1112type selectsMockModuleProperties struct {
Cole Faust60f6bb22024-04-30 13:58:55 -07001113 My_bool proptools.Configurable[bool]
1114 My_string proptools.Configurable[string]
1115 My_string_list proptools.Configurable[[]string]
1116 My_paths proptools.Configurable[[]string] `android:"path"`
1117 Replacing_string_list proptools.Configurable[[]string] `android:"replace_instead_of_append,arch_variant"`
Cole Faustba483662024-06-17 15:03:33 -07001118 Arch_variant_configurable_bool proptools.Configurable[bool] `android:"replace_instead_of_append,arch_variant"`
Cole Faust60f6bb22024-04-30 13:58:55 -07001119 My_nonconfigurable_bool *bool
1120 My_nonconfigurable_string *string
1121 My_nonconfigurable_string_list []string
Cole Faust5a231bd2024-02-07 09:43:59 -08001122}
1123
1124type selectsMockModule struct {
1125 ModuleBase
1126 DefaultableModuleBase
1127 properties selectsMockModuleProperties
1128}
1129
Cole Faust749eeaa2024-05-21 14:19:05 -07001130func optionalToPtr[T any](o proptools.ConfigurableOptional[T]) *T {
1131 if o.IsEmpty() {
1132 return nil
1133 }
1134 x := o.Get()
1135 return &x
1136}
1137
Cole Faust5a231bd2024-02-07 09:43:59 -08001138func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Cole Faustfee6fde2024-06-13 15:35:17 -07001139 toAppend := ctx.Config().VendorConfig("selects_test").String("append_to_string_list")
1140 if toAppend != "" {
1141 p.properties.My_string_list.AppendSimpleValue([]string{toAppend})
1142 }
Cole Faustbdd8aee2024-03-14 14:33:02 -07001143 SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{
Cole Faust749eeaa2024-05-21 14:19:05 -07001144 my_bool: optionalToPtr(p.properties.My_bool.Get(ctx)),
1145 my_string: optionalToPtr(p.properties.My_string.Get(ctx)),
1146 my_string_list: optionalToPtr(p.properties.My_string_list.Get(ctx)),
1147 my_paths: optionalToPtr(p.properties.My_paths.Get(ctx)),
1148 replacing_string_list: optionalToPtr(p.properties.Replacing_string_list.Get(ctx)),
Cole Faustba483662024-06-17 15:03:33 -07001149 arch_variant_configurable_bool: optionalToPtr(p.properties.Arch_variant_configurable_bool.Get(ctx)),
Cole Faust60f6bb22024-04-30 13:58:55 -07001150 my_nonconfigurable_bool: p.properties.My_nonconfigurable_bool,
1151 my_nonconfigurable_string: p.properties.My_nonconfigurable_string,
1152 my_nonconfigurable_string_list: p.properties.My_nonconfigurable_string_list,
Cole Faust5a231bd2024-02-07 09:43:59 -08001153 })
1154}
1155
1156func newSelectsMockModule() Module {
1157 m := &selectsMockModule{}
1158 m.AddProperties(&m.properties)
Cole Faust0aa21cc2024-03-20 12:28:03 -07001159 InitAndroidArchModule(m, HostAndDeviceSupported, MultilibFirst)
Cole Faust5a231bd2024-02-07 09:43:59 -08001160 InitDefaultableModule(m)
1161 return m
1162}
Cole Faust02dd6e52024-04-03 17:04:57 -07001163
1164type selectsMockModuleDefaults struct {
1165 ModuleBase
1166 DefaultsModuleBase
1167}
1168
1169func (d *selectsMockModuleDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
1170}
1171
1172func newSelectsMockModuleDefaults() Module {
1173 module := &selectsMockModuleDefaults{}
1174
1175 module.AddProperties(
1176 &selectsMockModuleProperties{},
1177 )
1178
1179 InitDefaultsModule(module)
1180
1181 return module
1182}