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