From 15053516f888fe1bb085061f39cd7fb2e6e992f0 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Mon, 21 Feb 2022 21:59:41 +0100 Subject: [PATCH 1/3] Rewrite tests for coverage and less duplication Address minor warnings Revert making GetInternalMetadataPath mockable --- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- .../MediaInfo/AudioResolver.cs | 2 +- .../MediaInfo/MediaInfoResolver.cs | 2 +- .../MediaInfo/SubtitleResolver.cs | 2 +- .../ExternalFiles/ExternalPathParserTests.cs | 98 +++++ .../Jellyfin.Naming.Tests.csproj | 1 + .../MediaInfo/AudioResolverTests.cs | 192 +++------ .../MediaInfo/MediaInfoResolverTests.cs | 375 ++++++++++++++++++ .../MediaInfo/SubtitleResolverTests.cs | 215 +++------- 9 files changed, 572 insertions(+), 317 deletions(-) create mode 100644 tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs create mode 100644 tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index c527328583..0f62e8e1eb 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -887,7 +887,7 @@ namespace MediaBrowser.Controller.Entities return Name; } - public virtual string GetInternalMetadataPath() + public string GetInternalMetadataPath() { var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath; diff --git a/MediaBrowser.Providers/MediaInfo/AudioResolver.cs b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs index 9329978a84..ff90eeffbc 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Providers.MediaInfo public class AudioResolver : MediaInfoResolver { /// - /// Initializes a new instance of the class for external audio file processing. + /// Initializes a new instance of the class for external audio file processing. /// /// The localization manager. /// The media encoder. diff --git a/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs b/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs index 83d5e15e29..e88b88cead 100644 --- a/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs @@ -102,7 +102,7 @@ namespace MediaBrowser.Providers.MediaInfo if (mediaInfo.MediaStreams.Count == 1) { - MediaStream mediaStream = mediaInfo.MediaStreams.First(); + MediaStream mediaStream = mediaInfo.MediaStreams[0]; mediaStream.Index = startIndex++; mediaStream.IsDefault = pathInfo.IsDefault || mediaStream.IsDefault; mediaStream.IsForced = pathInfo.IsForced || mediaStream.IsForced; diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index 78b3836e78..289036fdab 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Providers.MediaInfo public class SubtitleResolver : MediaInfoResolver { /// - /// Initializes a new instance of the class for external subtitle file processing. + /// Initializes a new instance of the class for external subtitle file processing. /// /// The localization manager. /// The media encoder. diff --git a/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs b/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs new file mode 100644 index 0000000000..7bc97aa081 --- /dev/null +++ b/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs @@ -0,0 +1,98 @@ +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(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("", false)] + [InlineData("MyVideo.srt", false)] + [InlineData("MyVideo.mka", true)] + public void ParseFile_AudioFile_ReturnsPathWhenAudio(string path, bool valid) + { + var actual = _audioPathParser.ParseFile(path, string.Empty); + + if (valid) + { + Assert.NotNull(actual); + Assert.Equal(path, actual!.Path); + } + else + { + Assert.Null(actual); + } + } + + [Theory] + [InlineData("", false)] + [InlineData("MyVideo.srt", true)] + [InlineData("MyVideo.mka", false)] + public void ParseFile_SubtitleFile_ReturnsPathWhenSubtitle(string path, bool valid) + { + var actual = _subtitlePathParser.ParseFile(path, string.Empty); + + if (valid) + { + Assert.NotNull(actual); + Assert.Equal(path, actual!.Path); + } + else + { + Assert.Null(actual); + } + } + + [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 c4f01b2712..cc3d4faa03 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs index 69f10d6700..381d6c72d5 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs @@ -1,177 +1,79 @@ -using System; using System.Collections.Generic; -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.Providers.MediaInfo; using Moq; using Xunit; -namespace Jellyfin.Providers.Tests.MediaInfo +namespace Jellyfin.Providers.Tests.MediaInfo; + +public class AudioResolverTests { - public class AudioResolverTests + private readonly AudioResolver _audioResolver; + + public AudioResolverTests() { - private const string VideoDirectoryPath = "Test Data/Video"; - private const string MetadataDirectoryPath = "Test Data/Metadata"; - private readonly AudioResolver _audioResolver; + // prep BaseItem and Video for calls made that expect managers + Video.LiveTvManager = Mock.Of(); - public AudioResolverTests() - { - var englishCultureDto = new CultureDto("English", "English", "en", new[] { "eng" }); + var applicationPaths = new Mock().Object; + var serverConfig = new Mock(); + serverConfig.Setup(c => c.ApplicationPaths) + .Returns(applicationPaths); + BaseItem.ConfigurationManager = serverConfig.Object; - var localizationManager = new Mock(MockBehavior.Loose); - localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"en.*", RegexOptions.IgnoreCase))) - .Returns(englishCultureDto); + // build resolver to test with + var localizationManager = Mock.Of(); - var mediaEncoder = new Mock(MockBehavior.Strict); - mediaEncoder.Setup(me => me.GetMediaInfo(It.IsAny(), It.IsAny())) - .Returns((_, _) => Task.FromResult(new MediaBrowser.Model.MediaInfo.MediaInfo + var mediaEncoder = new Mock(MockBehavior.Strict); + mediaEncoder.Setup(me => me.GetMediaInfo(It.IsAny(), It.IsAny())) + .Returns((_, _) => Task.FromResult(new MediaBrowser.Model.MediaInfo.MediaInfo + { + MediaStreams = new List { - MediaStreams = new List - { - new() - } - })); + new() + } + })); - _audioResolver = new AudioResolver(localizationManager.Object, mediaEncoder.Object, new NamingOptions()); - } + _audioResolver = new AudioResolver(localizationManager, mediaEncoder.Object, new NamingOptions()); + } - [Fact] - public async void AddExternalStreamsAsync_GivenMixedFilenames_ReturnsValidSubtitles() + [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(); + + var video = new Movie { - var startIndex = 0; - var index = startIndex; - var files = new[] - { - VideoDirectoryPath + "/MyVideo.en.aac", - VideoDirectoryPath + "/MyVideo.en.forced.default.dts", - VideoDirectoryPath + "/My.Video.mp3", - VideoDirectoryPath + "/Some.Other.Video.mp3", - VideoDirectoryPath + "/My.Video.png", - VideoDirectoryPath + "/My.Video.srt", - VideoDirectoryPath + "/My.Video.txt", - VideoDirectoryPath + "/My.Video.vtt", - VideoDirectoryPath + "/My.Video.ass", - VideoDirectoryPath + "/My.Video.sub", - VideoDirectoryPath + "/My.Video.ssa", - VideoDirectoryPath + "/My.Video.smi", - VideoDirectoryPath + "/My.Video.sami", - VideoDirectoryPath + "/My.Video.en.mp3", - VideoDirectoryPath + "/My.Video.en.forced.mp3", - VideoDirectoryPath + "/My.Video.en.default.forced.aac", - VideoDirectoryPath + "/My.Video.Label.mp3", - VideoDirectoryPath + "/My.Video.With Additional Garbage.en.aac", - VideoDirectoryPath + "/My.Video.With.Additional.Garbage.en.mp3" - }; - var metadataFiles = new[] - { - MetadataDirectoryPath + "/My.Video.en.aac" - }; - var expectedResult = new[] - { - CreateMediaStream(VideoDirectoryPath + "/MyVideo.en.aac", "eng", null, index++), - CreateMediaStream(VideoDirectoryPath + "/MyVideo.en.forced.default.dts", "eng", null, index++, isDefault: true, isForced: true), - CreateMediaStream(VideoDirectoryPath + "/My.Video.mp3", null, null, index++), - CreateMediaStream(VideoDirectoryPath + "/My.Video.en.mp3", "eng", null, index++), - CreateMediaStream(VideoDirectoryPath + "/My.Video.en.forced.mp3", "eng", null, index++, isDefault: false, isForced: true), - CreateMediaStream(VideoDirectoryPath + "/My.Video.en.default.forced.aac", "eng", null, index++, isDefault: true, isForced: true), - CreateMediaStream(VideoDirectoryPath + "/My.Video.Label.mp3", null, "Label", index++), - CreateMediaStream(VideoDirectoryPath + "/My.Video.With Additional Garbage.en.aac", "eng", "With Additional Garbage", index++), - CreateMediaStream(VideoDirectoryPath + "/My.Video.With.Additional.Garbage.en.mp3", "eng", "With.Additional.Garbage", index++), - CreateMediaStream(MetadataDirectoryPath + "/My.Video.en.aac", "eng", null, index) - }; + Path = MediaInfoResolverTests.VideoDirectoryPath + "/My.Video.mkv" + }; - BaseItem.MediaSourceManager = Mock.Of(); + var directoryService = MediaInfoResolverTests.GetDirectoryServiceForExternalFile(file, metadataDirectory); + var streams = await _audioResolver.GetExternalStreamsAsync(video, 0, directoryService, false, CancellationToken.None); - var video = new Mock