aboutsummaryrefslogtreecommitdiff
path: root/tests/Jellyfin.Extensions.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Jellyfin.Extensions.Tests')
-rw-r--r--tests/Jellyfin.Extensions.Tests/PathHelperTests.cs60
-rw-r--r--tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs23
2 files changed, 83 insertions, 0 deletions
diff --git a/tests/Jellyfin.Extensions.Tests/PathHelperTests.cs b/tests/Jellyfin.Extensions.Tests/PathHelperTests.cs
new file mode 100644
index 0000000000..71fd853ba2
--- /dev/null
+++ b/tests/Jellyfin.Extensions.Tests/PathHelperTests.cs
@@ -0,0 +1,60 @@
+using System.IO;
+using Jellyfin.Extensions;
+using Xunit;
+
+namespace Jellyfin.Extensions.Tests
+{
+ public static class PathHelperTests
+ {
+ [Theory]
+ [InlineData("file.txt", "file.txt")]
+ [InlineData("sub/file.txt", "file.txt")]
+ [InlineData("../../etc/passwd", "passwd")]
+ public static void GetSafeLeafFileName_ReducesToLeaf(string input, string expected)
+ {
+ Assert.Equal(expected, PathHelper.GetSafeLeafFileName(input));
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData(".")]
+ [InlineData("..")]
+ public static void GetSafeLeafFileName_RejectsUnusableLeaf(string? input)
+ {
+ Assert.Null(PathHelper.GetSafeLeafFileName(input));
+ }
+
+ [Fact]
+ public static void IsContainedIn_ChildPath_ReturnsTrue()
+ {
+ var root = Path.Combine(Path.GetTempPath(), "root");
+ var child = Path.Combine(root, "sub", "file.txt");
+ Assert.True(PathHelper.IsContainedIn(root, child));
+ }
+
+ [Fact]
+ public static void IsContainedIn_RootItself_ReturnsTrue()
+ {
+ var root = Path.Combine(Path.GetTempPath(), "root");
+ Assert.True(PathHelper.IsContainedIn(root, root));
+ }
+
+ [Fact]
+ public static void IsContainedIn_TraversalEscape_ReturnsFalse()
+ {
+ var root = Path.Combine(Path.GetTempPath(), "root");
+ var escape = Path.Combine(root, "..", "..", "etc", "passwd");
+ Assert.False(PathHelper.IsContainedIn(root, escape));
+ }
+
+ [Fact]
+ public static void IsContainedIn_SiblingPrefixCollision_ReturnsFalse()
+ {
+ // "/var/data" must not be accepted as a parent of "/var/dataset".
+ var root = Path.Combine(Path.GetTempPath(), "data");
+ var sibling = Path.Combine(Path.GetTempPath(), "dataset", "file.txt");
+ Assert.False(PathHelper.IsContainedIn(root, sibling));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs
index 028f12afa7..0851570396 100644
--- a/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs
@@ -75,5 +75,28 @@ namespace Jellyfin.Extensions.Tests
var result = str.AsSpan().RightPart(needle).ToString();
Assert.Equal(expectedResult, result);
}
+
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("/media/movies/Film.mkv", "/media/movies/Film.mkv")]
+ [InlineData(@"C:\media\movies\Film.mkv", @"C:\media\movies\Film.mkv")]
+ [InlineData(@"/media/a""b.mkv", @"/media/a\""b.mkv")]
+ [InlineData(@"/media/a\""b.mkv", @"/media/a\\\""b.mkv")]
+ [InlineData(@"/media/a\\""b.mkv", @"/media/a\\\\\""b.mkv")]
+ [InlineData(@"/media/a\b""c.mkv", @"/media/a\b\""c.mkv")]
+ [InlineData(@"/media/trailing\", @"/media/trailing\\")]
+ [InlineData(@"/media/evil\"" -f lavfi -i sine .mkv", @"/media/evil\\\"" -f lavfi -i sine .mkv")]
+ public void EscapeProcessArgument_ValidInput_Corrects(string input, string expectedResult)
+ {
+ Assert.Equal(expectedResult, input.EscapeProcessArgument());
+ }
+
+ [Theory]
+ [InlineData("/media/movies/Film with spaces.mkv")]
+ [InlineData(@"C:\media\movies\Film.mkv")]
+ public void EscapeProcessArgument_NothingToEscape_ReturnsSameInstance(string input)
+ {
+ Assert.Same(input, input.EscapeProcessArgument());
+ }
}
}