Use file-scoped namespace in EncodingHelperTests

This commit is contained in:
Piotr Niełacny
2026-05-19 13:01:25 +02:00
parent 405d987557
commit f6af1a9fb6

View File

@@ -16,244 +16,243 @@ using Xunit;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;
namespace Jellyfin.Controller.Tests.MediaEncoding
namespace Jellyfin.Controller.Tests.MediaEncoding;
public class EncodingHelperTests
{
public class EncodingHelperTests
[Fact]
public void GetMapArgs_NoSubtitle_ExcludesAllSubs()
{
[Fact]
public void GetMapArgs_NoSubtitle_ExcludesAllSubs()
var state = BuildState(subtitle: null, deliveryMethod: null);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map -0:s", args, StringComparison.Ordinal);
Assert.DoesNotContain("-map 1:", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_InternalSrt_MapsFromPrimaryInput()
{
var sub = new MediaStream { Index = 2, Type = MediaStreamType.Subtitle, Codec = "srt" };
var state = BuildState(sub, SubtitleDeliveryMethod.Embed);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 0:2", args, StringComparison.Ordinal);
Assert.DoesNotContain("-map 1:", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_InternalSubAtHigherIndex_MapsCorrectIndex()
{
var sub0 = new MediaStream { Index = 2, Type = MediaStreamType.Subtitle, Codec = "srt" };
var sub1 = new MediaStream { Index = 3, Type = MediaStreamType.Subtitle, Codec = "ass" };
var state = BuildState(sub1, SubtitleDeliveryMethod.Embed, additionalStreams: [sub0, sub1]);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 0:3", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_ExternalSrt_MapsFirstStreamFromInput1()
{
var sub = new MediaStream
{
var state = BuildState(subtitle: null, deliveryMethod: null);
var args = CreateHelper().GetMapArgs(state);
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "srt",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.en.srt"
};
var state = BuildState(sub, SubtitleDeliveryMethod.Embed);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map -0:s", args, StringComparison.Ordinal);
Assert.DoesNotContain("-map 1:", args, StringComparison.Ordinal);
}
Assert.Contains("-map 1:0", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_InternalSrt_MapsFromPrimaryInput()
[Fact]
public void GetMapArgs_SecondExternalSrt_StillMaps1Colon0()
{
// Two separate .srt files — selecting the second one still maps 1:0
// because Jellyfin feeds only the selected file as ffmpeg input 1.
var ext1 = new MediaStream
{
var sub = new MediaStream { Index = 2, Type = MediaStreamType.Subtitle, Codec = "srt" };
var state = BuildState(sub, SubtitleDeliveryMethod.Embed);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 0:2", args, StringComparison.Ordinal);
Assert.DoesNotContain("-map 1:", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_InternalSubAtHigherIndex_MapsCorrectIndex()
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "srt",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.en.srt"
};
var ext2 = new MediaStream
{
var sub0 = new MediaStream { Index = 2, Type = MediaStreamType.Subtitle, Codec = "srt" };
var sub1 = new MediaStream { Index = 3, Type = MediaStreamType.Subtitle, Codec = "ass" };
var state = BuildState(sub1, SubtitleDeliveryMethod.Embed, additionalStreams: [sub0, sub1]);
var args = CreateHelper().GetMapArgs(state);
Index = 3,
Type = MediaStreamType.Subtitle,
Codec = "srt",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.fr.srt"
};
var state = BuildState(ext2, SubtitleDeliveryMethod.Embed, additionalStreams: [ext1, ext2]);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 0:3", args, StringComparison.Ordinal);
}
Assert.Contains("-map 1:0", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_ExternalSrt_MapsFirstStreamFromInput1()
[Fact]
public void GetMapArgs_MksFirstTrack_MapsInFileIndex0()
{
var mks0 = new MediaStream
{
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "subrip",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var mks1 = new MediaStream
{
Index = 3,
Type = MediaStreamType.Subtitle,
Codec = "ass",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var state = BuildState(mks0, SubtitleDeliveryMethod.Embed, additionalStreams: [mks0, mks1]);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 1:0", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_MksSecondTrack_MapsInFileIndex1()
{
var mks0 = new MediaStream
{
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "subrip",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var mks1 = new MediaStream
{
Index = 3,
Type = MediaStreamType.Subtitle,
Codec = "ass",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var mks2 = new MediaStream
{
Index = 4,
Type = MediaStreamType.Subtitle,
Codec = "subrip",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var state = BuildState(mks1, SubtitleDeliveryMethod.Embed, additionalStreams: [mks0, mks1, mks2]);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 1:1", args, StringComparison.Ordinal);
}
[Theory]
[InlineData(SubtitleDeliveryMethod.Embed, true, "movie.idx")]
[InlineData(SubtitleDeliveryMethod.Encode, true, "movie.idx")]
[InlineData(SubtitleDeliveryMethod.Embed, false, "movie.sub")]
[InlineData(SubtitleDeliveryMethod.Encode, false, "movie.sub")]
public void GetInputArgument_VobSub_UsesCorrectPath(
SubtitleDeliveryMethod deliveryMethod,
bool createIdxFile,
string expectedFilename)
{
var tempDir = Directory.CreateTempSubdirectory("jellyfin-test-");
try
{
var subFile = Path.Combine(tempDir.FullName, "movie.sub");
File.WriteAllText(subFile, "dummy");
if (createIdxFile)
{
File.WriteAllText(Path.Combine(tempDir.FullName, "movie.idx"), "dummy");
}
var sub = new MediaStream
{
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "srt",
Codec = "dvdsub",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.en.srt"
Path = subFile
};
var state = BuildState(sub, SubtitleDeliveryMethod.Embed);
var args = CreateHelper().GetMapArgs(state);
var state = BuildState(sub, deliveryMethod);
var inputArgs = CreateHelper().GetInputArgument(state, new EncodingOptions(), null);
Assert.Contains("-map 1:0", args, StringComparison.Ordinal);
Assert.Contains(expectedFilename, inputArgs, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_SecondExternalSrt_StillMaps1Colon0()
finally
{
// Two separate .srt files — selecting the second one still maps 1:0
// because Jellyfin feeds only the selected file as ffmpeg input 1.
var ext1 = new MediaStream
{
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "srt",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.en.srt"
};
var ext2 = new MediaStream
{
Index = 3,
Type = MediaStreamType.Subtitle,
Codec = "srt",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.fr.srt"
};
var state = BuildState(ext2, SubtitleDeliveryMethod.Embed, additionalStreams: [ext1, ext2]);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 1:0", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_MksFirstTrack_MapsInFileIndex0()
{
var mks0 = new MediaStream
{
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "subrip",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var mks1 = new MediaStream
{
Index = 3,
Type = MediaStreamType.Subtitle,
Codec = "ass",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var state = BuildState(mks0, SubtitleDeliveryMethod.Embed, additionalStreams: [mks0, mks1]);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 1:0", args, StringComparison.Ordinal);
}
[Fact]
public void GetMapArgs_MksSecondTrack_MapsInFileIndex1()
{
var mks0 = new MediaStream
{
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "subrip",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var mks1 = new MediaStream
{
Index = 3,
Type = MediaStreamType.Subtitle,
Codec = "ass",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var mks2 = new MediaStream
{
Index = 4,
Type = MediaStreamType.Subtitle,
Codec = "subrip",
IsExternal = true,
SupportsExternalStream = true,
Path = "/media/movie.mks"
};
var state = BuildState(mks1, SubtitleDeliveryMethod.Embed, additionalStreams: [mks0, mks1, mks2]);
var args = CreateHelper().GetMapArgs(state);
Assert.Contains("-map 1:1", args, StringComparison.Ordinal);
}
[Theory]
[InlineData(SubtitleDeliveryMethod.Embed, true, "movie.idx")]
[InlineData(SubtitleDeliveryMethod.Encode, true, "movie.idx")]
[InlineData(SubtitleDeliveryMethod.Embed, false, "movie.sub")]
[InlineData(SubtitleDeliveryMethod.Encode, false, "movie.sub")]
public void GetInputArgument_VobSub_UsesCorrectPath(
SubtitleDeliveryMethod deliveryMethod,
bool createIdxFile,
string expectedFilename)
{
var tempDir = Directory.CreateTempSubdirectory("jellyfin-test-");
try
{
var subFile = Path.Combine(tempDir.FullName, "movie.sub");
File.WriteAllText(subFile, "dummy");
if (createIdxFile)
{
File.WriteAllText(Path.Combine(tempDir.FullName, "movie.idx"), "dummy");
}
var sub = new MediaStream
{
Index = 2,
Type = MediaStreamType.Subtitle,
Codec = "dvdsub",
IsExternal = true,
SupportsExternalStream = true,
Path = subFile
};
var state = BuildState(sub, deliveryMethod);
var inputArgs = CreateHelper().GetInputArgument(state, new EncodingOptions(), null);
Assert.Contains(expectedFilename, inputArgs, StringComparison.Ordinal);
}
finally
{
tempDir.Delete(true);
}
}
private static EncodingJobInfo BuildState(
MediaStream? subtitle,
SubtitleDeliveryMethod? deliveryMethod,
MediaStream[]? additionalStreams = null)
{
var video = new MediaStream { Index = 0, Type = MediaStreamType.Video, Codec = "h264" };
var audio = new MediaStream { Index = 1, Type = MediaStreamType.Audio, Codec = "aac" };
var streams = new List<MediaStream> { video, audio };
if (additionalStreams is not null)
{
streams.AddRange(additionalStreams);
}
else if (subtitle is not null)
{
streams.Add(subtitle);
}
return new EncodingJobInfo(TranscodingJobType.Progressive)
{
MediaSource = new MediaSourceInfo
{
Container = "mkv",
MediaStreams = streams,
},
VideoStream = video,
AudioStream = audio,
SubtitleStream = subtitle,
SubtitleDeliveryMethod = deliveryMethod ?? SubtitleDeliveryMethod.Drop,
BaseRequest = new VideoRequestDto(),
IsVideoRequest = true,
IsInputVideo = true,
};
}
private static EncodingHelper CreateHelper()
{
var appPaths = Mock.Of<IApplicationPaths>();
var mediaEncoder = new Mock<IMediaEncoder>();
var subtitleEncoder = new Mock<ISubtitleEncoder>();
var config = new Mock<IConfiguration>();
var configurationManager = new Mock<IConfigurationManager>();
var pathManager = new Mock<IPathManager>();
return new EncodingHelper(
appPaths,
mediaEncoder.Object,
subtitleEncoder.Object,
config.Object,
configurationManager.Object,
pathManager.Object);
tempDir.Delete(true);
}
}
private static EncodingJobInfo BuildState(
MediaStream? subtitle,
SubtitleDeliveryMethod? deliveryMethod,
MediaStream[]? additionalStreams = null)
{
var video = new MediaStream { Index = 0, Type = MediaStreamType.Video, Codec = "h264" };
var audio = new MediaStream { Index = 1, Type = MediaStreamType.Audio, Codec = "aac" };
var streams = new List<MediaStream> { video, audio };
if (additionalStreams is not null)
{
streams.AddRange(additionalStreams);
}
else if (subtitle is not null)
{
streams.Add(subtitle);
}
return new EncodingJobInfo(TranscodingJobType.Progressive)
{
MediaSource = new MediaSourceInfo
{
Container = "mkv",
MediaStreams = streams,
},
VideoStream = video,
AudioStream = audio,
SubtitleStream = subtitle,
SubtitleDeliveryMethod = deliveryMethod ?? SubtitleDeliveryMethod.Drop,
BaseRequest = new VideoRequestDto(),
IsVideoRequest = true,
IsInputVideo = true,
};
}
private static EncodingHelper CreateHelper()
{
var appPaths = Mock.Of<IApplicationPaths>();
var mediaEncoder = new Mock<IMediaEncoder>();
var subtitleEncoder = new Mock<ISubtitleEncoder>();
var config = new Mock<IConfiguration>();
var configurationManager = new Mock<IConfigurationManager>();
var pathManager = new Mock<IPathManager>();
return new EncodingHelper(
appPaths,
mediaEncoder.Object,
subtitleEncoder.Object,
config.Object,
configurationManager.Object,
pathManager.Object);
}
}