- Revert GetFileName to return unsanitized name. AllDebridDebridClient. GetSymlinkPath matches torrent.Files[].Path (original debrid data) against GetFileName, so sanitizing it broke AllDebrid Symlink lookups for any torrent with bracketed filenames. Sanitization now happens inside GetDownloadPath at the point the filesystem path is assembled, while matching still uses the unsanitized name. - Make SanitizeFilename / SanitizePath accept String? and return String.Empty for null/empty input so the declared non-null return type is honoured. - SanitizePath splits on both '/' and '\\' regardless of host OS, so paths arriving from the debrid provider with foreign separators are still segmented correctly on Linux containers. - Rewrite the control-character tests to use explicit \u escape sequences (, , , , ) so the test inputs are visible in diffs and survive editor/CI round-trips. Replace the single-row empty [Theory] with a [Fact] and add a null case. Add tests asserting SanitizeFilenameIfEnabled and SanitizePathIfEnabled return input unchanged when the toggle is disabled, and sanitize when enabled.
207 lines
6.9 KiB
C#
207 lines
6.9 KiB
C#
using RdtClient.Service.Helpers;
|
|
using RdtClient.Service.Services;
|
|
|
|
namespace RdtClient.Service.Test.Helpers;
|
|
|
|
public class FilenameSanitizerTest
|
|
{
|
|
[Theory]
|
|
[InlineData(
|
|
"Fixer.Upper.S04E11.Space.in.the.Suburbs.720p.HDTV.x264-W4F[eztv].mkv",
|
|
"Fixer.Upper.S04E11.Space.in.the.Suburbs.720p.HDTV.x264-W4Feztv.mkv")]
|
|
[InlineData(
|
|
"The.Bear.S03E01.Tomorrow.1080p.DSNP.WEB-DL.DDP5.1.H.264-NTb[EZTVx.to].mkv",
|
|
"The.Bear.S03E01.Tomorrow.1080p.DSNP.WEB-DL.DDP5.1.H.264-NTbEZTVx.to.mkv")]
|
|
public void SanitizeFilename_StripsSquareBrackets(String input, String expected)
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename(input);
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilename_StripsCurlyBraces()
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename("Movie{2024}.mkv");
|
|
Assert.Equal("Movie2024.mkv", result);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("Movie Name 2024.mkv", "Movie Name 2024.mkv")]
|
|
[InlineData("Too Many Spaces.mkv", "Too Many Spaces.mkv")]
|
|
public void SanitizeFilename_CollapsesMultipleSpaces(String input, String expected)
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename(input);
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(" Leading.mkv", "Leading.mkv")]
|
|
[InlineData("Trailing.mkv ", "Trailing.mkv")]
|
|
[InlineData(" Both Sides ", "Both Sides")]
|
|
public void SanitizeFilename_TrimsWhitespace(String input, String expected)
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename(input);
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
[Theory]
|
|
// Uses explicit \u escapes so the control characters survive editors,
|
|
// diffs, and CI log copy-paste. Each case verifies a different range
|
|
// of Unicode control characters.
|
|
[InlineData("Movie\u0001Name\u001F.mkv", "MovieName.mkv")] // C0 range (0x00-0x1F)
|
|
[InlineData("Movie\tName.mkv", "MovieName.mkv")] // tab
|
|
[InlineData("Movie\u007FName.mkv", "MovieName.mkv")] // DEL (0x7F)
|
|
[InlineData("Movie\u0080Name\u009F.mkv", "MovieName.mkv")] // C1 range (0x80-0x9F)
|
|
public void SanitizeFilename_StripsControlCharacters(String input, String expected)
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename(input);
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilename_LeavesCleanFilenamesUnchanged()
|
|
{
|
|
const String clean = "fixer.upper.s05e17.chip.and.jos.breakfast.joint.hdtv.x264-w4f.mkv";
|
|
var result = FilenameSanitizer.SanitizeFilename(clean);
|
|
Assert.Equal(clean, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilename_PreservesParentheses()
|
|
{
|
|
const String input = "Movie (2024) 1080p.mkv";
|
|
var result = FilenameSanitizer.SanitizeFilename(input);
|
|
Assert.Equal(input, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilename_ReturnsEmptyForEmpty()
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename("");
|
|
Assert.Equal("", result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilename_ReturnsEmptyForNull()
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename(null);
|
|
Assert.Equal("", result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilename_CombinedIssues()
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename("Some Show S01E01 720p HDTV [eztv].mkv");
|
|
Assert.Equal("Some Show S01E01 720p HDTV eztv.mkv", result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilename_StripsBracketsEvenWhenSpacedApart()
|
|
{
|
|
var result = FilenameSanitizer.SanitizeFilename("Some Show [2024] 1080p.mkv");
|
|
Assert.Equal("Some Show 2024 1080p.mkv", result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizePath_SanitizesFilenameSegment()
|
|
{
|
|
var path = Path.Combine(Path.DirectorySeparatorChar + "data", "downloads", "tv-sonarr", "Fixer.Upper.S04E11[eztv].mkv");
|
|
var expected = Path.Combine(Path.DirectorySeparatorChar + "data", "downloads", "tv-sonarr", "Fixer.Upper.S04E11eztv.mkv");
|
|
|
|
var result = FilenameSanitizer.SanitizePath(path);
|
|
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizePath_SanitizesDirectoryNames()
|
|
{
|
|
var path = Path.Combine(Path.DirectorySeparatorChar + "data", "downloads", "Some Show [2024]", "Episode[eztv].mkv");
|
|
var expected = Path.Combine(Path.DirectorySeparatorChar + "data", "downloads", "Some Show 2024", "Episodeeztv.mkv");
|
|
|
|
var result = FilenameSanitizer.SanitizePath(path);
|
|
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizePath_PreservesDirectorySeparators()
|
|
{
|
|
var path = Path.Combine(Path.DirectorySeparatorChar + "data", "downloads", "clean", "file.mkv");
|
|
|
|
var result = FilenameSanitizer.SanitizePath(path);
|
|
|
|
Assert.Equal(path, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizePath_HandlesMixedSeparators()
|
|
{
|
|
var result = FilenameSanitizer.SanitizePath("data/downloads\\Some Show [2024]/Episode[eztv].mkv");
|
|
var expected = String.Join(Path.DirectorySeparatorChar, "data", "downloads", "Some Show 2024", "Episodeeztv.mkv");
|
|
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizePath_ReturnsEmptyForEmpty()
|
|
{
|
|
Assert.Equal("", FilenameSanitizer.SanitizePath(""));
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizePath_ReturnsEmptyForNull()
|
|
{
|
|
Assert.Equal("", FilenameSanitizer.SanitizePath(null));
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilenameIfEnabled_ReturnsUnchangedWhenDisabled()
|
|
{
|
|
var original = Settings.Get.DownloadClient.SanitizeFilenames;
|
|
try
|
|
{
|
|
Settings.Get.DownloadClient.SanitizeFilenames = false;
|
|
|
|
const String input = "Movie [eztv].mkv";
|
|
Assert.Equal(input, FilenameSanitizer.SanitizeFilenameIfEnabled(input));
|
|
}
|
|
finally
|
|
{
|
|
Settings.Get.DownloadClient.SanitizeFilenames = original;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizeFilenameIfEnabled_SanitizesWhenEnabled()
|
|
{
|
|
var original = Settings.Get.DownloadClient.SanitizeFilenames;
|
|
try
|
|
{
|
|
Settings.Get.DownloadClient.SanitizeFilenames = true;
|
|
|
|
Assert.Equal("Movie eztv.mkv", FilenameSanitizer.SanitizeFilenameIfEnabled("Movie [eztv].mkv"));
|
|
}
|
|
finally
|
|
{
|
|
Settings.Get.DownloadClient.SanitizeFilenames = original;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SanitizePathIfEnabled_ReturnsUnchangedWhenDisabled()
|
|
{
|
|
var original = Settings.Get.DownloadClient.SanitizeFilenames;
|
|
try
|
|
{
|
|
Settings.Get.DownloadClient.SanitizeFilenames = false;
|
|
|
|
var input = Path.Combine(Path.DirectorySeparatorChar + "data", "downloads", "Show [2024]", "Episode[eztv].mkv");
|
|
Assert.Equal(input, FilenameSanitizer.SanitizePathIfEnabled(input));
|
|
}
|
|
finally
|
|
{
|
|
Settings.Get.DownloadClient.SanitizeFilenames = original;
|
|
}
|
|
}
|
|
}
|