Skip to content

Commit ccf506c

Browse files
committed
PathStrings: fix treatment of ""..." in the end of a path
1 parent 8a677f4 commit ccf506c

5 files changed

Lines changed: 34 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ All notable changes to this project will be documented in this file.
1111
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1212

1313
## [Unreleased]
14+
### Fixed
15+
- Incorrect path normalization: last ellipsis (`...`) in a path was treated as a `..` entry.
16+
1417
### Changed
1518
- [#18](https://github.com/ForNeVeR/TruePath/issues/18): update to behavior of `.Parent` on relative paths.
1619

TruePath.Tests/AbsolutePathTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ namespace TruePath.Tests;
88

99
public class AbsolutePathTests
1010
{
11+
[Fact]
12+
public void ConstructionTest()
13+
{
14+
var root = new AbsolutePath(OperatingSystem.IsWindows() ? @"A:\" : "/");
15+
var path = new AbsolutePath($"{root}/...");
16+
Assert.Equal($"{root}...", path.Value);
17+
}
18+
1119
[Fact]
1220
public void ReadKind_NonExistent()
1321
{

TruePath.Tests/LocalPathTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ public void AbsolutePathParent(string relativePath, string? expectedRelativePath
2020
Assert.Equal(expectedPath, parent.Parent);
2121
}
2222

23+
[Theory]
24+
[InlineData(".", "")]
25+
[InlineData("..", "..")]
26+
[InlineData("../..", "../..")]
27+
[InlineData(".../...", ".../...")]
28+
[InlineData(".../..", "")]
29+
public void ConstructionTest(string pathString, string expectedValue)
30+
{
31+
var path = new LocalPath(pathString);
32+
Assert.Equal(expectedValue.Replace('/', Path.DirectorySeparatorChar), path.Value);
33+
}
34+
2335
[Theory]
2436
[InlineData(".", "..")]
2537
[InlineData("..", "../..")]

TruePath.Tests/PathStringsTests.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ public void SeparatorsAreDeduplicated(string input, string expected)
5555
[InlineData("../../foo", "../../foo")]
5656
[InlineData("../../../foo", "../../../foo")]
5757
[InlineData("../foo/..", "..")]
58-
public void DotFoldersAreTraversed(string input, string expected)
58+
[InlineData("...", "...")]
59+
[InlineData(".../..", "")]
60+
[InlineData(".../...", ".../...")]
61+
[InlineData(".../../...", "...")]
62+
public void DotFoldersAreTraversedCorrectly(string input, string expected)
5963
{
6064
Assert.Equal(NormalizeSeparators(expected), PathStrings.Normalize(input));
6165
}

TruePath/PathStrings.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,12 @@ public static string Normalize(string path)
7575
else if (block.Length == 2 && block[0] == '.' && (block[1] == Path.DirectorySeparatorChar || block[1] == Path.AltDirectorySeparatorChar))
7676
skip = true;
7777
// cut if '..' or '../'
78-
else if (written != 0 && block.Length is 2 or 3 && block.StartsWith(".."))
78+
else if (written != 0
79+
&& (
80+
block is ".."
81+
|| block.SequenceEqual($"..{Path.DirectorySeparatorChar}")
82+
|| block.SequenceEqual($"..{Path.AltDirectorySeparatorChar}")
83+
))
7984
{
8085
var alreadyWrittenPart = normalized[..(written - 1)];
8186
var jump = alreadyWrittenPart.LastIndexOf(Path.DirectorySeparatorChar);

0 commit comments

Comments
 (0)