Skip to content

Commit

Permalink
update deps and add Path.HasTrailingDirectorySeparator
Browse files Browse the repository at this point in the history
  • Loading branch information
AnakinRaW committed Sep 22, 2024
1 parent a500761 commit 48e4243
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</PackageReference>
<PackageReference Include="Nerdbank.GitVersioning" Condition="!Exists('packages.config')">
<PrivateAssets>all</PrivateAssets>
<Version>3.6.141</Version>
<Version>3.6.143</Version>
</PackageReference>
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
</PackageReference>
<PackageReference Include="MartinCostello.Logging.XUnit" Version="0.4.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Testably.Abstractions" Version="3.2.2" />
<PackageReference Include="Testably.Abstractions.Testing" Version="3.2.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="Testably.Abstractions" Version="3.2.3" />
<PackageReference Include="Testably.Abstractions.Testing" Version="3.2.3" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
49 changes: 38 additions & 11 deletions src/CommonUtilities.FileSystem/src/Extensions/PathExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,22 @@ public static partial class PathExtensions
internal static readonly Lazy<bool> IsFileSystemCaseInsensitive = new(CheckIfFileSystemIsCaseInsensitive);

/// <summary>
/// Determines whether the specified path ends with a directory path separator
/// Returns a value that indicates whether the path ends in a directory separator.
/// </summary>
/// <param name="_"></param>
/// <param name="path">The path to check.</param>
/// <returns><see langword="true"/> if <paramref name="path"/> ends with a directory path separator; otherwise, <see langword="false"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
public static bool HasTrailingDirectorySeparator(this IPath _, string path)
/// <param name="path">The path to analyze.</param>
/// <returns><see langword="true"/> if the path ends in a directory separator; otherwise, <see langword="false"/>.</returns>
public static bool HasTrailingDirectorySeparator(this IPath _, [NotNullWhen(true)] string? path)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
return HasTrailingDirectorySeparator(path.AsSpan());
return path is not null && HasTrailingDirectorySeparator(path.AsSpan());
}

/// <summary>
/// Determines whether the specified path ends with a directory path separator.
/// Returns a value that indicates whether the path, specified as a read-only span, ends in a directory separator.
/// </summary>
/// <param name="_"></param>
/// <param name="path">The path to check.</param>
/// <returns><see langword="true"/> if <paramref name="path"/> ends with a directory path separator; otherwise, <see langword="false"/>.</returns>
/// <param name="path">The path to analyze.</param>
/// <returns><see langword="true"/> if the path ends in a directory separator; otherwise, <see langword="false"/>.</returns>
public static bool HasTrailingDirectorySeparator(this IPath _, ReadOnlySpan<char> path)
{
return HasTrailingDirectorySeparator(path);
Expand All @@ -68,6 +65,36 @@ private static bool HasTrailingDirectorySeparator(ReadOnlySpan<char> value)
return IsAnyDirectorySeparator(last);
}

/// <summary>
/// Returns a value that indicates whether the path starts with a directory separator.
/// </summary>
/// <param name="_"></param>
/// <param name="path">The path to analyze.</param>
/// <returns><see langword="true"/> if the path starts with a directory separator; otherwise, <see langword="false"/>.</returns>
public static bool HasLeadingDirectorySeparator(this IPath _, [NotNullWhen(true)] string? path)
{
return path is not null && HasLeadingDirectorySeparator(path.AsSpan());
}

/// <summary>
/// Returns a value that indicates whether the path, specified as a read-only span, starts with a directory separator.
/// </summary>
/// <param name="_"></param>
/// <param name="path">The path to analyze.</param>
/// <returns><see langword="true"/> if the path starts with a directory separator; otherwise, <see langword="false"/>.</returns>
public static bool HasLeadingDirectorySeparator(this IPath _, ReadOnlySpan<char> path)
{
return HasLeadingDirectorySeparator(path);
}

private static bool HasLeadingDirectorySeparator(ReadOnlySpan<char> value)
{
if (value.Length == 0)
return false;
var first = value[0];
return IsAnyDirectorySeparator(first);
}

private static bool IsAnyDirectorySeparator(char c)
{
return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Required" Version="1.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Testably.Abstractions" Version="3.2.2" />
<PackageReference Include="Testably.Abstractions.Testing" Version="3.2.2" />
<PackageReference Include="Testably.Abstractions" Version="3.2.3" />
<PackageReference Include="Testably.Abstractions.Testing" Version="3.2.3" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.IO.Abstractions;
using AnakinRaW.CommonUtilities.Testing;
using Xunit;

namespace AnakinRaW.CommonUtilities.FileSystem.Test;

public class HasLeadingPathSeparatorTest
{
// Using the actual file system here since we are not modifying it.
// Also, we want to assure that everything works on the real system,
// not that an arbitrary test implementation works.
private readonly IFileSystem _fileSystem = new System.IO.Abstractions.FileSystem();

[Theory]
[InlineData("")]
[InlineData(null)]
public void Test_HasLeadingPathSeparator(string? input)
{
Assert.False(_fileSystem.Path.HasLeadingDirectorySeparator(input));
Assert.False(_fileSystem.Path.HasLeadingDirectorySeparator(input.AsSpan()));
}

public static TheoryData<string, bool> TestData_StartsWithDirectorySeparator_Windows => new()
{
{ @"\", true },
{ @"/", true },
{ @"C:\folder\", false },
{ @"C:/folder/", false },
{ @"C:\", false },
{ @"C:/", false },
{ @"\\", true },
{ @"//", true },
{ @"\\server\share\", true },
{ @"\\?\UNC\a\", true },
{ @"\\?\C:\", true },
{ @"\\?\UNC\", true },
{ @"\folder", true },
{ @"folder", false },
};

[PlatformSpecificTheory(TestPlatformIdentifier.Windows)]
[MemberData(nameof(TestData_StartsWithDirectorySeparator_Windows))]
public void Test_HasLeadingPathSeparator_Windows(string input, bool expected)
{
Assert.Equal(expected, _fileSystem.Path.HasLeadingDirectorySeparator(input));
Assert.Equal(expected, _fileSystem.Path.HasLeadingDirectorySeparator(input.AsSpan()));
}


public static TheoryData<string, bool> TestData_StartsWithDirectorySeparator_Linux => new()
{
{ @"/", true },
{ @"/folder/", true },
{ @"//", true },
{ @"folder", false },
{ @"/folder", true }
};

[PlatformSpecificTheory(TestPlatformIdentifier.Linux)]
[MemberData(nameof(TestData_StartsWithDirectorySeparator_Linux))]
public void Test_HasLeadingPathSeparator_Linux(string input, bool expected)
{
Assert.Equal(expected, _fileSystem.Path.HasLeadingDirectorySeparator(input));
Assert.Equal(expected, _fileSystem.Path.HasLeadingDirectorySeparator(input.AsSpan()));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.IO.Abstractions;
using AnakinRaW.CommonUtilities.Testing;
using Xunit;
Expand All @@ -13,48 +14,63 @@ public class HasTrailingPathSeparatorTest
private readonly IFileSystem _fileSystem = new System.IO.Abstractions.FileSystem();

[Theory]
[InlineData("", false)]
[InlineData(null, false)]
public void Test_HasTrailingPathSeparator(string? input, bool expected)
[InlineData("")]
[InlineData(null)]
public void Test_HasTrailingPathSeparator(string? input)
{
if (input is null)
Assert.Throws<ArgumentNullException>(() => _fileSystem.Path.HasTrailingDirectorySeparator(input));
else
Assert.Equal(expected, _fileSystem.Path.HasTrailingDirectorySeparator(input));
Assert.Equal(expected, _fileSystem.Path.HasTrailingDirectorySeparator(input.AsSpan()));
Assert.False(_fileSystem.Path.HasTrailingDirectorySeparator(input));
Assert.False(_fileSystem.Path.HasTrailingDirectorySeparator(input.AsSpan()));
#if NET
Assert.False(Path.EndsInDirectorySeparator(input));
#endif
}

public static TheoryData<string, bool> TestData_EndsInDirectorySeparator_Windows => new()
{
{ @"\", true },
{ @"/", true },
{ @"C:\folder\", true },
{ @"C:/folder/", true },
{ @"C:\", true },
{ @"C:/", true },
{ @"\\", true },
{ @"//", true },
{ @"\\server\share\", true },
{ @"\\?\UNC\a\", true },
{ @"\\?\C:\", true },
{ @"\\?\UNC\", true },
{ @"folder\", true },
{ @"folder", false },
};

[PlatformSpecificTheory(TestPlatformIdentifier.Windows)]
[InlineData("/", true)]
[InlineData("\\", true)]
[InlineData("a", false)]
[InlineData("a/", true)]
[InlineData("a\\", true)]
[InlineData("a\\b", false)]
[InlineData("a/b", false)]
[InlineData("a/b\\", true)]
[InlineData("a\\b/", true)]
[MemberData(nameof(TestData_EndsInDirectorySeparator_Windows))]
public void Test_HasTrailingPathSeparator_Windows(string input, bool expected)
{
Assert.Equal(expected, _fileSystem.Path.HasTrailingDirectorySeparator(input));
Assert.Equal(expected, _fileSystem.Path.HasTrailingDirectorySeparator(input.AsSpan()));
#if NET
Assert.Equal(Path.EndsInDirectorySeparator(input), expected);
#endif
}

public static TheoryData<string, bool> TestData_EndsInDirectorySeparator_Linux => new()
{
{ @"/", true },
{ @"/folder/", true },
{ @"//", true },
{ @"folder", false },
{ @"folder/", true }
};

[PlatformSpecificTheory(TestPlatformIdentifier.Linux)]
[InlineData("/", true)]
[InlineData("\\", false)]
[InlineData("a", false)]
[InlineData("a/", true)]
[InlineData("a\\", false)]
[InlineData("a\\b", false)]
[InlineData("a/b", false)]
[InlineData("a/b\\", false)]
[InlineData("a\\b/", true)]
[InlineData("a\\b\\/", true)]
[InlineData("a\\b/\\", false)]
[MemberData(nameof(TestData_EndsInDirectorySeparator_Linux))]
public void Test_HasTrailingPathSeparator_Linux(string input, bool expected)
{
Assert.Equal(expected, _fileSystem.Path.HasTrailingDirectorySeparator(input));
Assert.Equal(expected, _fileSystem.Path.HasTrailingDirectorySeparator(input.AsSpan()));
#if NET
Assert.Equal(Path.EndsInDirectorySeparator(input), expected);
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
</PackageReference>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="21.0.29" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="xunit" Version="2.9.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
Expand Down
8 changes: 4 additions & 4 deletions src/CommonUtilities/test/CommonUtilities.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Testably.Abstractions" Version="3.2.2" />
<PackageReference Include="Testably.Abstractions.Testing" Version="3.2.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="Testably.Abstractions" Version="3.2.3" />
<PackageReference Include="Testably.Abstractions.Testing" Version="3.2.3" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down

0 comments on commit 48e4243

Please sign in to comment.