What's wrong
In FileDeduplicator/Verbs/Stats.cs (around lines 78-88), the extension breakdown reads the extension from group.Files[0] and adds the whole group.Files.Count to that one extension:
string ext = System.IO.Path.GetExtension(group.Files[0].WeakString);
...
extensionCounts[ext] = count + group.Files.Count;
This causes three problems:
- Wrong attribution. When identical content exists under different extensions, every copy is counted under one of them. For example,
photo.jpg, photo-copy.png and backup.bak all land under a single extension.
- Nondeterministic output.
Files[0] is whichever copy comes first in the group built from the parallel hash (FileHasher.HashFiles fills a ConcurrentDictionary, which GroupByHash then groups). The same tree can report a different extension on every run.
- Inconsistent totals. The breakdown counts the kept copy too. Its totals exceed the "Duplicate files" line printed just above it, which counts only the redundant copies.
Repro
Put the three files above, with identical content, in a temp directory, then run ConsoleCapture.Run(new Stats { PathString = root }) three times.
- Actual: the runs print
.png: 3 file(s), .jpg: 3 file(s), .jpg: 3 file(s), while "Duplicate files" says 2.
- Expected: a stable per-file breakdown whose total matches "Duplicate files".
Suggested fix
Iterate the files in each group and count each file's own extension. To stay consistent with "Duplicate files" and "Wasted space", count only the copies that would be removed, i.e. skip Deduplicator.SelectFileToKeep(group.Files).
Acceptance criteria
- A test with mixed-extension duplicates gets the same breakdown on repeated runs, with each extension counted once per redundant file, and the breakdown sums to the "Duplicate files" count.
What's wrong
In
FileDeduplicator/Verbs/Stats.cs(around lines 78-88), the extension breakdown reads the extension fromgroup.Files[0]and adds the wholegroup.Files.Countto that one extension:This causes three problems:
photo.jpg,photo-copy.pngandbackup.bakall land under a single extension.Files[0]is whichever copy comes first in the group built from the parallel hash (FileHasher.HashFilesfills aConcurrentDictionary, whichGroupByHashthen groups). The same tree can report a different extension on every run.Repro
Put the three files above, with identical content, in a temp directory, then run
ConsoleCapture.Run(new Stats { PathString = root })three times..png: 3 file(s),.jpg: 3 file(s),.jpg: 3 file(s), while "Duplicate files" says 2.Suggested fix
Iterate the files in each group and count each file's own extension. To stay consistent with "Duplicate files" and "Wasted space", count only the copies that would be removed, i.e. skip
Deduplicator.SelectFileToKeep(group.Files).Acceptance criteria