• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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		providers     map[string]selectsTestProvider
32		vendorVars    map[string]map[string]string
33		expectedError string
34	}{
35		{
36			name: "basic string list",
37			bp: `
38			my_module_type {
39				name: "foo",
40				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
41					"a": ["a.cpp"],
42					"b": ["b.cpp"],
43					default: ["c.cpp"],
44				}),
45			}
46			`,
47			provider: selectsTestProvider{
48				my_string_list: &[]string{"c.cpp"},
49			},
50		},
51		{
52			name: "basic string",
53			bp: `
54			my_module_type {
55				name: "foo",
56				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
57					"a": "a.cpp",
58					"b": "b.cpp",
59					default: "c.cpp",
60				}),
61			}
62			`,
63			provider: selectsTestProvider{
64				my_string: proptools.StringPtr("c.cpp"),
65			},
66		},
67		{
68			name: "basic bool",
69			bp: `
70			my_module_type {
71				name: "foo",
72				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
73					"a": true,
74					"b": false,
75					default: true,
76				}),
77			}
78			`,
79			provider: selectsTestProvider{
80				my_bool: proptools.BoolPtr(true),
81			},
82		},
83		{
84			name: "basic paths",
85			bp: `
86			my_module_type {
87				name: "foo",
88				my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
89					"a": ["foo.txt"],
90					"b": ["bar.txt"],
91					default: ["baz.txt"],
92				}),
93			}
94			`,
95			provider: selectsTestProvider{
96				my_paths: &[]string{"baz.txt"},
97			},
98		},
99		{
100			name: "paths with module references",
101			bp: `
102			my_module_type {
103				name: "foo",
104				my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
105					"a": [":a"],
106					"b": [":b"],
107					default: [":c"],
108				}),
109			}
110			`,
111			expectedError: `"foo" depends on undefined module "c"`,
112		},
113		{
114			name: "Differing types",
115			bp: `
116			my_module_type {
117				name: "foo",
118				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
119					"a": "a.cpp",
120					"b": true,
121					default: "c.cpp",
122				}),
123			}
124			`,
125			expectedError: `Android.bp:8:5: Found select statement with differing types "string" and "bool" in its cases`,
126		},
127		{
128			name: "Select type doesn't match property type",
129			bp: `
130			my_module_type {
131				name: "foo",
132				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
133					"a": false,
134					"b": true,
135					default: true,
136				}),
137			}
138			`,
139			expectedError: `can't assign bool value to string property "my_string\[0\]"`,
140		},
141		{
142			name: "String list non-default",
143			bp: `
144			my_module_type {
145				name: "foo",
146				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
147					"a": ["a.cpp"],
148					"b": ["b.cpp"],
149					default: ["c.cpp"],
150				}),
151			}
152			`,
153			provider: selectsTestProvider{
154				my_string_list: &[]string{"a.cpp"},
155			},
156			vendorVars: map[string]map[string]string{
157				"my_namespace": {
158					"my_variable": "a",
159				},
160			},
161		},
162		{
163			name: "String list append",
164			bp: `
165			my_module_type {
166				name: "foo",
167				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
168					"a": ["a.cpp"],
169					"b": ["b.cpp"],
170					default: ["c.cpp"],
171				}) + select(soong_config_variable("my_namespace", "my_variable_2"), {
172					"a2": ["a2.cpp"],
173					"b2": ["b2.cpp"],
174					default: ["c2.cpp"],
175				}),
176			}
177			`,
178			provider: selectsTestProvider{
179				my_string_list: &[]string{"a.cpp", "c2.cpp"},
180			},
181			vendorVars: map[string]map[string]string{
182				"my_namespace": {
183					"my_variable": "a",
184				},
185			},
186		},
187		{
188			name: "String list prepend literal",
189			bp: `
190			my_module_type {
191				name: "foo",
192				my_string_list: ["literal.cpp"] + select(soong_config_variable("my_namespace", "my_variable"), {
193					"a2": ["a2.cpp"],
194					"b2": ["b2.cpp"],
195					default: ["c2.cpp"],
196				}),
197			}
198			`,
199			provider: selectsTestProvider{
200				my_string_list: &[]string{"literal.cpp", "c2.cpp"},
201			},
202		},
203		{
204			name: "String list append literal",
205			bp: `
206			my_module_type {
207				name: "foo",
208				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
209					"a2": ["a2.cpp"],
210					"b2": ["b2.cpp"],
211					default: ["c2.cpp"],
212				}) + ["literal.cpp"],
213			}
214			`,
215			provider: selectsTestProvider{
216				my_string_list: &[]string{"c2.cpp", "literal.cpp"},
217			},
218		},
219		{
220			name: "true + false = true",
221			bp: `
222			my_module_type {
223				name: "foo",
224				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
225					"a": true,
226					"b": false,
227					default: true,
228				}) + false,
229			}
230			`,
231			provider: selectsTestProvider{
232				my_bool: proptools.BoolPtr(true),
233			},
234		},
235		{
236			name: "false + false = false",
237			bp: `
238			my_module_type {
239				name: "foo",
240				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
241					"a": true,
242					"b": false,
243					default: true,
244				}) + false,
245			}
246			`,
247			vendorVars: map[string]map[string]string{
248				"my_namespace": {
249					"my_variable": "b",
250				},
251			},
252			provider: selectsTestProvider{
253				my_bool: proptools.BoolPtr(false),
254			},
255		},
256		{
257			name: "Append string",
258			bp: `
259			my_module_type {
260				name: "foo",
261				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
262					"a": "a",
263					"b": "b",
264					default: "c",
265				}) + ".cpp",
266			}
267			`,
268			provider: selectsTestProvider{
269				my_string: proptools.StringPtr("c.cpp"),
270			},
271		},
272		{
273			name: "Select on arch",
274			bp: `
275			my_module_type {
276				name: "foo",
277				my_string: select(arch(), {
278					"x86": "my_x86",
279					"x86_64": "my_x86_64",
280					"arm": "my_arm",
281					"arm64": "my_arm64",
282					default: "my_default",
283				}),
284			}
285			`,
286			provider: selectsTestProvider{
287				my_string: proptools.StringPtr("my_arm64"),
288			},
289		},
290		{
291			name: "Select on os",
292			bp: `
293			my_module_type {
294				name: "foo",
295				my_string: select(os(), {
296					"android": "my_android",
297					"linux": "my_linux",
298					default: "my_default",
299				}),
300			}
301			`,
302			provider: selectsTestProvider{
303				my_string: proptools.StringPtr("my_android"),
304			},
305		},
306		{
307			name: "Unset value",
308			bp: `
309			my_module_type {
310				name: "foo",
311				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
312					"a": unset,
313					"b": "b",
314					default: "c",
315				})
316			}
317			`,
318			vendorVars: map[string]map[string]string{
319				"my_namespace": {
320					"my_variable": "a",
321				},
322			},
323			provider: selectsTestProvider{},
324		},
325		{
326			name: "Unset value on different branch",
327			bp: `
328			my_module_type {
329				name: "foo",
330				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
331					"a": unset,
332					"b": "b",
333					default: "c",
334				})
335			}
336			`,
337			provider: selectsTestProvider{
338				my_string: proptools.StringPtr("c"),
339			},
340		},
341		{
342			name: "unset + unset = unset",
343			bp: `
344			my_module_type {
345				name: "foo",
346				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
347					"foo": "bar",
348					default: unset,
349				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
350					"baz": "qux",
351					default: unset,
352				})
353			}
354			`,
355			provider: selectsTestProvider{},
356		},
357		{
358			name: "unset + string = string",
359			bp: `
360			my_module_type {
361				name: "foo",
362				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
363					"foo": "bar",
364					default: unset,
365				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
366					default: "a",
367				})
368			}
369			`,
370			provider: selectsTestProvider{
371				my_string: proptools.StringPtr("a"),
372			},
373		},
374		{
375			name: "unset + bool = bool",
376			bp: `
377			my_module_type {
378				name: "foo",
379				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
380					"a": true,
381					default: unset,
382				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
383					default: true,
384				})
385			}
386			`,
387			provider: selectsTestProvider{
388				my_bool: proptools.BoolPtr(true),
389			},
390		},
391		{
392			name: "defaults with lists are appended",
393			bp: `
394			my_module_type {
395				name: "foo",
396				defaults: ["bar"],
397				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
398					"a": ["a1"],
399					default: ["b1"],
400				}),
401			}
402			my_defaults {
403				name: "bar",
404				my_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
405					"a": ["a2"],
406					default: ["b2"],
407				}),
408			}
409			`,
410			provider: selectsTestProvider{
411				my_string_list: &[]string{"b2", "b1"},
412			},
413		},
414		{
415			name: "defaults applied to multiple modules",
416			bp: `
417			my_module_type {
418				name: "foo2",
419				defaults: ["bar"],
420				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
421					"a": ["a1"],
422					default: ["b1"],
423				}),
424			}
425			my_module_type {
426				name: "foo",
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_defaults {
434				name: "bar",
435				my_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
436					"a": ["a2"],
437					default: ["b2"],
438				}),
439			}
440			`,
441			providers: map[string]selectsTestProvider{
442				"foo": {
443					my_string_list: &[]string{"b2", "b1"},
444				},
445				"foo2": {
446					my_string_list: &[]string{"b2", "b1"},
447				},
448			},
449		},
450		{
451			name: "Replacing string list",
452			bp: `
453			my_module_type {
454				name: "foo",
455				defaults: ["bar"],
456				replacing_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
457					"a": ["a1"],
458					default: ["b1"],
459				}),
460			}
461			my_defaults {
462				name: "bar",
463				replacing_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
464					"a": ["a2"],
465					default: ["b2"],
466				}),
467			}
468			`,
469			provider: selectsTestProvider{
470				replacing_string_list: &[]string{"b1"},
471			},
472		},
473		{
474			name: "Multi-condition string 1",
475			bp: `
476			my_module_type {
477				name: "foo",
478				my_string: select((
479					soong_config_variable("my_namespace", "my_variable"),
480					soong_config_variable("my_namespace", "my_variable2"),
481				), {
482					("a", "b"): "a+b",
483					("a", default): "a+default",
484					(default, default): "default",
485				}),
486			}
487			`,
488			vendorVars: map[string]map[string]string{
489				"my_namespace": {
490					"my_variable":  "a",
491					"my_variable2": "b",
492				},
493			},
494			provider: selectsTestProvider{
495				my_string: proptools.StringPtr("a+b"),
496			},
497		},
498		{
499			name: "Multi-condition string 2",
500			bp: `
501			my_module_type {
502				name: "foo",
503				my_string: select((
504					soong_config_variable("my_namespace", "my_variable"),
505					soong_config_variable("my_namespace", "my_variable2"),
506				), {
507					("a", "b"): "a+b",
508					("a", default): "a+default",
509					(default, default): "default",
510				}),
511			}
512			`,
513			vendorVars: map[string]map[string]string{
514				"my_namespace": {
515					"my_variable":  "a",
516					"my_variable2": "c",
517				},
518			},
519			provider: selectsTestProvider{
520				my_string: proptools.StringPtr("a+default"),
521			},
522		},
523		{
524			name: "Multi-condition string 3",
525			bp: `
526			my_module_type {
527				name: "foo",
528				my_string: select((
529					soong_config_variable("my_namespace", "my_variable"),
530					soong_config_variable("my_namespace", "my_variable2"),
531				), {
532					("a", "b"): "a+b",
533					("a", default): "a+default",
534					(default, default): "default",
535				}),
536			}
537			`,
538			vendorVars: map[string]map[string]string{
539				"my_namespace": {
540					"my_variable":  "c",
541					"my_variable2": "b",
542				},
543			},
544			provider: selectsTestProvider{
545				my_string: proptools.StringPtr("default"),
546			},
547		},
548		{
549			name: "Unhandled string value",
550			bp: `
551			my_module_type {
552				name: "foo",
553				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
554					"foo": "a",
555					"bar": "b",
556				}),
557			}
558			`,
559			vendorVars: map[string]map[string]string{
560				"my_namespace": {
561					"my_variable": "baz",
562				},
563			},
564			expectedError: `my_string: soong_config_variable\("my_namespace", "my_variable"\) had value "baz", which was not handled by the select statement`,
565		},
566		{
567			name: "Select on boolean",
568			bp: `
569			my_module_type {
570				name: "foo",
571				my_string: select(boolean_var_for_testing(), {
572					true: "t",
573					false: "f",
574				}),
575			}
576			`,
577			vendorVars: map[string]map[string]string{
578				"boolean_var": {
579					"for_testing": "true",
580				},
581			},
582			provider: selectsTestProvider{
583				my_string: proptools.StringPtr("t"),
584			},
585		},
586		{
587			name: "Select on boolean false",
588			bp: `
589			my_module_type {
590				name: "foo",
591				my_string: select(boolean_var_for_testing(), {
592					true: "t",
593					false: "f",
594				}),
595			}
596			`,
597			vendorVars: map[string]map[string]string{
598				"boolean_var": {
599					"for_testing": "false",
600				},
601			},
602			provider: selectsTestProvider{
603				my_string: proptools.StringPtr("f"),
604			},
605		},
606		{
607			name: "Select on boolean undefined",
608			bp: `
609			my_module_type {
610				name: "foo",
611				my_string: select(boolean_var_for_testing(), {
612					true: "t",
613					false: "f",
614				}),
615			}
616			`,
617			expectedError: `my_string: boolean_var_for_testing\(\) had value undefined, which was not handled by the select statement`,
618		},
619		{
620			name: "Select on boolean undefined with default",
621			bp: `
622			my_module_type {
623				name: "foo",
624				my_string: select(boolean_var_for_testing(), {
625					true: "t",
626					false: "f",
627					default: "default",
628				}),
629			}
630			`,
631			provider: selectsTestProvider{
632				my_string: proptools.StringPtr("default"),
633			},
634		},
635		{
636			name: "Mismatched condition types",
637			bp: `
638			my_module_type {
639				name: "foo",
640				my_string: select(boolean_var_for_testing(), {
641					"true": "t",
642					"false": "f",
643					default: "default",
644				}),
645			}
646			`,
647			vendorVars: map[string]map[string]string{
648				"boolean_var": {
649					"for_testing": "false",
650				},
651			},
652			expectedError: "Expected all branches of a select on condition boolean_var_for_testing\\(\\) to have type bool, found string",
653		},
654		{
655			name: "Assigning select to nonconfigurable bool",
656			bp: `
657			my_module_type {
658				name: "foo",
659				my_nonconfigurable_bool: select(arch(), {
660					"x86_64": true,
661					default: false,
662				}),
663			}
664			`,
665			expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_bool"`,
666		},
667		{
668			name: "Assigning select to nonconfigurable string",
669			bp: `
670			my_module_type {
671				name: "foo",
672				my_nonconfigurable_string: select(arch(), {
673					"x86_64": "x86!",
674					default: "unknown!",
675				}),
676			}
677			`,
678			expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`,
679		},
680		{
681			name: "Assigning appended selects to nonconfigurable string",
682			bp: `
683			my_module_type {
684				name: "foo",
685				my_nonconfigurable_string: select(arch(), {
686					"x86_64": "x86!",
687					default: "unknown!",
688				}) + select(os(), {
689					"darwin": "_darwin!",
690					default: "unknown!",
691				}),
692			}
693			`,
694			expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`,
695		},
696		{
697			name: "Assigning select to nonconfigurable string list",
698			bp: `
699			my_module_type {
700				name: "foo",
701				my_nonconfigurable_string_list: select(arch(), {
702					"x86_64": ["foo", "bar"],
703					default: ["baz", "qux"],
704				}),
705			}
706			`,
707			expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string_list"`,
708		},
709		{
710			name: "Select in variable",
711			bp: `
712			my_second_variable = ["after.cpp"]
713			my_variable = select(soong_config_variable("my_namespace", "my_variable"), {
714				"a": ["a.cpp"],
715				"b": ["b.cpp"],
716				default: ["c.cpp"],
717			}) + my_second_variable
718			my_module_type {
719				name: "foo",
720				my_string_list: ["before.cpp"] + my_variable,
721			}
722			`,
723			provider: selectsTestProvider{
724				my_string_list: &[]string{"before.cpp", "a.cpp", "after.cpp"},
725			},
726			vendorVars: map[string]map[string]string{
727				"my_namespace": {
728					"my_variable": "a",
729				},
730			},
731		},
732		{
733			name: "Soong config value variable on configurable property",
734			bp: `
735			soong_config_module_type {
736				name: "soong_config_my_module_type",
737				module_type: "my_module_type",
738				config_namespace: "my_namespace",
739				value_variables: ["my_variable"],
740				properties: ["my_string", "my_string_list"],
741			}
742
743			soong_config_my_module_type {
744				name: "foo",
745				my_string_list: ["before.cpp"],
746				soong_config_variables: {
747					my_variable: {
748						my_string_list: ["after_%s.cpp"],
749						my_string: "%s.cpp",
750					},
751				},
752			}
753			`,
754			provider: selectsTestProvider{
755				my_string:      proptools.StringPtr("foo.cpp"),
756				my_string_list: &[]string{"before.cpp", "after_foo.cpp"},
757			},
758			vendorVars: map[string]map[string]string{
759				"my_namespace": {
760					"my_variable": "foo",
761				},
762			},
763		},
764		{
765			name: "Property appending with variable",
766			bp: `
767			my_variable = ["b.cpp"]
768			my_module_type {
769				name: "foo",
770				my_string_list: ["a.cpp"] + my_variable + select(soong_config_variable("my_namespace", "my_variable"), {
771					"a": ["a.cpp"],
772					"b": ["b.cpp"],
773					default: ["c.cpp"],
774				}),
775			}
776			`,
777			provider: selectsTestProvider{
778				my_string_list: &[]string{"a.cpp", "b.cpp", "c.cpp"},
779			},
780		},
781		{
782			name: "Test AppendSimpleValue",
783			bp: `
784			my_module_type {
785				name: "foo",
786				my_string_list: ["a.cpp"] + select(soong_config_variable("my_namespace", "my_variable"), {
787					"a": ["a.cpp"],
788					"b": ["b.cpp"],
789					default: ["c.cpp"],
790				}),
791			}
792			`,
793			vendorVars: map[string]map[string]string{
794				"selects_test": {
795					"append_to_string_list": "foo.cpp",
796				},
797			},
798			provider: selectsTestProvider{
799				my_string_list: &[]string{"a.cpp", "c.cpp", "foo.cpp"},
800			},
801		},
802	}
803
804	for _, tc := range testCases {
805		t.Run(tc.name, func(t *testing.T) {
806			fixtures := GroupFixturePreparers(
807				PrepareForTestWithDefaults,
808				PrepareForTestWithArchMutator,
809				PrepareForTestWithSoongConfigModuleBuildComponents,
810				FixtureRegisterWithContext(func(ctx RegistrationContext) {
811					ctx.RegisterModuleType("my_module_type", newSelectsMockModule)
812					ctx.RegisterModuleType("my_defaults", newSelectsMockModuleDefaults)
813				}),
814				FixtureModifyProductVariables(func(variables FixtureProductVariables) {
815					variables.VendorVars = tc.vendorVars
816				}),
817			)
818			if tc.expectedError != "" {
819				fixtures = fixtures.ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(tc.expectedError))
820			}
821			result := fixtures.RunTestWithBp(t, tc.bp)
822
823			if tc.expectedError == "" {
824				if len(tc.providers) == 0 {
825					tc.providers = map[string]selectsTestProvider{
826						"foo": tc.provider,
827					}
828				}
829
830				for moduleName := range tc.providers {
831					expected := tc.providers[moduleName]
832					m := result.ModuleForTests(moduleName, "android_arm64_armv8-a")
833					p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
834					if !reflect.DeepEqual(p, expected) {
835						t.Errorf("Expected:\n  %q\ngot:\n  %q", expected.String(), p.String())
836					}
837				}
838			}
839		})
840	}
841}
842
843type selectsTestProvider struct {
844	my_bool                        *bool
845	my_string                      *string
846	my_string_list                 *[]string
847	my_paths                       *[]string
848	replacing_string_list          *[]string
849	my_nonconfigurable_bool        *bool
850	my_nonconfigurable_string      *string
851	my_nonconfigurable_string_list []string
852}
853
854func (p *selectsTestProvider) String() string {
855	myBoolStr := "nil"
856	if p.my_bool != nil {
857		myBoolStr = fmt.Sprintf("%t", *p.my_bool)
858	}
859	myStringStr := "nil"
860	if p.my_string != nil {
861		myStringStr = *p.my_string
862	}
863	myNonconfigurableStringStr := "nil"
864	if p.my_nonconfigurable_string != nil {
865		myNonconfigurableStringStr = *p.my_nonconfigurable_string
866	}
867	return fmt.Sprintf(`selectsTestProvider {
868	my_bool: %v,
869	my_string: %s,
870    my_string_list: %s,
871    my_paths: %s,
872	replacing_string_list %s,
873	my_nonconfigurable_bool: %v,
874	my_nonconfigurable_string: %s,
875	my_nonconfigurable_string_list: %s,
876}`,
877		myBoolStr,
878		myStringStr,
879		p.my_string_list,
880		p.my_paths,
881		p.replacing_string_list,
882		p.my_nonconfigurable_bool,
883		myNonconfigurableStringStr,
884		p.my_nonconfigurable_string_list,
885	)
886}
887
888var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]()
889
890type selectsMockModuleProperties struct {
891	My_bool                        proptools.Configurable[bool]
892	My_string                      proptools.Configurable[string]
893	My_string_list                 proptools.Configurable[[]string]
894	My_paths                       proptools.Configurable[[]string] `android:"path"`
895	Replacing_string_list          proptools.Configurable[[]string] `android:"replace_instead_of_append,arch_variant"`
896	My_nonconfigurable_bool        *bool
897	My_nonconfigurable_string      *string
898	My_nonconfigurable_string_list []string
899}
900
901type selectsMockModule struct {
902	ModuleBase
903	DefaultableModuleBase
904	properties selectsMockModuleProperties
905}
906
907func optionalToPtr[T any](o proptools.ConfigurableOptional[T]) *T {
908	if o.IsEmpty() {
909		return nil
910	}
911	x := o.Get()
912	return &x
913}
914
915func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) {
916	toAppend := ctx.Config().VendorConfig("selects_test").String("append_to_string_list")
917	if toAppend != "" {
918		p.properties.My_string_list.AppendSimpleValue([]string{toAppend})
919	}
920	SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{
921		my_bool:                        optionalToPtr(p.properties.My_bool.Get(ctx)),
922		my_string:                      optionalToPtr(p.properties.My_string.Get(ctx)),
923		my_string_list:                 optionalToPtr(p.properties.My_string_list.Get(ctx)),
924		my_paths:                       optionalToPtr(p.properties.My_paths.Get(ctx)),
925		replacing_string_list:          optionalToPtr(p.properties.Replacing_string_list.Get(ctx)),
926		my_nonconfigurable_bool:        p.properties.My_nonconfigurable_bool,
927		my_nonconfigurable_string:      p.properties.My_nonconfigurable_string,
928		my_nonconfigurable_string_list: p.properties.My_nonconfigurable_string_list,
929	})
930}
931
932func newSelectsMockModule() Module {
933	m := &selectsMockModule{}
934	m.AddProperties(&m.properties)
935	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibFirst)
936	InitDefaultableModule(m)
937	return m
938}
939
940type selectsMockModuleDefaults struct {
941	ModuleBase
942	DefaultsModuleBase
943}
944
945func (d *selectsMockModuleDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
946}
947
948func newSelectsMockModuleDefaults() Module {
949	module := &selectsMockModuleDefaults{}
950
951	module.AddProperties(
952		&selectsMockModuleProperties{},
953	)
954
955	InitDefaultsModule(module)
956
957	return module
958}
959