diff --git a/TruePath.Tests/PathStringsTests.cs b/TruePath.Tests/PathStringsTests.cs index 5ed8d84..d2cb083 100644 --- a/TruePath.Tests/PathStringsTests.cs +++ b/TruePath.Tests/PathStringsTests.cs @@ -128,6 +128,35 @@ public void WindowsSpecificDotFoldersAreTraversed(string input, string expected) } } + [Theory] + [InlineData("C:/", "C:")] + [InlineData("C:/../file", "file")] + public void Normalize_DriveLetterCheckDisabled_TreatsColonAsRegularPathCharacter(string input, string expected) + { + var actual = PathStrings.Normalize(input, driveBasedSystem: false); + + Assert.Equal(NormalizeSeparators(expected), actual); + } + + [Theory] + [InlineData("C:/", "C:/")] + [InlineData("C:/../file", "C:/../file")] + public void Normalize_DriveLetterCheckEnabled_PreservesWindowsDrivePrefix(string input, string expected) + { + var actual = PathStrings.Normalize(input, driveBasedSystem: true); + + Assert.Equal(NormalizeSeparators(expected), actual); + } + + [Fact] + public void Normalize_DriveLetterHandling_MatchesCurrentPlatform() + { + var actual = PathStrings.Normalize("C:/../file"); + var expected = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:/../file" : "file"; + + Assert.Equal(NormalizeSeparators(expected), actual); + } + private static string NormalizeSeparators(string path) => path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); } diff --git a/TruePath/LocalPath.cs b/TruePath/LocalPath.cs index 350b0a1..bdc8578 100644 --- a/TruePath/LocalPath.cs +++ b/TruePath/LocalPath.cs @@ -15,8 +15,8 @@ namespace TruePath; /// (e.g. the parent of foo). /// /// -/// Always stored in a normalized form. Read the documentation on to -/// know what form of normalization the path uses. +/// Always stored in a normalized form. Read the documentation on +/// to know what form of normalization the path uses. /// /// public readonly struct LocalPath(string value) : IEquatable, IComparable, IPath, IPath diff --git a/TruePath/PathStrings.cs b/TruePath/PathStrings.cs index 1054176..f65ce1a 100644 --- a/TruePath/PathStrings.cs +++ b/TruePath/PathStrings.cs @@ -1,9 +1,12 @@ -// SPDX-FileCopyrightText: 2024 TruePath contributors +// SPDX-FileCopyrightText: 2024-2026 TruePath contributors // // SPDX-License-Identifier: MIT using System.Buffers; +using System.Runtime.InteropServices; +#if NET8_0_OR_GREATER using System.Runtime.CompilerServices; +#endif namespace TruePath; @@ -46,12 +49,15 @@ public static class PathStrings /// Note that this operation will never perform any file IO, and is purely string manipulation. /// /// + public static string Normalize(string path) => + Normalize(path, driveBasedSystem: RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + #if NET8_0_OR_GREATER [SkipLocalsInit] // is necessary to prevent the CLR from filling stackalloc with zeros. #endif - public static string Normalize(string path) + internal static string Normalize(string path, bool driveBasedSystem) { - bool containsDriveLetter = SourceContainsDriveLetter(path.AsSpan()); + bool containsDriveLetter = driveBasedSystem && SourceContainsDriveLetter(path.AsSpan()); int written = 0;