diff options
Diffstat (limited to 'tests')
25 files changed, 741 insertions, 180 deletions
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 38fb37f17..6f3b83455 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -15,13 +15,13 @@ <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.2" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Moq" Version="4.17.2" /> </ItemGroup> <!-- Code Analyzers --> diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 7b20823ba..1ad0f4e00 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -12,7 +12,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index 374a17e2f..9e6f7c0c1 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -12,8 +12,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj index d178837b2..4918e2e82 100644 --- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj +++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj @@ -7,8 +7,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj index 725947577..55125eb11 100644 --- a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj +++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj index 7ab34775a..c53dab6d8 100644 --- a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj index 639c84240..268631e58 100644 --- a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj @@ -8,7 +8,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index e7534e308..1a7c21084 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -22,8 +22,8 @@ <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> </ItemGroup> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index 0fc8724b6..53e1550ed 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -31,6 +31,16 @@ namespace Jellyfin.MediaEncoding.Tests.Probing public void GetFrameRate_Success(string value, float? expected) => Assert.Equal(expected, ProbeResultNormalizer.GetFrameRate(value)); + [Theory] + [InlineData(0.5f, "0/1", false)] + [InlineData(24.5f, "8/196", false)] + [InlineData(63.5f, "1/127", true)] + [InlineData(null, "1/60", false)] + [InlineData(30f, "2/120", true)] + [InlineData(59.999996f, "1563/187560", true)] + public void IsCodecTimeBaseDoubleTheFrameRate_Success(float? frameRate, string codecTimeBase, bool expected) + => Assert.Equal(expected, ProbeResultNormalizer.IsCodecTimeBaseDoubleTheFrameRate(frameRate, codecTimeBase)); + [Fact] public void GetMediaInfo_MetaData_Success() { diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj index 22db5bea2..9da80c312 100644 --- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj +++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> diff --git a/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs b/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs new file mode 100644 index 000000000..b396b5440 --- /dev/null +++ b/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs @@ -0,0 +1,111 @@ +using System.Text.RegularExpressions; +using Emby.Naming.Common; +using Emby.Naming.ExternalFiles; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Globalization; +using Moq; +using Xunit; + +namespace Jellyfin.Naming.Tests.ExternalFiles; + +public class ExternalPathParserTests +{ + private readonly ExternalPathParser _audioPathParser; + private readonly ExternalPathParser _subtitlePathParser; + + public ExternalPathParserTests() + { + var englishCultureDto = new CultureDto("English", "English", "en", new[] { "eng" }); + var frenchCultureDto = new CultureDto("French", "French", "fr", new[] { "fre", "fra" }); + + var localizationManager = new Mock<ILocalizationManager>(MockBehavior.Loose); + localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"en.*", RegexOptions.IgnoreCase))) + .Returns(englishCultureDto); + localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"fr.*", RegexOptions.IgnoreCase))) + .Returns(frenchCultureDto); + + _audioPathParser = new ExternalPathParser(new NamingOptions(), localizationManager.Object, DlnaProfileType.Audio); + _subtitlePathParser = new ExternalPathParser(new NamingOptions(), localizationManager.Object, DlnaProfileType.Subtitle); + } + + [Theory] + [InlineData("")] + [InlineData("MyVideo.ass")] + [InlineData("MyVideo.mks")] + [InlineData("MyVideo.sami")] + [InlineData("MyVideo.srt")] + [InlineData("MyVideo.m4v")] + public void ParseFile_AudioExtensionsNotMatched_ReturnsNull(string path) + { + Assert.Null(_audioPathParser.ParseFile(path, string.Empty)); + } + + [Theory] + [InlineData("MyVideo.aa")] + [InlineData("MyVideo.aac")] + [InlineData("MyVideo.flac")] + [InlineData("MyVideo.m4a")] + [InlineData("MyVideo.mka")] + [InlineData("MyVideo.mp3")] + public void ParseFile_AudioExtensionsMatched_ReturnsPath(string path) + { + var actual = _audioPathParser.ParseFile(path, string.Empty); + Assert.NotNull(actual); + Assert.Equal(path, actual!.Path); + } + + [Theory] + [InlineData("")] + [InlineData("MyVideo.aa")] + [InlineData("MyVideo.aac")] + [InlineData("MyVideo.flac")] + [InlineData("MyVideo.mka")] + [InlineData("MyVideo.m4v")] + public void ParseFile_SubtitleExtensionsNotMatched_ReturnsNull(string path) + { + Assert.Null(_subtitlePathParser.ParseFile(path, string.Empty)); + } + + [Theory] + [InlineData("MyVideo.ass")] + [InlineData("MyVideo.mks")] + [InlineData("MyVideo.sami")] + [InlineData("MyVideo.srt")] + [InlineData("MyVideo.vtt")] + public void ParseFile_SubtitleExtensionsMatched_ReturnsPath(string path) + { + var actual = _subtitlePathParser.ParseFile(path, string.Empty); + Assert.NotNull(actual); + Assert.Equal(path, actual!.Path); + } + + [Theory] + [InlineData("", null, null)] + [InlineData(".default", null, null, true, false)] + [InlineData(".forced", null, null, false, true)] + [InlineData(".foreign", null, null, false, true)] + [InlineData(".default.forced", null, null, true, true)] + [InlineData(".forced.default", null, null, true, true)] + [InlineData(".DEFAULT.FORCED", null, null, true, true)] + [InlineData(".en", null, "eng")] + [InlineData(".EN", null, "eng")] + [InlineData(".fr.en", "fr", "eng")] + [InlineData(".en.fr", "en", "fre")] + [InlineData(".title.en.fr", "title.en", "fre")] + [InlineData(".Title Goes Here", "Title Goes Here", null)] + [InlineData(".Title.with.Separator", "Title.with.Separator", null)] + [InlineData(".title.en.default.forced", "title", "eng", true, true)] + [InlineData(".forced.default.en.title", "title", "eng", true, true)] + public void ParseFile_ExtraTokens_ParseToValues(string tokens, string? title, string? language, bool isDefault = false, bool isForced = false) + { + var path = "My.Video" + tokens + ".srt"; + + var actual = _subtitlePathParser.ParseFile(path, tokens); + + Assert.NotNull(actual); + Assert.Equal(title, actual!.Title); + Assert.Equal(language, actual.Language); + Assert.Equal(isDefault, actual.IsDefault); + Assert.Equal(isForced, actual.IsForced); + } +} diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index 59b7e1cbe..ea86906e7 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -12,7 +12,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> diff --git a/tests/Jellyfin.Naming.Tests/Subtitles/SubtitleParserTests.cs b/tests/Jellyfin.Naming.Tests/Subtitles/SubtitleParserTests.cs deleted file mode 100644 index 2446660f3..000000000 --- a/tests/Jellyfin.Naming.Tests/Subtitles/SubtitleParserTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Emby.Naming.Common; -using Emby.Naming.Subtitles; -using Xunit; - -namespace Jellyfin.Naming.Tests.Subtitles -{ - public class SubtitleParserTests - { - private readonly NamingOptions _namingOptions = new NamingOptions(); - - [Theory] - [InlineData("The Skin I Live In (2011).srt", null, false, false)] - [InlineData("The Skin I Live In (2011).eng.srt", "eng", false, false)] - [InlineData("The Skin I Live In (2011).eng.default.srt", "eng", true, false)] - [InlineData("The Skin I Live In (2011).eng.forced.srt", "eng", false, true)] - [InlineData("The Skin I Live In (2011).eng.foreign.srt", "eng", false, true)] - [InlineData("The Skin I Live In (2011).eng.default.foreign.srt", "eng", true, true)] - [InlineData("The Skin I Live In (2011).default.foreign.eng.srt", "eng", true, true)] - public void SubtitleParser_ValidFileName_Parses(string input, string language, bool isDefault, bool isForced) - { - var parser = new SubtitleParser(_namingOptions); - - var result = parser.ParseFile(input); - - Assert.Equal(language, result?.Language, true); - Assert.Equal(isDefault, result?.IsDefault); - Assert.Equal(isForced, result?.IsForced); - Assert.Equal(input, result?.Path); - } - - [Theory] - [InlineData("The Skin I Live In (2011).mp4")] - [InlineData("")] - public void SubtitleParser_InvalidFileName_ReturnsNull(string input) - { - var parser = new SubtitleParser(_namingOptions); - - Assert.Null(parser.ParseFile(input)); - } - } -} diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj index 3d3288df6..e15f59e5a 100644 --- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj +++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj @@ -12,12 +12,12 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> <PackageReference Include="FsCheck.Xunit" Version="2.16.4" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Moq" Version="4.17.2" /> </ItemGroup> <!-- Code Analyzers--> diff --git a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj index 9f571273f..9d6923d05 100644 --- a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj +++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj @@ -13,8 +13,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs new file mode 100644 index 000000000..aec523882 --- /dev/null +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Emby.Naming.Common; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.IO; +using MediaBrowser.Providers.MediaInfo; +using Moq; +using Xunit; + +namespace Jellyfin.Providers.Tests.MediaInfo; + +public class AudioResolverTests +{ + private readonly AudioResolver _audioResolver; + + public AudioResolverTests() + { + // prep BaseItem and Video for calls made that expect managers + Video.LiveTvManager = Mock.Of<ILiveTvManager>(); + + var applicationPaths = new Mock<IServerApplicationPaths>().Object; + var serverConfig = new Mock<IServerConfigurationManager>(); + serverConfig.Setup(c => c.ApplicationPaths) + .Returns(applicationPaths); + BaseItem.ConfigurationManager = serverConfig.Object; + + // build resolver to test with + var localizationManager = Mock.Of<ILocalizationManager>(); + + var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict); + mediaEncoder.Setup(me => me.GetMediaInfo(It.IsAny<MediaInfoRequest>(), It.IsAny<CancellationToken>())) + .Returns<MediaInfoRequest, CancellationToken>((_, _) => Task.FromResult(new MediaBrowser.Model.MediaInfo.MediaInfo + { + MediaStreams = new List<MediaStream> + { + new() + } + })); + + var fileSystem = new Mock<IFileSystem>(MockBehavior.Strict); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(MediaInfoResolverTests.VideoDirectoryRegex))) + .Returns(true); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(MediaInfoResolverTests.MetadataDirectoryRegex))) + .Returns(true); + + _audioResolver = new AudioResolver(localizationManager, mediaEncoder.Object, fileSystem.Object, new NamingOptions()); + } + + [Theory] + [InlineData("My.Video.srt", false, false)] + [InlineData("My.Video.mp3", false, true)] + [InlineData("My.Video.srt", true, false)] + [InlineData("My.Video.mp3", true, true)] + public async void GetExternalStreams_MixedFilenames_PicksAudio(string file, bool metadataDirectory, bool matches) + { + BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); + + var video = new Movie + { + Path = MediaInfoResolverTests.VideoDirectoryPath + "/My.Video.mkv" + }; + + var directoryService = MediaInfoResolverTests.GetDirectoryServiceForExternalFile(file, metadataDirectory); + var streams = await _audioResolver.GetExternalStreamsAsync(video, 0, directoryService, false, CancellationToken.None); + + if (matches) + { + Assert.Single(streams); + var actual = streams[0]; + Assert.Equal(MediaStreamType.Audio, actual.Type); + } + else + { + Assert.Empty(streams); + } + } +} diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs new file mode 100644 index 000000000..98b4a6ccf --- /dev/null +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs @@ -0,0 +1,435 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Emby.Naming.Common; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Providers.MediaInfo; +using Moq; +using Xunit; + +namespace Jellyfin.Providers.Tests.MediaInfo; + +public class MediaInfoResolverTests +{ + public const string VideoDirectoryPath = "Test Data/Video"; + public const string VideoDirectoryRegex = @"Test Data[/\\]Video"; + public const string MetadataDirectoryPath = "library/00/00000000000000000000000000000000"; + public const string MetadataDirectoryRegex = @"library.*"; + + private readonly ILocalizationManager _localizationManager; + private readonly MediaInfoResolver _subtitleResolver; + + public MediaInfoResolverTests() + { + // prep BaseItem and Video for calls made that expect managers + Video.LiveTvManager = Mock.Of<ILiveTvManager>(); + + var applicationPaths = new Mock<IServerApplicationPaths>().Object; + var serverConfig = new Mock<IServerConfigurationManager>(); + serverConfig.Setup(c => c.ApplicationPaths) + .Returns(applicationPaths); + BaseItem.ConfigurationManager = serverConfig.Object; + + // build resolver to test with + var englishCultureDto = new CultureDto("English", "English", "en", new[] { "eng" }); + + var localizationManager = new Mock<ILocalizationManager>(MockBehavior.Loose); + localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"en.*", RegexOptions.IgnoreCase))) + .Returns(englishCultureDto); + _localizationManager = localizationManager.Object; + + var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict); + mediaEncoder.Setup(me => me.GetMediaInfo(It.IsAny<MediaInfoRequest>(), It.IsAny<CancellationToken>())) + .Returns<MediaInfoRequest, CancellationToken>((_, _) => Task.FromResult(new MediaBrowser.Model.MediaInfo.MediaInfo + { + MediaStreams = new List<MediaStream> + { + new() + } + })); + + var fileSystem = new Mock<IFileSystem>(MockBehavior.Strict); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsAny<string>())) + .Returns(false); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(VideoDirectoryRegex))) + .Returns(true); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(MetadataDirectoryRegex))) + .Returns(true); + + _subtitleResolver = new SubtitleResolver(_localizationManager, mediaEncoder.Object, fileSystem.Object, new NamingOptions()); + } + + [Fact] + public void GetExternalFiles_BadProtocol_ReturnsNoSubtitles() + { + // need a media source manager capable of returning something other than file protocol + var mediaSourceManager = new Mock<IMediaSourceManager>(); + mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex(@"http.*"))) + .Returns(MediaProtocol.Http); + BaseItem.MediaSourceManager = mediaSourceManager.Object; + + var video = new Movie + { + Path = "https://url.com/My.Video.mkv" + }; + + Assert.Empty(_subtitleResolver.GetExternalFiles(video, Mock.Of<IDirectoryService>(), false)); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GetExternalFiles_MissingDirectory_DirectoryNotQueried(bool metadataDirectory) + { + BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); + + string containingFolderPath, metadataPath; + + if (metadataDirectory) + { + containingFolderPath = VideoDirectoryPath; + metadataPath = "invalid"; + } + else + { + containingFolderPath = "invalid"; + metadataPath = MetadataDirectoryPath; + } + + var video = new Mock<Movie>(); + video.Setup(m => m.Path) + .Returns(VideoDirectoryPath + "/My.Video.mkv"); + video.Setup(m => m.ContainingFolderPath) + .Returns(containingFolderPath); + video.Setup(m => m.GetInternalMetadataPath()) + .Returns(metadataPath); + + string pathNotFoundRegex = metadataDirectory ? MetadataDirectoryRegex : VideoDirectoryRegex; + + var directoryService = new Mock<IDirectoryService>(MockBehavior.Strict); + // any path other than test target exists and provides an empty listing + directoryService.Setup(ds => ds.GetFilePaths(It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(Array.Empty<string>()); + + _subtitleResolver.GetExternalFiles(video.Object, directoryService.Object, false); + + directoryService.Verify( + ds => ds.GetFilePaths(It.IsRegex(pathNotFoundRegex), It.IsAny<bool>(), It.IsAny<bool>()), + Times.Never); + } + + [Theory] + [InlineData("My.Video.mkv", "My.Video.srt", null)] + [InlineData("My.Video.mkv", "My.Video.en.srt", "eng")] + [InlineData("My.Video.mkv", "My.Video.en.srt", "eng", true)] + [InlineData("Example Movie (2021).mp4", "Example Movie (2021).English.Srt", "eng")] + [InlineData("[LTDB] Who Framed Roger Rabbit (1998) - [Bluray-1080p].mkv", "[LTDB] Who Framed Roger Rabbit (1998) - [Bluray-1080p].en.srt", "eng")] + public void GetExternalFiles_NameMatching_MatchesAndParsesToken(string movie, string file, string? language, bool metadataDirectory = false) + { + BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); + + var video = new Movie + { + Path = VideoDirectoryPath + "/" + movie + }; + + var directoryService = GetDirectoryServiceForExternalFile(file, metadataDirectory); + var streams = _subtitleResolver.GetExternalFiles(video, directoryService, false).ToList(); + + Assert.Single(streams); + var actual = streams[0]; + Assert.Equal(language, actual.Language); + Assert.Null(actual.Title); + } + + [Theory] + [InlineData("cover.jpg")] + [InlineData("My.Video.mp3")] + [InlineData("My.Video.png")] + [InlineData("My.Video.txt")] + [InlineData("My.Video Sequel.srt")] + [InlineData("Some.Other.Video.srt")] + public void GetExternalFiles_NameMatching_RejectsNonMatches(string file) + { + BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); + + var video = new Movie + { + Path = VideoDirectoryPath + "/My.Video.mkv" + }; + + var directoryService = GetDirectoryServiceForExternalFile(file); + var streams = _subtitleResolver.GetExternalFiles(video, directoryService, false).ToList(); + + Assert.Empty(streams); + } + + [Theory] + [InlineData("https://url.com/My.Video.mkv")] + [InlineData(VideoDirectoryPath)] // valid but no files found for this test + public async void GetExternalStreams_BadPaths_ReturnsNoSubtitles(string path) + { + // need a media source manager capable of returning something other than file protocol + var mediaSourceManager = new Mock<IMediaSourceManager>(); + mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex(@"http.*"))) + .Returns(MediaProtocol.Http); + BaseItem.MediaSourceManager = mediaSourceManager.Object; + + var video = new Movie + { + Path = path + }; + + var directoryService = new Mock<IDirectoryService>(MockBehavior.Strict); + directoryService.Setup(ds => ds.GetFilePaths(It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(Array.Empty<string>()); + + var mediaEncoder = Mock.Of<IMediaEncoder>(MockBehavior.Strict); + var fileSystem = Mock.Of<IFileSystem>(); + + var subtitleResolver = new SubtitleResolver(_localizationManager, mediaEncoder, fileSystem, new NamingOptions()); + + var streams = await subtitleResolver.GetExternalStreamsAsync(video, 0, directoryService.Object, false, CancellationToken.None); + + Assert.Empty(streams); + } + + private static TheoryData<string, MediaStream[], MediaStream[]> GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly_Data() + { + var data = new TheoryData<string, MediaStream[], MediaStream[]>(); + + // filename and stream have no metadata set + string file = "My.Video.srt"; + data.Add( + file, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, null, null, 0) + }, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, null, null, 0) + }); + + // filename has metadata + file = "My.Video.Title1.default.forced.en.srt"; + data.Add( + file, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, null, null, 0) + }, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, "eng", "Title1", 0, true, true) + }); + + // single stream with metadata + file = "My.Video.mks"; + data.Add( + file, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, "eng", "Title", 0, true, true) + }, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, "eng", "Title", 0, true, true) + }); + + // stream wins for title/language, filename wins for flags when conflicting + file = "My.Video.Title2.default.forced.en.srt"; + data.Add( + file, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, "fra", "Metadata", 0) + }, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, "fra", "Metadata", 0, true, true) + }); + + // multiple stream with metadata - filename flags ignored but other data filled in when missing from stream + file = "My.Video.Title3.default.forced.en.srt"; + data.Add( + file, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, null, null, 0, true, true), + CreateMediaStream(VideoDirectoryPath + "/" + file, "fra", "Metadata", 1) + }, + new[] + { + CreateMediaStream(VideoDirectoryPath + "/" + file, "eng", "Title3", 0, true, true), + CreateMediaStream(VideoDirectoryPath + "/" + file, "fra", "Metadata", 1) + }); + + return data; + } + + [Theory] + [MemberData(nameof(GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly_Data))] + public async void GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly(string file, MediaStream[] inputStreams, MediaStream[] expectedStreams) + { + BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); + + var video = new Movie + { + Path = VideoDirectoryPath + "/My.Video.mkv" + }; + + var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict); + mediaEncoder.Setup(me => me.GetMediaInfo(It.IsAny<MediaInfoRequest>(), It.IsAny<CancellationToken>())) + .Returns<MediaInfoRequest, CancellationToken>((_, _) => Task.FromResult(new MediaBrowser.Model.MediaInfo.MediaInfo + { + MediaStreams = inputStreams.ToList() + })); + + var fileSystem = new Mock<IFileSystem>(MockBehavior.Strict); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(VideoDirectoryRegex))) + .Returns(true); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(MetadataDirectoryRegex))) + .Returns(true); + + var subtitleResolver = new SubtitleResolver(_localizationManager, mediaEncoder.Object, fileSystem.Object, new NamingOptions()); + + var directoryService = GetDirectoryServiceForExternalFile(file); + var streams = await subtitleResolver.GetExternalStreamsAsync(video, 0, directoryService, false, CancellationToken.None); + + Assert.Equal(expectedStreams.Length, streams.Count); + for (var i = 0; i < expectedStreams.Length; i++) + { + var expected = expectedStreams[i]; + var actual = streams[i]; + + Assert.True(actual.IsExternal); + Assert.Equal(expected.Index, actual.Index); + Assert.Equal(expected.Type, actual.Type); + Assert.Equal(expected.Path, actual.Path); + Assert.Equal(expected.IsDefault, actual.IsDefault); + Assert.Equal(expected.IsForced, actual.IsForced); + Assert.Equal(expected.Language, actual.Language); + Assert.Equal(expected.Title, actual.Title); + } + } + + [Theory] + [InlineData(1, 1)] + [InlineData(1, 2)] + [InlineData(2, 1)] + [InlineData(2, 2)] + public async void GetExternalStreams_StreamIndex_HandlesFilesAndContainers(int fileCount, int streamCount) + { + BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); + + var video = new Movie + { + Path = VideoDirectoryPath + "/My.Video.mkv" + }; + + var files = new string[fileCount]; + for (int i = 0; i < fileCount; i++) + { + files[i] = $"{VideoDirectoryPath}/My.Video.{i}.srt"; + } + + var directoryService = new Mock<IDirectoryService>(MockBehavior.Strict); + directoryService.Setup(ds => ds.GetFilePaths(It.IsRegex(VideoDirectoryRegex), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(files); + directoryService.Setup(ds => ds.GetFilePaths(It.IsRegex(MetadataDirectoryRegex), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(Array.Empty<string>()); + + List<MediaStream> GenerateMediaStreams() + { + var mediaStreams = new List<MediaStream>(); + for (int i = 0; i < streamCount; i++) + { + mediaStreams.Add(new()); + } + + return mediaStreams; + } + + var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict); + mediaEncoder.Setup(me => me.GetMediaInfo(It.IsAny<MediaInfoRequest>(), It.IsAny<CancellationToken>())) + .Returns<MediaInfoRequest, CancellationToken>((_, _) => Task.FromResult(new MediaBrowser.Model.MediaInfo.MediaInfo + { + MediaStreams = GenerateMediaStreams() + })); + + var fileSystem = new Mock<IFileSystem>(MockBehavior.Strict); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(VideoDirectoryRegex))) + .Returns(true); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(MetadataDirectoryRegex))) + .Returns(true); + + var subtitleResolver = new SubtitleResolver(_localizationManager, mediaEncoder.Object, fileSystem.Object, new NamingOptions()); + + int startIndex = 1; + var streams = await subtitleResolver.GetExternalStreamsAsync(video, startIndex, directoryService.Object, false, CancellationToken.None); + + Assert.Equal(fileCount * streamCount, streams.Count); + for (var i = 0; i < streams.Count; i++) + { + Assert.Equal(startIndex + i, streams[i].Index); + // intentional integer division to ensure correct number of streams come back from each file + Assert.Matches(@$".*\.{i / streamCount}\.srt", streams[i].Path); + } + } + + private static MediaStream CreateMediaStream(string path, string? language, string? title, int index, bool isForced = false, bool isDefault = false) + { + return new MediaStream + { + Index = index, + Type = MediaStreamType.Subtitle, + Path = path, + IsDefault = isDefault, + IsForced = isForced, + Language = language, + Title = title + }; + } + + /// <summary> + /// Provides an <see cref="IDirectoryService"/> that when queried for the test video/metadata directory will return a path including the provided file name. + /// </summary> + /// <param name="file">The name of the file to locate.</param> + /// <param name="useMetadataDirectory"><c>true</c> if the file belongs in the metadata directory.</param> + /// <returns>A mocked <see cref="IDirectoryService"/>.</returns> + public static IDirectoryService GetDirectoryServiceForExternalFile(string file, bool useMetadataDirectory = false) + { + var directoryService = new Mock<IDirectoryService>(MockBehavior.Strict); + if (useMetadataDirectory) + { + directoryService.Setup(ds => ds.GetFilePaths(It.IsRegex(VideoDirectoryRegex), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(Array.Empty<string>()); + directoryService.Setup(ds => ds.GetFilePaths(It.IsRegex(MetadataDirectoryRegex), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(new[] { MetadataDirectoryPath + "/" + file }); + } + else + { + directoryService.Setup(ds => ds.GetFilePaths(It.IsRegex(VideoDirectoryRegex), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(new[] { VideoDirectoryPath + "/" + file }); + directoryService.Setup(ds => ds.GetFilePaths(It.IsRegex(MetadataDirectoryRegex), It.IsAny<bool>(), It.IsAny<bool>())) + .Returns(Array.Empty<string>()); + } + + return directoryService.Object; + } +} diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs index 040ea5d1d..0e6457ce3 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs @@ -1,129 +1,86 @@ -#pragma warning disable CA1002 // Do not expose generic lists - using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Emby.Naming.Common; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.IO; using MediaBrowser.Providers.MediaInfo; using Moq; using Xunit; -namespace Jellyfin.Providers.Tests.MediaInfo +namespace Jellyfin.Providers.Tests.MediaInfo; + +public class SubtitleResolverTests { - public class SubtitleResolverTests - { - public static TheoryData<List<MediaStream>, string, int, string[], MediaStream[]> AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles_TestData() - { - var data = new TheoryData<List<MediaStream>, string, int, string[], MediaStream[]>(); + private readonly SubtitleResolver _subtitleResolver; - var index = 0; - data.Add( - new List<MediaStream>(), - "/video/My.Video.mkv", - index, - new[] - { - "/video/My.Video.mp3", - "/video/My.Video.png", - "/video/My.Video.srt", - "/video/My.Video.txt", - "/video/My.Video.vtt", - "/video/My.Video.ass", - "/video/My.Video.sub", - "/video/My.Video.ssa", - "/video/My.Video.smi", - "/video/My.Video.sami", - "/video/My.Video.en.srt", - "/video/My.Video.default.en.srt", - "/video/My.Video.default.forced.en.srt", - "/video/My.Video.en.default.forced.srt", - "/video/My.Video.With.Additional.Garbage.en.srt", - "/video/My.Video With Additional Garbage.srt" - }, - new[] - { - CreateMediaStream("/video/My.Video.srt", "srt", null, index++), - CreateMediaStream("/video/My.Video.vtt", "vtt", null, index++), - CreateMediaStream("/video/My.Video.ass", "ass", null, index++), - CreateMediaStream("/video/My.Video.sub", "sub", null, index++), - CreateMediaStream("/video/My.Video.ssa", "ssa", null, index++), - CreateMediaStream("/video/My.Video.smi", "smi", null, index++), - CreateMediaStream("/video/My.Video.sami", "sami", null, index++), - CreateMediaStream("/video/My.Video.en.srt", "srt", "en", index++), - CreateMediaStream("/video/My.Video.default.en.srt", "srt", "en", index++, isDefault: true), - CreateMediaStream("/video/My.Video.default.forced.en.srt", "srt", "en", index++, isForced: true, isDefault: true), - CreateMediaStream("/video/My.Video.en.default.forced.srt", "srt", "en", index++, isForced: true, isDefault: true), - CreateMediaStream("/video/My.Video.With.Additional.Garbage.en.srt", "srt", "en", index), - }); + public SubtitleResolverTests() + { + // prep BaseItem and Video for calls made that expect managers + Video.LiveTvManager = Mock.Of<ILiveTvManager>(); - return data; - } + var applicationPaths = new Mock<IServerApplicationPaths>().Object; + var serverConfig = new Mock<IServerConfigurationManager>(); + serverConfig.Setup(c => c.ApplicationPaths) + .Returns(applicationPaths); + BaseItem.ConfigurationManager = serverConfig.Object; - [Theory] - [MemberData(nameof(AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles_TestData))] - public void AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles(List<MediaStream> streams, string videoPath, int startIndex, string[] files, MediaStream[] expectedResult) - { - new SubtitleResolver(Mock.Of<ILocalizationManager>()).AddExternalSubtitleStreams(streams, videoPath, startIndex, files); + // build resolver to test with + var localizationManager = Mock.Of<ILocalizationManager>(); - Assert.Equal(expectedResult.Length, streams.Count); - for (var i = 0; i < expectedResult.Length; i++) + var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict); + mediaEncoder.Setup(me => me.GetMediaInfo(It.IsAny<MediaInfoRequest>(), It.IsAny<CancellationToken>())) + .Returns<MediaInfoRequest, CancellationToken>((_, _) => Task.FromResult(new MediaBrowser.Model.MediaInfo.MediaInfo { - var expected = expectedResult[i]; - var actual = streams[i]; + MediaStreams = new List<MediaStream> + { + new() + } + })); - Assert.Equal(expected.Index, actual.Index); - Assert.Equal(expected.Type, actual.Type); - Assert.Equal(expected.IsExternal, actual.IsExternal); - Assert.Equal(expected.Path, actual.Path); - Assert.Equal(expected.IsDefault, actual.IsDefault); - Assert.Equal(expected.IsForced, actual.IsForced); - Assert.Equal(expected.Language, actual.Language); - } - } + var fileSystem = new Mock<IFileSystem>(MockBehavior.Strict); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(MediaInfoResolverTests.VideoDirectoryRegex))) + .Returns(true); + fileSystem.Setup(fs => fs.DirectoryExists(It.IsRegex(MediaInfoResolverTests.MetadataDirectoryRegex))) + .Returns(true); + + _subtitleResolver = new SubtitleResolver(localizationManager, mediaEncoder.Object, fileSystem.Object, new NamingOptions()); + } + + [Theory] + [InlineData("My.Video.srt", false, true)] + [InlineData("My.Video.mp3", false, false)] + [InlineData("My.Video.srt", true, true)] + [InlineData("My.Video.mp3", true, false)] + public async void GetExternalStreams_MixedFilenames_PicksSubtitles(string file, bool metadataDirectory, bool matches) + { + BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); - [Theory] - [InlineData("/video/My Video.mkv", "/video/My Video.srt", "srt", null, false, false)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.srt", "srt", null, false, false)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.foreign.srt", "srt", null, true, false)] - [InlineData("/video/My Video.mkv", "/video/My Video.forced.srt", "srt", null, true, false)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.default.srt", "srt", null, false, true)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.forced.default.srt", "srt", null, true, true)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.en.srt", "srt", "en", false, false)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.default.en.srt", "srt", "en", false, true)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.default.forced.en.srt", "srt", "en", true, true)] - [InlineData("/video/My.Video.mkv", "/video/My.Video.en.default.forced.srt", "srt", "en", true, true)] - public void AddExternalSubtitleStreams_GivenSingleFile_ReturnsExpectedSubtitle(string videoPath, string file, string codec, string? language, bool isForced, bool isDefault) + var video = new Movie { - var streams = new List<MediaStream>(); - var expected = CreateMediaStream(file, codec, language, 0, isForced, isDefault); + Path = MediaInfoResolverTests.VideoDirectoryPath + "/My.Video.mkv" + }; - new SubtitleResolver(Mock.Of<ILocalizationManager>()).AddExternalSubtitleStreams(streams, videoPath, 0, new[] { file }); + var directoryService = MediaInfoResolverTests.GetDirectoryServiceForExternalFile(file, metadataDirectory); + var streams = await _subtitleResolver.GetExternalStreamsAsync(video, 0, directoryService, false, CancellationToken.None); + if (matches) + { Assert.Single(streams); - var actual = streams[0]; - - Assert.Equal(expected.Index, actual.Index); - Assert.Equal(expected.Type, actual.Type); - Assert.Equal(expected.IsExternal, actual.IsExternal); - Assert.Equal(expected.Path, actual.Path); - Assert.Equal(expected.IsDefault, actual.IsDefault); - Assert.Equal(expected.IsForced, actual.IsForced); - Assert.Equal(expected.Language, actual.Language); + Assert.Equal(MediaStreamType.Subtitle, actual.Type); } - - private static MediaStream CreateMediaStream(string path, string codec, string? language, int index, bool isForced = false, bool isDefault = false) + else { - return new() - { - Index = index, - Codec = codec, - Type = MediaStreamType.Subtitle, - IsExternal = true, - Path = path, - IsDefault = isDefault, - IsForced = isForced, - Language = language - }; + Assert.Empty(streams); } } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 3146f277f..55920c928 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -21,8 +21,8 @@ <ItemGroup> <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="Xunit.SkippableFact" Version="1.4.13" /> diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs index 5c7c983c2..c21871297 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs @@ -1,4 +1,4 @@ -using Emby.Naming.Common; +using Emby.Naming.Common; using Emby.Server.Implementations.Library.Resolvers.TV; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; +using Microsoft.Extensions.Logging; using Moq; using Xunit; @@ -21,7 +22,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library { var parent = new Folder { Name = "extras" }; - var episodeResolver = new EpisodeResolver(_namingOptions); + var episodeResolver = new EpisodeResolver(Mock.Of<ILogger<EpisodeResolver>>(), _namingOptions); var itemResolveArgs = new ItemResolveArgs( Mock.Of<IServerApplicationPaths>(), Mock.Of<IDirectoryService>()) @@ -44,7 +45,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library // Have to create a mock because of moq proxies not being castable to a concrete implementation // https://github.com/jellyfin/jellyfin/blob/ab0cff8556403e123642dc9717ba778329554634/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs#L48 - var episodeResolver = new EpisodeResolverMock(_namingOptions); + var episodeResolver = new EpisodeResolverMock(Mock.Of<ILogger<EpisodeResolver>>(), _namingOptions); var itemResolveArgs = new ItemResolveArgs( Mock.Of<IServerApplicationPaths>(), Mock.Of<IDirectoryService>()) @@ -61,7 +62,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library private class EpisodeResolverMock : EpisodeResolver { - public EpisodeResolverMock(NamingOptions namingOptions) : base(namingOptions) + public EpisodeResolverMock(ILogger<EpisodeResolver> logger, NamingOptions namingOptions) : base(logger, namingOptions) { } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs index f5c8cc970..599599071 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs index f2efcddba..efc3ac0c2 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/MovieResolverTests.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; +using Microsoft.Extensions.Logging; using Moq; using Xunit; @@ -17,7 +18,7 @@ public class MovieResolverTests [Fact] public void Resolve_GivenLocalAlternateVersion_ResolvesToVideo() { - var movieResolver = new MovieResolver(Mock.Of<IImageProcessor>(), _namingOptions); + var movieResolver = new MovieResolver(Mock.Of<IImageProcessor>(), Mock.Of<ILogger<MovieResolver>>(), _namingOptions); var itemResolveArgs = new ItemResolveArgs( Mock.Of<IServerApplicationPaths>(), Mock.Of<IDirectoryService>()) diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index 08eea4b15..55101ce10d 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -9,14 +9,14 @@ <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.2" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="Xunit.Priority" Version="1.1.6" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Moq" Version="4.17.2" /> </ItemGroup> <ItemGroup> diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index 2ab32d6f6..f5d60d2d3 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -10,13 +10,13 @@ <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.2" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Moq" Version="4.17.2" /> </ItemGroup> <!-- Code Analyzers --> diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj index 1bb2115cc..7689d1da3 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj +++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj @@ -13,8 +13,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> - <PackageReference Include="Moq" Version="4.16.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> |
