using Explorer.Domain; using Explorer.Domain.Abstractions; namespace Explorer.Domain.Tests; public class NameNormalizerTests { [Fact] public void Normalize_folds_case_and_keeps_unicode() { Assert.Equal("straße", NameNormalizer.Normalize("Straße")); Assert.Equal("abc", NameNormalizer.Normalize("ABC")); } [Fact] public void Extension_skips_leading_dot_names() { Assert.Equal("mkv", NameNormalizer.Extension("film.mkv")); Assert.Null(NameNormalizer.Extension(".gitignore")); Assert.Null(NameNormalizer.Extension("Makefile")); } } public class PathRulesTests { [Fact] public void Extended_roundtrip_local_and_unc() { Assert.Equal(@"\\?\C:\Temp", PathRules.ToExtended(@"C:\Temp")); Assert.Equal(@"\\?\UNC\server\share", PathRules.ToExtended(@"\\server\share")); Assert.Equal(@"C:\Temp", PathRules.FromExtended(@"\\?\C:\Temp")); Assert.Equal(@"\\server\share", PathRules.FromExtended(@"\\?\UNC\server\share")); } [Fact] public void Canonical_unc_lowercases_server() { Assert.Equal(@"\\media\Movies", PathRules.CanonicalUncRoot(@"\\Media\Movies\Action")); } [Fact] public void Relative_and_parent() { Assert.Equal(@"Windows\System32", PathRules.MakeRelative(@"C:\", @"C:\Windows\System32")); Assert.Equal(@"C:\Windows", PathRules.Parent(@"C:\Windows\System32")); Assert.Equal(@"C:\", PathRules.Parent(@"C:\Windows")); Assert.True(PathRules.DriveLetterSortKey(@"D:\") < PathRules.DriveLetterSortKey(@"F:\")); Assert.True(PathRules.DriveLetterSortKey(@"C:\") < PathRules.DriveLetterSortKey(@"\\media\movies")); Assert.Equal(@"pack.zip\docs", PathRules.RelativeParent(@"pack.zip\docs\a.txt")); Assert.Equal("pack.zip", PathRules.RelativeParent(@"pack.zip\docs")); Assert.Equal("", PathRules.RelativeParent("pack.zip")); } [Fact] public void Join_display_combines_root_and_relative() { Assert.Equal(@"C:\Users\Docs", PathRules.JoinDisplay(@"C:\Users", "Docs")); Assert.Equal(@"C:\", PathRules.JoinDisplay(@"C:\", "")); Assert.Equal("Docs", PathRules.JoinDisplay(null, "Docs")); } [Fact] public void Shorten_keeps_root_and_leaf() { Assert.Equal(@"C:\Temp", PathRules.ShortenDisplay(@"C:\Temp")); Assert.Equal(@"C:\Users\…\Documents\Budget", PathRules.ShortenDisplay(@"C:\Users\Dominique\Documents\Budget", 28)); Assert.Equal(@"\\media\movies\…\Action\Dune", PathRules.ShortenDisplay(@"\\media\movies\New\Action\Dune", 28)); } } public class WindowsFileNamesTests { [Fact] public void Rejects_reserved_and_illegal_names() { Assert.False(WindowsFileNames.IsValid("CON", out _)); Assert.False(WindowsFileNames.IsValid("a<.txt", out _)); Assert.False(WindowsFileNames.IsValid("ends.", out _)); Assert.True(WindowsFileNames.IsValid("Vacation.jpg", out _)); Assert.Equal(("Vacation", "jpg"), WindowsFileNames.Split("Vacation.jpg")); Assert.Equal("Hello World", WindowsFileNames.ApplyCase("hello world", RenameCaseMode.Title)); Assert.Equal("007", WindowsFileNames.FormatCounter(7, 3)); } } public class ArchiveFormatsTests { [Fact] public void Detects_common_archive_extensions() { Assert.True(ArchiveFormats.IsArchive("pack.zip")); Assert.True(ArchiveFormats.IsArchive("film.7z")); Assert.True(ArchiveFormats.IsArchive("backup.rar")); Assert.True(ArchiveFormats.IsArchive("src.tar.gz")); Assert.True(ArchiveFormats.IsZipFamily("photos.cbz")); Assert.False(ArchiveFormats.IsArchive("notes.txt")); Assert.False(ArchiveFormats.IsArchive("report.docx")); Assert.Equal("2019-backup", ArchiveFormats.Stem("2019-backup.7z")); Assert.Equal("bundle", ArchiveFormats.Stem("bundle.tar.gz")); } [Fact] public void Rejects_unsafe_archive_entry_paths() { Assert.True(ArchiveFormats.TryNormalizeEntryPath("docs/a.txt", out var ok)); Assert.Equal(@"docs\a.txt", ok); Assert.False(ArchiveFormats.TryNormalizeEntryPath(@"..\escape.txt", out _)); Assert.False(ArchiveFormats.TryNormalizeEntryPath(@"C:\abs.txt", out _)); Assert.False(ArchiveFormats.TryNormalizeEntryPath("/", out _)); } } public class VolumeIdentityTests { [Fact] public void Matches_volume_guid_across_drive_letters() { var known = new List { new() { Id = 1, StableKey = "a", DisplayName = "SanDisk Ultra 64 GB", VolumeGuid = @"\\?\Volume{abc}\", LastRootPath = @"E:\", Kind = SourceKind.Removable } }; var fp = new VolumeFingerprint { Kind = SourceKind.Removable, VolumeGuid = @"\\?\Volume{abc}\", RootPath = @"G:\", DisplayName = "SanDisk" }; var match = VolumeIdentityMatcher.Match(fp, known); Assert.NotNull(match.Source); Assert.Equal(1, match.Source!.Id); Assert.Equal(VolumeIdentityMatcher.MatchStrength.Guid, match.Strength); Assert.False(match.Ambiguous); } [Fact] public void Matches_unc_share() { var known = new List { new() { Id = 7, StableKey = "s", DisplayName = @"\\media\movies", Kind = SourceKind.Smb, LastRootPath = @"\\Media\Movies" } }; var fp = new VolumeFingerprint { Kind = SourceKind.Smb, RootPath = @"\\media\movies", DisplayName = "x" }; Assert.Equal(7, VolumeIdentityMatcher.Match(fp, known).Source?.Id); } } public class LocationClassifierTests { [Fact] public void Classifies_known_protected_locations() { var svi = LocationClassifier.Classify( @"C:\System Volume Information", "System Volume Information", AttributeFlags.Directory | AttributeFlags.Hidden | AttributeFlags.System, true); Assert.True(svi.IsProtected); Assert.True(svi.IsHidden); Assert.True(svi.IsSystem); Assert.False(svi.IsRecycleBin); var recycle = LocationClassifier.Classify( @"D:\$RECYCLE.BIN", "$RECYCLE.BIN", AttributeFlags.Directory | AttributeFlags.Hidden | AttributeFlags.System, true); Assert.True(recycle.IsProtected); Assert.True(recycle.IsRecycleBin); var pagefile = LocationClassifier.Classify( @"C:\pagefile.sys", "pagefile.sys", AttributeFlags.Hidden | AttributeFlags.System, false); Assert.True(pagefile.IsProtected); Assert.False(pagefile.IsRecycleBin); } [Fact] public void Does_not_treat_normal_hidden_user_files_as_protected() { var desktopIni = LocationClassifier.Classify( @"C:\Users\Ada\Desktop\desktop.ini", "desktop.ini", AttributeFlags.Hidden | AttributeFlags.System, false); Assert.True(desktopIni.IsHidden); Assert.True(desktopIni.IsSystem); Assert.False(desktopIni.IsProtected); var movies = LocationClassifier.Classify( @"C:\Movies", "Movies", AttributeFlags.Directory, true); Assert.False(movies.IsProtected); Assert.False(movies.IsHidden); } [Fact] public void Access_denied_marks_protected() { var info = LocationClassifier.Classify(@"C:\locked", "locked", AttributeFlags.Directory, true, accessDenied: true); Assert.True(info.AccessDenied); Assert.True(info.IsProtected); } } public class ExcludeEvaluatorTests { [Fact] public void Excludes_path_glob_and_extension() { var ev = new ExcludeEvaluator( [ new() { Kind = ExcludeKind.PathPrefix, Pattern = @"C:\Windows" }, new() { Kind = ExcludeKind.Glob, Pattern = "node_modules" }, new() { Kind = ExcludeKind.Extension, Pattern = "tmp" } ], skipHidden: false, skipSystem: false); Assert.True(ev.ShouldExclude(@"C:\Windows\System32", "System32", true, 0, null)); Assert.True(ev.ShouldExclude(@"D:\proj\node_modules", "node_modules", true, 0, null)); Assert.True(ev.ShouldExclude(@"D:\a.tmp", "a.tmp", false, 0, null)); Assert.False(ev.ShouldExclude(@"D:\a.txt", "a.txt", false, 0, null)); } [Fact] public void Hidden_policy() { var ev = new ExcludeEvaluator([], skipHidden: true, skipSystem: true); Assert.True(ev.ShouldExclude(@"C:\x", "x", false, AttributeFlags.Hidden, null)); } } public class ReparsePolicyTests { [Fact] public void Does_not_recurse_reparse_directories() { var item = new FileSystemItem { FullPath = @"C:\link", Name = "link", IsDirectory = true, Attributes = AttributeFlags.Directory | AttributeFlags.ReparsePoint, ReparseTag = ReparsePolicy.IoReparseTagSymlink }; Assert.False(ReparsePolicy.ShouldRecurseIntoDirectory(item)); } } public class DragDropPolicyTests { [Fact] public void Modifiers_match_windows_explorer() { Assert.Equal(DropAction.Move, DragDropPolicy.Resolve(false, false, false, sameVolume: true)); Assert.Equal(DropAction.Copy, DragDropPolicy.Resolve(false, false, false, sameVolume: false)); Assert.Equal(DropAction.Copy, DragDropPolicy.Resolve(control: true, shift: false, alt: false, sameVolume: true)); Assert.Equal(DropAction.Move, DragDropPolicy.Resolve(control: false, shift: true, alt: false, sameVolume: false)); Assert.Equal(DropAction.Link, DragDropPolicy.Resolve(control: false, shift: false, alt: true, sameVolume: true)); Assert.Equal(DropAction.Link, DragDropPolicy.Resolve(control: true, shift: true, alt: false, sameVolume: false)); } [Fact] public void Rejects_virtual_and_self_targets() { Assert.True(DragDropPolicy.IsInvalidTarget([@"C:\Docs"], LocationRoots.ThisPc)); Assert.True(DragDropPolicy.IsInvalidTarget([@"C:\Docs"], @"C:\Docs")); Assert.True(DragDropPolicy.IsInvalidTarget([@"C:\Docs"], @"C:\Docs\sub")); Assert.False(DragDropPolicy.IsInvalidTarget([@"C:\Docs\file.txt"], @"C:\Docs")); Assert.False(DragDropPolicy.IsInvalidTarget([@"C:\Docs"], @"D:\Other")); } [Fact] public void Same_volume_uses_drive_or_unc_share() { Assert.True(PathRules.IsSameVolume(@"C:\a", @"C:\b")); Assert.False(PathRules.IsSameVolume(@"C:\a", @"D:\b")); Assert.True(PathRules.IsSameVolume(@"\\media\movies\a", @"\\media\movies\b")); Assert.False(PathRules.IsSameVolume(@"\\media\movies\a", @"\\media\tv\b")); } } public class DuplicateClassifierTests { [Fact] public void Same_source_and_file_id_is_hardlink_not_duplicate() { var entries = new[] { File(1, 10, 100), File(2, 10, 100) }; Assert.True(DuplicateClassifier.IsHardlinkOnly(entries)); Assert.Equal(DuplicateClass.Hardlink, DuplicateClassifier.Classify(entries, [])); Assert.True(DuplicateClassifier.IsHiddenByDefault(DuplicateClass.Hardlink)); Assert.Equal(0, DuplicateClassifier.ClassifyGroup(new DuplicateGroup { SizeBytes = 50, Entries = entries }, []).WastedBytes); } [Fact] public void Same_file_id_on_different_volumes_is_not_a_hardlink() { var entries = new[] { File(1, 10, 100, sourceId: 1), File(2, 10, 100, sourceId: 2) }; Assert.False(DuplicateClassifier.IsHardlinkOnly(entries)); Assert.Equal(DuplicateClass.Unknown, DuplicateClassifier.Classify(entries, [])); Assert.Equal(2, DuplicateClassifier.UniqueFileCount(entries)); } [Fact] public void Marked_intentional_relation_is_hidden_by_default() { var entries = new[] { File(1, 10, null), File(2, 11, null) }; var relations = new[] { new FileRelation { LeftEntryId = 1, RightEntryId = 2, Kind = FileRelationKind.IntentionalDuplicate, Origin = FileRelationOrigin.User, CreatedUtc = DateTimeOffset.UtcNow } }; var classified = DuplicateClassifier.Classify(entries, relations); Assert.Equal(DuplicateClass.Intentional, classified); Assert.True(DuplicateClassifier.IsHiddenByDefault(classified)); Assert.False(DuplicateClassifier.IsHiddenByDefault(DuplicateClass.Unknown)); Assert.False(DuplicateClassifier.IsHiddenByDefault(DuplicateClass.Accidental)); } [Fact] public void Sync_and_backup_relations_classify_ahead_of_unknown() { var entries = new[] { File(1, 10, 1), File(2, 11, 2) }; Assert.Equal(DuplicateClass.Synchronized, DuplicateClassifier.Classify(entries, [ Rel(1, 2, FileRelationKind.SyncCopy) ])); Assert.Equal(DuplicateClass.Backup, DuplicateClassifier.Classify(entries, [ Rel(1, 2, FileRelationKind.BackupCopy) ])); } private static IndexEntry File(long id, long sourceFileId, long? fileId, long sourceId = 1) => new() { Id = id, SourceId = sourceId, Name = id + ".bin", NameNorm = id + ".bin", PathRel = id + ".bin", SizeBytes = 50, FileId = fileId, LastSeenUtc = DateTimeOffset.UtcNow }; private static FileRelation Rel(long left, long right, FileRelationKind kind) => new() { LeftEntryId = left, RightEntryId = right, Kind = kind, Origin = FileRelationOrigin.User, CreatedUtc = DateTimeOffset.UtcNow }; } public class OperationProfileTests { [Fact] public void Auto_run_is_copy_only() { var copy = new OperationProfile { Name = "Copy", DoCopy = true, AutoRun = true }; Assert.True(copy.CanAutoRun); var compress = new OperationProfile { Name = "Archive", DoCopy = true, DoCompress = true, AutoRun = true }; Assert.False(compress.CanAutoRun); var rename = new OperationProfile { Name = "Rename", DoCopy = true, DoRename = true, RenamePrefix = "x_", AutoRun = true }; Assert.False(rename.CanAutoRun); } } public class FileClassifierTests { [Fact] public void Extension_and_archive_signals() { Assert.Equal(FileCategory.Photos, Classify("sunset.jpg")); Assert.Equal(FileCategory.Video, Classify("clip.mkv")); Assert.Equal(FileCategory.Audio, Classify("track.mp3")); Assert.Equal(FileCategory.Documents, Classify("notes.pdf")); Assert.Equal(FileCategory.Installer, Classify("Git-64-bit.exe")); Assert.Equal(FileCategory.Archive, Classify("pack.7z")); Assert.Equal(FileCategory.Backup, Classify("db.bak")); Assert.Equal(FileCategory.Unknown, Classify("mystery.bin")); } [Fact] public void Folder_structure_and_git() { Assert.Equal(FileCategory.CodeRepository, Classify("Explorer", isDirectory: true, isRepoRoot: true)); Assert.Equal(FileCategory.BuildOutput, Classify("node_modules", isDirectory: true)); Assert.Equal(FileCategory.BuildOutput, Classify("bin", isDirectory: true)); Assert.Equal(FileCategory.Photos, Classify("DCIM", isDirectory: true)); Assert.Equal(FileCategory.SystemData, FileClassifier.Classify( "$RECYCLE.BIN", @"C:\$RECYCLE.BIN", true, AttributeFlags.Directory | AttributeFlags.Hidden | AttributeFlags.System).Category); Assert.True(FileClassifier.ShouldLeave(FileCategory.Unknown)); Assert.True(FileClassifier.ShouldLeave(FileCategory.BuildOutput)); Assert.False(FileClassifier.ShouldLeave(FileCategory.Photos)); } [Fact] public void Majority_of_children_classifies_a_folder() { var mixed = FileClassifier.Classify( "Vacation", @"C:\Downloads\Vacation", true, AttributeFlags.Directory, childCategories: [FileCategory.Photos, FileCategory.Photos, FileCategory.Photos, FileCategory.Documents]); Assert.Equal(FileCategory.Photos, mixed.Category); var split = FileClassifier.Classify( "Misc", @"C:\Downloads\Misc", true, AttributeFlags.Directory, childCategories: [FileCategory.Photos, FileCategory.Video]); Assert.Equal(FileCategory.Unknown, split.Category); } private static FileCategory Classify(string name, bool isDirectory = false, bool isRepoRoot = false) => FileClassifier.Classify(name, @"C:\Downloads\" + name, isDirectory, isDirectory ? AttributeFlags.Directory : 0, isRepoRoot).Category; }