diff --git a/FileDeduplicator.Test/VerbOutputTests.cs b/FileDeduplicator.Test/VerbOutputTests.cs index f650ade..ad6db6e 100644 --- a/FileDeduplicator.Test/VerbOutputTests.cs +++ b/FileDeduplicator.Test/VerbOutputTests.cs @@ -152,6 +152,26 @@ public void StatsReportsAFileItCannotHashAsUnreadable() Assert.Contains("Duplicate groups: 0", output); } + /// + /// A file that cannot be hashed is named by its full path, so the failing copy can be found + /// among others sharing its file name. + /// + [TestMethod] + public void AHashingErrorNamesTheFullPath() + { + // Arrange + using TempTree tree = new(); + _ = tree.Write("one/IMG_0001.jpg", "alpha"); + AbsoluteFilePath locked = tree.Write("two/IMG_0001.jpg", "beta"); + using FileStream holder = new(locked.WeakString, FileMode.Open, FileAccess.ReadWrite, FileShare.None); + + // Act + string output = ConsoleCapture.Run(new Stats { PathString = tree.Root.WeakString }); + + // Assert + Assert.Contains($"Error hashing {locked}:", output); + } + /// /// A tree where every file hashes has no unreadable line at all. /// diff --git a/FileDeduplicator/FileHasher.cs b/FileDeduplicator/FileHasher.cs index bfb5ff0..84b5ce9 100644 --- a/FileDeduplicator/FileHasher.cs +++ b/FileDeduplicator/FileHasher.cs @@ -51,7 +51,9 @@ private static void ReportSkipped(AbsoluteFilePath filePath, Exception ex) { lock (ConsoleLock) { - Console.WriteLine($" Error hashing {filePath.FileName}: {ex.Message}"); + // The full path, not the file name: index.js or IMG_0001.jpg can repeat dozens of times in + // one tree, and this line is the only place the failing copy is ever named. + Console.WriteLine($" Error hashing {filePath}: {ex.Message}"); } }