diff --git a/src/DiffEngine.Tests/ExtensionCaseTests.cs b/src/DiffEngine.Tests/ExtensionCaseTests.cs
new file mode 100644
index 00000000..38ed8808
--- /dev/null
+++ b/src/DiffEngine.Tests/ExtensionCaseTests.cs
@@ -0,0 +1,39 @@
+///
+/// Extensions are matched the way file systems produce them.
+///
+/// ExtensionLookup, PathLookup and BinaryExtensions all compared ordinally while every
+/// registration is lowercase, so .PNG, .JPG and .Docx - which is exactly what Windows and macOS
+/// hand back - matched nothing. The tool resolved for foo.png and not for foo.PNG.
+/// Viewer/ImageExtensions already uses OrdinalIgnoreCase for the same kind of lookup.
+///
+///
+[NotInParallel]
+public class ExtensionCaseTests
+{
+ [Test]
+ public async Task ExtensionsResolveWhateverTheirCasing()
+ {
+ var extension = $".zz{Guid.NewGuid():N}";
+ var tool = DiffTools.AddTool(
+ name: $"CaseProbe{Guid.NewGuid():N}",
+ autoRefresh: false,
+ isMdi: false,
+ supportsText: false,
+ requiresTarget: true,
+ useShellExecute: false,
+ launchArguments: new(
+ Left: (temp, target) => $"\"{temp}\" \"{target}\"",
+ Right: (temp, target) => $"\"{target}\" \"{temp}\""),
+ exePath: Environment.ProcessPath!,
+ binaryExtensions: [extension]);
+
+ await Assert.That(tool).IsNotNull();
+
+ await Assert.That(DiffTools.TryFindByExtension(extension, out _)).IsTrue();
+ await Assert.That(DiffTools.TryFindByExtension(extension.ToUpperInvariant(), out _)).IsTrue();
+
+ await Assert.That(DiffTools.TryFindForInputFilePath($"file{extension.ToUpperInvariant()}", out _)).IsTrue();
+
+ await Assert.That(tool!.BinaryExtensions.Contains(extension.ToUpperInvariant())).IsTrue();
+ }
+}
diff --git a/src/DiffEngine/DiffTools.cs b/src/DiffEngine/DiffTools.cs
index 103cbf35..aeb3fb06 100644
--- a/src/DiffEngine/DiffTools.cs
+++ b/src/DiffEngine/DiffTools.cs
@@ -2,8 +2,12 @@
public static partial class DiffTools
{
- static Dictionary ExtensionLookup = [];
- static Dictionary PathLookup = [];
+ // Case insensitive, because the keys are file extensions and executable paths and the file
+ // systems that produce them are. An ordinal lookup meant .PNG, .JPG and .Docx - which is what
+ // Windows and macOS hand back - matched none of the lowercase registrations, so the tool
+ // resolved for foo.png and not for foo.PNG. Viewer/ImageExtensions already does this
+ static Dictionary ExtensionLookup = new(StringComparer.OrdinalIgnoreCase);
+ static Dictionary PathLookup = new(StringComparer.OrdinalIgnoreCase);
static Dictionary ToolLookup = [];
static ResolvedTool? firstTextTool;
static List resolved = [];
diff --git a/src/DiffEngine/ResolvedTool.cs b/src/DiffEngine/ResolvedTool.cs
index d94e547b..24f1f4de 100644
--- a/src/DiffEngine/ResolvedTool.cs
+++ b/src/DiffEngine/ResolvedTool.cs
@@ -62,7 +62,9 @@ Extensions must begin with a period.
}
}
- BinaryExtensions = binaryExtensions.ToFrozenSet();
+ // Case insensitive for the same reason ExtensionLookup is: a binary extension is compared
+ // against whatever casing the file system produced
+ BinaryExtensions = binaryExtensions.ToFrozenSet(StringComparer.OrdinalIgnoreCase);
RequiresTarget = requiresTarget;
SupportsText = supportsText;