From 51a6261657fc94cb646f4c6b0a90cb2e6ef23b08 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 18:29:09 +0000 Subject: [PATCH] Skip generated icons by file name, not by full path [patch] Directory.GetFiles hands back full paths, so testing the whole string for ".new.png" let a directory anywhere above the input decide that every file below it was already generated. An input path containing that substring in a parent folder -- a user name, a date stamp, a project name -- processed nothing and still exited 0. The documented contract, in README.md and CLAUDE.md alike, has always been about file names: "Files whose names contain .new.png are skipped". The check now matches that. Fixes #116 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012betVHk3gFcj5RYkEe4vrm --- IconHelper.Test/ProcessDirectoryTests.cs | 39 ++++++++++++++++++++++++ IconHelper/IconHelper.cs | 6 +++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/IconHelper.Test/ProcessDirectoryTests.cs b/IconHelper.Test/ProcessDirectoryTests.cs index 67fd630..a107b19 100644 --- a/IconHelper.Test/ProcessDirectoryTests.cs +++ b/IconHelper.Test/ProcessDirectoryTests.cs @@ -85,6 +85,45 @@ public void SkipsFilesAlreadyMarkedAsGenerated() Assert.IsFalse(File.Exists(Path.Combine(output, "already.new.png"))); } + [TestMethod] + public void SkipsOnTheFileNameRatherThanTheContainingPath() + { + using TempDirectory temp = new(); + // The marker is in the directory name, and in no file name. Directory.GetFiles hands back + // full paths, so testing the whole string made every file below such a directory look + // already generated -- nothing written, and exit 0 to say so. + string input = temp.Combine(Path.Combine("icons.new.png.dir", "in")); + string output = temp.Combine("out"); + Directory.CreateDirectory(input); + WritePng(Path.Combine(input, "keep.png"), 64); + WritePng(Path.Combine(input, "also-keep.png"), 64); + + BatchResult result = IconHelper.ProcessDirectory(ArgumentsFor(input, output), NamedColors.White); + + Assert.AreEqual(2, result.Written, "'.new.png' in a parent directory should not skip anything."); + Assert.IsTrue(File.Exists(Path.Combine(output, "keep.png"))); + Assert.IsTrue(File.Exists(Path.Combine(output, "also-keep.png"))); + } + + [TestMethod] + public void SkipsOnTheFileNameEvenBelowAMatchingPath() + { + using TempDirectory temp = new(); + // Both at once, so a fix that stops looking at the path cannot also stop looking at the + // name: the marked file is still skipped, and the unmarked one beside it is still written. + string input = temp.Combine(Path.Combine("icons.new.png.dir", "in")); + string output = temp.Combine("out"); + Directory.CreateDirectory(input); + WritePng(Path.Combine(input, "keep.png"), 64); + WritePng(Path.Combine(input, "already.new.png"), 64); + + BatchResult result = IconHelper.ProcessDirectory(ArgumentsFor(input, output), NamedColors.White); + + Assert.AreEqual(1, result.Written, "The marked file should be skipped and the other one written."); + Assert.IsTrue(File.Exists(Path.Combine(output, "keep.png"))); + Assert.IsFalse(File.Exists(Path.Combine(output, "already.new.png"))); + } + [TestMethod] public void ContinuesAfterAFileThatCannotBeDecoded() { diff --git a/IconHelper/IconHelper.cs b/IconHelper/IconHelper.cs index 09a4e7f..56f9478 100644 --- a/IconHelper/IconHelper.cs +++ b/IconHelper/IconHelper.cs @@ -116,7 +116,11 @@ internal static BatchResult ProcessDirectory(Arguments args, Color color) System.Collections.ObjectModel.Collection files = Directory.GetFiles(inputDirectory, "*").ToCollection(); foreach (string? file in files) { - if (file.Contains(".new.png")) + // The name, not the path. Directory.GetFiles hands back full paths, so testing the + // whole string let a directory anywhere above the input -- a user name, a date stamp, + // a project folder -- decide that every file below it was already generated. That + // failure is silent and total: nothing is written and the run still exits 0. + if (Path.GetFileName(file).Contains(".new.png", StringComparison.Ordinal)) { continue; }