blob: f53fdc1dec0e6e21944ce6228f93c499c208e521 [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{
239 "arm": makeLabelList([]string{}, []string{"arm_exclude"}),
240 "x86": makeLabelList([]string{"x86_include"}, []string{}),
241 },
242 OsConfigurationAxis: labelListSelectValues{
243 "android": makeLabelList([]string{}, []string{"android_exclude"}),
244 "linux": makeLabelList([]string{"linux_include"}, []string{}),
245 },
246 OsArchConfigurationAxis: labelListSelectValues{
247 "linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
248 },
249 ProductVariableConfigurationAxis("a"): labelListSelectValues{
250 "a": makeLabelList([]string{}, []string{"not_in_value"}),
251 },
252 },
253 }
254
255 attr.ResolveExcludes()
256
257 expectedBaseIncludes := []Label{Label{Label: "all_include"}}
258 if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) {
259 t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes)
260 }
261 var nilLabels []Label
262 expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{
263 ArchConfigurationAxis: map[string][]Label{
264 "arm": nilLabels,
265 "x86": makeLabels("arm_exclude", "x86_include"),
266 "conditions_default": makeLabels("arm_exclude"),
267 },
268 OsConfigurationAxis: map[string][]Label{
269 "android": nilLabels,
270 "linux": makeLabels("android_exclude", "linux_include"),
271 "conditions_default": makeLabels("android_exclude"),
272 },
273 OsArchConfigurationAxis: map[string][]Label{
274 "linux_x86": makeLabels("linux_x86_include"),
275 "conditions_default": nilLabels,
276 },
277 }
278 for _, axis := range attr.SortedConfigurationAxes() {
279 if _, ok := expectedConfiguredIncludes[axis]; !ok {
280 t.Errorf("Found unexpected axis %s", axis)
281 continue
282 }
283 expectedForAxis := expectedConfiguredIncludes[axis]
284 gotForAxis := attr.ConfigurableValues[axis]
285 if len(expectedForAxis) != len(gotForAxis) {
286 t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
287 }
288 for config, value := range gotForAxis {
289 if expected, ok := expectedForAxis[config]; ok {
290 if !reflect.DeepEqual(expected, value.Includes) {
291 t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value.Includes)
292 }
293 } else {
294 t.Errorf("Got unexpected config %q for %s", config, axis)
295 }
296 }
297 }
298}
Liz Kammer5fad5012021-09-09 14:08:21 -0400299
Liz Kammer57e2e7a2021-09-20 12:55:02 -0400300// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of
301// typ
302func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper {
303 return func(omc OtherModuleContext, label string) (string, bool) {
304 m, ok := omc.ModuleFromName(label)
305 if !ok {
306 return label, false
307 }
308 mTyp := omc.OtherModuleType(m)
309 if typ == mTyp {
310 return label + suffix, true
311 }
312 return label, false
313 }
314}
315
316func TestPartitionLabelListAttribute(t *testing.T) {
317 testCases := []struct {
318 name string
319 ctx *otherModuleTestContext
320 labelList LabelListAttribute
321 filters LabelPartitions
322 expected PartitionToLabelListAttribute
323 expectedErrMsg *string
324 }{
325 {
326 name: "no configurable values",
327 ctx: &otherModuleTestContext{},
328 labelList: LabelListAttribute{
329 Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
330 },
331 filters: LabelPartitions{
332 "A": LabelPartition{Extensions: []string{".a"}},
333 "B": LabelPartition{Extensions: []string{".b"}},
334 "C": LabelPartition{Extensions: []string{".c"}},
335 },
336 expected: PartitionToLabelListAttribute{
337 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
338 "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
339 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
340 },
341 },
342 {
343 name: "no configurable values, remainder partition",
344 ctx: &otherModuleTestContext{},
345 labelList: LabelListAttribute{
346 Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
347 },
348 filters: LabelPartitions{
349 "A": LabelPartition{Extensions: []string{".a"}, Keep_remainder: true},
350 "B": LabelPartition{Extensions: []string{".b"}},
351 "C": LabelPartition{Extensions: []string{".c"}},
352 },
353 expected: PartitionToLabelListAttribute{
354 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "d.d", "e.e"}, []string{})},
355 "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
356 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
357 },
358 },
359 {
360 name: "no configurable values, empty partition",
361 ctx: &otherModuleTestContext{},
362 labelList: LabelListAttribute{
363 Value: makeLabelList([]string{"a.a", "c.c"}, []string{}),
364 },
365 filters: LabelPartitions{
366 "A": LabelPartition{Extensions: []string{".a"}},
367 "B": LabelPartition{Extensions: []string{".b"}},
368 "C": LabelPartition{Extensions: []string{".c"}},
369 },
370 expected: PartitionToLabelListAttribute{
371 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
372 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
373 },
374 },
375 {
376 name: "no configurable values, has map",
377 ctx: &otherModuleTestContext{
378 modules: []testModuleInfo{testModuleInfo{name: "srcs", typ: "fg", dir: "dir"}},
379 },
380 labelList: LabelListAttribute{
381 Value: makeLabelList([]string{"a.a", "srcs", "b.b", "c.c"}, []string{}),
382 },
383 filters: LabelPartitions{
384 "A": LabelPartition{Extensions: []string{".a"}, LabelMapper: labelAddSuffixForTypeMapper("_a", "fg")},
385 "B": LabelPartition{Extensions: []string{".b"}},
386 "C": LabelPartition{Extensions: []string{".c"}},
387 },
388 expected: PartitionToLabelListAttribute{
389 "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "srcs_a"}, []string{})},
390 "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
391 "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
392 },
393 },
394 {
395 name: "configurable values, keeps empty if excludes",
396 ctx: &otherModuleTestContext{},
397 labelList: LabelListAttribute{
398 ConfigurableValues: configurableLabelLists{
399 ArchConfigurationAxis: labelListSelectValues{
400 "x86": makeLabelList([]string{"a.a", "c.c"}, []string{}),
401 "arm": makeLabelList([]string{"b.b"}, []string{}),
402 "x86_64": makeLabelList([]string{"b.b"}, []string{"d.d"}),
403 },
404 },
405 },
406 filters: LabelPartitions{
407 "A": LabelPartition{Extensions: []string{".a"}},
408 "B": LabelPartition{Extensions: []string{".b"}},
409 "C": LabelPartition{Extensions: []string{".c"}},
410 },
411 expected: PartitionToLabelListAttribute{
412 "A": LabelListAttribute{
413 ConfigurableValues: configurableLabelLists{
414 ArchConfigurationAxis: labelListSelectValues{
415 "x86": makeLabelList([]string{"a.a"}, []string{}),
416 "x86_64": makeLabelList([]string{}, []string{"c.c"}),
417 },
418 },
419 },
420 "B": LabelListAttribute{
421 ConfigurableValues: configurableLabelLists{
422 ArchConfigurationAxis: labelListSelectValues{
423 "arm": makeLabelList([]string{"b.b"}, []string{}),
424 "x86_64": makeLabelList([]string{"b.b"}, []string{"c.c"}),
425 },
426 },
427 },
428 "C": LabelListAttribute{
429 ConfigurableValues: configurableLabelLists{
430 ArchConfigurationAxis: labelListSelectValues{
431 "x86": makeLabelList([]string{"c.c"}, []string{}),
432 "x86_64": makeLabelList([]string{}, []string{"c.c"}),
433 },
434 },
435 },
436 },
437 },
438 {
439 name: "error for multiple partitions same value",
440 ctx: &otherModuleTestContext{},
441 labelList: LabelListAttribute{
442 Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
443 },
444 filters: LabelPartitions{
445 "A": LabelPartition{Extensions: []string{".a"}},
446 "other A": LabelPartition{Extensions: []string{".a"}},
447 },
448 expected: PartitionToLabelListAttribute{},
449 expectedErrMsg: proptools.StringPtr(`"a.a" was found in multiple partitions:`),
450 },
451 }
452
453 for _, tc := range testCases {
454 t.Run(tc.name, func(t *testing.T) {
455 got := PartitionLabelListAttribute(tc.ctx, &tc.labelList, tc.filters)
456
457 if hasErrors, expectsErr := len(tc.ctx.errors) > 0, tc.expectedErrMsg != nil; hasErrors != expectsErr {
458 t.Errorf("Unexpected error(s): %q, expected: %q", tc.ctx.errors, *tc.expectedErrMsg)
459 } else if tc.expectedErrMsg != nil {
460 found := false
461 for _, err := range tc.ctx.errors {
462 if strings.Contains(err, *tc.expectedErrMsg) {
463 found = true
464 break
465 }
466 }
467
468 if !found {
469 t.Errorf("Expected error message: %q, got %q", *tc.expectedErrMsg, tc.ctx.errors)
470 }
471 return
472 }
473
474 if len(tc.expected) != len(got) {
475 t.Errorf("Expected %d partitions, got %d partitions", len(tc.expected), len(got))
476 }
477 for partition, expectedLla := range tc.expected {
478 gotLla, ok := got[partition]
479 if !ok {
480 t.Errorf("Expected partition %q, but it was not found %v", partition, got)
481 continue
482 }
483 expectedLabelList := expectedLla.Value
484 gotLabelList := gotLla.Value
485 if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
486 t.Errorf("Expected no config includes %v, got %v", expectedLabelList.Includes, gotLabelList.Includes)
487 }
488 expectedAxes := expectedLla.SortedConfigurationAxes()
489 gotAxes := gotLla.SortedConfigurationAxes()
490 if !reflect.DeepEqual(expectedAxes, gotAxes) {
491 t.Errorf("Expected axes %v, got %v (%#v)", expectedAxes, gotAxes, gotLla)
492 }
493 for _, axis := range expectedLla.SortedConfigurationAxes() {
494 if _, exists := gotLla.ConfigurableValues[axis]; !exists {
495 t.Errorf("Expected %s to be a supported axis, but it was not found", axis)
496 }
497 if expected, got := expectedLla.ConfigurableValues[axis], gotLla.ConfigurableValues[axis]; len(expected) != len(got) {
498 t.Errorf("For axis %q: expected configs %v, got %v", axis, expected, got)
499 }
500 for config, expectedLabelList := range expectedLla.ConfigurableValues[axis] {
501 gotLabelList, exists := gotLla.ConfigurableValues[axis][config]
502 if !exists {
503 t.Errorf("Expected %s to be a supported config, but config was not found", config)
504 continue
505 }
506 if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
507 t.Errorf("Expected %s %s includes %v, got %v", axis, config, expectedLabelList.Includes, gotLabelList.Includes)
508 }
509 }
510 }
511 }
512 })
513 }
514}
515
Liz Kammer5fad5012021-09-09 14:08:21 -0400516func TestDeduplicateAxesFromBase(t *testing.T) {
517 attr := StringListAttribute{
518 Value: []string{
519 "all_include",
520 "arm_include",
521 "android_include",
522 "linux_x86_include",
523 },
524 ConfigurableValues: configurableStringLists{
525 ArchConfigurationAxis: stringListSelectValues{
526 "arm": []string{"arm_include"},
527 "x86": []string{"x86_include"},
528 },
529 OsConfigurationAxis: stringListSelectValues{
530 "android": []string{"android_include"},
531 "linux": []string{"linux_include"},
532 },
533 OsArchConfigurationAxis: stringListSelectValues{
534 "linux_x86": {"linux_x86_include"},
535 },
536 ProductVariableConfigurationAxis("a"): stringListSelectValues{
537 "a": []string{"not_in_value"},
538 },
539 },
540 }
541
542 attr.DeduplicateAxesFromBase()
543
544 expectedBaseIncludes := []string{
545 "all_include",
546 "arm_include",
547 "android_include",
548 "linux_x86_include",
549 }
550 if !reflect.DeepEqual(expectedBaseIncludes, attr.Value) {
551 t.Errorf("Expected Value includes %q, got %q", attr.Value, expectedBaseIncludes)
552 }
553 expectedConfiguredIncludes := configurableStringLists{
554 ArchConfigurationAxis: stringListSelectValues{
555 "x86": []string{"x86_include"},
556 },
557 OsConfigurationAxis: stringListSelectValues{
558 "linux": []string{"linux_include"},
559 },
560 OsArchConfigurationAxis: stringListSelectValues{},
561 ProductVariableConfigurationAxis("a"): stringListSelectValues{
562 "a": []string{"not_in_value"},
563 },
564 }
565 for _, axis := range attr.SortedConfigurationAxes() {
566 if _, ok := expectedConfiguredIncludes[axis]; !ok {
567 t.Errorf("Found unexpected axis %s", axis)
568 continue
569 }
570 expectedForAxis := expectedConfiguredIncludes[axis]
571 gotForAxis := attr.ConfigurableValues[axis]
572 if len(expectedForAxis) != len(gotForAxis) {
573 t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
574 }
575 for config, value := range gotForAxis {
576 if expected, ok := expectedForAxis[config]; ok {
577 if !reflect.DeepEqual(expected, value) {
578 t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value)
579 }
580 } else {
581 t.Errorf("Got unexpected config %q for %s", config, axis)
582 }
583 }
584 }
585}