github.com/abayer/test-infra@v0.0.5/mungegithub/mungers/approvers/owners_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package approvers 18 19 import ( 20 "testing" 21 22 "k8s.io/apimachinery/pkg/util/sets" 23 24 "path/filepath" 25 "reflect" 26 "strings" 27 ) 28 29 const ( 30 TEST_SEED = int64(0) 31 FAKE_REPO_ORG = "fake_org" 32 FAKE_REPO_PROJECT = "fake_project" 33 ) 34 35 type FakeRepo struct { 36 ApproversMap map[string]sets.String 37 LeafApproversMap map[string]sets.String 38 } 39 40 func (f FakeRepo) Org() string { 41 return FAKE_REPO_ORG 42 } 43 44 func (f FakeRepo) Project() string { 45 return FAKE_REPO_PROJECT 46 } 47 48 func (f FakeRepo) Approvers(path string) sets.String { 49 return f.ApproversMap[path] 50 } 51 52 func (f FakeRepo) LeafApprovers(path string) sets.String { 53 return f.LeafApproversMap[path] 54 } 55 56 func (f FakeRepo) FindApproverOwnersForPath(path string) string { 57 dir, _ := filepath.Split(path) 58 for dir != "." { 59 if _, ok := f.LeafApproversMap[dir]; ok { 60 return dir 61 } 62 dir = filepath.Dir(dir) 63 } 64 return "" 65 } 66 67 type dir struct { 68 fullPath string 69 approvers sets.String 70 } 71 72 func canonicalize(path string) string { 73 if path == "." { 74 return "" 75 } 76 return strings.TrimSuffix(path, "/") 77 } 78 79 func createFakeRepo(la map[string]sets.String) FakeRepo { 80 // github doesn't use / at the root 81 a := map[string]sets.String{} 82 for dir, approvers := range la { 83 la[dir] = setToLower(approvers) 84 a[dir] = setToLower(approvers) 85 starting_path := dir 86 for { 87 dir = canonicalize(filepath.Dir(dir)) 88 if parent_approvers, ok := la[dir]; ok { 89 a[starting_path] = a[starting_path].Union(setToLower(parent_approvers)) 90 } 91 if dir == "" { 92 break 93 } 94 } 95 } 96 97 return FakeRepo{ApproversMap: a, LeafApproversMap: la} 98 } 99 100 func setToLower(s sets.String) sets.String { 101 lowered := sets.NewString() 102 for _, elem := range s.List() { 103 lowered.Insert(strings.ToLower(elem)) 104 } 105 return lowered 106 } 107 108 func TestCreateFakeRepo(t *testing.T) { 109 rootApprovers := sets.NewString("Alice", "Bob") 110 aApprovers := sets.NewString("Art", "Anne") 111 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 112 cApprovers := sets.NewString("Chris", "Carol") 113 eApprovers := sets.NewString("Eve", "Erin") 114 edcApprovers := eApprovers.Union(cApprovers) 115 FakeRepoMap := map[string]sets.String{ 116 "": rootApprovers, 117 "a": aApprovers, 118 "b": bApprovers, 119 "c": cApprovers, 120 "a/combo": edcApprovers, 121 } 122 fake_repo := createFakeRepo(FakeRepoMap) 123 124 tests := []struct { 125 testName string 126 ownersFile string 127 expectedLeafApprovers sets.String 128 expectedApprovers sets.String 129 }{ 130 { 131 testName: "Root Owners", 132 ownersFile: "", 133 expectedApprovers: rootApprovers, 134 expectedLeafApprovers: rootApprovers, 135 }, 136 { 137 testName: "A Owners", 138 ownersFile: "a", 139 expectedLeafApprovers: aApprovers, 140 expectedApprovers: aApprovers.Union(rootApprovers), 141 }, 142 { 143 testName: "B Owners", 144 ownersFile: "b", 145 expectedLeafApprovers: bApprovers, 146 expectedApprovers: bApprovers.Union(rootApprovers), 147 }, 148 { 149 testName: "C Owners", 150 ownersFile: "c", 151 expectedLeafApprovers: cApprovers, 152 expectedApprovers: cApprovers.Union(rootApprovers), 153 }, 154 { 155 testName: "Combo Owners", 156 ownersFile: "a/combo", 157 expectedLeafApprovers: edcApprovers, 158 expectedApprovers: edcApprovers.Union(aApprovers).Union(rootApprovers), 159 }, 160 } 161 162 for _, test := range tests { 163 calculated_leaf_approvers := fake_repo.LeafApprovers(test.ownersFile) 164 calculated_approvers := fake_repo.Approvers(test.ownersFile) 165 166 test.expectedLeafApprovers = setToLower(test.expectedLeafApprovers) 167 if !calculated_leaf_approvers.Equal(test.expectedLeafApprovers) { 168 t.Errorf("Failed for test %v. Expected Leaf Approvers: %v. Actual Leaf Approvers %v", test.testName, test.expectedLeafApprovers, calculated_leaf_approvers) 169 } 170 171 test.expectedApprovers = setToLower(test.expectedApprovers) 172 if !calculated_approvers.Equal(test.expectedApprovers) { 173 t.Errorf("Failed for test %v. Expected Approvers: %v. Actual Approvers %v", test.testName, test.expectedApprovers, calculated_approvers) 174 } 175 } 176 } 177 178 func TestGetLeafApprovers(t *testing.T) { 179 rootApprovers := sets.NewString("Alice", "Bob") 180 aApprovers := sets.NewString("Art", "Anne") 181 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 182 dApprovers := sets.NewString("David", "Dan", "Debbie") 183 FakeRepoMap := map[string]sets.String{ 184 "": rootApprovers, 185 "a": aApprovers, 186 "b": bApprovers, 187 "a/d": dApprovers, 188 } 189 190 tests := []struct { 191 testName string 192 filenames []string 193 expectedMap map[string]sets.String 194 }{ 195 { 196 testName: "Empty PR", 197 filenames: []string{}, 198 expectedMap: map[string]sets.String{}, 199 }, 200 { 201 testName: "Single Root File PR", 202 filenames: []string{"kubernetes.go"}, 203 expectedMap: map[string]sets.String{"": setToLower(rootApprovers)}, 204 }, 205 { 206 testName: "Internal Node File PR", 207 filenames: []string{"a/test.go"}, 208 expectedMap: map[string]sets.String{"a": setToLower(aApprovers)}, 209 }, 210 { 211 testName: "Two Leaf File PR", 212 filenames: []string{"a/d/test.go", "b/test.go"}, 213 expectedMap: map[string]sets.String{ 214 "a/d": setToLower(dApprovers), 215 "b": setToLower(bApprovers)}, 216 }, 217 { 218 testName: "Leaf and Parent 2 File PR", 219 filenames: []string{"a/test.go", "a/d/test.go"}, 220 expectedMap: map[string]sets.String{ 221 "a": setToLower(aApprovers), 222 }, 223 }, 224 } 225 226 for _, test := range tests { 227 testOwners := Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED} 228 oMap := testOwners.GetLeafApprovers() 229 if !reflect.DeepEqual(test.expectedMap, oMap) { 230 t.Errorf("Failed for test %v. Expected Owners: %v. Actual Owners %v", test.testName, test.expectedMap, oMap) 231 } 232 } 233 } 234 func TestGetOwnersSet(t *testing.T) { 235 rootApprovers := sets.NewString("Alice", "Bob") 236 aApprovers := sets.NewString("Art", "Anne") 237 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 238 dApprovers := sets.NewString("David", "Dan", "Debbie") 239 FakeRepoMap := map[string]sets.String{ 240 "": rootApprovers, 241 "a": aApprovers, 242 "b": bApprovers, 243 "a/d": dApprovers, 244 } 245 246 tests := []struct { 247 testName string 248 filenames []string 249 expectedOwnersFiles sets.String 250 }{ 251 { 252 testName: "Empty PR", 253 filenames: []string{}, 254 expectedOwnersFiles: sets.NewString(), 255 }, 256 { 257 testName: "Single Root File PR", 258 filenames: []string{"kubernetes.go"}, 259 expectedOwnersFiles: sets.NewString(""), 260 }, 261 { 262 testName: "Multiple Root File PR", 263 filenames: []string{"test.go", "kubernetes.go"}, 264 expectedOwnersFiles: sets.NewString(""), 265 }, 266 { 267 testName: "Internal Node File PR", 268 filenames: []string{"a/test.go"}, 269 expectedOwnersFiles: sets.NewString("a"), 270 }, 271 { 272 testName: "Two Leaf File PR", 273 filenames: []string{"a/test.go", "b/test.go"}, 274 expectedOwnersFiles: sets.NewString("a", "b"), 275 }, 276 { 277 testName: "Leaf and Parent 2 File PR", 278 filenames: []string{"a/test.go", "a/c/test.go"}, 279 expectedOwnersFiles: sets.NewString("a"), 280 }, 281 } 282 283 for _, test := range tests { 284 testOwners := Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED} 285 oSet := testOwners.GetOwnersSet() 286 if !oSet.Equal(test.expectedOwnersFiles) { 287 t.Errorf("Failed for test %v. Expected Owners: %v. Actual Owners %v", test.testName, test.expectedOwnersFiles, oSet) 288 } 289 } 290 } 291 292 func TestGetSuggestedApprovers(t *testing.T) { 293 var rootApprovers = sets.NewString("Alice", "Bob") 294 var aApprovers = sets.NewString("Art", "Anne") 295 var bApprovers = sets.NewString("Bill", "Ben", "Barbara") 296 var dApprovers = sets.NewString("David", "Dan", "Debbie") 297 var eApprovers = sets.NewString("Eve", "Erin") 298 var edcApprovers = eApprovers.Union(dApprovers) 299 var FakeRepoMap = map[string]sets.String{ 300 "": rootApprovers, 301 "a": aApprovers, 302 "b": bApprovers, 303 "a/d": dApprovers, 304 "a/combo": edcApprovers, 305 } 306 tests := []struct { 307 testName string 308 filenames []string 309 // need at least one person from each set 310 expectedOwners []sets.String 311 }{ 312 { 313 testName: "Empty PR", 314 filenames: []string{}, 315 expectedOwners: []sets.String{}, 316 }, 317 { 318 testName: "Single Root File PR", 319 filenames: []string{"kubernetes.go"}, 320 expectedOwners: []sets.String{setToLower(rootApprovers)}, 321 }, 322 { 323 testName: "Internal Node File PR", 324 filenames: []string{"a/test.go"}, 325 expectedOwners: []sets.String{setToLower(aApprovers)}, 326 }, 327 { 328 testName: "Multiple Files Internal Node File PR", 329 filenames: []string{"a/test.go", "a/test1.go"}, 330 expectedOwners: []sets.String{setToLower(aApprovers)}, 331 }, 332 { 333 testName: "Two Leaf File PR", 334 filenames: []string{"a/test.go", "b/test.go"}, 335 expectedOwners: []sets.String{setToLower(aApprovers), setToLower(bApprovers)}, 336 }, 337 { 338 testName: "Leaf and Parent 2 File PR", 339 filenames: []string{"a/test.go", "a/d/test.go"}, 340 expectedOwners: []sets.String{setToLower(aApprovers)}, 341 }, 342 { 343 testName: "Combo and B", 344 filenames: []string{"a/combo/test.go", "b/test.go"}, 345 expectedOwners: []sets.String{setToLower(edcApprovers), setToLower(bApprovers)}, 346 }, 347 { 348 testName: "Lowest Leaf", 349 filenames: []string{"a/combo/test.go"}, 350 expectedOwners: []sets.String{setToLower(edcApprovers)}, 351 }, 352 } 353 354 for _, test := range tests { 355 testOwners := Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED} 356 suggested := testOwners.GetSuggestedApprovers(testOwners.GetReverseMap(testOwners.GetLeafApprovers()), testOwners.GetShuffledApprovers()) 357 for _, ownersSet := range test.expectedOwners { 358 if ownersSet.Intersection(suggested).Len() == 0 { 359 t.Errorf("Failed for test %v. Didn't find an approver from: %v. Actual Owners %v", test.testName, ownersSet, suggested) 360 t.Errorf("%v", test.filenames) 361 } 362 } 363 } 364 } 365 366 func TestGetAllPotentialApprovers(t *testing.T) { 367 rootApprovers := sets.NewString("Alice", "Bob") 368 aApprovers := sets.NewString("Art", "Anne") 369 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 370 cApprovers := sets.NewString("Chris", "Carol") 371 dApprovers := sets.NewString("David", "Dan", "Debbie") 372 eApprovers := sets.NewString("Eve", "Erin") 373 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 374 FakeRepoMap := map[string]sets.String{ 375 "": rootApprovers, 376 "a": aApprovers, 377 "b": bApprovers, 378 "c": cApprovers, 379 "a/d": dApprovers, 380 "a/combo": edcApprovers, 381 } 382 tests := []struct { 383 testName string 384 filenames []string 385 // use an array because we expected output of this function to be sorted 386 expectedApprovers []string 387 }{ 388 { 389 testName: "Empty PR", 390 filenames: []string{}, 391 expectedApprovers: []string{}, 392 }, 393 { 394 testName: "Single Root File PR", 395 filenames: []string{"kubernetes.go"}, 396 expectedApprovers: setToLower(rootApprovers).List(), 397 }, 398 { 399 testName: "Internal Node File PR", 400 filenames: []string{"a/test.go"}, 401 expectedApprovers: setToLower(aApprovers).List(), 402 }, 403 { 404 testName: "One Leaf One Internal Node File PR", 405 filenames: []string{"a/test.go", "b/test.go"}, 406 expectedApprovers: setToLower(aApprovers.Union(bApprovers)).List(), 407 }, 408 { 409 testName: "Two Leaf Files PR", 410 filenames: []string{"a/d/test.go", "c/test.go"}, 411 expectedApprovers: setToLower(dApprovers.Union(cApprovers)).List(), 412 }, 413 { 414 testName: "Leaf and Parent 2 File PR", 415 filenames: []string{"a/test.go", "a/combo/test.go"}, 416 expectedApprovers: setToLower(aApprovers).List(), 417 }, 418 { 419 testName: "Two Leafs", 420 filenames: []string{"a/d/test.go", "b/test.go"}, 421 expectedApprovers: setToLower(dApprovers.Union(bApprovers)).List(), 422 }, 423 { 424 testName: "Lowest Leaf", 425 filenames: []string{"a/combo/test.go"}, 426 expectedApprovers: setToLower(edcApprovers).List(), 427 }, 428 { 429 testName: "Root And Everything Else PR", 430 filenames: []string{"a/combo/test.go", "b/test.go", "c/test.go", "d/test.go"}, 431 expectedApprovers: setToLower(rootApprovers).List(), 432 }, 433 } 434 435 for _, test := range tests { 436 testOwners := Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED} 437 all := testOwners.GetAllPotentialApprovers() 438 if !reflect.DeepEqual(all, test.expectedApprovers) { 439 t.Errorf("Failed for test %v. Didn't correct approvers list. Expected: %v. Found %v", test.testName, test.expectedApprovers, all) 440 } 441 } 442 } 443 444 func TestFindMostCoveringApprover(t *testing.T) { 445 rootApprovers := sets.NewString("Alice", "Bob") 446 aApprovers := sets.NewString("Art", "Anne") 447 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 448 cApprovers := sets.NewString("Chris", "Carol") 449 dApprovers := sets.NewString("David", "Dan", "Debbie") 450 eApprovers := sets.NewString("Eve", "Erin") 451 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 452 FakeRepoMap := map[string]sets.String{ 453 "": rootApprovers, 454 "a": aApprovers, 455 "b": bApprovers, 456 "c": cApprovers, 457 "a/d": dApprovers, 458 "a/combo": edcApprovers, 459 } 460 tests := []struct { 461 testName string 462 filenames []string 463 unapproved sets.String 464 // because most covering could be two or more people 465 expectedMostCovering sets.String 466 }{ 467 { 468 testName: "Empty PR", 469 filenames: []string{}, 470 unapproved: sets.String{}, 471 expectedMostCovering: sets.NewString(""), 472 }, 473 { 474 testName: "Single Root File PR", 475 filenames: []string{"kubernetes.go"}, 476 unapproved: sets.NewString(""), 477 expectedMostCovering: setToLower(rootApprovers), 478 }, 479 { 480 testName: "Internal Node File PR", 481 filenames: []string{"a/test.go"}, 482 unapproved: sets.NewString("a"), 483 expectedMostCovering: setToLower(aApprovers), 484 }, 485 { 486 testName: "Combo and Intersecting Leaf PR", 487 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 488 unapproved: sets.NewString("a/combo", "a/d"), 489 expectedMostCovering: setToLower(edcApprovers.Intersection(dApprovers)), 490 }, 491 { 492 testName: "Three Leaf PR Only B Approved", 493 filenames: []string{"a/combo/test.go", "c/test.go", "b/test.go"}, 494 unapproved: sets.NewString("a/combo", "c/"), 495 expectedMostCovering: setToLower(edcApprovers.Intersection(cApprovers)), 496 }, 497 { 498 testName: "Three Leaf PR Only B Left Unapproved", 499 filenames: []string{"a/combo/test.go", "a/d/test.go", "b/test.go"}, 500 unapproved: sets.NewString("b"), 501 expectedMostCovering: setToLower(bApprovers), 502 }, 503 { 504 testName: "Leaf and Parent 2 File PR", 505 filenames: []string{"a/test.go", "a/d/test.go"}, 506 unapproved: sets.NewString("a", "a/d"), 507 expectedMostCovering: setToLower(aApprovers.Union(dApprovers)), 508 }, 509 } 510 511 for _, test := range tests { 512 testOwners := Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED} 513 bestPerson := findMostCoveringApprover(testOwners.GetAllPotentialApprovers(), testOwners.GetReverseMap(testOwners.GetLeafApprovers()), test.unapproved) 514 if test.expectedMostCovering.Intersection(sets.NewString(bestPerson)).Len() != 1 { 515 t.Errorf("Failed for test %v. Didn't correct approvers list. Expected: %v. Found %v", test.testName, test.expectedMostCovering, bestPerson) 516 } 517 } 518 } 519 520 func TestGetReverseMap(t *testing.T) { 521 rootApprovers := sets.NewString("Alice", "Bob") 522 aApprovers := sets.NewString("Art", "Anne") 523 cApprovers := sets.NewString("Chris", "Carol") 524 dApprovers := sets.NewString("David", "Dan", "Debbie") 525 eApprovers := sets.NewString("Eve", "Erin") 526 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 527 FakeRepoMap := map[string]sets.String{ 528 "": rootApprovers, 529 "a": aApprovers, 530 "c": cApprovers, 531 "a/d": dApprovers, 532 "a/combo": edcApprovers, 533 } 534 tests := []struct { 535 testName string 536 filenames []string 537 expectedRevMap map[string]sets.String // people -> files they can approve 538 }{ 539 { 540 testName: "Empty PR", 541 filenames: []string{}, 542 expectedRevMap: map[string]sets.String{}, 543 }, 544 { 545 testName: "Single Root File PR", 546 filenames: []string{"kubernetes.go"}, 547 expectedRevMap: map[string]sets.String{ 548 "alice": sets.NewString(""), 549 "bob": sets.NewString(""), 550 }, 551 }, 552 { 553 testName: "Two Leaf PRs", 554 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 555 expectedRevMap: map[string]sets.String{ 556 "david": sets.NewString("a/d", "a/combo"), 557 "dan": sets.NewString("a/d", "a/combo"), 558 "debbie": sets.NewString("a/d", "a/combo"), 559 "eve": sets.NewString("a/combo"), 560 "erin": sets.NewString("a/combo"), 561 "chris": sets.NewString("a/combo"), 562 "carol": sets.NewString("a/combo"), 563 }, 564 }, 565 } 566 567 for _, test := range tests { 568 testOwners := Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED} 569 calculatedRevMap := testOwners.GetReverseMap(testOwners.GetLeafApprovers()) 570 if !reflect.DeepEqual(calculatedRevMap, test.expectedRevMap) { 571 t.Errorf("Failed for test %v. Didn't find correct reverse map.", test.testName) 572 t.Errorf("Person \t\t Expected \t\tFound ") 573 // printing the calculated vs expected in a nicer way for debugging 574 for k, v := range test.expectedRevMap { 575 if calcVal, ok := calculatedRevMap[k]; ok { 576 t.Errorf("%v\t\t%v\t\t%v ", k, v, calcVal) 577 } else { 578 t.Errorf("%v\t\t%v", k, v) 579 } 580 } 581 } 582 } 583 } 584 585 func TestGetShuffledApprovers(t *testing.T) { 586 rootApprovers := sets.NewString("Alice", "Bob") 587 aApprovers := sets.NewString("Art", "Anne") 588 bApprovers := sets.NewString("Bill", "Ben", "Barbara") 589 cApprovers := sets.NewString("Chris", "Carol") 590 dApprovers := sets.NewString("David", "Dan", "Debbie") 591 eApprovers := sets.NewString("Eve", "Erin") 592 edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers) 593 FakeRepoMap := map[string]sets.String{ 594 "": rootApprovers, 595 "a": aApprovers, 596 "b": bApprovers, 597 "c": cApprovers, 598 "a/d": dApprovers, 599 "a/combo": edcApprovers, 600 } 601 tests := []struct { 602 testName string 603 filenames []string 604 seed int64 605 expectedOrder []string 606 }{ 607 { 608 testName: "Empty PR", 609 filenames: []string{}, 610 seed: 0, 611 expectedOrder: []string{}, 612 }, 613 { 614 testName: "Single Root File PR Approved", 615 filenames: []string{"kubernetes.go"}, 616 seed: 0, 617 expectedOrder: []string{"bob", "alice"}, 618 }, 619 { 620 testName: "Combo And B PR", 621 filenames: []string{"a/combo/test.go", "b/test.go"}, 622 seed: 0, 623 expectedOrder: []string{"erin", "bill", "carol", "barbara", "dan", "debbie", "ben", "david", "eve", "chris"}, 624 }, 625 { 626 testName: "Combo and D, Seed 0", 627 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 628 seed: 0, 629 expectedOrder: []string{"erin", "dan", "dan", "carol", "david", "debbie", "chris", "debbie", "eve", "david"}, 630 }, 631 { 632 testName: "Combo and D, Seed 2", 633 filenames: []string{"a/combo/test.go", "a/d/test.go"}, 634 seed: 2, 635 expectedOrder: []string{"dan", "carol", "debbie", "dan", "erin", "chris", "eve", "david", "debbie", "david"}, 636 }, 637 } 638 639 for _, test := range tests { 640 testOwners := Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: test.seed} 641 calculated := testOwners.GetShuffledApprovers() 642 if !reflect.DeepEqual(test.expectedOrder, calculated) { 643 t.Errorf("Failed for test %v. Expected unapproved files: %v. Found %v", test.testName, test.expectedOrder, calculated) 644 } 645 } 646 } 647 648 func TestRemoveSubdirs(t *testing.T) { 649 tests := []struct { 650 testName string 651 directories []string 652 expected sets.String 653 }{ 654 { 655 testName: "Empty PR", 656 directories: []string{}, 657 expected: sets.NewString(), 658 }, 659 { 660 testName: "Root and One Level Below PR", 661 directories: []string{"", "a/"}, 662 expected: sets.NewString(""), 663 }, 664 { 665 testName: "Two Separate Branches", 666 directories: []string{"a/", "c/"}, 667 expected: sets.NewString("a/", "c/"), 668 }, 669 { 670 testName: "Lots of Branches and Leaves", 671 directories: []string{"a", "a/combo", "a/d", "b", "c"}, 672 expected: sets.NewString("a", "b", "c"), 673 }, 674 } 675 676 for _, test := range tests { 677 calculated := removeSubdirs(test.directories) 678 if !reflect.DeepEqual(test.expected, calculated) { 679 t.Errorf("Failed to remove subdirectories for test %v. Expected files: %v. Found %v", test.testName, test.expected, calculated) 680 681 } 682 } 683 }