github.com/boyter/gocodewalker@v1.3.2/file_test.go (about) 1 // SPDX-License-Identifier: MIT OR Unlicense 2 3 package gocodewalker 4 5 import ( 6 "errors" 7 "math/rand" 8 "os" 9 "path/filepath" 10 "regexp" 11 "strings" 12 "testing" 13 ) 14 15 func TestFindRepositoryRoot(t *testing.T) { 16 // We expect this to walk back from file to root 17 curdir, _ := os.Getwd() 18 root := FindRepositoryRoot(curdir) 19 20 if strings.HasSuffix(root, "file") { 21 t.Error("Expected to walk back to root") 22 } 23 } 24 25 func TestNewFileWalker(t *testing.T) { 26 fileListQueue := make(chan *File, 10_000) // NB we set buffered to ensure we get everything 27 curdir, _ := os.Getwd() 28 walker := NewFileWalker(curdir, fileListQueue) 29 _ = walker.Start() 30 31 count := 0 32 for range fileListQueue { 33 count++ 34 } 35 36 if count == 0 { 37 t.Error("Expected to find at least one file") 38 } 39 } 40 41 func TestNewFileWalkerEmptyEverything(t *testing.T) { 42 fileListQueue := make(chan *File, 10_000) // NB we set buffered to ensure we get everything 43 walker := NewFileWalker("", fileListQueue) 44 45 called := false 46 walker.SetErrorHandler(func(err error) bool { 47 called = true 48 return true 49 }) 50 _ = walker.Start() 51 52 count := 0 53 for range fileListQueue { 54 count++ 55 } 56 57 if count != 0 { 58 t.Error("Expected to find nothing") 59 } 60 61 if called { 62 t.Error("expected to not be called") 63 } 64 } 65 66 func TestNewFileWalkerEmptyEverythingParallel(t *testing.T) { 67 fileListQueue := make(chan *File, 10_000) // NB we set buffered to ensure we get everything 68 walker := NewParallelFileWalker([]string{}, fileListQueue) 69 70 called := false 71 walker.SetErrorHandler(func(err error) bool { 72 called = true 73 return true 74 }) 75 _ = walker.Start() 76 77 count := 0 78 for range fileListQueue { 79 count++ 80 } 81 82 if count != 0 { 83 t.Error("Expected to find nothing") 84 } 85 86 if called { 87 t.Error("expected to not be called") 88 } 89 } 90 91 func TestNewParallelFileWalker(t *testing.T) { 92 fileListQueue := make(chan *File, 10_000) // NB we set buffered to ensure we get everything 93 curdir, _ := os.Getwd() 94 walker := NewParallelFileWalker([]string{curdir, curdir}, fileListQueue) 95 _ = walker.Start() 96 97 count := 0 98 for range fileListQueue { 99 count++ 100 } 101 102 if count == 0 { 103 t.Error("Expected to find at least one file") 104 } 105 } 106 107 func TestNewFileWalkerStuff(t *testing.T) { 108 fileListQueue := make(chan *File, 10_000) // NB we set buffered to ensure we get everything 109 curdir, _ := os.Getwd() 110 walker := NewFileWalker(curdir, fileListQueue) 111 112 if walker.Walking() != false { 113 t.Error("should not be walking yet") 114 } 115 116 walker.Terminate() 117 _ = walker.Start() 118 119 count := 0 120 for range fileListQueue { 121 count++ 122 } 123 124 if count != 0 { 125 t.Error("Expected to find no files") 126 } 127 } 128 129 func TestNewFileWalkerFsOpenErrorHandler(t *testing.T) { 130 osOpen := func(name string) (*os.File, error) { 131 return nil, errors.New("error was handled") 132 } 133 134 walker := NewFileWalker(".", make(chan *File, 1000)) 135 walker.osOpen = osOpen 136 137 wasCalled := false 138 errorHandler := func(e error) bool { 139 if e.Error() == "error was handled" { 140 wasCalled = true 141 } 142 return false 143 } 144 walker.SetErrorHandler(errorHandler) 145 err := walker.Start() 146 147 if !wasCalled { 148 t.Error("expected error to be called") 149 } 150 if err == nil { 151 t.Error("expected error got nil") 152 } 153 } 154 155 func TestNewFileWalkerNotDirectory(t *testing.T) { 156 osOpen := func(name string) (*os.File, error) { 157 f, _ := os.CreateTemp("", ".ignore") 158 return f, nil 159 } 160 161 walker := NewFileWalker(".", make(chan *File, 10)) 162 walker.osOpen = osOpen 163 walker.SetErrorHandler(func(e error) bool { return false }) 164 165 err := walker.Start() 166 if !strings.Contains(err.Error(), "not a directory") { 167 t.Error("expected not a directory got", err.Error()) 168 } 169 } 170 171 func randSeq(n int) string { 172 letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") 173 b := make([]rune, n) 174 for i := range b { 175 b[i] = letters[rand.Intn(len(letters))] 176 } 177 return string(b) 178 } 179 180 func TestNewFileWalkerIgnoreFileCases(t *testing.T) { 181 type testcase struct { 182 Name string 183 Case func() *FileWalker 184 ExpectCall bool 185 } 186 187 testCases := []testcase{ 188 { 189 Name: ".ignorefile ignore", 190 Case: func() *FileWalker { 191 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 192 _, _ = os.Create(filepath.Join(d, ".ignore")) 193 194 fileListQueue := make(chan *File, 10) 195 walker := NewFileWalker(d, fileListQueue) 196 197 // what we want to test is here 198 walker.IgnoreIgnoreFile = true 199 return walker 200 }, 201 ExpectCall: false, 202 }, 203 { 204 Name: ".ignorefile include", 205 Case: func() *FileWalker { 206 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 207 _, _ = os.Create(filepath.Join(d, ".ignore")) 208 209 fileListQueue := make(chan *File, 10) 210 walker := NewFileWalker(d, fileListQueue) 211 212 walker.IgnoreIgnoreFile = false 213 return walker 214 }, 215 ExpectCall: true, 216 }, 217 { 218 Name: ".gitignore ignore", 219 Case: func() *FileWalker { 220 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 221 _, _ = os.Create(filepath.Join(d, ".gitignore")) 222 223 fileListQueue := make(chan *File, 10) 224 walker := NewFileWalker(d, fileListQueue) 225 226 walker.IgnoreGitIgnore = true 227 return walker 228 }, 229 ExpectCall: false, 230 }, 231 { 232 Name: ".gitignore include", 233 Case: func() *FileWalker { 234 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 235 _, _ = os.Create(filepath.Join(d, ".gitignore")) 236 237 fileListQueue := make(chan *File, 10) 238 walker := NewFileWalker(d, fileListQueue) 239 240 walker.IgnoreGitIgnore = false 241 return walker 242 }, 243 ExpectCall: true, 244 }, 245 } 246 247 for _, tc := range testCases { 248 t.Run(tc.Name, func(t *testing.T) { 249 called := false 250 osReadFile := func(name string) ([]byte, error) { 251 called = true 252 return nil, nil 253 } 254 255 walker := tc.Case() 256 walker.osReadFile = osReadFile 257 _ = walker.Start() 258 259 if tc.ExpectCall { 260 if !called { 261 t.Errorf("expected to be called but was not!") 262 } 263 } else { 264 if called { 265 t.Errorf("expected to be ignored but was not!") 266 } 267 } 268 }) 269 } 270 } 271 272 func TestNewFileWalkerFileCases(t *testing.T) { 273 type testcase struct { 274 Name string 275 Case func() (*FileWalker, chan *File) 276 Expected int 277 } 278 279 testCases := []testcase{ 280 { 281 Name: "ExcludeListExtensions 0", 282 Case: func() (*FileWalker, chan *File) { 283 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 284 _, _ = os.Create(filepath.Join(d, "test.txt")) 285 286 fileListQueue := make(chan *File, 10) 287 walker := NewFileWalker(d, fileListQueue) 288 289 walker.ExcludeListExtensions = []string{"txt"} 290 return walker, fileListQueue 291 }, 292 Expected: 0, 293 }, 294 { 295 Name: "ExcludeListExtensions 1", 296 Case: func() (*FileWalker, chan *File) { 297 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 298 _, _ = os.Create(filepath.Join(d, "test.txt")) 299 300 fileListQueue := make(chan *File, 10) 301 walker := NewFileWalker(d, fileListQueue) 302 303 walker.ExcludeListExtensions = []string{"md"} 304 return walker, fileListQueue 305 }, 306 Expected: 1, 307 }, 308 { 309 Name: "AllowListExtensions 1", 310 Case: func() (*FileWalker, chan *File) { 311 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 312 _, _ = os.Create(filepath.Join(d, "test.txt")) 313 314 fileListQueue := make(chan *File, 10) 315 walker := NewFileWalker(d, fileListQueue) 316 317 walker.AllowListExtensions = []string{"txt"} 318 return walker, fileListQueue 319 }, 320 Expected: 1, 321 }, 322 { 323 Name: "ExcludeListExtensions 0 Multiple", 324 Case: func() (*FileWalker, chan *File) { 325 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 326 _, _ = os.Create(filepath.Join(d, "test.txt")) 327 328 fileListQueue := make(chan *File, 10) 329 walker := NewFileWalker(d, fileListQueue) 330 331 walker.ExcludeListExtensions = []string{"md", "go", "txt"} 332 return walker, fileListQueue 333 }, 334 Expected: 0, 335 }, 336 { 337 Name: "AllowListExtensions 0", 338 Case: func() (*FileWalker, chan *File) { 339 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 340 _, _ = os.Create(filepath.Join(d, "test.md")) 341 342 fileListQueue := make(chan *File, 10) 343 walker := NewFileWalker(d, fileListQueue) 344 345 walker.AllowListExtensions = []string{"txt"} 346 return walker, fileListQueue 347 }, 348 Expected: 0, 349 }, 350 { 351 Name: "AllowListExtensions 1 Multiple", 352 Case: func() (*FileWalker, chan *File) { 353 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 354 _, _ = os.Create(filepath.Join(d, "test.md")) 355 356 fileListQueue := make(chan *File, 10) 357 walker := NewFileWalker(d, fileListQueue) 358 359 walker.AllowListExtensions = []string{"txt", "md"} 360 return walker, fileListQueue 361 }, 362 Expected: 1, 363 }, 364 { 365 Name: "IncludeFilenameRegex 1", 366 Case: func() (*FileWalker, chan *File) { 367 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 368 _, _ = os.Create(filepath.Join(d, "test.md")) 369 370 fileListQueue := make(chan *File, 10) 371 walker := NewFileWalker(d, fileListQueue) 372 373 walker.IncludeFilenameRegex = []*regexp.Regexp{regexp.MustCompile(".*")} 374 return walker, fileListQueue 375 }, 376 Expected: 1, 377 }, 378 { 379 Name: "IncludeFilenameRegex 0", 380 Case: func() (*FileWalker, chan *File) { 381 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 382 _, _ = os.Create(filepath.Join(d, "test.md")) 383 384 fileListQueue := make(chan *File, 10) 385 walker := NewFileWalker(d, fileListQueue) 386 387 walker.IncludeFilenameRegex = []*regexp.Regexp{regexp.MustCompile("test.go")} 388 return walker, fileListQueue 389 }, 390 Expected: 0, 391 }, 392 { 393 Name: "ExcludeFilenameRegex 0", 394 Case: func() (*FileWalker, chan *File) { 395 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 396 _, _ = os.Create(filepath.Join(d, "test.md")) 397 398 fileListQueue := make(chan *File, 10) 399 walker := NewFileWalker(d, fileListQueue) 400 401 walker.ExcludeFilenameRegex = []*regexp.Regexp{regexp.MustCompile(".*")} 402 return walker, fileListQueue 403 }, 404 Expected: 0, 405 }, 406 { 407 Name: "ExcludeFilenameRegex 1", 408 Case: func() (*FileWalker, chan *File) { 409 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 410 _, _ = os.Create(filepath.Join(d, "test.md")) 411 412 fileListQueue := make(chan *File, 10) 413 walker := NewFileWalker(d, fileListQueue) 414 415 walker.ExcludeFilenameRegex = []*regexp.Regexp{regexp.MustCompile("nothing")} 416 return walker, fileListQueue 417 }, 418 Expected: 1, 419 }, 420 { 421 Name: "IncludeFilenameRegex 1", 422 Case: func() (*FileWalker, chan *File) { 423 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 424 _, _ = os.Create(filepath.Join(d, "test.md")) 425 426 fileListQueue := make(chan *File, 10) 427 walker := NewFileWalker(d, fileListQueue) 428 429 walker.IncludeFilenameRegex = []*regexp.Regexp{regexp.MustCompile(".*")} 430 return walker, fileListQueue 431 }, 432 Expected: 1, 433 }, 434 { 435 Name: "IncludeFilenameRegex 0", 436 Case: func() (*FileWalker, chan *File) { 437 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 438 _, _ = os.Create(filepath.Join(d, "test.md")) 439 440 fileListQueue := make(chan *File, 10) 441 walker := NewFileWalker(d, fileListQueue) 442 443 walker.IncludeFilenameRegex = []*regexp.Regexp{regexp.MustCompile("nothing")} 444 return walker, fileListQueue 445 }, 446 Expected: 0, 447 }, 448 } 449 450 for _, tc := range testCases { 451 t.Run(tc.Name, func(t *testing.T) { 452 osReadFile := func(name string) ([]byte, error) { 453 return nil, nil 454 } 455 456 walker, fileListQueue := tc.Case() 457 walker.osReadFile = osReadFile 458 _ = walker.Start() 459 460 c := 0 461 for range fileListQueue { 462 c++ 463 } 464 465 if c != tc.Expected { 466 t.Errorf("expected %v but got %v", tc.Expected, c) 467 } 468 }) 469 } 470 } 471 472 func TestNewFileWalkerDirectoryCases(t *testing.T) { 473 type testcase struct { 474 Name string 475 Case func() (*FileWalker, chan *File) 476 Expected int 477 } 478 479 testCases := []testcase{ 480 { 481 Name: "ExcludeDirectory 0", 482 Case: func() (*FileWalker, chan *File) { 483 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 484 d2 := filepath.Join(d, "stuff") 485 _ = os.Mkdir(d2, 0777) 486 _, _ = os.Create(filepath.Join(d2, "/test.md")) 487 488 fileListQueue := make(chan *File, 10) 489 walker := NewFileWalker(d, fileListQueue) 490 491 walker.ExcludeDirectory = []string{"stuff"} 492 return walker, fileListQueue 493 }, 494 Expected: 0, 495 }, 496 { 497 Name: "ExcludeDirectory 1", 498 Case: func() (*FileWalker, chan *File) { 499 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 500 d2 := filepath.Join(d, "stuff") 501 _ = os.Mkdir(d2, 0777) 502 _, _ = os.Create(filepath.Join(d2, "/test.md")) 503 504 fileListQueue := make(chan *File, 10) 505 walker := NewFileWalker(d, fileListQueue) 506 507 walker.ExcludeDirectory = []string{"notmatching"} 508 return walker, fileListQueue 509 }, 510 Expected: 1, 511 }, 512 { 513 Name: "IncludeDirectory 1", 514 Case: func() (*FileWalker, chan *File) { 515 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 516 d2 := filepath.Join(d, "stuff") 517 _ = os.Mkdir(d2, 0777) 518 _, _ = os.Create(filepath.Join(d2, "/test.md")) 519 520 fileListQueue := make(chan *File, 10) 521 walker := NewFileWalker(d, fileListQueue) 522 523 walker.IncludeDirectory = []string{"stuff"} 524 return walker, fileListQueue 525 }, 526 Expected: 1, 527 }, 528 { 529 Name: "IncludeDirectory 0", 530 Case: func() (*FileWalker, chan *File) { 531 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 532 d2 := filepath.Join(d, "stuff") 533 _ = os.Mkdir(d2, 0777) 534 _, _ = os.Create(filepath.Join(d2, "/test.md")) 535 536 fileListQueue := make(chan *File, 10) 537 walker := NewFileWalker(d, fileListQueue) 538 539 walker.IncludeDirectory = []string{"otherthing"} 540 return walker, fileListQueue 541 }, 542 Expected: 0, 543 }, 544 { 545 Name: "IncludeDirectoryRegex 0", 546 Case: func() (*FileWalker, chan *File) { 547 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 548 d2 := filepath.Join(d, "stuff") 549 _ = os.Mkdir(d2, 0777) 550 _, _ = os.Create(filepath.Join(d2, "/test.md")) 551 552 fileListQueue := make(chan *File, 10) 553 walker := NewFileWalker(d, fileListQueue) 554 555 walker.IncludeDirectoryRegex = []*regexp.Regexp{regexp.MustCompile("nothing")} 556 return walker, fileListQueue 557 }, 558 Expected: 0, 559 }, 560 { 561 Name: "IncludeDirectoryRegex 1", 562 Case: func() (*FileWalker, chan *File) { 563 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 564 d2 := filepath.Join(d, "stuff") 565 _ = os.Mkdir(d2, 0777) 566 _, _ = os.Create(filepath.Join(d2, "/test.md")) 567 568 fileListQueue := make(chan *File, 10) 569 walker := NewFileWalker(d, fileListQueue) 570 571 walker.IncludeDirectoryRegex = []*regexp.Regexp{regexp.MustCompile("stuff")} 572 return walker, fileListQueue 573 }, 574 Expected: 1, 575 }, 576 { 577 Name: "ExcludeDirectoryRegex 0", 578 Case: func() (*FileWalker, chan *File) { 579 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 580 d2 := filepath.Join(d, "stuff") 581 _ = os.Mkdir(d2, 0777) 582 _, _ = os.Create(filepath.Join(d2, "/test.md")) 583 584 fileListQueue := make(chan *File, 10) 585 walker := NewFileWalker(d, fileListQueue) 586 587 walker.ExcludeDirectoryRegex = []*regexp.Regexp{regexp.MustCompile("stuff")} 588 return walker, fileListQueue 589 }, 590 Expected: 0, 591 }, 592 { 593 Name: "ExcludeDirectoryRegex 0", 594 Case: func() (*FileWalker, chan *File) { 595 d, _ := os.MkdirTemp(os.TempDir(), randSeq(10)) 596 d2 := filepath.Join(d, "stuff") 597 _ = os.Mkdir(d2, 0777) 598 _, _ = os.Create(filepath.Join(d2, "/test.md")) 599 600 fileListQueue := make(chan *File, 10) 601 walker := NewFileWalker(d, fileListQueue) 602 603 walker.ExcludeDirectoryRegex = []*regexp.Regexp{regexp.MustCompile(".*")} 604 return walker, fileListQueue 605 }, 606 Expected: 0, 607 }, 608 } 609 610 for _, tc := range testCases { 611 t.Run(tc.Name, func(t *testing.T) { 612 osReadFile := func(name string) ([]byte, error) { 613 return nil, nil 614 } 615 616 walker, fileListQueue := tc.Case() 617 walker.osReadFile = osReadFile 618 _ = walker.Start() 619 620 c := 0 621 for range fileListQueue { 622 c++ 623 } 624 625 if c != tc.Expected { 626 t.Errorf("expected %v but got %v", tc.Expected, c) 627 } 628 }) 629 } 630 } 631 632 func TestGetExtension(t *testing.T) { 633 got := GetExtension("something.c") 634 expected := "c" 635 636 if got != expected { 637 t.Errorf("Expected %s got %s", expected, got) 638 } 639 } 640 641 func TestGetExtensionNoExtension(t *testing.T) { 642 got := GetExtension("something") 643 expected := "something" 644 645 if got != expected { 646 t.Errorf("Expected %s got %s", expected, got) 647 } 648 } 649 650 func TestGetExtensionMultipleDots(t *testing.T) { 651 got := GetExtension(".travis.yml") 652 expected := "yml" 653 654 if got != expected { 655 t.Errorf("Expected %s got %s", expected, got) 656 } 657 } 658 659 func TestGetExtensionMultipleExtensions(t *testing.T) { 660 got := GetExtension("something.go.yml") 661 expected := "yml" 662 663 if got != expected { 664 t.Errorf("Expected %s got %s", expected, got) 665 } 666 } 667 668 func TestGetExtensionStartsWith(t *testing.T) { 669 got := GetExtension(".gitignore") 670 expected := ".gitignore" 671 672 if got != expected { 673 t.Errorf("Expected %s got %s", expected, got) 674 } 675 } 676 677 func TestGetExtensionTypeScriptDefinition(t *testing.T) { 678 got := GetExtension("test.d.ts") 679 expected := "ts" 680 681 if got != expected { 682 t.Errorf("Expected %s got %s", expected, got) 683 } 684 } 685 686 func TestGetExtensionRegression(t *testing.T) { 687 got := GetExtension("DeviceDescription.stories.tsx") 688 expected := "tsx" 689 690 if got != expected { 691 t.Errorf("Expected %s got %s", expected, got) 692 } 693 }