Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions TruePath.Tests/PathExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,28 @@ public void WithExtensionTests_Windows(string inputPath, string newExtension, st
Assert.Equal(expected, newPath.Value);
}

[Theory]
[InlineData("file.txt", "md", "file.md")]
[InlineData("file.txt", ".md", "file.md")]
[InlineData("file", "md", "file.md")]
[InlineData("file", ".md", "file.md")]
[InlineData("archive.tar.gz", "zip", "archive.tar.zip")]
[InlineData("archive.zip", ".tar.gz", "archive.tar.gz")]
[InlineData("file.txt", "", "file.")]
[InlineData("file.txt", null, "file")]
[InlineData(".gitignore", "hgignore", ".hgignore")]
public void WithExtensionArgumentTests(string inputPath, string? newExtension, string expected)
{
// Arrange
var path = new LocalPath(inputPath);

// Act
var newPath = path.WithExtension(newExtension);

// Assert
Assert.Equal(expected, newPath.Value);
}

[Theory]
[InlineData("/", "bar", "/.bar")]
[InlineData("/file", "bar", "/file.bar")]
Expand Down
72 changes: 69 additions & 3 deletions TruePath/PathExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,33 @@ public static string GetFilenameWithoutExtension(this IPath path) =>
/// </summary>
/// <typeparam name="TPath">The type of the path, which must implement <see cref="IPath{TPath}"/>.</typeparam>
/// <param name="path">The original path.</param>
/// <param name="extension">The new extension to apply.</param>
/// <param name="extension">
/// <para>
/// The new extension, either with or without the leading dot: both <c>txt</c> and <c>.txt</c> give the
/// same result, since the dot is added when missing.
/// </para>
/// <para>
/// Pass <see langword="null"/> to remove the extension entirely (<c>file.txt</c> becomes <c>file</c>), or
/// an empty string to remove it but keep the trailing dot (<c>file.txt</c> becomes <c>file.</c>).
/// </para>
/// </param>
/// <returns>
/// A new path of type <typeparamref name="TPath"/> with the modified file name component.
/// The original <paramref name="path"/> object is not modified.
/// </returns>
/// <remarks>
/// <para>
/// Only the last extension is replaced: for <c>archive.tar.gz</c> and the extension <c>zip</c>, the result
/// is <c>archive.tar.zip</c>. The extension itself may contain dots, so <c>.tar.gz</c> applied to
/// <c>archive.zip</c> gives <c>archive.tar.gz</c>.
/// </para>
/// <para>If the file name has no extension, the new one is appended: <c>file</c> becomes <c>file.txt</c>.</para>
/// <para>
/// A file name consisting entirely of an extension is treated as an extension, consistently with
/// <see cref="GetExtensionWithDot"/>: <c>.gitignore</c> with the extension <c>hgignore</c> becomes
/// <c>.hgignore</c>.
/// </para>
/// </remarks>
public static TPath WithExtension<TPath>(this TPath path, string? extension) where TPath : IPath<TPath> =>
TPath.Create(Path.ChangeExtension(((IPath)path).Value, extension));
#else
Expand All @@ -70,11 +92,33 @@ public static TPath WithExtension<TPath>(this TPath path, string? extension) whe
/// or with a new extension-like component if the original file name was empty.
/// </summary>
/// <param name="path">The original path.</param>
/// <param name="extension">The new extension to apply.</param>
/// <param name="extension">
/// <para>
/// The new extension, either with or without the leading dot: both <c>txt</c> and <c>.txt</c> give the
/// same result, since the dot is added when missing.
/// </para>
/// <para>
/// Pass <see langword="null"/> to remove the extension entirely (<c>file.txt</c> becomes <c>file</c>), or
/// an empty string to remove it but keep the trailing dot (<c>file.txt</c> becomes <c>file.</c>).
/// </para>
/// </param>
/// <returns>
/// A new path of type <see cref="AbsolutePath"/> with the modified file name component.
/// The original <paramref name="path"/> object is not modified.
/// </returns>
/// <remarks>
/// <para>
/// Only the last extension is replaced: for <c>archive.tar.gz</c> and the extension <c>zip</c>, the result
/// is <c>archive.tar.zip</c>. The extension itself may contain dots, so <c>.tar.gz</c> applied to
/// <c>archive.zip</c> gives <c>archive.tar.gz</c>.
/// </para>
/// <para>If the file name has no extension, the new one is appended: <c>file</c> becomes <c>file.txt</c>.</para>
/// <para>
/// A file name consisting entirely of an extension is treated as an extension, consistently with
/// <see cref="GetExtensionWithDot"/>: <c>.gitignore</c> with the extension <c>hgignore</c> becomes
/// <c>.hgignore</c>.
/// </para>
/// </remarks>
public static AbsolutePath WithExtension(this AbsolutePath path, string? extension) =>
AbsolutePath.Create(Path.ChangeExtension(path.Value, extension));

Expand All @@ -83,11 +127,33 @@ public static AbsolutePath WithExtension(this AbsolutePath path, string? extensi
/// or with a new extension-like component if the original file name was empty.
/// </summary>
/// <param name="path">The original path.</param>
/// <param name="extension">The new extension to apply.</param>
/// <param name="extension">
/// <para>
/// The new extension, either with or without the leading dot: both <c>txt</c> and <c>.txt</c> give the
/// same result, since the dot is added when missing.
/// </para>
/// <para>
/// Pass <see langword="null"/> to remove the extension entirely (<c>file.txt</c> becomes <c>file</c>), or
/// an empty string to remove it but keep the trailing dot (<c>file.txt</c> becomes <c>file.</c>).
/// </para>
/// </param>
/// <returns>
/// A new path of type <see cref="LocalPath"/> with the modified file name component.
/// The original <paramref name="path"/> object is not modified.
/// </returns>
/// <remarks>
/// <para>
/// Only the last extension is replaced: for <c>archive.tar.gz</c> and the extension <c>zip</c>, the result
/// is <c>archive.tar.zip</c>. The extension itself may contain dots, so <c>.tar.gz</c> applied to
/// <c>archive.zip</c> gives <c>archive.tar.gz</c>.
/// </para>
/// <para>If the file name has no extension, the new one is appended: <c>file</c> becomes <c>file.txt</c>.</para>
/// <para>
/// A file name consisting entirely of an extension is treated as an extension, consistently with
/// <see cref="GetExtensionWithDot"/>: <c>.gitignore</c> with the extension <c>hgignore</c> becomes
/// <c>.hgignore</c>.
/// </para>
/// </remarks>
public static LocalPath WithExtension(this LocalPath path, string? extension) =>
LocalPath.Create(Path.ChangeExtension(path.Value, extension));
#endif
Expand Down
Loading