• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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"
19	"strings"
20	"testing"
21
22	"github.com/google/blueprint/proptools"
23)
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				// namespaces
37				{Label: "//foo:bar", OriginalModuleName: "bar"},       // when referenced from foo namespace
38				{Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when reference from root namespace
39			},
40			expectedUniqueLabels: []Label{
41				{Label: "//foo:bar", OriginalModuleName: "bar"},
42				{Label: "a"},
43				{Label: "b"},
44				{Label: "c"},
45			},
46		},
47	}
48	for _, tc := range testCases {
49		actualUniqueLabels := UniqueSortedBazelLabels(tc.originalLabels)
50		if !reflect.DeepEqual(tc.expectedUniqueLabels, actualUniqueLabels) {
51			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabels, actualUniqueLabels)
52		}
53	}
54}
55
56func TestSubtractStrings(t *testing.T) {
57	testCases := []struct {
58		haystack       []string
59		needle         []string
60		expectedResult []string
61	}{
62		{
63			haystack: []string{
64				"a",
65				"b",
66				"c",
67			},
68			needle: []string{
69				"a",
70			},
71			expectedResult: []string{
72				"b", "c",
73			},
74		},
75	}
76	for _, tc := range testCases {
77		actualResult := SubtractStrings(tc.haystack, tc.needle)
78		if !reflect.DeepEqual(tc.expectedResult, actualResult) {
79			t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
80		}
81	}
82}
83
84func TestSubtractBazelLabelList(t *testing.T) {
85	testCases := []struct {
86		haystack       LabelList
87		needle         LabelList
88		expectedResult LabelList
89	}{
90		{
91			haystack: LabelList{
92				Includes: []Label{
93					{Label: "a"},
94					{Label: "b"},
95					{Label: "c"},
96				},
97				Excludes: []Label{
98					{Label: "x"},
99					{Label: "y"},
100					{Label: "z"},
101				},
102			},
103			needle: LabelList{
104				Includes: []Label{
105					{Label: "a"},
106				},
107				Excludes: []Label{
108					{Label: "z"},
109				},
110			},
111			// NOTE: Excludes are intentionally not subtracted
112			expectedResult: LabelList{
113				Includes: []Label{
114					{Label: "b"},
115					{Label: "c"},
116				},
117				Excludes: []Label{
118					{Label: "x"},
119					{Label: "y"},
120					{Label: "z"},
121				},
122			},
123		},
124	}
125	for _, tc := range testCases {
126		actualResult := SubtractBazelLabelList(tc.haystack, tc.needle)
127		if !reflect.DeepEqual(tc.expectedResult, actualResult) {
128			t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
129		}
130	}
131}
132
133func TestSubtractBazelLabelListAttribute(t *testing.T) {
134	testCases := []struct {
135		haystack LabelListAttribute
136		needle   LabelListAttribute
137		expected LabelListAttribute
138	}{
139		{
140			haystack: LabelListAttribute{
141				Value: makeLabelList(
142					[]string{"a", "b", "a", "c"},
143					[]string{"x", "x", "y", "z"},
144				),
145				ConfigurableValues: configurableLabelLists{
146					ArchConfigurationAxis: labelListSelectValues{
147						"arm": makeLabelList([]string{"arm_1", "arm_2"}, []string{}),
148						"x86": makeLabelList([]string{"x86_3", "x86_4", "x86_5"}, []string{"x86_5"}),
149					},
150				},
151			},
152			needle: LabelListAttribute{
153				Value: makeLabelList(
154					[]string{"d", "a"},
155					[]string{"x", "y2", "z2"},
156				),
157				ConfigurableValues: configurableLabelLists{
158					ArchConfigurationAxis: labelListSelectValues{
159						"arm": makeLabelList([]string{"arm_1", "arm_3"}, []string{}),
160						"x86": makeLabelList([]string{"x86_3", "x86_4"}, []string{"x86_6"}),
161					},
162				},
163			},
164			expected: LabelListAttribute{
165				Value: makeLabelList(
166					[]string{"b", "c"},
167					[]string{"x", "x", "y", "z"},
168				),
169				ConfigurableValues: configurableLabelLists{
170					ArchConfigurationAxis: labelListSelectValues{
171						"arm": makeLabelList([]string{"arm_2"}, []string{}),
172						"x86": makeLabelList([]string{"x86_5"}, []string{"x86_5"}),
173					},
174				},
175				ForceSpecifyEmptyList: false,
176				EmitEmptyList:         false,
177				Prepend:               false,
178			},
179		},
180	}
181	for _, tc := range testCases {
182		got := SubtractBazelLabelListAttribute(tc.haystack, tc.needle)
183		if !reflect.DeepEqual(tc.expected, got) {
184			t.Fatalf("Expected\n%v, but got\n%v", tc.expected, got)
185		}
186	}
187}
188
189func TestFirstUniqueBazelLabelList(t *testing.T) {
190	testCases := []struct {
191		originalLabelList       LabelList
192		expectedUniqueLabelList LabelList
193	}{
194		{
195			originalLabelList: LabelList{
196				Includes: []Label{
197					{Label: "a"},
198					{Label: "b"},
199					{Label: "a"},
200					{Label: "c"},
201					// namespaces
202					{Label: "//foo:bar", OriginalModuleName: "bar"},       // when referenced from foo namespace
203					{Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when referenced from root namespace
204				},
205				Excludes: []Label{
206					{Label: "x"},
207					{Label: "x"},
208					{Label: "y"},
209					{Label: "z"},
210				},
211			},
212			expectedUniqueLabelList: LabelList{
213				Includes: []Label{
214					{Label: "a"},
215					{Label: "b"},
216					{Label: "c"},
217					{Label: "//foo:bar", OriginalModuleName: "bar"},
218				},
219				Excludes: []Label{
220					{Label: "x"},
221					{Label: "y"},
222					{Label: "z"},
223				},
224			},
225		},
226	}
227	for _, tc := range testCases {
228		actualUniqueLabelList := FirstUniqueBazelLabelList(tc.originalLabelList)
229		if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
230			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
231		}
232	}
233}
234
235func TestFirstUniqueBazelLabelListAttribute(t *testing.T) {
236	testCases := []struct {
237		originalLabelList       LabelListAttribute
238		expectedUniqueLabelList LabelListAttribute
239	}{
240		{
241			originalLabelList: LabelListAttribute{
242				Value: makeLabelList(
243					[]string{"a", "b", "a", "c"},
244					[]string{"x", "x", "y", "z"},
245				),
246				ConfigurableValues: configurableLabelLists{
247					ArchConfigurationAxis: labelListSelectValues{
248						"arm": makeLabelList([]string{"1", "2", "1"}, []string{}),
249						"x86": makeLabelList([]string{"3", "4", "4"}, []string{"5", "5"}),
250					},
251				},
252			},
253			expectedUniqueLabelList: LabelListAttribute{
254				Value: makeLabelList(
255					[]string{"a", "b", "c"},
256					[]string{"x", "y", "z"},
257				),
258				ConfigurableValues: configurableLabelLists{
259					ArchConfigurationAxis: labelListSelectValues{
260						"arm": makeLabelList([]string{"1", "2"}, []string{}),
261						"x86": makeLabelList([]string{"3", "4"}, []string{"5"}),
262					},
263				},
264			},
265		},
266	}
267	for _, tc := range testCases {
268		actualUniqueLabelList := FirstUniqueBazelLabelListAttribute(tc.originalLabelList)
269		if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
270			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
271		}
272	}
273}
274
275func TestUniqueSortedBazelLabelList(t *testing.T) {
276	testCases := []struct {
277		originalLabelList       LabelList
278		expectedUniqueLabelList LabelList
279	}{
280		{
281			originalLabelList: LabelList{
282				Includes: []Label{
283					{Label: "c"},
284					{Label: "a"},
285					{Label: "a"},
286					{Label: "b"},
287				},
288				Excludes: []Label{
289					{Label: "y"},
290					{Label: "z"},
291					{Label: "x"},
292					{Label: "x"},
293				},
294			},
295			expectedUniqueLabelList: LabelList{
296				Includes: []Label{
297					{Label: "a"},
298					{Label: "b"},
299					{Label: "c"},
300				},
301				Excludes: []Label{
302					{Label: "x"},
303					{Label: "y"},
304					{Label: "z"},
305				},
306			},
307		},
308	}
309	for _, tc := range testCases {
310		actualUniqueLabelList := UniqueSortedBazelLabelList(tc.originalLabelList)
311		if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
312			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
313		}
314	}
315}
316
317func makeLabels(labels ...string) []Label {
318	var ret []Label
319	for _, l := range labels {
320		ret = append(ret, Label{Label: l})
321	}
322	return ret
323}
324
325func makeLabelList(includes, excludes []string) LabelList {
326	return LabelList{
327		Includes: makeLabels(includes...),
328		Excludes: makeLabels(excludes...),
329	}
330}
331
332func TestResolveExcludes(t *testing.T) {
333	attr := LabelListAttribute{
334		Value: makeLabelList(
335			[]string{
336				"all_include",
337				"arm_exclude",
338				"android_exclude",
339				"product_config_exclude",
340			},
341			[]string{"all_exclude"},
342		),
343		ConfigurableValues: configurableLabelLists{
344			ArchConfigurationAxis: labelListSelectValues{
345				"arm":                      makeLabelList([]string{}, []string{"arm_exclude"}),
346				"x86":                      makeLabelList([]string{"x86_include"}, []string{}),
347				ConditionsDefaultConfigKey: makeLabelList([]string{"default_include"}, []string{}),
348			},
349			OsConfigurationAxis: labelListSelectValues{
350				"android": makeLabelList([]string{}, []string{"android_exclude"}),
351				"linux":   makeLabelList([]string{"linux_include"}, []string{}),
352			},
353			OsArchConfigurationAxis: labelListSelectValues{
354				"linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
355			},
356			ProductVariableConfigurationAxis(false, "product_with_defaults"): labelListSelectValues{
357				"a":                        makeLabelList([]string{}, []string{"not_in_value"}),
358				"b":                        makeLabelList([]string{"b_val"}, []string{}),
359				"c":                        makeLabelList([]string{"c_val"}, []string{}),
360				ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2", "all_exclude"}, []string{}),
361			},
362			ProductVariableConfigurationAxis(false, "product_only_with_excludes"): labelListSelectValues{
363				"a": makeLabelList([]string{}, []string{"product_config_exclude"}),
364			},
365		},
366	}
367
368	attr.ResolveExcludes()
369
370	expectedBaseIncludes := []Label{{Label: "all_include"}}
371	if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) {
372		t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes)
373	}
374	var nilLabels []Label
375	expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{
376		ArchConfigurationAxis: {
377			"arm":                      nilLabels,
378			"x86":                      makeLabels("arm_exclude", "x86_include"),
379			ConditionsDefaultConfigKey: makeLabels("arm_exclude", "default_include"),
380		},
381		OsConfigurationAxis: {
382			"android":                  nilLabels,
383			"linux":                    makeLabels("android_exclude", "linux_include"),
384			ConditionsDefaultConfigKey: makeLabels("android_exclude"),
385		},
386		OsArchConfigurationAxis: {
387			"linux_x86":                makeLabels("linux_x86_include"),
388			ConditionsDefaultConfigKey: nilLabels,
389		},
390		ProductVariableConfigurationAxis(false, "product_with_defaults"): {
391			"a":                        nilLabels,
392			"b":                        makeLabels("b_val"),
393			"c":                        makeLabels("c_val"),
394			ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"),
395		},
396		ProductVariableConfigurationAxis(false, "product_only_with_excludes"): {
397			"a":                        nilLabels,
398			ConditionsDefaultConfigKey: makeLabels("product_config_exclude"),
399		},
400	}
401	for _, axis := range attr.SortedConfigurationAxes() {
402		if _, ok := expectedConfiguredIncludes[axis]; !ok {
403			t.Errorf("Found unexpected axis %s", axis)
404			continue
405		}
406		expectedForAxis := expectedConfiguredIncludes[axis]
407		gotForAxis := attr.ConfigurableValues[axis]
408		if len(expectedForAxis) != len(gotForAxis) {
409			t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
410		}
411		for config, value := range gotForAxis {
412			if expected, ok := expectedForAxis[config]; ok {
413				if !reflect.DeepEqual(expected, value.Includes) {
414					t.Errorf("For %s,\nexpected: %#v\ngot %#v", axis, expected, value.Includes)
415				}
416			} else {
417				t.Errorf("Got unexpected config %q for %s", config, axis)
418			}
419		}
420	}
421}
422
423func TestLabelListAttributePartition(t *testing.T) {
424	testCases := []struct {
425		name         string
426		input        LabelListAttribute
427		predicated   LabelListAttribute
428		unpredicated LabelListAttribute
429		predicate    func(label Label) bool
430	}{
431		{
432			name: "move all to predicated partition",
433			input: MakeLabelListAttribute(makeLabelList(
434				[]string{"keep1", "throw1", "keep2", "throw2"},
435				[]string{"keep1", "throw1", "keep2", "throw2"},
436			)),
437			predicated: MakeLabelListAttribute(makeLabelList(
438				[]string{"keep1", "throw1", "keep2", "throw2"},
439				[]string{"keep1", "throw1", "keep2", "throw2"},
440			)),
441			unpredicated: LabelListAttribute{},
442			predicate: func(label Label) bool {
443				return true
444			},
445		},
446		{
447			name: "move all to unpredicated partition",
448			input: MakeLabelListAttribute(makeLabelList(
449				[]string{"keep1", "throw1", "keep2", "throw2"},
450				[]string{"keep1", "throw1", "keep2", "throw2"},
451			)),
452			predicated: LabelListAttribute{},
453			unpredicated: MakeLabelListAttribute(makeLabelList(
454				[]string{"keep1", "throw1", "keep2", "throw2"},
455				[]string{"keep1", "throw1", "keep2", "throw2"},
456			)),
457			predicate: func(label Label) bool {
458				return false
459			},
460		},
461		{
462			name: "partition includes and excludes",
463			input: MakeLabelListAttribute(makeLabelList(
464				[]string{"keep1", "throw1", "keep2", "throw2"},
465				[]string{"keep1", "throw1", "keep2", "throw2"},
466			)),
467			predicated: MakeLabelListAttribute(makeLabelList(
468				[]string{"keep1", "keep2"},
469				[]string{"keep1", "keep2"},
470			)),
471			unpredicated: MakeLabelListAttribute(makeLabelList(
472				[]string{"throw1", "throw2"},
473				[]string{"throw1", "throw2"},
474			)),
475			predicate: func(label Label) bool {
476				return strings.HasPrefix(label.Label, "keep")
477			},
478		},
479		{
480			name: "partition excludes only",
481			input: MakeLabelListAttribute(makeLabelList(
482				[]string{},
483				[]string{"keep1", "throw1", "keep2", "throw2"},
484			)),
485			predicated: MakeLabelListAttribute(makeLabelList(
486				[]string{},
487				[]string{"keep1", "keep2"},
488			)),
489			unpredicated: MakeLabelListAttribute(makeLabelList(
490				[]string{},
491				[]string{"throw1", "throw2"},
492			)),
493			predicate: func(label Label) bool {
494				return strings.HasPrefix(label.Label, "keep")
495			},
496		},
497		{
498			name: "partition includes only",
499			input: MakeLabelListAttribute(makeLabelList(
500				[]string{"keep1", "throw1", "keep2", "throw2"},
501				[]string{},
502			)),
503			predicated: MakeLabelListAttribute(makeLabelList(
504				[]string{"keep1", "keep2"},
505				[]string{},
506			)),
507			unpredicated: MakeLabelListAttribute(makeLabelList(
508				[]string{"throw1", "throw2"},
509				[]string{},
510			)),
511			predicate: func(label Label) bool {
512				return strings.HasPrefix(label.Label, "keep")
513			},
514		},
515		{
516			name:         "empty partition",
517			input:        MakeLabelListAttribute(makeLabelList([]string{}, []string{})),
518			predicated:   LabelListAttribute{},
519			unpredicated: LabelListAttribute{},
520			predicate: func(label Label) bool {
521				return true
522			},
523		},
524	}
525
526	for _, tc := range testCases {
527		t.Run(tc.name, func(t *testing.T) {
528			predicated, unpredicated := tc.input.Partition(tc.predicate)
529			if !predicated.Value.Equals(tc.predicated.Value) {
530				t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
531			}
532			for axis, configs := range predicated.ConfigurableValues {
533				tcConfigs, ok := tc.predicated.ConfigurableValues[axis]
534				if !ok || !reflect.DeepEqual(configs, tcConfigs) {
535					t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
536				}
537			}
538			if !unpredicated.Value.Equals(tc.unpredicated.Value) {
539				t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
540			}
541			for axis, configs := range unpredicated.ConfigurableValues {
542				tcConfigs, ok := tc.unpredicated.ConfigurableValues[axis]
543				if !ok || !reflect.DeepEqual(configs, tcConfigs) {
544					t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
545				}
546			}
547		})
548	}
549}
550
551// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of
552// typ
553func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper {
554	return func(omc OtherModuleContext, label Label) (string, bool) {
555		m, ok := omc.ModuleFromName(label.Label)
556		if !ok {
557			return label.Label, false
558		}
559		mTyp := omc.OtherModuleType(m)
560		if typ == mTyp {
561			return label.Label + suffix, true
562		}
563		return label.Label, false
564	}
565}
566
567func TestPartitionLabelListAttribute(t *testing.T) {
568	testCases := []struct {
569		name           string
570		ctx            *OtherModuleTestContext
571		labelList      LabelListAttribute
572		filters        LabelPartitions
573		expected       PartitionToLabelListAttribute
574		expectedErrMsg *string
575	}{
576		{
577			name: "no configurable values",
578			ctx:  &OtherModuleTestContext{},
579			labelList: LabelListAttribute{
580				Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
581			},
582			filters: LabelPartitions{
583				"A": LabelPartition{Extensions: []string{".a"}},
584				"B": LabelPartition{Extensions: []string{".b"}},
585				"C": LabelPartition{Extensions: []string{".c"}},
586			},
587			expected: PartitionToLabelListAttribute{
588				"A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
589				"B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
590				"C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
591			},
592		},
593		{
594			name: "no configurable values, remainder partition",
595			ctx:  &OtherModuleTestContext{},
596			labelList: LabelListAttribute{
597				Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
598			},
599			filters: LabelPartitions{
600				"A": LabelPartition{Extensions: []string{".a"}, Keep_remainder: true},
601				"B": LabelPartition{Extensions: []string{".b"}},
602				"C": LabelPartition{Extensions: []string{".c"}},
603			},
604			expected: PartitionToLabelListAttribute{
605				"A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "d.d", "e.e"}, []string{})},
606				"B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
607				"C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
608			},
609		},
610		{
611			name: "no configurable values, empty partition",
612			ctx:  &OtherModuleTestContext{},
613			labelList: LabelListAttribute{
614				Value: makeLabelList([]string{"a.a", "c.c"}, []string{}),
615			},
616			filters: LabelPartitions{
617				"A": LabelPartition{Extensions: []string{".a"}},
618				"B": LabelPartition{Extensions: []string{".b"}},
619				"C": LabelPartition{Extensions: []string{".c"}},
620			},
621			expected: PartitionToLabelListAttribute{
622				"A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
623				"C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
624			},
625		},
626		{
627			name: "no configurable values, has map",
628			ctx: &OtherModuleTestContext{
629				Modules: []TestModuleInfo{{ModuleName: "srcs", Typ: "fg", Dir: "dir"}},
630			},
631			labelList: LabelListAttribute{
632				Value: makeLabelList([]string{"a.a", "srcs", "b.b", "c.c"}, []string{}),
633			},
634			filters: LabelPartitions{
635				"A": LabelPartition{Extensions: []string{".a"}, LabelMapper: labelAddSuffixForTypeMapper("_a", "fg")},
636				"B": LabelPartition{Extensions: []string{".b"}},
637				"C": LabelPartition{Extensions: []string{".c"}},
638			},
639			expected: PartitionToLabelListAttribute{
640				"A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "srcs_a"}, []string{})},
641				"B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
642				"C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
643			},
644		},
645		{
646			name: "configurable values, keeps empty if excludes",
647			ctx:  &OtherModuleTestContext{},
648			labelList: LabelListAttribute{
649				ConfigurableValues: configurableLabelLists{
650					ArchConfigurationAxis: labelListSelectValues{
651						"x86":    makeLabelList([]string{"a.a", "c.c"}, []string{}),
652						"arm":    makeLabelList([]string{"b.b"}, []string{}),
653						"x86_64": makeLabelList([]string{"b.b"}, []string{"d.d"}),
654					},
655				},
656			},
657			filters: LabelPartitions{
658				"A": LabelPartition{Extensions: []string{".a"}},
659				"B": LabelPartition{Extensions: []string{".b"}},
660				"C": LabelPartition{Extensions: []string{".c"}},
661			},
662			expected: PartitionToLabelListAttribute{
663				"A": LabelListAttribute{
664					ConfigurableValues: configurableLabelLists{
665						ArchConfigurationAxis: labelListSelectValues{
666							"x86":    makeLabelList([]string{"a.a"}, []string{}),
667							"x86_64": makeLabelList([]string{}, []string{"c.c"}),
668						},
669					},
670				},
671				"B": LabelListAttribute{
672					ConfigurableValues: configurableLabelLists{
673						ArchConfigurationAxis: labelListSelectValues{
674							"arm":    makeLabelList([]string{"b.b"}, []string{}),
675							"x86_64": makeLabelList([]string{"b.b"}, []string{"c.c"}),
676						},
677					},
678				},
679				"C": LabelListAttribute{
680					ConfigurableValues: configurableLabelLists{
681						ArchConfigurationAxis: labelListSelectValues{
682							"x86":    makeLabelList([]string{"c.c"}, []string{}),
683							"x86_64": makeLabelList([]string{}, []string{"c.c"}),
684						},
685					},
686				},
687			},
688		},
689		{
690			name: "error for multiple partitions same value",
691			ctx:  &OtherModuleTestContext{},
692			labelList: LabelListAttribute{
693				Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
694			},
695			filters: LabelPartitions{
696				"A":       LabelPartition{Extensions: []string{".a"}},
697				"other A": LabelPartition{Extensions: []string{".a"}},
698			},
699			expected:       PartitionToLabelListAttribute{},
700			expectedErrMsg: proptools.StringPtr(`"a.a" was found in multiple partitions:`),
701		},
702	}
703
704	for _, tc := range testCases {
705		t.Run(tc.name, func(t *testing.T) {
706			got := PartitionLabelListAttribute(tc.ctx, &tc.labelList, tc.filters)
707
708			if hasErrors, expectsErr := len(tc.ctx.errors) > 0, tc.expectedErrMsg != nil; hasErrors != expectsErr {
709				t.Errorf("Unexpected error(s): %q, expected: %q", tc.ctx.errors, *tc.expectedErrMsg)
710			} else if tc.expectedErrMsg != nil {
711				found := false
712				for _, err := range tc.ctx.errors {
713					if strings.Contains(err, *tc.expectedErrMsg) {
714						found = true
715						break
716					}
717				}
718
719				if !found {
720					t.Errorf("Expected error message: %q, got %q", *tc.expectedErrMsg, tc.ctx.errors)
721				}
722				return
723			}
724
725			if len(tc.expected) != len(got) {
726				t.Errorf("Expected %d partitions, got %d partitions", len(tc.expected), len(got))
727			}
728			for partition, expectedLla := range tc.expected {
729				gotLla, ok := got[partition]
730				if !ok {
731					t.Errorf("Expected partition %q, but it was not found %v", partition, got)
732					continue
733				}
734				expectedLabelList := expectedLla.Value
735				gotLabelList := gotLla.Value
736				if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
737					t.Errorf("Expected no config includes %v, got %v", expectedLabelList.Includes, gotLabelList.Includes)
738				}
739				expectedAxes := expectedLla.SortedConfigurationAxes()
740				gotAxes := gotLla.SortedConfigurationAxes()
741				if !reflect.DeepEqual(expectedAxes, gotAxes) {
742					t.Errorf("Expected axes %v, got %v (%#v)", expectedAxes, gotAxes, gotLla)
743				}
744				for _, axis := range expectedLla.SortedConfigurationAxes() {
745					if _, exists := gotLla.ConfigurableValues[axis]; !exists {
746						t.Errorf("Expected %s to be a supported axis, but it was not found", axis)
747					}
748					if expected, got := expectedLla.ConfigurableValues[axis], gotLla.ConfigurableValues[axis]; len(expected) != len(got) {
749						t.Errorf("For axis %q: expected configs %v, got %v", axis, expected, got)
750					}
751					for config, expectedLabelList := range expectedLla.ConfigurableValues[axis] {
752						gotLabelList, exists := gotLla.ConfigurableValues[axis][config]
753						if !exists {
754							t.Errorf("Expected %s to be a supported config, but config was not found", config)
755							continue
756						}
757						if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
758							t.Errorf("Expected %s %s includes %v, got %v", axis, config, expectedLabelList.Includes, gotLabelList.Includes)
759						}
760					}
761				}
762			}
763		})
764	}
765}
766
767func TestDeduplicateAxesFromBase(t *testing.T) {
768	attr := StringListAttribute{
769		Value: []string{
770			"all_include",
771			"arm_include",
772			"android_include",
773			"linux_x86_include",
774		},
775		ConfigurableValues: configurableStringLists{
776			ArchConfigurationAxis: stringListSelectValues{
777				"arm": []string{"arm_include"},
778				"x86": []string{"x86_include"},
779			},
780			OsConfigurationAxis: stringListSelectValues{
781				"android": []string{"android_include"},
782				"linux":   []string{"linux_include"},
783			},
784			OsArchConfigurationAxis: stringListSelectValues{
785				"linux_x86": {"linux_x86_include"},
786			},
787			ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
788				"a": []string{"not_in_value"},
789			},
790		},
791	}
792
793	attr.DeduplicateAxesFromBase()
794
795	expectedBaseIncludes := []string{
796		"all_include",
797		"arm_include",
798		"android_include",
799		"linux_x86_include",
800	}
801	if !reflect.DeepEqual(expectedBaseIncludes, attr.Value) {
802		t.Errorf("Expected Value includes %q, got %q", attr.Value, expectedBaseIncludes)
803	}
804	expectedConfiguredIncludes := configurableStringLists{
805		ArchConfigurationAxis: stringListSelectValues{
806			"x86": []string{"x86_include"},
807		},
808		OsConfigurationAxis: stringListSelectValues{
809			"linux": []string{"linux_include"},
810		},
811		OsArchConfigurationAxis: stringListSelectValues{},
812		ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
813			"a": []string{"not_in_value"},
814		},
815	}
816	for _, axis := range attr.SortedConfigurationAxes() {
817		if _, ok := expectedConfiguredIncludes[axis]; !ok {
818			t.Errorf("Found unexpected axis %s", axis)
819			continue
820		}
821		expectedForAxis := expectedConfiguredIncludes[axis]
822		gotForAxis := attr.ConfigurableValues[axis]
823		if len(expectedForAxis) != len(gotForAxis) {
824			t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
825		}
826		for config, value := range gotForAxis {
827			if expected, ok := expectedForAxis[config]; ok {
828				if !reflect.DeepEqual(expected, value) {
829					t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value)
830				}
831			} else {
832				t.Errorf("Got unexpected config %q for %s", config, axis)
833			}
834		}
835	}
836}
837