From e753ddd188021a92bb3c52c7fb545bd042006246 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 08:24:43 +0000 Subject: [PATCH 1/2] Drop a trailing period from a suggested file name [patch] Models often end the answer with a full stop. SanitizeFileName kept it, so "sunset-over-the-lake." became "sunset-over-the-lake..jpg", "photo.jpg." kept its extension, and "..." became "....jpg" instead of "unnamed.jpg". Trim trailing periods before the extension check, and include the period in the final trim so a name left as only dots falls back to "unnamed". Fixes ktsu-dev/ImageDescriber#196 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01URmxVUpdaWCEUSPudDfLsq --- ImageDescriber.Test/ScanTests.cs | 39 ++++++++++++++++++++++++++++++++ ImageDescriber/Verbs/Scan.cs | 6 +++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/ImageDescriber.Test/ScanTests.cs b/ImageDescriber.Test/ScanTests.cs index ddea4bf..a453418 100644 --- a/ImageDescriber.Test/ScanTests.cs +++ b/ImageDescriber.Test/ScanTests.cs @@ -181,6 +181,45 @@ public void SanitizeFileNameStripsUpperCaseImageExtension() Assert.AreEqual("photo.png", result.WeakString); } + [TestMethod] + [DataRow("sunset-over-the-lake.", "sunset-over-the-lake.jpg")] + [DataRow("Sunset over the lake.", "Sunset over the lake.jpg")] + [DataRow("sunset-over-the-lake. ", "sunset-over-the-lake.jpg")] + [DataRow("\"sunset-over-the-lake.\"", "sunset-over-the-lake.jpg")] + public void SanitizeFileNameDropsTrailingPeriod(string suggestion, string expected) + { + FileName result = Scan.SanitizeFileName(suggestion, ".jpg".As()); + + Assert.AreEqual(expected, result.WeakString); + } + + [TestMethod] + public void SanitizeFileNameStripsImageExtensionFollowedByPeriod() + { + FileName result = Scan.SanitizeFileName("photo.jpg.", ".png".As()); + + Assert.AreEqual("photo.png", result.WeakString); + } + + [TestMethod] + [DataRow("...")] + [DataRow(". . .")] + [DataRow("-.-")] + public void SanitizeFileNameReturnsUnnamedForOnlyPeriods(string suggestion) + { + FileName result = Scan.SanitizeFileName(suggestion, ".jpg".As()); + + Assert.AreEqual("unnamed.jpg", result.WeakString); + } + + [TestMethod] + public void SanitizeFileNameDropsPeriodLeftBeforeReplacedCharacter() + { + FileName result = Scan.SanitizeFileName("sunset.?", ".jpg".As()); + + Assert.AreEqual("sunset.jpg", result.WeakString); + } + [TestMethod] public void HashFilesSkipsFilesThatCannotBeRead() { diff --git a/ImageDescriber/Verbs/Scan.cs b/ImageDescriber/Verbs/Scan.cs index 8c58f49..f2e860c 100644 --- a/ImageDescriber/Verbs/Scan.cs +++ b/ImageDescriber/Verbs/Scan.cs @@ -263,7 +263,9 @@ internal static FileName SanitizeFileName(string rawSuggestion, FileExtension ex .Split('\n') .Select(line => line.Trim()) .FirstOrDefault(line => line.Length > 0 && !IsCodeFence(line)) ?? string.Empty; - name = name.Trim('"', '\'', '`').Trim(); + // Models often end the answer with a full stop. Drop it before the extension check, so + // "photo.jpg." still loses its extension and "sunset." does not become "sunset..jpg" + name = name.Trim('"', '\'', '`').Trim().TrimEnd('.', ' '); // Strip an image extension the model may have included. A suggestion normally has no // extension, so any other dot is part of the name ("st.-louis-arch", "sunset-at-5.30pm") @@ -283,7 +285,7 @@ internal static FileName SanitizeFileName(string rawSuggestion, FileExtension ex name = name.Replace("--", "-", StringComparison.Ordinal); } - name = name.Trim('-', ' '); + name = name.Trim('-', ' ', '.'); if (string.IsNullOrEmpty(name)) { From de7f22053c70a56ce023a9127c0de029ee254436 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 08:32:15 +0000 Subject: [PATCH 2/2] Use a test input that is a legal extension on Windows too Path.GetExtension("sunset.?") is ".?" on Windows, which FileExtension refuses, so the case threw before reaching the trim it was meant to test. "sunset.-" exercises the same trailing-period trim on every platform. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01URmxVUpdaWCEUSPudDfLsq --- ImageDescriber.Test/ScanTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImageDescriber.Test/ScanTests.cs b/ImageDescriber.Test/ScanTests.cs index a453418..eaaa0ca 100644 --- a/ImageDescriber.Test/ScanTests.cs +++ b/ImageDescriber.Test/ScanTests.cs @@ -213,9 +213,9 @@ public void SanitizeFileNameReturnsUnnamedForOnlyPeriods(string suggestion) } [TestMethod] - public void SanitizeFileNameDropsPeriodLeftBeforeReplacedCharacter() + public void SanitizeFileNameDropsPeriodLeftBeforeTrimmedHyphen() { - FileName result = Scan.SanitizeFileName("sunset.?", ".jpg".As()); + FileName result = Scan.SanitizeFileName("sunset.-", ".jpg".As()); Assert.AreEqual("sunset.jpg", result.WeakString); }