From 49c67f02371bc6c6a07468e594434c4425c8ef42 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 04:26:31 +0000 Subject: [PATCH] Drop the "." parent when DirectoryPath's / operators combine [patch] Since #504 the parent of a one-segment relative path, and the directory of a bare file name, is ".". DirectoryPath's four / operators still called Path.Combine, which keeps it, so DirectoryPath("a").Parent / Name was "./a" and FilePath("x.txt").DirectoryPath / FileName was "./x.txt", neither equal to the original. Route them through PooledStringBuilder.CombinePaths, as the Relative* and Absolute* directory types already do. Fixes ktsu-dev/Semantics#539 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017vfJW4iaJ7gETqBaPbNzq1 --- Semantics.Paths/Primitives/DirectoryPath.cs | 8 ++-- .../Paths/DirectoryNameRebuildTests.cs | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Semantics.Paths/Primitives/DirectoryPath.cs b/Semantics.Paths/Primitives/DirectoryPath.cs index 3406dab..2edfcb4 100644 --- a/Semantics.Paths/Primitives/DirectoryPath.cs +++ b/Semantics.Paths/Primitives/DirectoryPath.cs @@ -85,7 +85,7 @@ public RelativeDirectoryPath AsRelative(AbsoluteDirectoryPath baseDirectory) Ensure.NotNull(left); Ensure.NotNull(right); - string combinedPath = Path.Combine(left.WeakString, right.WeakString); + string combinedPath = PooledStringBuilder.CombinePaths(left.WeakString, right.WeakString); return Create(combinedPath); } @@ -101,7 +101,7 @@ public RelativeDirectoryPath AsRelative(AbsoluteDirectoryPath baseDirectory) Ensure.NotNull(left); Ensure.NotNull(right); - string combinedPath = Path.Combine(left.WeakString, right.WeakString); + string combinedPath = PooledStringBuilder.CombinePaths(left.WeakString, right.WeakString); return FilePath.Create(combinedPath); } @@ -117,7 +117,7 @@ public RelativeDirectoryPath AsRelative(AbsoluteDirectoryPath baseDirectory) Ensure.NotNull(left); Ensure.NotNull(right); - string combinedPath = Path.Combine(left.WeakString, right.WeakString); + string combinedPath = PooledStringBuilder.CombinePaths(left.WeakString, right.WeakString); return Create(combinedPath); } @@ -133,7 +133,7 @@ public RelativeDirectoryPath AsRelative(AbsoluteDirectoryPath baseDirectory) Ensure.NotNull(left); Ensure.NotNull(right); - string combinedPath = Path.Combine(left.WeakString, right.WeakString); + string combinedPath = PooledStringBuilder.CombinePaths(left.WeakString, right.WeakString); return FilePath.Create(combinedPath); } } diff --git a/Semantics.Test/Paths/DirectoryNameRebuildTests.cs b/Semantics.Test/Paths/DirectoryNameRebuildTests.cs index 9308bf6..cd36e7d 100644 --- a/Semantics.Test/Paths/DirectoryNameRebuildTests.cs +++ b/Semantics.Test/Paths/DirectoryNameRebuildTests.cs @@ -38,6 +38,45 @@ public void DirectoryPath_ParentSlashName_IsTheSameDirectory() Assert.AreEqual(dir, rebuilt); } + [TestMethod] + public void DirectoryPath_SingleSegment_ParentSlashName_IsTheSameDirectory() + { + // The parent of "a" is "." (#504); combining it back must not give "./a" (#539). + DirectoryPath dir = DirectoryPath.Create("a"); + + DirectoryPath rebuilt = dir.Parent / dir.Name; + + Assert.AreEqual("a", rebuilt.WeakString); + Assert.AreEqual(dir, rebuilt); + } + + [TestMethod] + public void FilePath_BareFileName_DirectorySlashFileName_IsTheSameFile() + { + FilePath file = FilePath.Create("x.txt"); + + FilePath rebuilt = file.DirectoryPath / file.FileName; + + Assert.AreEqual("x.txt", rebuilt.WeakString); + Assert.AreEqual(file, rebuilt); + } + + [TestMethod] + public void DirectoryPath_Dot_SlashRelativeFilePath_IsTheRelativeFilePath() + { + FilePath combined = DirectoryPath.Create(".") / RelativeFilePath.Create("x.txt"); + + Assert.AreEqual("x.txt", combined.WeakString); + } + + [TestMethod] + public void DirectoryPath_Dot_SlashRelativeDirectoryPath_IsTheRelativeDirectoryPath() + { + DirectoryPath combined = DirectoryPath.Create(".") / RelativeDirectoryPath.Create("a"); + + Assert.AreEqual("a", combined.WeakString); + } + [TestMethod] public void RelativeDirectoryPath_ParentSlashName_IsTheSameDirectory() {