Skip to content

Commit

Permalink
feat: implement Combine for simulated Path (#572)
Browse files Browse the repository at this point in the history
Implement the `Combine` methods for `Path`.
  • Loading branch information
vbreuss authored Apr 20, 2024
1 parent 2932ab1 commit 760b601
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,66 @@ public bool TryJoin(ReadOnlySpan<char> path1,

#endregion

private static string CombineInternal(string[] paths)
=> System.IO.Path.Combine(paths);
private string CombineInternal(string[] paths)
{
string NormalizePath(string path, bool ignoreStartingSeparator)
{
if (!ignoreStartingSeparator && (
path[0] == DirectorySeparatorChar ||
path[0] == AltDirectorySeparatorChar))
{
path = path.Substring(1);
}

if (path[path.Length - 1] == DirectorySeparatorChar ||
path[path.Length - 1] == AltDirectorySeparatorChar)
{
path = path.Substring(0, path.Length - 1);
}

return NormalizeDirectorySeparators(path);
}

if (paths == null)
{
throw new ArgumentNullException(nameof(paths));
}

StringBuilder sb = new();

bool isFirst = true;
bool endsWithDirectorySeparator = false;
foreach (string path in paths)
{
if (path == null)
{
throw new ArgumentNullException(nameof(paths));
}

if (string.IsNullOrEmpty(path))
{
continue;
}

if (IsPathRooted(path))
{
sb.Clear();
isFirst = true;
}

sb.Append(NormalizePath(path, isFirst));
sb.Append(DirectorySeparatorChar);
endsWithDirectorySeparator = path.EndsWith(DirectorySeparatorChar) ||
path.EndsWith(AltDirectorySeparatorChar);
}

if (!endsWithDirectorySeparator)
{
return sb.ToString(0, sb.Length - 1);
}

return sb.ToString();
}

protected abstract int GetRootLength(string path);
protected abstract bool IsDirectorySeparator(char c);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ private bool IncludeSimulatedTests(ClassModel @class)
string[] supportedPathTests =
[
"ChangeExtensionTests",
"CombineTests",
"EndsInDirectorySeparatorTests",
"GetDirectoryNameTests",
"GetExtensionTests",
Expand Down
85 changes: 85 additions & 0 deletions Tests/Testably.Abstractions.Tests/FileSystem/Path/CombineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@ public void Combine_2Paths_Rooted_ShouldReturnLastRootedPath(
result.Should().Be(path2);
}

[SkippableTheory]
[InlineAutoData("/foo/", "/bar/", "/bar/")]
[InlineAutoData("foo/", "/bar", "/bar")]
[InlineAutoData("foo/", "bar", "foo/bar")]
[InlineAutoData("foo", "/bar", "/bar")]
[InlineAutoData("foo", "bar", "foo/bar")]
[InlineAutoData("/foo", "bar/", "/foo/bar/")]
public void Combine_2Paths_ShouldReturnExpectedResult(
string path1, string path2, string expectedResult)
{
path1 = path1.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path2 = path2.Replace('/', FileSystem.Path.DirectorySeparatorChar);
expectedResult = expectedResult.Replace('/', FileSystem.Path.DirectorySeparatorChar);

string result = FileSystem.Path.Combine(path1, path2);

result.Should().Be(expectedResult);
}

[SkippableTheory]
[InlineAutoData]
[InlineAutoData(" ")]
Expand Down Expand Up @@ -109,6 +128,27 @@ public void Combine_3Paths_Rooted_ShouldReturnLastRootedPath(
result.Should().Be(path3);
}

[SkippableTheory]
[InlineAutoData("/foo/", "/bar/", "/baz/", "/baz/")]
[InlineAutoData("foo/", "/bar/", "/baz", "/baz")]
[InlineAutoData("foo/", "bar", "/baz", "/baz")]
[InlineAutoData("foo", "/bar", "/baz", "/baz")]
[InlineAutoData("foo", "/bar/", "baz", "/bar/baz")]
[InlineAutoData("foo", "bar", "baz", "foo/bar/baz")]
[InlineAutoData("/foo", "bar", "baz/", "/foo/bar/baz/")]
public void Combine_3Paths_ShouldReturnExpectedResult(
string path1, string path2, string path3, string expectedResult)
{
path1 = path1.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path2 = path2.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path3 = path3.Replace('/', FileSystem.Path.DirectorySeparatorChar);
expectedResult = expectedResult.Replace('/', FileSystem.Path.DirectorySeparatorChar);

string result = FileSystem.Path.Combine(path1, path2, path3);

result.Should().Be(expectedResult);
}

[SkippableTheory]
[InlineAutoData]
[InlineAutoData(" ")]
Expand Down Expand Up @@ -183,6 +223,28 @@ public void Combine_4Paths_Rooted_ShouldReturnLastRootedPath(
result.Should().Be(path4);
}

[SkippableTheory]
[InlineAutoData("/foo/", "/bar/", "/baz/", "/muh/", "/muh/")]
[InlineAutoData("foo/", "/bar/", "/baz/", "/muh", "/muh")]
[InlineAutoData("foo/", "bar", "/baz", "/muh", "/muh")]
[InlineAutoData("foo", "/bar", "/baz", "/muh", "/muh")]
[InlineAutoData("foo", "/bar/", "baz/", "muh", "/bar/baz/muh")]
[InlineAutoData("foo", "bar", "baz", "muh", "foo/bar/baz/muh")]
[InlineAutoData("/foo", "bar", "baz", "muh/", "/foo/bar/baz/muh/")]
public void Combine_4Paths_ShouldReturnExpectedResult(
string path1, string path2, string path3, string path4, string expectedResult)
{
path1 = path1.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path2 = path2.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path3 = path3.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path4 = path4.Replace('/', FileSystem.Path.DirectorySeparatorChar);
expectedResult = expectedResult.Replace('/', FileSystem.Path.DirectorySeparatorChar);

string result = FileSystem.Path.Combine(path1, path2, path3, path4);

result.Should().Be(expectedResult);
}

[SkippableTheory]
[InlineAutoData]
[InlineAutoData(" ")]
Expand Down Expand Up @@ -281,6 +343,29 @@ public void Combine_ParamPaths_Rooted_ShouldReturnLastRootedPath(
result.Should().Be(path5);
}

[SkippableTheory]
[InlineAutoData("/foo/", "/bar/", "/baz/", "/muh/", "/maeh/", "/maeh/")]
[InlineAutoData("foo/", "/bar/", "/baz/", "/muh", "/maeh", "/maeh")]
[InlineAutoData("foo/", "bar", "/baz", "/muh", "/maeh", "/maeh")]
[InlineAutoData("foo", "/bar", "/baz", "/muh", "/maeh", "/maeh")]
[InlineAutoData("foo", "/bar/", "baz/", "muh/", "maeh", "/bar/baz/muh/maeh")]
[InlineAutoData("foo", "bar", "baz", "muh", "maeh", "foo/bar/baz/muh/maeh")]
[InlineAutoData("/foo", "bar", "baz", "muh", "maeh/", "/foo/bar/baz/muh/maeh/")]
public void Combine_ParamPaths_ShouldReturnExpectedResult(
string path1, string path2, string path3, string path4, string path5, string expectedResult)
{
path1 = path1.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path2 = path2.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path3 = path3.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path4 = path4.Replace('/', FileSystem.Path.DirectorySeparatorChar);
path5 = path5.Replace('/', FileSystem.Path.DirectorySeparatorChar);
expectedResult = expectedResult.Replace('/', FileSystem.Path.DirectorySeparatorChar);

string result = FileSystem.Path.Combine(path1, path2, path3, path4, path5);

result.Should().Be(expectedResult);
}

[SkippableTheory]
[InlineAutoData]
[InlineAutoData(" ")]
Expand Down

0 comments on commit 760b601

Please sign in to comment.