| @@ -578,7 +578,7 @@ fn untracked_and_ignored_pathspec_guidance() -> crate::Result { · 577 unmodified lines |
| 578 | } | 578 | } |
| 579 | | 579 | |
| 580 | #[test] | 580 | #[test] |
| 581 | fn untracked_and_ignored_for_deletion_negative_spec() -> crate::Result { | 581 | fn untracked_and_ignored_for_deletion_negative_wildcard_spec() -> crate::Result { |
| 582 | let root = fixture("subdir-untracked-and-ignored"); | 582 | let root = fixture("subdir-untracked-and-ignored"); |
| 583 | let (out, entries) = collect_filtered( | 583 | let (out, entries) = collect_filtered( |
| 584 | &root, | 584 | &root, |
| @@ -632,6 +632,274 @@ fn untracked_and_ignored_for_deletion_negative_spec() -> crate::Result { · 47 unmodified lines |
| 632 | Ok(()) | 632 | Ok(()) |
| 633 | } | 633 | } |
| 634 | | 634 | |
| | 635 | #[test] |
| | 636 | fn untracked_and_ignored_for_deletion_positive_wildcard_spec() -> crate::Result { |
| | 637 | let root = fixture("subdir-untracked-and-ignored"); |
| | 638 | let (out, entries) = collect_filtered( |
| | 639 | &root, |
| | 640 | |keep, ctx| { |
| | 641 | walk( |
| | 642 | &root, |
| | 643 | &root, |
| | 644 | ctx, |
| | 645 | walk::Options { |
| | 646 | emit_ignored: Some(CollapseDirectory), |
| | 647 | emit_untracked: CollapseDirectory, |
| | 648 | emit_pruned: true, |
| | 649 | for_deletion: Some(Default::default()), |
| | 650 | ..options() |
| | 651 | }, |
| | 652 | keep, |
| | 653 | ) |
| | 654 | }, |
| | 655 | Some("*generated*"), |
| | 656 | ); |
| | 657 | assert_eq!( |
| | 658 | out, |
| | 659 | walk::Outcome { |
| | 660 | read_dir_calls: 8, |
| | 661 | returned_entries: entries.len(), |
| | 662 | seen_entries: 27, |
| | 663 | }, |
| | 664 | ); |
| | 665 | assert_eq!( |
| | 666 | &entries, |
| | 667 | &[ |
| | 668 | entry_nokind(".git", DotGit), |
| | 669 | entry_nomatch(".gitignore", Pruned, File), |
| | 670 | entry_nomatch("a.o", Ignored(Expendable), File), |
| | 671 | entry_nomatch("b.o", Ignored(Expendable), File), |
| | 672 | entry_nomatch("c.o", Ignored(Expendable), File), |
| | 673 | entry_nomatch("d/a.o", Ignored(Expendable), File), |
| | 674 | entry_nomatch("d/b.o", Ignored(Expendable), File), |
| | 675 | entry_nomatch("d/d/a", Pruned, File), |
| | 676 | entry_nomatch("d/d/a.o", Ignored(Expendable), File), |
| | 677 | entry_nomatch("d/d/b.o", Ignored(Expendable), File), |
| | 678 | entryps("d/d/generated", Ignored(Expendable), Directory, WildcardMatch), |
| | 679 | entryps("d/generated", Ignored(Expendable), Directory, WildcardMatch), |
| | 680 | entryps("generated", Ignored(Expendable), Directory, WildcardMatch), |
| | 681 | entry_nomatch("objs", Ignored(Expendable), Directory), |
| | 682 | ], |
| | 683 | "'generated' folders are included, and collapsing is done where possible" |
| | 684 | ); |
| | 685 | Ok(()) |
| | 686 | } |
| | 687 | |
| | 688 | #[test] |
| | 689 | fn untracked_and_ignored_for_deletion_nonmatching_wildcard_spec() -> crate::Result { |
| | 690 | let root = fixture("subdir-untracked-and-ignored"); |
| | 691 | let (out, entries) = collect_filtered( |
| | 692 | &root, |
| | 693 | |keep, ctx| { |
| | 694 | walk( |
| | 695 | &root, |
| | 696 | &root, |
| | 697 | ctx, |
| | 698 | walk::Options { |
| | 699 | emit_ignored: Some(CollapseDirectory), |
| | 700 | emit_untracked: CollapseDirectory, |
| | 701 | emit_pruned: true, |
| | 702 | for_deletion: Some(Default::default()), |
| | 703 | ..options() |
| | 704 | }, |
| | 705 | keep, |
| | 706 | ) |
| | 707 | }, |
| | 708 | Some("*foo*"), |
| | 709 | ); |
| | 710 | assert_eq!( |
| | 711 | out, |
| | 712 | walk::Outcome { |
| | 713 | read_dir_calls: 8, |
| | 714 | returned_entries: entries.len(), |
| | 715 | seen_entries: 28, |
| | 716 | }, |
| | 717 | ); |
| | 718 | assert_eq!( |
| | 719 | &entries, |
| | 720 | &[ |
| | 721 | entry_nokind(".git", DotGit), |
| | 722 | entry_nomatch(".gitignore", Pruned, File), |
| | 723 | entry_nomatch("a.o", Ignored(Expendable), File), |
| | 724 | entry_nomatch("b.o", Ignored(Expendable), File), |
| | 725 | entry_nomatch("c.o", Ignored(Expendable), File), |
| | 726 | entry_nomatch("d/a.o", Ignored(Expendable), File), |
| | 727 | entry_nomatch("d/b.o", Ignored(Expendable), File), |
| | 728 | entry_nomatch("d/d", Ignored(Expendable), Directory), |
| | 729 | entry_nomatch("d/d/a", Pruned, File), |
| | 730 | entry_nomatch("d/generated", Ignored(Expendable), Directory), |
| | 731 | entry_nomatch("generated", Ignored(Expendable), Directory), |
| | 732 | entry_nomatch("objs", Ignored(Expendable), Directory), |
| | 733 | ], |
| | 734 | "'generated' folders are included, and collapsing is done where possible" |
| | 735 | ); |
| | 736 | Ok(()) |
| | 737 | } |
| | 738 | |
| | 739 | #[test] |
| | 740 | fn nested_ignored_dirs_for_deletion_nonmatching_wildcard_spec() -> crate::Result { |
| | 741 | let root = fixture("ignored-dir-nested-minimal"); |
| | 742 | let (_out, entries) = collect_filtered( |
| | 743 | &root, |
| | 744 | |keep, ctx| { |
| | 745 | walk( |
| | 746 | &root, |
| | 747 | &root, |
| | 748 | ctx, |
| | 749 | walk::Options { |
| | 750 | emit_ignored: Some(CollapseDirectory), |
| | 751 | emit_untracked: CollapseDirectory, |
| | 752 | emit_pruned: false, |
| | 753 | for_deletion: Some(Default::default()), |
| | 754 | ..options() |
| | 755 | }, |
| | 756 | keep, |
| | 757 | ) |
| | 758 | }, |
| | 759 | Some("*foo*"), |
| | 760 | ); |
| | 761 | // NOTE: do not use `_out` as `.git` directory contents can change, it's controlled by Git, causing flakiness. |
| | 762 | |
| | 763 | assert_eq!( |
| | 764 | &entries, |
| | 765 | &[], |
| | 766 | "it figures out that nothing actually matches, even though it has to check everything" |
| | 767 | ); |
| | 768 | |
| | 769 | let (_out, entries) = collect_filtered( |
| | 770 | &root, |
| | 771 | |keep, ctx| { |
| | 772 | walk( |
| | 773 | &root, |
| | 774 | &root, |
| | 775 | ctx, |
| | 776 | walk::Options { |
| | 777 | emit_ignored: Some(CollapseDirectory), |
| | 778 | emit_untracked: CollapseDirectory, |
| | 779 | emit_pruned: true, |
| | 780 | for_deletion: Some(Default::default()), |
| | 781 | ..options() |
| | 782 | }, |
| | 783 | keep, |
| | 784 | ) |
| | 785 | }, |
| | 786 | Some("*foo*"), |
| | 787 | ); |
| | 788 | // NOTE: do not use `_out` as `.git` directory contents can change, it's controlled by Git, causing flakiness. |
| | 789 | |
| | 790 | assert_eq!( |
| | 791 | &entries, |
| | 792 | &[ |
| | 793 | entry_nokind(".git", DotGit), |
| | 794 | entry_nomatch(".gitignore", Pruned, File), |
| | 795 | entry_nomatch("bare/HEAD", Pruned, File), |
| | 796 | entry_nomatch("bare/info/exclude", Pruned, File), |
| | 797 | entry_nomatch("bare/objects", Untracked, Directory), |
| | 798 | entry_nomatch("bare/refs", Untracked, Directory), |
| | 799 | entry_nomatch("dir", Ignored(Expendable), Directory), |
| | 800 | ], |
| | 801 | "it's possible to observe pruned entries like before" |
| | 802 | ); |
| | 803 | Ok(()) |
| | 804 | } |
| | 805 | |
| | 806 | #[test] |
| | 807 | fn expendable_and_precious_in_ignored_dir_with_pathspec() -> crate::Result { |
| | 808 | let root = fixture("expendable-and-precious-nested-in-ignored-dir"); |
| | 809 | let (out, entries) = collect(&root, |keep, ctx| { |
| | 810 | walk( |
| | 811 | &root, |
| | 812 | &root, |
| | 813 | ctx, |
| | 814 | walk::Options { |
| | 815 | emit_ignored: Some(CollapseDirectory), |
| | 816 | emit_untracked: CollapseDirectory, |
| | 817 | emit_pruned: true, |
| | 818 | emit_tracked: true, |
| | 819 | for_deletion: Some(Default::default()), |
| | 820 | ..options() |
| | 821 | }, |
| | 822 | keep, |
| | 823 | ) |
| | 824 | }); |
| | 825 | assert_eq!( |
| | 826 | out, |
| | 827 | walk::Outcome { |
| | 828 | read_dir_calls: 2, |
| | 829 | returned_entries: entries.len(), |
| | 830 | seen_entries: 5, |
| | 831 | }, |
| | 832 | ); |
| | 833 | |
| | 834 | assert_eq!( |
| | 835 | &entries, |
| | 836 | &[ |
| | 837 | entry_nokind(".git", DotGit), |
| | 838 | entry(".gitignore", Tracked, File).with_index_kind(File), |
| | 839 | entry("ignored", Ignored(Expendable), Directory), |
| | 840 | entry("other", Ignored(Expendable), Directory), |
| | 841 | ], |
| | 842 | "without pathspec, it collapses completely. \ |
| | 843 | It's interesting that 'other' claims to be ignored - due to the collapse of `other/ignored` it inherits the sub-directory status.\ |
| | 844 | However, it's what we want, compared to the alternative of leaving it empty, and then detecting it as empty\ |
| | 845 | the next time we run." |
| | 846 | ); |
| | 847 | |
| | 848 | let (out, entries) = collect_filtered( |
| | 849 | &root, |
| | 850 | |keep, ctx| { |
| | 851 | walk( |
| | 852 | &root, |
| | 853 | &root, |
| | 854 | ctx, |
| | 855 | walk::Options { |
| | 856 | emit_ignored: Some(CollapseDirectory), |
| | 857 | emit_untracked: CollapseDirectory, |
| | 858 | emit_pruned: true, |
| | 859 | for_deletion: Some(Default::default()), |
| | 860 | ..options() |
| | 861 | }, |
| | 862 | keep, |
| | 863 | ) |
| | 864 | }, |
| | 865 | Some("*ignored*"), |
| | 866 | ); |
| | 867 | assert_eq!( |
| | 868 | out, |
| | 869 | walk::Outcome { |
| | 870 | read_dir_calls: 9, |
| | 871 | returned_entries: entries.len(), |
| | 872 | seen_entries: 19, |
| | 873 | }, |
| | 874 | ); |
| | 875 | |
| | 876 | assert_eq!( |
| | 877 | &entries, |
| | 878 | &[ |
| | 879 | entry_nokind(".git", DotGit), |
| | 880 | entry_nokind("ignored/d/.git", DotGit), |
| | 881 | entryps("ignored/d/.gitignore", Ignored(Expendable), File, WildcardMatch), |
| | 882 | entryps("ignored/d/a.o", Ignored(Expendable), File, WildcardMatch), |
| | 883 | entryps( |
| | 884 | "ignored/d/all-expendable", |
| | 885 | Ignored(Expendable), |
| | 886 | Directory, |
| | 887 | WildcardMatch |
| | 888 | ), |
| | 889 | entryps("ignored/d/all-precious", Ignored(Precious), Directory, WildcardMatch), |
| | 890 | entryps("ignored/d/mixed", Ignored(Expendable), Directory, WildcardMatch), |
| | 891 | entryps("ignored/d/precious", Ignored(Expendable), File, WildcardMatch), |
| | 892 | entryps("other", Ignored(Expendable), Directory, WildcardMatch), |
| | 893 | ], |
| | 894 | "with pathspec, we match what's inside and expect to have all the lowest-level paths that have 'ignored' in them.\ |
| | 895 | It seems strange that 'precious' isn't precious, while 'all-precious' is. However, the ignore-search is special |
| | 896 | as it goes backward through directories (using directory-declarations), and aborts if it matched. Thus it finds |
| | 897 | that '$/all-precious/' matched, but in the other cases it maches 'ignored/'. |
| | 898 | 'other' gets folded and inherits, just like before." |
| | 899 | ); |
| | 900 | Ok(()) |
| | 901 | } |
| | 902 | |
| 635 | #[test] | 903 | #[test] |
| 636 | fn untracked_and_ignored() -> crate::Result { | 904 | fn untracked_and_ignored() -> crate::Result { |
| 637 | let root = fixture("subdir-untracked-and-ignored"); | 905 | let root = fixture("subdir-untracked-and-ignored"); |