blob: a5fa349382f079a00f387aa245a7d7cdc3a8a3fa [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
294}
Liz Kammer432bd592020-12-16 12:42:02 -0800295
296type boolVarProps struct {
297 A *string
298 B bool
299 Conditions_default *properties
Liz Kammerfe8853d2020-12-16 09:34:33 -0800300}
301
Liz Kammer432bd592020-12-16 12:42:02 -0800302type soongConfigVars struct {
303 Bool_var interface{}
Liz Kammerfe8853d2020-12-16 09:34:33 -0800304}
305
Cole Faustb0a91332022-11-01 17:10:23 +0000306type stringSoongConfigVars struct {
307 String_var interface{}
308}
309
Liz Kammerfe8853d2020-12-16 09:34:33 -0800310func Test_PropertiesToApply(t *testing.T) {
Liz Kammer432bd592020-12-16 12:42:02 -0800311 mt, _ := newModuleType(&ModuleTypeProperties{
312 Module_type: "foo",
313 Config_namespace: "bar",
314 Bool_variables: []string{"bool_var"},
315 Properties: []string{"a", "b"},
316 })
317 boolVarPositive := &properties{
318 A: proptools.StringPtr("A"),
319 B: true,
Liz Kammerfe8853d2020-12-16 09:34:33 -0800320 }
Liz Kammer432bd592020-12-16 12:42:02 -0800321 conditionsDefault := &properties{
322 A: proptools.StringPtr("default"),
323 B: false,
324 }
325 actualProps := &struct {
326 Soong_config_variables soongConfigVars
327 }{
328 Soong_config_variables: soongConfigVars{
329 Bool_var: &boolVarProps{
330 A: boolVarPositive.A,
331 B: boolVarPositive.B,
332 Conditions_default: conditionsDefault,
Liz Kammerfe8853d2020-12-16 09:34:33 -0800333 },
334 },
335 }
Liz Kammer432bd592020-12-16 12:42:02 -0800336 props := reflect.ValueOf(actualProps)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800337
338 testCases := []struct {
Liz Kammer432bd592020-12-16 12:42:02 -0800339 name string
Liz Kammerfe8853d2020-12-16 09:34:33 -0800340 config SoongConfig
341 wantProps []interface{}
342 }{
343 {
Liz Kammer432bd592020-12-16 12:42:02 -0800344 name: "no_vendor_config",
345 config: Config(map[string]string{}),
346 wantProps: []interface{}{conditionsDefault},
Liz Kammerfe8853d2020-12-16 09:34:33 -0800347 },
348 {
Liz Kammer432bd592020-12-16 12:42:02 -0800349 name: "vendor_config_false",
350 config: Config(map[string]string{"bool_var": "n"}),
351 wantProps: []interface{}{conditionsDefault},
352 },
353 {
354 name: "bool_var_true",
Liz Kammerfe8853d2020-12-16 09:34:33 -0800355 config: Config(map[string]string{"bool_var": "y"}),
Liz Kammer432bd592020-12-16 12:42:02 -0800356 wantProps: []interface{}{boolVarPositive},
Liz Kammerfe8853d2020-12-16 09:34:33 -0800357 },
358 }
359
360 for _, tc := range testCases {
Liz Kammer432bd592020-12-16 12:42:02 -0800361 gotProps, err := PropertiesToApply(mt, props, tc.config)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800362 if err != nil {
Liz Kammer432bd592020-12-16 12:42:02 -0800363 t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800364 }
365
366 if !reflect.DeepEqual(gotProps, tc.wantProps) {
Liz Kammer432bd592020-12-16 12:42:02 -0800367 t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
Liz Kammerfe8853d2020-12-16 09:34:33 -0800368 }
369 }
370}
Jingwen Chen01812022021-11-19 14:29:43 +0000371
Cole Faustb0a91332022-11-01 17:10:23 +0000372func Test_PropertiesToApply_String_Error(t *testing.T) {
373 mt, _ := newModuleType(&ModuleTypeProperties{
374 Module_type: "foo",
375 Config_namespace: "bar",
376 Variables: []string{"string_var"},
377 Properties: []string{"a", "b"},
378 })
379 mt.Variables = append(mt.Variables, &stringVariable{
380 baseVariable: baseVariable{
381 variable: "string_var",
382 },
383 values: []string{"a", "b", "c"},
384 })
385 stringVarPositive := &properties{
386 A: proptools.StringPtr("A"),
387 B: true,
388 }
389 conditionsDefault := &properties{
390 A: proptools.StringPtr("default"),
391 B: false,
392 }
393 actualProps := &struct {
394 Soong_config_variables stringSoongConfigVars
395 }{
396 Soong_config_variables: stringSoongConfigVars{
397 String_var: &boolVarProps{
398 A: stringVarPositive.A,
399 B: stringVarPositive.B,
400 Conditions_default: conditionsDefault,
401 },
402 },
403 }
404 props := reflect.ValueOf(actualProps)
405
406 _, err := PropertiesToApply(mt, props, Config(map[string]string{
407 "string_var": "x",
408 }))
409 expected := `Soong config property "string_var" must be one of [a b c], found "x"`
410 if err == nil {
411 t.Fatalf("Expected an error, got nil")
412 } else if err.Error() != expected {
413 t.Fatalf("Error message was not correct, expected %q, got %q", expected, err.Error())
414 }
415}
416
Liz Kammer8103dc42023-03-06 09:02:38 -0500417func Test_Bp2BuildSoongConfigDefinitionsAddVars(t *testing.T) {
418 testCases := []struct {
419 desc string
420 defs []*SoongConfigDefinition
421 expected Bp2BuildSoongConfigDefinitions
422 }{
423 {
424 desc: "non-overlapping",
425 defs: []*SoongConfigDefinition{
426 &SoongConfigDefinition{
427 ModuleTypes: map[string]*ModuleType{
428 "a": &ModuleType{
429 ConfigNamespace: "foo",
430 Variables: []soongConfigVariable{
431 &stringVariable{
432 baseVariable: baseVariable{"string_var"},
433 values: []string{"a", "b", "c"},
434 },
435 },
436 },
437 },
438 },
439 &SoongConfigDefinition{
440 ModuleTypes: map[string]*ModuleType{
441 "b": &ModuleType{
442 ConfigNamespace: "foo",
443 Variables: []soongConfigVariable{
444 &stringVariable{
445 baseVariable: baseVariable{"string_var"},
446 values: []string{"a", "b", "c"},
447 },
448 &boolVariable{baseVariable: baseVariable{"bool_var"}},
449 &valueVariable{baseVariable: baseVariable{"variable_var"}},
450 },
451 },
452 },
453 },
454 },
455 expected: Bp2BuildSoongConfigDefinitions{
456 StringVars: map[string]map[string]bool{
457 "foo__string_var": map[string]bool{"a": true, "b": true, "c": true},
458 },
459 BoolVars: map[string]bool{"foo__bool_var": true},
460 ValueVars: map[string]bool{"foo__variable_var": true},
461 },
462 },
463 {
464 desc: "overlapping",
465 defs: []*SoongConfigDefinition{
466 &SoongConfigDefinition{
467 ModuleTypes: map[string]*ModuleType{
468 "a": &ModuleType{
469 ConfigNamespace: "foo",
470 Variables: []soongConfigVariable{
471 &stringVariable{
472 baseVariable: baseVariable{"string_var"},
473 values: []string{"a", "b", "c"},
474 },
475 },
476 },
477 },
478 },
479 &SoongConfigDefinition{
480 ModuleTypes: map[string]*ModuleType{
481 "b": &ModuleType{
482 ConfigNamespace: "foo",
483 Variables: []soongConfigVariable{
484 &stringVariable{
485 baseVariable: baseVariable{"string_var"},
486 values: []string{"b", "c", "d"},
487 },
488 &boolVariable{baseVariable: baseVariable{"bool_var"}},
489 &valueVariable{baseVariable: baseVariable{"variable_var"}},
490 },
491 },
492 },
493 },
494 },
495 expected: Bp2BuildSoongConfigDefinitions{
496 StringVars: map[string]map[string]bool{
497 "foo__string_var": map[string]bool{"a": true, "b": true, "c": true, "d": true},
498 },
499 BoolVars: map[string]bool{"foo__bool_var": true},
500 ValueVars: map[string]bool{"foo__variable_var": true},
501 },
502 },
503 }
504
505 for _, tc := range testCases {
506 t.Run(tc.desc, func(t *testing.T) {
507 actual := &Bp2BuildSoongConfigDefinitions{}
508 for _, d := range tc.defs {
509 func(def *SoongConfigDefinition) {
510 actual.AddVars(def)
511 }(d)
512 }
513 if !reflect.DeepEqual(*actual, tc.expected) {
514 t.Errorf("Expected %#v, got %#v", tc.expected, *actual)
515 }
516 })
517 }
518
519}
520
Jingwen Chen01812022021-11-19 14:29:43 +0000521func Test_Bp2BuildSoongConfigDefinitions(t *testing.T) {
522 testCases := []struct {
Liz Kammer72beb342022-02-03 08:42:10 -0500523 desc string
Jingwen Chen01812022021-11-19 14:29:43 +0000524 defs Bp2BuildSoongConfigDefinitions
525 expected string
526 }{
527 {
Liz Kammer72beb342022-02-03 08:42:10 -0500528 desc: "all empty",
Jingwen Chen01812022021-11-19 14:29:43 +0000529 defs: Bp2BuildSoongConfigDefinitions{},
Liz Kammer72beb342022-02-03 08:42:10 -0500530 expected: `soong_config_bool_variables = {}
Jingwen Chen01812022021-11-19 14:29:43 +0000531
Liz Kammer72beb342022-02-03 08:42:10 -0500532soong_config_value_variables = {}
Jingwen Chen01812022021-11-19 14:29:43 +0000533
Liz Kammer72beb342022-02-03 08:42:10 -0500534soong_config_string_variables = {}`}, {
535 desc: "only bool",
Jingwen Chen01812022021-11-19 14:29:43 +0000536 defs: Bp2BuildSoongConfigDefinitions{
537 BoolVars: map[string]bool{
538 "bool_var": true,
539 },
540 },
541 expected: `soong_config_bool_variables = {
542 "bool_var": True,
543}
544
Liz Kammer72beb342022-02-03 08:42:10 -0500545soong_config_value_variables = {}
Jingwen Chen01812022021-11-19 14:29:43 +0000546
Liz Kammer72beb342022-02-03 08:42:10 -0500547soong_config_string_variables = {}`}, {
548 desc: "only value vars",
Jingwen Chen01812022021-11-19 14:29:43 +0000549 defs: Bp2BuildSoongConfigDefinitions{
550 ValueVars: map[string]bool{
551 "value_var": true,
552 },
553 },
Liz Kammer72beb342022-02-03 08:42:10 -0500554 expected: `soong_config_bool_variables = {}
Jingwen Chen01812022021-11-19 14:29:43 +0000555
556soong_config_value_variables = {
557 "value_var": True,
558}
559
Liz Kammer72beb342022-02-03 08:42:10 -0500560soong_config_string_variables = {}`}, {
561 desc: "only string vars",
Jingwen Chen01812022021-11-19 14:29:43 +0000562 defs: Bp2BuildSoongConfigDefinitions{
Liz Kammer8103dc42023-03-06 09:02:38 -0500563 StringVars: map[string]map[string]bool{
564 "string_var": map[string]bool{
565 "choice1": true,
566 "choice2": true,
567 "choice3": true,
Jingwen Chen01812022021-11-19 14:29:43 +0000568 },
569 },
570 },
Liz Kammer72beb342022-02-03 08:42:10 -0500571 expected: `soong_config_bool_variables = {}
Jingwen Chen01812022021-11-19 14:29:43 +0000572
Liz Kammer72beb342022-02-03 08:42:10 -0500573soong_config_value_variables = {}
Jingwen Chen01812022021-11-19 14:29:43 +0000574
575soong_config_string_variables = {
576 "string_var": [
577 "choice1",
578 "choice2",
579 "choice3",
580 ],
581}`}, {
Liz Kammer72beb342022-02-03 08:42:10 -0500582 desc: "all vars",
Jingwen Chen01812022021-11-19 14:29:43 +0000583 defs: Bp2BuildSoongConfigDefinitions{
584 BoolVars: map[string]bool{
585 "bool_var_one": true,
586 },
587 ValueVars: map[string]bool{
588 "value_var_one": true,
589 "value_var_two": true,
590 },
Liz Kammer8103dc42023-03-06 09:02:38 -0500591 StringVars: map[string]map[string]bool{
592 "string_var_one": map[string]bool{
593 "choice1": true,
594 "choice2": true,
595 "choice3": true,
Jingwen Chen01812022021-11-19 14:29:43 +0000596 },
Liz Kammer8103dc42023-03-06 09:02:38 -0500597 "string_var_two": map[string]bool{
598 "foo": true,
599 "bar": true,
Jingwen Chen01812022021-11-19 14:29:43 +0000600 },
601 },
602 },
603 expected: `soong_config_bool_variables = {
604 "bool_var_one": True,
605}
606
607soong_config_value_variables = {
608 "value_var_one": True,
609 "value_var_two": True,
610}
611
612soong_config_string_variables = {
613 "string_var_one": [
614 "choice1",
615 "choice2",
616 "choice3",
617 ],
618 "string_var_two": [
Liz Kammer72beb342022-02-03 08:42:10 -0500619 "bar",
Liz Kammer8103dc42023-03-06 09:02:38 -0500620 "foo",
Jingwen Chen01812022021-11-19 14:29:43 +0000621 ],
622}`},
623 }
624 for _, test := range testCases {
Liz Kammer72beb342022-02-03 08:42:10 -0500625 t.Run(test.desc, func(t *testing.T) {
626 actual := test.defs.String()
627 if actual != test.expected {
628 t.Errorf("Expected:\n%s\nbut got:\n%s", test.expected, actual)
629 }
630 })
Jingwen Chen01812022021-11-19 14:29:43 +0000631 }
632}