blob: 7a7d6f3b8064bab44131faf237a4b42794f5c0de [file] [log] [blame]
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +00001// Copyright 2021 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 bazel
16
17import (
18 "reflect"
Liz Kammer57e2e7a2021-09-20 12:55:02 -040019 "strings"
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000020 "testing"
Liz Kammer57e2e7a2021-09-20 12:55:02 -040021
22 "github.com/google/blueprint/proptools"
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000023)
24
25func TestUniqueBazelLabels(t *testing.T) {
26 testCases := []struct {
27 originalLabels []Label
28 expectedUniqueLabels []Label
29 }{
30 {
31 originalLabels: []Label{
32 {Label: "a"},
33 {Label: "b"},
34 {Label: "a"},
35 {Label: "c"},
36 },
37 expectedUniqueLabels: []Label{
38 {Label: "a"},
39 {Label: "b"},
40 {Label: "c"},
41 },
42 },
43 }
44 for _, tc := range testCases {
Jingwen Chened9c17d2021-04-13 07:14:55 +000045 actualUniqueLabels := UniqueSortedBazelLabels(tc.originalLabels)
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000046 if !reflect.DeepEqual(tc.expectedUniqueLabels, actualUniqueLabels) {
47 t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabels, actualUniqueLabels)
48 }
49 }
50}
51
Rupert Shuttleworthb8151682021-04-06 20:06:21 +000052func TestSubtractStrings(t *testing.T) {
53 testCases := []struct {
54 haystack []string
55 needle []string
56 expectedResult []string
57 }{
58 {
59 haystack: []string{
60 "a",
61 "b",
62 "c",
63 },
64 needle: []string{
65 "a",
66 },
67 expectedResult: []string{
68 "b", "c",
69 },
70 },
71 }
72 for _, tc := range testCases {
73 actualResult := SubtractStrings(tc.haystack, tc.needle)
74 if !reflect.DeepEqual(tc.expectedResult, actualResult) {
75 t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
76 }
77 }
78}
79
80func TestSubtractBazelLabelList(t *testing.T) {
81 testCases := []struct {
82 haystack LabelList
83 needle LabelList
84 expectedResult LabelList
85 }{
86 {
87 haystack: LabelList{
88 Includes: []Label{
89 {Label: "a"},
90 {Label: "b"},
91 {Label: "c"},
92 },
93 Excludes: []Label{
94 {Label: "x"},
95 {Label: "y"},
96 {Label: "z"},
97 },
98 },
99 needle: LabelList{
100 Includes: []Label{
101 {Label: "a"},
102 },
103 Excludes: []Label{
104 {Label: "z"},
105 },
106 },
107 // NOTE: Excludes are intentionally not subtracted
108 expectedResult: LabelList{
109 Includes: []Label{
110 {Label: "b"},
111 {Label: "c"},
112 },
113 Excludes: []Label{
114 {Label: "x"},
115 {Label: "y"},
116 {Label: "z"},
117 },
118 },
119 },
120 }
121 for _, tc := range testCases {
122 actualResult := SubtractBazelLabelList(tc.haystack, tc.needle)
123 if !reflect.DeepEqual(tc.expectedResult, actualResult) {
124 t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
125 }
126 }
127}
Liz Kammer9abd62d2021-05-21 08:37:59 -0400128func TestFirstUniqueBazelLabelList(t *testing.T) {
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000129 testCases := []struct {
130 originalLabelList LabelList
131 expectedUniqueLabelList LabelList
132 }{
133 {
134 originalLabelList: LabelList{
135 Includes: []Label{
136 {Label: "a"},
137 {Label: "b"},
138 {Label: "a"},
139 {Label: "c"},
140 },
141 Excludes: []Label{
142 {Label: "x"},
143 {Label: "x"},
144 {Label: "y"},
145 {Label: "z"},
146 },
147 },
148 expectedUniqueLabelList: LabelList{
149 Includes: []Label{
150 {Label: "a"},
151 {Label: "b"},
152 {Label: "c"},
153 },
154 Excludes: []Label{
155 {Label: "x"},
156 {Label: "y"},
157 {Label: "z"},
158 },
159 },
160 },
161 }
162 for _, tc := range testCases {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400163 actualUniqueLabelList := FirstUniqueBazelLabelList(tc.originalLabelList)
164 if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
165 t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
166 }
167 }
168}
169
170func TestUniqueSortedBazelLabelList(t *testing.T) {
171 testCases := []struct {
172 originalLabelList LabelList
173 expectedUniqueLabelList LabelList
174 }{
175 {
176 originalLabelList: LabelList{
177 Includes: []Label{
178 {Label: "c"},
179 {Label: "a"},
180 {Label: "a"},
181 {Label: "b"},
182 },
183 Excludes: []Label{
184 {Label: "y"},
185 {Label: "z"},
186 {Label: "x"},
187 {Label: "x"},
188 },
189 },
190 expectedUniqueLabelList: LabelList{
191 Includes: []Label{
192 {Label: "a"},
193 {Label: "b"},
194 {Label: "c"},
195 },
196 Excludes: []Label{
197 {Label: "x"},
198 {Label: "y"},
199 {Label: "z"},
200 },
201 },
202 },
203 }
204 for _, tc := range testCases {
205 actualUniqueLabelList := UniqueSortedBazelLabelList(tc.originalLabelList)
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000206 if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
207 t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
208 }
209 }
210}
Liz Kammer74deed42021-06-02 13:02:03 -0400211
212func makeLabels(labels ...string) []Label {
213 var ret []Label
214 for _, l := range labels {
215 ret = append(ret, Label{Label: l})
216 }
217 return ret
218}
219
220func makeLabelList(includes, excludes []string) LabelList {
221 return LabelList{
222 Includes: makeLabels(includes...),
223 Excludes: makeLabels(excludes...),
224 }
225}
226
227func TestResolveExcludes(t *testing.T) {
228 attr := LabelListAttribute{
229 Value: makeLabelList(
230 []string{
231 "all_include",
232 "arm_exclude",
233 "android_exclude",
234 },
235 []string{"all_exclude"},
236 ),
237 ConfigurableValues: configurableLabelLists{
238 ArchConfigurationAxis: labelListSelectValues{
Jingwen Chen9af49a42021-11-02 10:27:17 +0000239 "arm": makeLabelList([]string{}, []string{"arm_exclude"}),
240 "x86": makeLabelList([]string{"x86_include"}, []string{}),
241 ConditionsDefaultConfigKey: makeLabelList([]string{"default_include"}, []string{}),
Liz Kammer74deed42021-06-02 13:02:03 -0400242 },
243 OsConfigurationAxis: labelListSelectValues{
244 "android": makeLabelList([]string{}, []string{"android_exclude"}),
245 "linux": makeLabelList([]string{"linux_include"}, []string{}),
246 },
247 OsArchConfigurationAxis: labelListSelectValues{
248 "linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
249 },
Jingwen Chen9af49a42021-11-02 10:27:17 +0000250 ProductVariableConfigurationAxis("product_with_defaults"): labelListSelectValues{
251 "a": makeLabelList([]string{}, []string{"not_in_value"}),
252 "b": makeLabelList([]string{"b_val"}, []string{}),
253 "c": makeLabelList([]string{"c_val"}, []string{}),
254 ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2"}, []string{}),
255 },
256 ProductVariableConfigurationAxis("product_only_with_excludes"): labelListSelectValues{
Liz Kammer74deed42021-06-02 13:02:03 -0400257 "a": makeLabelList([]string{}, []string{"not_in_value"}),
258 },
259 },
260 }
261
262 attr.ResolveExcludes()
263
Jingwen Chen9af49a42021-11-02 10:27:17 +0000264 expectedBaseIncludes := []Label{{Label: "all_include"}}
Liz Kammer74deed42021-06-02 13:02:03 -0400265 if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) {
266 t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes)
267 }
268 var nilLabels []Label
269 expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{
Jingwen Chen9af49a42021-11-02 10:27:17 +0000270 ArchConfigurationAxis: {
271 "arm": nilLabels,
272 "x86": makeLabels("arm_exclude", "x86_include"),
273 ConditionsDefaultConfigKey: makeLabels("arm_exclude", "default_include"),
Liz Kammer74deed42021-06-02 13:02:03 -0400274 },
Jingwen Chen9af49a42021-11-02 10:27:17 +0000275 OsConfigurationAxis: {
276 "android": nilLabels,
277 "linux": makeLabels("android_exclude", "linux_include"),
278 ConditionsDefaultConfigKey: makeLabels("android_exclude"),
Liz Kammer74deed42021-06-02 13:02:03 -0400279 },
Jingwen Chen9af49a42021-11-02 10:27:17 +0000280 OsArchConfigurationAxis: {
281 "linux_x86": makeLabels("linux_x86_include"),
282 ConditionsDefaultConfigKey: nilLabels,
283 },
284 ProductVariableConfigurationAxis("product_with_defaults"): {
285 "a": nilLabels,
286 "b": makeLabels("b_val"),
287 "c": makeLabels("c_val"),
288 ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"),
Liz Kammer74deed42021-06-02 13:02:03 -0400289 },
290 }
291 for _, axis := range attr.SortedConfigurationAxes() {
292 if _, ok := expectedConfiguredIncludes[axis]; !ok {
293 t.Errorf("Found unexpected axis %s", axis)
294 continue
295 }
296 expectedForAxis := expectedConfiguredIncludes[axis]
297 gotForAxis := attr.ConfigurableValues[axis]
298 if len(expectedForAxis) != len(gotForAxis) {
299 t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
300 }
301 for config, value := range gotForAxis {
302 if expected, ok := expectedForAxis[config]; ok {
303 if !reflect.DeepEqual(expected, value.Includes) {
Jingwen Chen9af49a42021-11-02 10:27:17 +0000304 t.Errorf("For %s,\nexpected: %#v\ngot %#v", axis, expected, value.Includes)
Liz Kammer74deed42021-06-02 13:02:03 -0400305 }
306 } else {
307 t.Errorf("Got unexpected config %q for %s", config, axis)
308 }
309 }
310 }
311}
Liz Kammer5fad5012021-09-09 14:08:21 -0400312
Liz Kammer57e2e7a2021-09-20 12:55:02 -0400313// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of
314// typ
315func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper {
316 return func(omc OtherModuleContext, label string) (string, bool) {
317 m, ok := omc.ModuleFromName(label)
318 if !ok {
319 return label, false
320 }
321 mTyp := omc.OtherModuleType(m)
322 if typ == mTyp {
323 return label + suffix, true
324 }
325 return label, false
326 }
327}
328
329func TestPartitionLabelListAttribute(t *testing.T) {
330 testCases := []struct {
331 name string
332 ctx *otherModuleTestContext
333 labelList LabelListAttribute
334 filters LabelPartitions
335 expected PartitionToLabelListAttribute
336 expectedErrMsg *string
337 }{
338 {
339 name: "no configurable values",
340 ctx: &otherModuleTestContext{},
341 labelList: LabelListAttribute{
342 Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
343 },
344 filters: LabelPartitions{
345 "A": LabelPartition{Extensions: []string{".a"}},
346 "B": LabelPartition{Extensions: []string{".b"}},
347 "C": LabelPartition{Extensions: []string{".c"}},
348 },
349 expected: PartitionToLabelListAttribute{
350 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
351 "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
352 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
353 },
354 },
355 {
356 name: "no configurable values, remainder partition",
357 ctx: &otherModuleTestContext{},
358 labelList: LabelListAttribute{
359 Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
360 },
361 filters: LabelPartitions{
362 "A": LabelPartition{Extensions: []string{".a"}, Keep_remainder: true},
363 "B": LabelPartition{Extensions: []string{".b"}},
364 "C": LabelPartition{Extensions: []string{".c"}},
365 },
366 expected: PartitionToLabelListAttribute{
367 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "d.d", "e.e"}, []string{})},
368 "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
369 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
370 },
371 },
372 {
373 name: "no configurable values, empty partition",
374 ctx: &otherModuleTestContext{},
375 labelList: LabelListAttribute{
376 Value: makeLabelList([]string{"a.a", "c.c"}, []string{}),
377 },
378 filters: LabelPartitions{
379 "A": LabelPartition{Extensions: []string{".a"}},
380 "B": LabelPartition{Extensions: []string{".b"}},
381 "C": LabelPartition{Extensions: []string{".c"}},
382 },
383 expected: PartitionToLabelListAttribute{
384 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
385 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
386 },
387 },
388 {
389 name: "no configurable values, has map",
390 ctx: &otherModuleTestContext{
391 modules: []testModuleInfo{testModuleInfo{name: "srcs", typ: "fg", dir: "dir"}},
392 },
393 labelList: LabelListAttribute{
394 Value: makeLabelList([]string{"a.a", "srcs", "b.b", "c.c"}, []string{}),
395 },
396 filters: LabelPartitions{
397 "A": LabelPartition{Extensions: []string{".a"}, LabelMapper: labelAddSuffixForTypeMapper("_a", "fg")},
398 "B": LabelPartition{Extensions: []string{".b"}},
399 "C": LabelPartition{Extensions: []string{".c"}},
400 },
401 expected: PartitionToLabelListAttribute{
402 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "srcs_a"}, []string{})},
403 "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
404 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
405 },
406 },
407 {
408 name: "configurable values, keeps empty if excludes",
409 ctx: &otherModuleTestContext{},
410 labelList: LabelListAttribute{
411 ConfigurableValues: configurableLabelLists{
412 ArchConfigurationAxis: labelListSelectValues{
413 "x86": makeLabelList([]string{"a.a", "c.c"}, []string{}),
414 "arm": makeLabelList([]string{"b.b"}, []string{}),
415 "x86_64": makeLabelList([]string{"b.b"}, []string{"d.d"}),
416 },
417 },
418 },
419 filters: LabelPartitions{
420 "A": LabelPartition{Extensions: []string{".a"}},
421 "B": LabelPartition{Extensions: []string{".b"}},
422 "C": LabelPartition{Extensions: []string{".c"}},
423 },
424 expected: PartitionToLabelListAttribute{
425 "A": LabelListAttribute{
426 ConfigurableValues: configurableLabelLists{
427 ArchConfigurationAxis: labelListSelectValues{
428 "x86": makeLabelList([]string{"a.a"}, []string{}),
429 "x86_64": makeLabelList([]string{}, []string{"c.c"}),
430 },
431 },
432 },
433 "B": LabelListAttribute{
434 ConfigurableValues: configurableLabelLists{
435 ArchConfigurationAxis: labelListSelectValues{
436 "arm": makeLabelList([]string{"b.b"}, []string{}),
437 "x86_64": makeLabelList([]string{"b.b"}, []string{"c.c"}),
438 },
439 },
440 },
441 "C": LabelListAttribute{
442 ConfigurableValues: configurableLabelLists{
443 ArchConfigurationAxis: labelListSelectValues{
444 "x86": makeLabelList([]string{"c.c"}, []string{}),
445 "x86_64": makeLabelList([]string{}, []string{"c.c"}),
446 },
447 },
448 },
449 },
450 },
451 {
452 name: "error for multiple partitions same value",
453 ctx: &otherModuleTestContext{},
454 labelList: LabelListAttribute{
455 Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
456 },
457 filters: LabelPartitions{
458 "A": LabelPartition{Extensions: []string{".a"}},
459 "other A": LabelPartition{Extensions: []string{".a"}},
460 },
461 expected: PartitionToLabelListAttribute{},
462 expectedErrMsg: proptools.StringPtr(`"a.a" was found in multiple partitions:`),
463 },
464 }
465
466 for _, tc := range testCases {
467 t.Run(tc.name, func(t *testing.T) {
468 got := PartitionLabelListAttribute(tc.ctx, &tc.labelList, tc.filters)
469
470 if hasErrors, expectsErr := len(tc.ctx.errors) > 0, tc.expectedErrMsg != nil; hasErrors != expectsErr {
471 t.Errorf("Unexpected error(s): %q, expected: %q", tc.ctx.errors, *tc.expectedErrMsg)
472 } else if tc.expectedErrMsg != nil {
473 found := false
474 for _, err := range tc.ctx.errors {
475 if strings.Contains(err, *tc.expectedErrMsg) {
476 found = true
477 break
478 }
479 }
480
481 if !found {
482 t.Errorf("Expected error message: %q, got %q", *tc.expectedErrMsg, tc.ctx.errors)
483 }
484 return
485 }
486
487 if len(tc.expected) != len(got) {
488 t.Errorf("Expected %d partitions, got %d partitions", len(tc.expected), len(got))
489 }
490 for partition, expectedLla := range tc.expected {
491 gotLla, ok := got[partition]
492 if !ok {
493 t.Errorf("Expected partition %q, but it was not found %v", partition, got)
494 continue
495 }
496 expectedLabelList := expectedLla.Value
497 gotLabelList := gotLla.Value
498 if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
499 t.Errorf("Expected no config includes %v, got %v", expectedLabelList.Includes, gotLabelList.Includes)
500 }
501 expectedAxes := expectedLla.SortedConfigurationAxes()
502 gotAxes := gotLla.SortedConfigurationAxes()
503 if !reflect.DeepEqual(expectedAxes, gotAxes) {
504 t.Errorf("Expected axes %v, got %v (%#v)", expectedAxes, gotAxes, gotLla)
505 }
506 for _, axis := range expectedLla.SortedConfigurationAxes() {
507 if _, exists := gotLla.ConfigurableValues[axis]; !exists {
508 t.Errorf("Expected %s to be a supported axis, but it was not found", axis)
509 }
510 if expected, got := expectedLla.ConfigurableValues[axis], gotLla.ConfigurableValues[axis]; len(expected) != len(got) {
511 t.Errorf("For axis %q: expected configs %v, got %v", axis, expected, got)
512 }
513 for config, expectedLabelList := range expectedLla.ConfigurableValues[axis] {
514 gotLabelList, exists := gotLla.ConfigurableValues[axis][config]
515 if !exists {
516 t.Errorf("Expected %s to be a supported config, but config was not found", config)
517 continue
518 }
519 if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
520 t.Errorf("Expected %s %s includes %v, got %v", axis, config, expectedLabelList.Includes, gotLabelList.Includes)
521 }
522 }
523 }
524 }
525 })
526 }
527}
528
Liz Kammer5fad5012021-09-09 14:08:21 -0400529func TestDeduplicateAxesFromBase(t *testing.T) {
530 attr := StringListAttribute{
531 Value: []string{
532 "all_include",
533 "arm_include",
534 "android_include",
535 "linux_x86_include",
536 },
537 ConfigurableValues: configurableStringLists{
538 ArchConfigurationAxis: stringListSelectValues{
539 "arm": []string{"arm_include"},
540 "x86": []string{"x86_include"},
541 },
542 OsConfigurationAxis: stringListSelectValues{
543 "android": []string{"android_include"},
544 "linux": []string{"linux_include"},
545 },
546 OsArchConfigurationAxis: stringListSelectValues{
547 "linux_x86": {"linux_x86_include"},
548 },
549 ProductVariableConfigurationAxis("a"): stringListSelectValues{
550 "a": []string{"not_in_value"},
551 },
552 },
553 }
554
555 attr.DeduplicateAxesFromBase()
556
557 expectedBaseIncludes := []string{
558 "all_include",
559 "arm_include",
560 "android_include",
561 "linux_x86_include",
562 }
563 if !reflect.DeepEqual(expectedBaseIncludes, attr.Value) {
564 t.Errorf("Expected Value includes %q, got %q", attr.Value, expectedBaseIncludes)
565 }
566 expectedConfiguredIncludes := configurableStringLists{
567 ArchConfigurationAxis: stringListSelectValues{
568 "x86": []string{"x86_include"},
569 },
570 OsConfigurationAxis: stringListSelectValues{
571 "linux": []string{"linux_include"},
572 },
573 OsArchConfigurationAxis: stringListSelectValues{},
574 ProductVariableConfigurationAxis("a"): stringListSelectValues{
575 "a": []string{"not_in_value"},
576 },
577 }
578 for _, axis := range attr.SortedConfigurationAxes() {
579 if _, ok := expectedConfiguredIncludes[axis]; !ok {
580 t.Errorf("Found unexpected axis %s", axis)
581 continue
582 }
583 expectedForAxis := expectedConfiguredIncludes[axis]
584 gotForAxis := attr.ConfigurableValues[axis]
585 if len(expectedForAxis) != len(gotForAxis) {
586 t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
587 }
588 for config, value := range gotForAxis {
589 if expected, ok := expectedForAxis[config]; ok {
590 if !reflect.DeepEqual(expected, value) {
591 t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value)
592 }
593 } else {
594 t.Errorf("Got unexpected config %q for %s", config, axis)
595 }
596 }
597 }
598}