blob: d76794ca540739ced8a3408cda98e4908ed451cc [file] [log] [blame]
Colin Cross9d34f352019-11-22 16:03:51 -08001// Copyright 2020 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 soongconfig
16
17import (
18 "reflect"
19 "testing"
Liz Kammerfe8853d2020-12-16 09:34:33 -080020
21 "github.com/google/blueprint/proptools"
Colin Cross9d34f352019-11-22 16:03:51 -080022)
23
24func Test_CanonicalizeToProperty(t *testing.T) {
25 tests := []struct {
26 name string
27 arg string
28 want string
29 }{
30 {
31 name: "lowercase",
32 arg: "board",
33 want: "board",
34 },
35 {
36 name: "uppercase",
37 arg: "BOARD",
38 want: "BOARD",
39 },
40 {
41 name: "numbers",
42 arg: "BOARD123",
43 want: "BOARD123",
44 },
45 {
46 name: "underscore",
47 arg: "TARGET_BOARD",
48 want: "TARGET_BOARD",
49 },
50 {
51 name: "dash",
52 arg: "TARGET-BOARD",
53 want: "TARGET_BOARD",
54 },
55 {
56 name: "unicode",
57 arg: "boardĪ»",
58 want: "board_",
59 },
60 }
61 for _, tt := range tests {
62 t.Run(tt.name, func(t *testing.T) {
63 if got := CanonicalizeToProperty(tt.arg); got != tt.want {
64 t.Errorf("canonicalizeToProperty() = %v, want %v", got, tt.want)
65 }
66 })
67 }
68}
69
70func Test_typeForPropertyFromPropertyStruct(t *testing.T) {
71 tests := []struct {
72 name string
73 ps interface{}
74 property string
75 want string
76 }{
77 {
78 name: "string",
79 ps: struct {
80 A string
81 }{},
82 property: "a",
83 want: "string",
84 },
85 {
86 name: "list",
87 ps: struct {
88 A []string
89 }{},
90 property: "a",
91 want: "[]string",
92 },
93 {
94 name: "missing",
95 ps: struct {
96 A []string
97 }{},
98 property: "b",
99 want: "",
100 },
101 {
102 name: "nested",
103 ps: struct {
104 A struct {
105 B string
106 }
107 }{},
108 property: "a.b",
109 want: "string",
110 },
111 {
112 name: "missing nested",
113 ps: struct {
114 A struct {
115 B string
116 }
117 }{},
118 property: "a.c",
119 want: "",
120 },
121 {
122 name: "not a struct",
123 ps: struct {
124 A string
125 }{},
126 property: "a.b",
127 want: "",
128 },
129 {
130 name: "nested pointer",
131 ps: struct {
132 A *struct {
133 B string
134 }
135 }{},
136 property: "a.b",
137 want: "string",
138 },
139 {
140 name: "nested interface",
141 ps: struct {
142 A interface{}
143 }{
144 A: struct {
145 B string
146 }{},
147 },
148 property: "a.b",
149 want: "string",
150 },
151 {
152 name: "nested interface pointer",
153 ps: struct {
154 A interface{}
155 }{
156 A: &struct {
157 B string
158 }{},
159 },
160 property: "a.b",
161 want: "string",
162 },
163 {
164 name: "nested interface nil pointer",
165 ps: struct {
166 A interface{}
167 }{
168 A: (*struct {
169 B string
170 })(nil),
171 },
172 property: "a.b",
173 want: "string",
174 },
175 }
176 for _, tt := range tests {
177 t.Run(tt.name, func(t *testing.T) {
178 typ := typeForPropertyFromPropertyStruct(tt.ps, tt.property)
179 got := ""
180 if typ != nil {
181 got = typ.String()
182 }
183 if got != tt.want {
184 t.Errorf("typeForPropertyFromPropertyStruct() = %v, want %v", got, tt.want)
185 }
186 })
187 }
188}
189
190func Test_createAffectablePropertiesType(t *testing.T) {
Colin Cross9d34f352019-11-22 16:03:51 -0800191 tests := []struct {
192 name string
193 affectableProperties []string
194 factoryProps interface{}
195 want string
196 }{
197 {
198 name: "string",
199 affectableProperties: []string{"cflags"},
200 factoryProps: struct {
201 Cflags string
202 }{},
203 want: "*struct { Cflags string }",
204 },
205 {
206 name: "list",
207 affectableProperties: []string{"cflags"},
208 factoryProps: struct {
209 Cflags []string
210 }{},
211 want: "*struct { Cflags []string }",
212 },
213 {
214 name: "string pointer",
215 affectableProperties: []string{"cflags"},
216 factoryProps: struct {
217 Cflags *string
218 }{},
219 want: "*struct { Cflags *string }",
220 },
221 {
222 name: "subset",
223 affectableProperties: []string{"cflags"},
224 factoryProps: struct {
225 Cflags string
226 Ldflags string
227 }{},
228 want: "*struct { Cflags string }",
229 },
230 {
231 name: "none",
232 affectableProperties: []string{"cflags"},
233 factoryProps: struct {
234 Ldflags string
235 }{},
236 want: "",
237 },
Colin Cross997f27a2021-03-05 17:25:41 -0800238 {
239 name: "nested",
240 affectableProperties: []string{"multilib.lib32.cflags"},
241 factoryProps: struct {
242 Multilib struct {
243 Lib32 struct {
244 Cflags string
245 }
246 }
247 }{},
248 want: "*struct { Multilib struct { Lib32 struct { Cflags string } } }",
249 },
250 {
251 name: "complex",
252 affectableProperties: []string{
253 "cflags",
254 "multilib.lib32.cflags",
255 "multilib.lib32.ldflags",
256 "multilib.lib64.cflags",
257 "multilib.lib64.ldflags",
258 "zflags",
259 },
260 factoryProps: struct {
261 Cflags string
262 Multilib struct {
263 Lib32 struct {
264 Cflags string
265 Ldflags string
266 }
267 Lib64 struct {
268 Cflags string
269 Ldflags string
270 }
271 }
272 Zflags string
273 }{},
274 want: "*struct { Cflags string; Multilib struct { Lib32 struct { Cflags string; Ldflags string }; Lib64 struct { Cflags string; Ldflags string } }; Zflags string }",
275 },
Colin Cross9d34f352019-11-22 16:03:51 -0800276 }
277 for _, tt := range tests {
278 t.Run(tt.name, func(t *testing.T) {
279 typ := createAffectablePropertiesType(tt.affectableProperties, []interface{}{tt.factoryProps})
280 got := ""
281 if typ != nil {
282 got = typ.String()
283 }
284 if !reflect.DeepEqual(got, tt.want) {
285 t.Errorf("createAffectablePropertiesType() = %v, want %v", got, tt.want)
286 }
287 })
288 }
289}
Liz Kammerfe8853d2020-12-16 09:34:33 -0800290
291type properties struct {
292 A *string
293 B bool
Inseob Kim02c86182024-04-05 17:52:06 +0900294 C []string
Liz Kammerfe8853d2020-12-16 09:34:33 -0800295}
Liz Kammer432bd592020-12-16 12:42:02 -0800296
Inseob Kim02c86182024-04-05 17:52:06 +0900297type varProps struct {
Liz Kammer432bd592020-12-16 12:42:02 -0800298 A *string
299 B bool
Inseob Kim02c86182024-04-05 17:52:06 +0900300 C []string
Liz Kammer432bd592020-12-16 12:42:02 -0800301 Conditions_default *properties
Liz Kammerfe8853d2020-12-16 09:34:33 -0800302}
303
Cole Fausta03ac3a2024-01-12 12:12:26 -0800304type boolSoongConfigVars struct {
Liz Kammer432bd592020-12-16 12:42:02 -0800305 Bool_var interface{}
Liz Kammerfe8853d2020-12-16 09:34:33 -0800306}
307
Cole Faustb0a91332022-11-01 17:10:23 +0000308type stringSoongConfigVars struct {
309 String_var interface{}
310}
311
Cole Fausta03ac3a2024-01-12 12:12:26 -0800312type valueSoongConfigVars struct {
313 My_value_var interface{}
314}
315
Inseob Kim02c86182024-04-05 17:52:06 +0900316type listProperties struct {
317 C []string
318}
319
320type listVarProps struct {
321 C []string
322 Conditions_default *listProperties
323}
324
325type listSoongConfigVars struct {
326 List_var interface{}
327}
328
Cole Fausta03ac3a2024-01-12 12:12:26 -0800329func Test_PropertiesToApply_Bool(t *testing.T) {
Liz Kammer432bd592020-12-16 12:42:02 -0800330 mt, _ := newModuleType(&ModuleTypeProperties{
331 Module_type: "foo",
332 Config_namespace: "bar",
333 Bool_variables: []string{"bool_var"},
334 Properties: []string{"a", "b"},
335 })
336 boolVarPositive := &properties{
337 A: proptools.StringPtr("A"),
338 B: true,
Liz Kammerfe8853d2020-12-16 09:34:33 -0800339 }
Liz Kammer432bd592020-12-16 12:42:02 -0800340 conditionsDefault := &properties{
341 A: proptools.StringPtr("default"),
342 B: false,
343 }
344 actualProps := &struct {
Cole Fausta03ac3a2024-01-12 12:12:26 -0800345 Soong_config_variables boolSoongConfigVars
Liz Kammer432bd592020-12-16 12:42:02 -0800346 }{
Cole Fausta03ac3a2024-01-12 12:12:26 -0800347 Soong_config_variables: boolSoongConfigVars{
Inseob Kim02c86182024-04-05 17:52:06 +0900348 Bool_var: &varProps{
Liz Kammer432bd592020-12-16 12:42:02 -0800349 A: boolVarPositive.A,
350 B: boolVarPositive.B,
351 Conditions_default: conditionsDefault,
Liz Kammerfe8853d2020-12-16 09:34:33 -0800352 },
353 },
354 }
Liz Kammer432bd592020-12-16 12:42:02 -0800355 props := reflect.ValueOf(actualProps)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800356
357 testCases := []struct {
Liz Kammer432bd592020-12-16 12:42:02 -0800358 name string
Liz Kammerfe8853d2020-12-16 09:34:33 -0800359 config SoongConfig
360 wantProps []interface{}
361 }{
362 {
Liz Kammer432bd592020-12-16 12:42:02 -0800363 name: "no_vendor_config",
364 config: Config(map[string]string{}),
365 wantProps: []interface{}{conditionsDefault},
Liz Kammerfe8853d2020-12-16 09:34:33 -0800366 },
367 {
Liz Kammer432bd592020-12-16 12:42:02 -0800368 name: "vendor_config_false",
369 config: Config(map[string]string{"bool_var": "n"}),
370 wantProps: []interface{}{conditionsDefault},
371 },
372 {
373 name: "bool_var_true",
Liz Kammerfe8853d2020-12-16 09:34:33 -0800374 config: Config(map[string]string{"bool_var": "y"}),
Liz Kammer432bd592020-12-16 12:42:02 -0800375 wantProps: []interface{}{boolVarPositive},
Liz Kammerfe8853d2020-12-16 09:34:33 -0800376 },
377 }
378
379 for _, tc := range testCases {
Liz Kammer432bd592020-12-16 12:42:02 -0800380 gotProps, err := PropertiesToApply(mt, props, tc.config)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800381 if err != nil {
Liz Kammer432bd592020-12-16 12:42:02 -0800382 t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800383 }
384
385 if !reflect.DeepEqual(gotProps, tc.wantProps) {
Liz Kammer432bd592020-12-16 12:42:02 -0800386 t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800387 }
388 }
389}
Jingwen Chen01812022021-11-19 14:29:43 +0000390
Inseob Kim02c86182024-04-05 17:52:06 +0900391func Test_PropertiesToApply_List(t *testing.T) {
392 mt, _ := newModuleType(&ModuleTypeProperties{
393 Module_type: "foo",
394 Config_namespace: "bar",
395 List_variables: []string{"my_list_var"},
396 Properties: []string{"c"},
397 })
398 conditionsDefault := &listProperties{
399 C: []string{"default"},
400 }
401 actualProps := &struct {
402 Soong_config_variables listSoongConfigVars
403 }{
404 Soong_config_variables: listSoongConfigVars{
405 List_var: &listVarProps{
406 C: []string{"A=%s", "B=%s"},
407 Conditions_default: conditionsDefault,
408 },
409 },
410 }
411 props := reflect.ValueOf(actualProps)
412
413 testCases := []struct {
414 name string
415 config SoongConfig
416 wantProps []interface{}
417 }{
418 {
419 name: "no_vendor_config",
420 config: Config(map[string]string{}),
421 wantProps: []interface{}{conditionsDefault},
422 },
423 {
424 name: "value_var_set",
425 config: Config(map[string]string{"my_list_var": "hello there"}),
426 wantProps: []interface{}{&listProperties{
427 C: []string{"A=hello", "A=there", "B=hello", "B=there"},
428 }},
429 },
430 }
431
432 for _, tc := range testCases {
433 gotProps, err := PropertiesToApply(mt, props, tc.config)
434 if err != nil {
435 t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
436 }
437
438 if !reflect.DeepEqual(gotProps, tc.wantProps) {
439 t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
440 }
441 }
442}
443
Cole Fausta03ac3a2024-01-12 12:12:26 -0800444func Test_PropertiesToApply_Value(t *testing.T) {
445 mt, _ := newModuleType(&ModuleTypeProperties{
446 Module_type: "foo",
447 Config_namespace: "bar",
448 Value_variables: []string{"my_value_var"},
449 Properties: []string{"a", "b"},
450 })
451 conditionsDefault := &properties{
452 A: proptools.StringPtr("default"),
453 B: false,
454 }
455 actualProps := &struct {
456 Soong_config_variables valueSoongConfigVars
457 }{
458 Soong_config_variables: valueSoongConfigVars{
Inseob Kim02c86182024-04-05 17:52:06 +0900459 My_value_var: &varProps{
Cole Fausta03ac3a2024-01-12 12:12:26 -0800460 A: proptools.StringPtr("A=%s"),
461 B: true,
462 Conditions_default: conditionsDefault,
463 },
464 },
465 }
466 props := reflect.ValueOf(actualProps)
467
468 testCases := []struct {
469 name string
470 config SoongConfig
471 wantProps []interface{}
472 }{
473 {
474 name: "no_vendor_config",
475 config: Config(map[string]string{}),
476 wantProps: []interface{}{conditionsDefault},
477 },
478 {
479 name: "value_var_set",
480 config: Config(map[string]string{"my_value_var": "Hello"}),
481 wantProps: []interface{}{&properties{
482 A: proptools.StringPtr("A=Hello"),
483 B: true,
484 }},
485 },
486 }
487
488 for _, tc := range testCases {
489 gotProps, err := PropertiesToApply(mt, props, tc.config)
490 if err != nil {
491 t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
492 }
493
494 if !reflect.DeepEqual(gotProps, tc.wantProps) {
495 t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
496 }
497 }
498}
499
Cole Faust1da0b202024-02-21 10:50:33 -0800500func Test_PropertiesToApply_Value_Nested(t *testing.T) {
501 mt, _ := newModuleType(&ModuleTypeProperties{
502 Module_type: "foo",
503 Config_namespace: "bar",
504 Value_variables: []string{"my_value_var"},
505 Properties: []string{"a.b"},
506 })
507 type properties struct {
508 A struct {
509 B string
510 }
511 }
512 conditionsDefault := &properties{
513 A: struct{ B string }{
514 B: "default",
515 },
516 }
517 type valueVarProps struct {
518 A struct {
519 B string
520 }
521 Conditions_default *properties
522 }
523 actualProps := &struct {
524 Soong_config_variables valueSoongConfigVars
525 }{
526 Soong_config_variables: valueSoongConfigVars{
527 My_value_var: &valueVarProps{
528 A: struct{ B string }{
529 B: "A.B=%s",
530 },
531 Conditions_default: conditionsDefault,
532 },
533 },
534 }
535 props := reflect.ValueOf(actualProps)
536
537 testCases := []struct {
538 name string
539 config SoongConfig
540 wantProps []interface{}
541 }{
542 {
543 name: "no_vendor_config",
544 config: Config(map[string]string{}),
545 wantProps: []interface{}{conditionsDefault},
546 },
547 {
548 name: "value_var_set",
549 config: Config(map[string]string{"my_value_var": "Hello"}),
550 wantProps: []interface{}{&properties{
551 A: struct{ B string }{
552 B: "A.B=Hello",
553 },
554 }},
555 },
556 }
557
558 for _, tc := range testCases {
559 gotProps, err := PropertiesToApply(mt, props, tc.config)
560 if err != nil {
561 t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
562 }
563
564 if !reflect.DeepEqual(gotProps, tc.wantProps) {
565 t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
566 }
567 }
568}
569
Cole Faustb0a91332022-11-01 17:10:23 +0000570func Test_PropertiesToApply_String_Error(t *testing.T) {
571 mt, _ := newModuleType(&ModuleTypeProperties{
572 Module_type: "foo",
573 Config_namespace: "bar",
574 Variables: []string{"string_var"},
575 Properties: []string{"a", "b"},
576 })
577 mt.Variables = append(mt.Variables, &stringVariable{
578 baseVariable: baseVariable{
579 variable: "string_var",
580 },
581 values: []string{"a", "b", "c"},
582 })
583 stringVarPositive := &properties{
584 A: proptools.StringPtr("A"),
585 B: true,
586 }
587 conditionsDefault := &properties{
588 A: proptools.StringPtr("default"),
589 B: false,
590 }
591 actualProps := &struct {
592 Soong_config_variables stringSoongConfigVars
593 }{
594 Soong_config_variables: stringSoongConfigVars{
Inseob Kim02c86182024-04-05 17:52:06 +0900595 String_var: &varProps{
Cole Faustb0a91332022-11-01 17:10:23 +0000596 A: stringVarPositive.A,
597 B: stringVarPositive.B,
598 Conditions_default: conditionsDefault,
599 },
600 },
601 }
602 props := reflect.ValueOf(actualProps)
603
604 _, err := PropertiesToApply(mt, props, Config(map[string]string{
605 "string_var": "x",
606 }))
607 expected := `Soong config property "string_var" must be one of [a b c], found "x"`
608 if err == nil {
609 t.Fatalf("Expected an error, got nil")
610 } else if err.Error() != expected {
611 t.Fatalf("Error message was not correct, expected %q, got %q", expected, err.Error())
612 }
613}