diff options
Diffstat (limited to 'tests/Jellyfin.Server.Implementations.Tests')
23 files changed, 801 insertions, 220 deletions
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs index a6e1dfe8f..4c7c56311 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs @@ -32,10 +32,11 @@ namespace Jellyfin.Server.Implementations.Tests.Data _sqliteItemRepository = _fixture.Create<SqliteItemRepository>(); } - public static IEnumerable<object[]> ItemImageInfoFromValueString_Valid_TestData() + public static TheoryData<string, ItemImageInfo> ItemImageInfoFromValueString_Valid_TestData() { - yield return new object[] - { + var data = new TheoryData<string, ItemImageInfo>(); + + data.Add( "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN", new ItemImageInfo { @@ -45,41 +46,33 @@ namespace Jellyfin.Server.Implementations.Tests.Data Width = 1920, Height = 1080, BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN" - } - }; + }); - yield return new object[] - { + data.Add( "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*0*0", new ItemImageInfo { Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg", Type = ImageType.Primary, - } - }; + }); - yield return new object[] - { + data.Add( "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary", new ItemImageInfo { Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg", Type = ImageType.Primary, - } - }; + }); - yield return new object[] - { + data.Add( "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*600", new ItemImageInfo { Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg", Type = ImageType.Primary, - } - }; + }); - yield return new object[] - { + data.Add( "%MetadataPath%/library/68/68578562b96c80a7ebd530848801f645/poster.jpg*637264380567586027*Primary*600*336", new ItemImageInfo { @@ -88,8 +81,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data DateModified = new DateTime(637264380567586027, DateTimeKind.Utc), Width = 600, Height = 336 - } - }; + }); + + return data; } [Theory] @@ -117,10 +111,10 @@ namespace Jellyfin.Server.Implementations.Tests.Data Assert.Null(_sqliteItemRepository.ItemImageInfoFromValueString(value)); } - public static IEnumerable<object[]> DeserializeImages_Valid_TestData() + public static TheoryData<string, ItemImageInfo[]> DeserializeImages_Valid_TestData() { - yield return new object[] - { + var data = new TheoryData<string, ItemImageInfo[]>(); + data.Add( "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN", new ItemImageInfo[] { @@ -133,11 +127,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data Height = 1080, BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN" } - } - }; + }); - yield return new object[] - { + data.Add( "%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/poster.jpg*637261226720645297*Primary*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/logo.png*637261226720805297*Logo*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/landscape.jpg*637261226721285297*Thumb*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/backdrop.jpg*637261226721685297*Backdrop*0*0", new ItemImageInfo[] { @@ -165,24 +157,23 @@ namespace Jellyfin.Server.Implementations.Tests.Data Type = ImageType.Backdrop, DateModified = new DateTime(637261226721685297, DateTimeKind.Utc), } - } - }; + }); + + return data; } - public static IEnumerable<object[]> DeserializeImages_ValidAndInvalid_TestData() + public static TheoryData<string, ItemImageInfo[]> DeserializeImages_ValidAndInvalid_TestData() { - yield return new object[] - { + var data = new TheoryData<string, ItemImageInfo[]>(); + data.Add( string.Empty, - Array.Empty<ItemImageInfo>() - }; + Array.Empty<ItemImageInfo>()); - yield return new object[] - { + data.Add( "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN|test|1234||ss", new ItemImageInfo[] { - new () + new() { Path = "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg", Type = ImageType.Primary, @@ -191,14 +182,13 @@ namespace Jellyfin.Server.Implementations.Tests.Data Height = 1080, BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN" } - } - }; + }); - yield return new object[] - { + data.Add( "|", - Array.Empty<ItemImageInfo>() - }; + Array.Empty<ItemImageInfo>()); + + return data; } [Theory] @@ -242,30 +232,27 @@ namespace Jellyfin.Server.Implementations.Tests.Data Assert.Equal(expected, _sqliteItemRepository.SerializeImages(value)); } - public static IEnumerable<object[]> DeserializeProviderIds_Valid_TestData() + public static TheoryData<string, Dictionary<string, string>> DeserializeProviderIds_Valid_TestData() { - yield return new object[] - { + var data = new TheoryData<string, Dictionary<string, string>>(); + + data.Add( "Imdb=tt0119567", new Dictionary<string, string>() { { "Imdb", "tt0119567" }, - } - }; + }); - yield return new object[] - { + data.Add( "Imdb=tt0119567|Tmdb=330|TmdbCollection=328", new Dictionary<string, string>() { { "Imdb", "tt0119567" }, { "Tmdb", "330" }, { "TmdbCollection", "328" }, - } - }; + }); - yield return new object[] - { + data.Add( "MusicBrainzAlbum=9d363e43-f24f-4b39-bc5a-7ef305c677c7|MusicBrainzReleaseGroup=63eba062-847c-3b73-8b0f-6baf27bba6fa|AudioDbArtist=111352|AudioDbAlbum=2116560|MusicBrainzAlbumArtist=20244d07-534f-4eff-b4d4-930878889970", new Dictionary<string, string>() { @@ -274,8 +261,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data { "AudioDbArtist", "111352" }, { "AudioDbAlbum", "2116560" }, { "MusicBrainzAlbumArtist", "20244d07-534f-4eff-b4d4-930878889970" }, - } - }; + }); + + return data; } [Theory] diff --git a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs index 1ce2096ea..ef8f7cd90 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs @@ -13,7 +13,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer [Fact] public void DeserializeWebSocketMessage_SingleSegment_Success() { - var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json"); con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed); Assert.Equal(109, bytesConsumed); @@ -23,7 +23,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer public void DeserializeWebSocketMessage_MultipleSegments_Success() { const int SplitPos = 64; - var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json"); var seg1 = new BufferSegment(new Memory<byte>(bytes, 0, SplitPos)); var seg2 = seg1.Append(new Memory<byte>(bytes, SplitPos, bytes.Length - SplitPos)); @@ -34,7 +34,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer [Fact] public void DeserializeWebSocketMessage_ValidPartial_Success() { - var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ValidPartial.json"); con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed); Assert.Equal(109, bytesConsumed); @@ -43,7 +43,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer [Fact] public void DeserializeWebSocketMessage_Partial_ThrowJsonException() { - var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/Partial.json"); Assert.Throws<JsonException>(() => con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed)); } 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 5ecd84604..f9228b1a7 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -21,7 +21,7 @@ <ItemGroup> <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> <PackageReference Include="Moq" Version="4.16.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> @@ -32,7 +32,7 @@ <!-- Code Analyzers --> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> - <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" /> + <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" /> <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs index c393742eb..5c7c983c2 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs @@ -1,4 +1,4 @@ -using System; +using Emby.Naming.Common; using Emby.Server.Implementations.Library.Resolvers.TV; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; @@ -14,22 +14,21 @@ namespace Jellyfin.Server.Implementations.Tests.Library { public class EpisodeResolverTest { + private static readonly NamingOptions _namingOptions = new(); + [Fact] public void Resolve_GivenVideoInExtrasFolder_DoesNotResolveToEpisode() { - var season = new Season { Name = "Season 1" }; var parent = new Folder { Name = "extras" }; - var libraryManagerMock = new Mock<ILibraryManager>(); - libraryManagerMock.Setup(x => x.GetItemById(It.IsAny<Guid>())).Returns(season); - var episodeResolver = new EpisodeResolver(libraryManagerMock.Object); + var episodeResolver = new EpisodeResolver(_namingOptions); var itemResolveArgs = new ItemResolveArgs( Mock.Of<IServerApplicationPaths>(), Mock.Of<IDirectoryService>()) { Parent = parent, CollectionType = CollectionType.TvShows, - FileInfo = new FileSystemMetadata() + FileInfo = new FileSystemMetadata { FullName = "All My Children/Season 01/Extras/All My Children S01E01 - Behind The Scenes.mkv" } @@ -45,14 +44,14 @@ 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(Mock.Of<ILibraryManager>()); + var episodeResolver = new EpisodeResolverMock(_namingOptions); var itemResolveArgs = new ItemResolveArgs( Mock.Of<IServerApplicationPaths>(), Mock.Of<IDirectoryService>()) { Parent = series, CollectionType = CollectionType.TvShows, - FileInfo = new FileSystemMetadata() + FileInfo = new FileSystemMetadata { FullName = "Extras/Extras S01E01.mkv" } @@ -62,11 +61,11 @@ namespace Jellyfin.Server.Implementations.Tests.Library private class EpisodeResolverMock : EpisodeResolver { - public EpisodeResolverMock(ILibraryManager libraryManager) : base(libraryManager) + public EpisodeResolverMock(NamingOptions namingOptions) : base(namingOptions) { } - protected override TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName) => new (); + protected override TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName) => new(); } } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs new file mode 100644 index 000000000..de4421320 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using AutoFixture; +using AutoFixture.AutoMoq; +using Emby.Naming.Common; +using Emby.Server.Implementations.Library.Resolvers.Audio; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using Moq; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Library.LibraryManager; + +public class FindExtrasTests +{ + private readonly Emby.Server.Implementations.Library.LibraryManager _libraryManager; + private readonly Mock<IFileSystem> _fileSystemMock; + + public FindExtrasTests() + { + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fixture.Register(() => new NamingOptions()); + var configMock = fixture.Freeze<Mock<IServerConfigurationManager>>(); + configMock.Setup(c => c.ApplicationPaths.ProgramDataPath).Returns("/data"); + var itemRepository = fixture.Freeze<Mock<IItemRepository>>(); + itemRepository.Setup(i => i.RetrieveItem(It.IsAny<Guid>())).Returns<BaseItem>(null); + _fileSystemMock = fixture.Freeze<Mock<IFileSystem>>(); + _fileSystemMock.Setup(f => f.GetFileInfo(It.IsAny<string>())).Returns<string>(path => new FileSystemMetadata { FullName = path }); + _libraryManager = fixture.Build<Emby.Server.Implementations.Library.LibraryManager>().Do(s => s.AddParts( + fixture.Create<IEnumerable<IResolverIgnoreRule>>(), + new List<IItemResolver> { new AudioResolver(fixture.Create<NamingOptions>()) }, + fixture.Create<IEnumerable<IIntroProvider>>(), + fixture.Create<IEnumerable<IBaseItemComparer>>(), + fixture.Create<IEnumerable<ILibraryPostScanTask>>())) + .Create(); + + // This is pretty terrible but unavoidable + BaseItem.FileSystem ??= fixture.Create<IFileSystem>(); + BaseItem.MediaSourceManager ??= fixture.Create<IMediaSourceManager>(); + } + + [Fact] + public void FindExtras_SeparateMovieFolder_FindsCorrectExtras() + { + var owner = new Movie { Name = "Up", Path = "/movies/Up/Up.mkv" }; + var paths = new List<string> + { + "/movies/Up/Up.mkv", + "/movies/Up/Up - trailer.mkv", + "/movies/Up/Up - sample.mkv", + "/movies/Up/Up something else.mkv" + }; + + var files = paths.Select(p => new FileSystemMetadata + { + FullName = p, + IsDirectory = false + }).ToList(); + + var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList(); + + Assert.Equal(2, extras.Count); + Assert.Equal(ExtraType.Trailer, extras[0].ExtraType); + Assert.Equal(typeof(Trailer), extras[0].GetType()); + Assert.Equal(ExtraType.Sample, extras[1].ExtraType); + } + + [Fact] + public void FindExtras_SeparateMovieFolderWithMixedExtras_FindsCorrectExtras() + { + var owner = new Movie { Name = "Up", Path = "/movies/Up/Up.mkv" }; + var paths = new List<string> + { + "/movies/Up/Up.mkv", + "/movies/Up/Up - trailer.mkv", + "/movies/Up/trailers", + "/movies/Up/theme-music", + "/movies/Up/theme.mp3", + "/movies/Up/not a theme.mp3", + "/movies/Up/behind the scenes", + "/movies/Up/behind the scenes.mkv", + "/movies/Up/Up - sample.mkv", + "/movies/Up/Up something else.mkv" + }; + + _fileSystemMock.Setup(f => f.GetFiles( + "/movies/Up/trailers", + It.IsAny<string[]>(), + false, + false)) + .Returns(new List<FileSystemMetadata> + { + new() + { + FullName = "/movies/Up/trailers/some trailer.mkv", + Name = "some trailer.mkv", + IsDirectory = false + } + }).Verifiable(); + + _fileSystemMock.Setup(f => f.GetFiles( + "/movies/Up/behind the scenes", + It.IsAny<string[]>(), + false, + false)) + .Returns(new List<FileSystemMetadata> + { + new() + { + FullName = "/movies/Up/behind the scenes/the making of Up.mkv", + Name = "the making of Up.mkv", + IsDirectory = false + } + }).Verifiable(); + + _fileSystemMock.Setup(f => f.GetFiles( + "/movies/Up/theme-music", + It.IsAny<string[]>(), + false, + false)) + .Returns(new List<FileSystemMetadata> + { + new() + { + FullName = "/movies/Up/theme-music/theme2.mp3", + Name = "theme2.mp3", + IsDirectory = false + } + }).Verifiable(); + + var files = paths.Select(p => new FileSystemMetadata + { + FullName = p, + Name = Path.GetFileName(p), + IsDirectory = !Path.HasExtension(p) + }).ToList(); + + var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList(); + + _fileSystemMock.Verify(); + Assert.Equal(6, extras.Count); + Assert.Equal(ExtraType.Trailer, extras[0].ExtraType); + Assert.Equal(typeof(Trailer), extras[0].GetType()); + Assert.Equal(ExtraType.Trailer, extras[1].ExtraType); + Assert.Equal(typeof(Trailer), extras[1].GetType()); + Assert.Equal(ExtraType.BehindTheScenes, extras[2].ExtraType); + Assert.Equal(ExtraType.Sample, extras[3].ExtraType); + Assert.Equal(ExtraType.ThemeSong, extras[4].ExtraType); + Assert.Equal(typeof(Audio), extras[4].GetType()); + Assert.Equal(ExtraType.ThemeSong, extras[5].ExtraType); + Assert.Equal(typeof(Audio), extras[5].GetType()); + } + + [Fact] + public void FindExtras_SeparateMovieFolderWithMixedExtras_FindsOnlyExtrasInMovieFolder() + { + var owner = new Movie { Name = "Up", Path = "/movies/Up/Up.mkv" }; + var paths = new List<string> + { + "/movies/Up/Up.mkv", + "/movies/Up/trailer.mkv", + "/movies/Another Movie/trailer.mkv" + }; + + var files = paths.Select(p => new FileSystemMetadata + { + FullName = p, + IsDirectory = false + }).ToList(); + + var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList(); + + Assert.Single(extras); + Assert.Equal(ExtraType.Trailer, extras[0].ExtraType); + Assert.Equal(typeof(Trailer), extras[0].GetType()); + Assert.Equal("trailer", extras[0].FileNameWithoutExtension); + Assert.Equal("/movies/Up/trailer.mkv", extras[0].Path); + } + + [Fact] + public void FindExtras_SeparateMovieFolderWithParts_FindsCorrectExtras() + { + var owner = new Movie { Name = "Up", Path = "/movies/Up/Up - part1.mkv" }; + var paths = new List<string> + { + "/movies/Up/Up - part1.mkv", + "/movies/Up/Up - part2.mkv", + "/movies/Up/trailer.mkv", + "/movies/Another Movie/trailer.mkv" + }; + + var files = paths.Select(p => new FileSystemMetadata + { + FullName = p, + IsDirectory = false + }).ToList(); + + var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList(); + + Assert.Single(extras); + Assert.Equal(ExtraType.Trailer, extras[0].ExtraType); + Assert.Equal(typeof(Trailer), extras[0].GetType()); + Assert.Equal("trailer", extras[0].FileNameWithoutExtension); + Assert.Equal("/movies/Up/trailer.mkv", extras[0].Path); + } + + [Fact] + public void FindExtras_WrongExtensions_FindsNoExtras() + { + var owner = new Movie { Name = "Up", Path = "/movies/Up/Up.mkv" }; + var paths = new List<string> + { + "/movies/Up/Up.mkv", + "/movies/Up/trailer.noext", + "/movies/Up/theme.png", + "/movies/Up/trailers" + }; + + var files = paths.Select(p => new FileSystemMetadata + { + FullName = p, + Name = Path.GetFileName(p), + IsDirectory = !Path.HasExtension(p) + }).ToList(); + + _fileSystemMock.Setup(f => f.GetFiles( + "/movies/Up/trailers", + It.IsAny<string[]>(), + false, + false)) + .Returns(new List<FileSystemMetadata> + { + new() + { + FullName = "/movies/Up/trailers/trailer.jpg", + Name = "trailer.jpg", + IsDirectory = false + } + }).Verifiable(); + + var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList(); + + _fileSystemMock.Verify(); + Assert.Empty(extras); + } + + [Fact] + public void FindExtras_SeriesWithTrailers_FindsCorrectExtras() + { + var owner = new Series { Name = "Dexter", Path = "/series/Dexter" }; + var paths = new List<string> + { + "/series/Dexter/Season 1/S01E01.mkv", + "/series/Dexter/trailer.mkv", + "/series/Dexter/trailers/trailer2.mkv", + }; + + var files = paths.Select(p => new FileSystemMetadata + { + FullName = p, + IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p)) + }).ToList(); + + var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList(); + + Assert.Equal(2, extras.Count); + Assert.Equal(ExtraType.Trailer, extras[0].ExtraType); + Assert.Equal(typeof(Trailer), extras[0].GetType()); + Assert.Equal("trailer", extras[0].FileNameWithoutExtension); + Assert.Equal("/series/Dexter/trailer.mkv", extras[0].Path); + Assert.Equal("/series/Dexter/trailers/trailer2.mkv", extras[1].Path); + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/MediaSourceManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/MediaSourceManagerTests.cs new file mode 100644 index 000000000..8ed3d8b94 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/MediaSourceManagerTests.cs @@ -0,0 +1,32 @@ +using AutoFixture; +using AutoFixture.AutoMoq; +using Emby.Server.Implementations.IO; +using Emby.Server.Implementations.Library; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Library +{ + public class MediaSourceManagerTests + { + private readonly MediaSourceManager _mediaSourceManager; + + public MediaSourceManagerTests() + { + IFixture fixture = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true }); + fixture.Inject<IFileSystem>(fixture.Create<ManagedFileSystem>()); + _mediaSourceManager = fixture.Create<MediaSourceManager>(); + } + + [Theory] + [InlineData(@"C:\mydir\myfile.ext", MediaProtocol.File)] + [InlineData("/mydir/myfile.ext", MediaProtocol.File)] + [InlineData("file:///mydir/myfile.ext", MediaProtocol.File)] + [InlineData("http://example.com/stream.m3u8", MediaProtocol.Http)] + [InlineData("https://example.com/stream.m3u8", MediaProtocol.Http)] + [InlineData("rtsp://media.example.com:554/twister/audiotrack", MediaProtocol.Rtsp)] + public void GetPathProtocol_ValidArg_Correct(string path, MediaProtocol expected) + => Assert.Equal(expected, _mediaSourceManager.GetPathProtocol(path)); + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs index c5cc056f5..be2dfe0a8 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs @@ -8,9 +8,27 @@ namespace Jellyfin.Server.Implementations.Tests.Library { [Theory] [InlineData("Superman: Red Son [imdbid=tt10985510]", "imdbid", "tt10985510")] + [InlineData("Superman: Red Son [imdbid-tt10985510]", "imdbid", "tt10985510")] [InlineData("Superman: Red Son - tt10985510", "imdbid", "tt10985510")] [InlineData("Superman: Red Son", "imdbid", null)] [InlineData("Superman: Red Son", "something", null)] + [InlineData("Superman: Red Son [imdbid1=tt11111111][imdbid=tt10985510]", "imdbid", "tt10985510")] + [InlineData("Superman: Red Son [imdbid1-tt11111111][imdbid=tt10985510]", "imdbid", "tt10985510")] + [InlineData("Superman: Red Son [tmdbid=618355][imdbid=tt10985510]", "imdbid", "tt10985510")] + [InlineData("Superman: Red Son [tmdbid-618355][imdbid-tt10985510]", "imdbid", "tt10985510")] + [InlineData("Superman: Red Son [tmdbid-618355][imdbid-tt10985510]", "tmdbid", "618355")] + [InlineData("[tmdbid=618355]", "tmdbid", "618355")] + [InlineData("[tmdbid-618355]", "tmdbid", "618355")] + [InlineData("tmdbid=111111][tmdbid=618355]", "tmdbid", "618355")] + [InlineData("[tmdbid=618355]tmdbid=111111]", "tmdbid", "618355")] + [InlineData("tmdbid=618355]", "tmdbid", null)] + [InlineData("[tmdbid=618355", "tmdbid", null)] + [InlineData("tmdbid=618355", "tmdbid", null)] + [InlineData("tmdbid=", "tmdbid", null)] + [InlineData("tmdbid", "tmdbid", null)] + [InlineData("[tmdbid=][imdbid=tt10985510]", "tmdbid", null)] + [InlineData("[tmdbid-][imdbid-tt10985510]", "tmdbid", null)] + [InlineData("Superman: Red Son [tmdbid-618355][tmdbid=1234567]", "tmdbid", "618355")] public void GetAttributeValue_ValidArgs_Correct(string input, string attribute, string? expectedResult) { Assert.Equal(expectedResult, PathExtensions.GetAttributeValue(input, attribute)); diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/RecordingHelperTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/RecordingHelperTests.cs index e8b93b437..09aec82b0 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/RecordingHelperTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/RecordingHelperTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Emby.Server.Implementations.LiveTv.EmbyTV; using MediaBrowser.Controller.LiveTv; using Xunit; @@ -8,43 +7,36 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv { public static class RecordingHelperTests { - public static IEnumerable<object[]> GetRecordingName_Success_TestData() + public static TheoryData<string, TimerInfo> GetRecordingName_Success_TestData() { - yield return new object[] - { + var data = new TheoryData<string, TimerInfo>(); + + data.Add( "The Incredibles 2020_04_20_21_06_00", new TimerInfo { Name = "The Incredibles", StartDate = new DateTime(2020, 4, 20, 21, 6, 0, DateTimeKind.Local), IsMovie = true - } - }; + }); - yield return new object[] - { + data.Add( "The Incredibles (2004)", new TimerInfo { Name = "The Incredibles", IsMovie = true, ProductionYear = 2004 - } - }; - - yield return new object[] - { + }); + data.Add( "The Big Bang Theory 2020_04_20_21_06_00", new TimerInfo { Name = "The Big Bang Theory", StartDate = new DateTime(2020, 4, 20, 21, 6, 0, DateTimeKind.Local), IsProgramSeries = true, - } - }; - - yield return new object[] - { + }); + data.Add( "The Big Bang Theory S12E10", new TimerInfo { @@ -52,11 +44,8 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv IsProgramSeries = true, SeasonNumber = 12, EpisodeNumber = 10 - } - }; - - yield return new object[] - { + }); + data.Add( "The Big Bang Theory S12E10 The VCR Illumination", new TimerInfo { @@ -65,34 +54,27 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv SeasonNumber = 12, EpisodeNumber = 10, EpisodeTitle = "The VCR Illumination" - } - }; - - yield return new object[] - { + }); + data.Add( "The Big Bang Theory 2018-12-06", new TimerInfo { Name = "The Big Bang Theory", IsProgramSeries = true, - OriginalAirDate = new DateTime(2018, 12, 6) - } - }; + OriginalAirDate = new DateTime(2018, 12, 6, 0, 0, 0, DateTimeKind.Local) + }); - yield return new object[] - { + data.Add( "The Big Bang Theory 2018-12-06 - The VCR Illumination", new TimerInfo { Name = "The Big Bang Theory", IsProgramSeries = true, - OriginalAirDate = new DateTime(2018, 12, 6), + OriginalAirDate = new DateTime(2018, 12, 6, 0, 0, 0, DateTimeKind.Local), EpisodeTitle = "The VCR Illumination" - } - }; + }); - yield return new object[] - { + data.Add( "The Big Bang Theory 2018_12_06_21_06_00 - The VCR Illumination", new TimerInfo { @@ -101,8 +83,9 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv IsProgramSeries = true, OriginalAirDate = new DateTime(2018, 12, 6), EpisodeTitle = "The VCR Illumination" - } - }; + }); + + return data; } [Theory] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs new file mode 100644 index 000000000..3b3e38bd1 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; +using Jellyfin.Extensions.Json; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect +{ + public class SchedulesDirectDeserializeTests + { + private readonly JsonSerializerOptions _jsonOptions; + + public SchedulesDirectDeserializeTests() + { + _jsonOptions = JsonDefaults.Options; + } + + /// <summary> + /// /token reponse. + /// </summary> + [Fact] + public void Deserialize_Token_Response_Live_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/token_live_response.json"); + var tokenDto = JsonSerializer.Deserialize<TokenDto>(bytes, _jsonOptions); + + Assert.NotNull(tokenDto); + Assert.Equal(0, tokenDto!.Code); + Assert.Equal("OK", tokenDto.Message); + Assert.Equal("AWS-SD-web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.TokenTimestamp); + Assert.Equal("f3fca79989cafe7dead71beefedc812b", tokenDto.Token); + } + + /// <summary> + /// /token response. + /// </summary> + [Fact] + public void Deserialize_Token_Response_Offline_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/token_offline_response.json"); + var tokenDto = JsonSerializer.Deserialize<TokenDto>(bytes, _jsonOptions); + + Assert.NotNull(tokenDto); + Assert.Equal(3_000, tokenDto!.Code); + Assert.Equal("Server offline for maintenance.", tokenDto.Message); + Assert.Equal("20141201.web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.TokenTimestamp); + Assert.Equal("CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE", tokenDto.Token); + Assert.Equal("SERVICE_OFFLINE", tokenDto.Response); + } + + /// <summary> + /// /schedules request. + /// </summary> + [Fact] + public void Serialize_Schedule_Request_Success() + { + var expectedString = File.ReadAllText("Test Data/SchedulesDirect/schedules_request.json").Trim(); + + var requestObject = new RequestScheduleForChannelDto[] + { + new RequestScheduleForChannelDto + { + StationId = "20454", + Date = new[] + { + "2015-03-13", + "2015-03-17" + } + }, + new RequestScheduleForChannelDto + { + StationId = "10021", + Date = new[] + { + "2015-03-12", + "2015-03-13" + } + } + }; + + var requestString = JsonSerializer.Serialize(requestObject, _jsonOptions); + Assert.Equal(expectedString, requestString); + } + + /// <summary> + /// /schedules response. + /// </summary> + [Fact] + public void Deserialize_Schedule_Response_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/schedules_response.json"); + var days = JsonSerializer.Deserialize<IReadOnlyList<DayDto>>(bytes, _jsonOptions); + + Assert.NotNull(days); + Assert.Equal(1, days!.Count); + + var dayDto = days[0]; + Assert.Equal("20454", dayDto.StationId); + Assert.Equal(2, dayDto.Programs.Count); + + Assert.Equal("SH005371070000", dayDto.Programs[0].ProgramId); + Assert.Equal(new DateTime(2015, 03, 03, 00, 00, 00, DateTimeKind.Utc), dayDto.Programs[0].AirDateTime); + Assert.Equal(1_800, dayDto.Programs[0].Duration); + Assert.Equal("Sy8HEMBPcuiAx3FBukUhKQ", dayDto.Programs[0].Md5); + Assert.True(dayDto.Programs[0].New); + Assert.Equal(2, dayDto.Programs[0].AudioProperties.Count); + Assert.Equal("stereo", dayDto.Programs[0].AudioProperties[0]); + Assert.Equal("cc", dayDto.Programs[0].AudioProperties[1]); + Assert.Equal(1, dayDto.Programs[0].VideoProperties.Count); + Assert.Equal("hdtv", dayDto.Programs[0].VideoProperties[0]); + } + + /// <summary> + /// /programs response. + /// </summary> + [Fact] + public void Deserialize_Program_Response_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/programs_response.json"); + var programDtos = JsonSerializer.Deserialize<IReadOnlyList<ProgramDetailsDto>>(bytes, _jsonOptions); + + Assert.NotNull(programDtos); + Assert.Equal(2, programDtos!.Count); + Assert.Equal("EP000000060003", programDtos[0].ProgramId); + Assert.Equal(1, programDtos[0].Titles.Count); + Assert.Equal("'Allo 'Allo!", programDtos[0].Titles[0].Title120); + Assert.Equal("Series", programDtos[0].EventDetails?.SubType); + Assert.Equal("en", programDtos[0].Descriptions?.Description1000[0].DescriptionLanguage); + Assert.Equal("A disguised British Intelligence officer is sent to help the airmen.", programDtos[0].Descriptions?.Description1000[0].Description); + Assert.Equal(new DateTime(1985, 11, 04), programDtos[0].OriginalAirDate); + Assert.Equal(1, programDtos[0].Genres.Count); + Assert.Equal("Sitcom", programDtos[0].Genres[0]); + Assert.Equal("The Poloceman Cometh", programDtos[0].EpisodeTitle150); + Assert.Equal(2, programDtos[0].Metadata[0].Gracenote?.Season); + Assert.Equal(3, programDtos[0].Metadata[0].Gracenote?.Episode); + Assert.Equal(13, programDtos[0].Cast.Count); + Assert.Equal("383774", programDtos[0].Cast[0].PersonId); + Assert.Equal("392649", programDtos[0].Cast[0].NameId); + Assert.Equal("Gorden Kaye", programDtos[0].Cast[0].Name); + Assert.Equal("Actor", programDtos[0].Cast[0].Role); + Assert.Equal("01", programDtos[0].Cast[0].BillingOrder); + Assert.Equal(3, programDtos[0].Crew.Count); + Assert.Equal("354407", programDtos[0].Crew[0].PersonId); + Assert.Equal("363281", programDtos[0].Crew[0].NameId); + Assert.Equal("David Croft", programDtos[0].Crew[0].Name); + Assert.Equal("Director", programDtos[0].Crew[0].Role); + Assert.Equal("01", programDtos[0].Crew[0].BillingOrder); + } + + /// <summary> + /// /metadata/programs response. + /// </summary> + [Fact] + public void Deserialize_Metadata_Programs_Response_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/metadata_programs_response.json"); + var showImagesDtos = JsonSerializer.Deserialize<IReadOnlyList<ShowImagesDto>>(bytes, _jsonOptions); + + Assert.NotNull(showImagesDtos); + Assert.Equal(1, showImagesDtos!.Count); + Assert.Equal("SH00712240", showImagesDtos[0].ProgramId); + Assert.Equal(4, showImagesDtos[0].Data.Count); + Assert.Equal("135", showImagesDtos[0].Data[0].Width); + Assert.Equal("180", showImagesDtos[0].Data[0].Height); + Assert.Equal("assets/p282288_b_v2_aa.jpg", showImagesDtos[0].Data[0].Uri); + Assert.Equal("Sm", showImagesDtos[0].Data[0].Size); + Assert.Equal("3x4", showImagesDtos[0].Data[0].Aspect); + Assert.Equal("Banner-L3", showImagesDtos[0].Data[0].Category); + Assert.Equal("yes", showImagesDtos[0].Data[0].Text); + Assert.Equal("true", showImagesDtos[0].Data[0].Primary); + Assert.Equal("Series", showImagesDtos[0].Data[0].Tier); + } + + /// <summary> + /// /headends response. + /// </summary> + [Fact] + public void Deserialize_Headends_Response_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/headends_response.json"); + var headendsDtos = JsonSerializer.Deserialize<IReadOnlyList<HeadendsDto>>(bytes, _jsonOptions); + + Assert.NotNull(headendsDtos); + Assert.Equal(8, headendsDtos!.Count); + Assert.Equal("CA00053", headendsDtos[0].Headend); + Assert.Equal("Cable", headendsDtos[0].Transport); + Assert.Equal("Beverly Hills", headendsDtos[0].Location); + Assert.Equal(2, headendsDtos[0].Lineups.Count); + Assert.Equal("Time Warner Cable - Cable", headendsDtos[0].Lineups[0].Name); + Assert.Equal("USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Lineup); + Assert.Equal("/20141201/lineups/USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Uri); + } + + /// <summary> + /// /lineups response. + /// </summary> + [Fact] + public void Deserialize_Lineups_Response_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/lineups_response.json"); + var lineupsDto = JsonSerializer.Deserialize<LineupsDto>(bytes, _jsonOptions); + + Assert.NotNull(lineupsDto); + Assert.Equal(0, lineupsDto!.Code); + Assert.Equal("20141201.web.1", lineupsDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.LineupTimestamp); + Assert.Equal(5, lineupsDto.Lineups.Count); + Assert.Equal("GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Lineup); + Assert.Equal("Freeview - Carlton - LWT (Southeast)", lineupsDto.Lineups[0].Name); + Assert.Equal("DVB-T", lineupsDto.Lineups[0].Transport); + Assert.Equal("London", lineupsDto.Lineups[0].Location); + Assert.Equal("/20141201/lineups/GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Uri); + + Assert.Equal("DELETED LINEUP", lineupsDto.Lineups[4].Name); + Assert.True(lineupsDto.Lineups[4].IsDeleted); + } + + /// <summary> + /// /lineup/:id response. + /// </summary> + [Fact] + public void Deserialize_Lineup_Response_Success() + { + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/lineup_response.json"); + var channelDto = JsonSerializer.Deserialize<ChannelDto>(bytes, _jsonOptions); + + Assert.NotNull(channelDto); + Assert.Equal(2, channelDto!.Map.Count); + Assert.Equal("24326", channelDto.Map[0].StationId); + Assert.Equal("001", channelDto.Map[0].Channel); + Assert.Equal("BBC ONE South", channelDto.Map[0].ProvderCallsign); + Assert.Equal("1", channelDto.Map[0].LogicalChannelNumber); + Assert.Equal("providerCallsign", channelDto.Map[0].MatchType); + } + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs index 143020d43..3e7d6ed1d 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Implementations.Tests.Localization await localizationManager.LoadAll(); var cultures = localizationManager.GetCultures().ToList(); - Assert.Equal(189, cultures.Count); + Assert.Equal(190, cultures.Count); var germany = cultures.FirstOrDefault(x => x.TwoLetterISOLanguageName.Equals("de", StringComparison.Ordinal)); Assert.NotNull(germany); diff --git a/tests/Jellyfin.Server.Implementations.Tests/QuickConnect/QuickConnectManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/QuickConnect/QuickConnectManagerTests.cs index 043363ae3..28d832ef8 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/QuickConnect/QuickConnectManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/QuickConnect/QuickConnectManagerTests.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using AutoFixture; using AutoFixture.AutoMoq; using Emby.Server.Implementations.QuickConnect; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; @@ -51,6 +52,21 @@ namespace Jellyfin.Server.Implementations.Tests.QuickConnect public void IsEnabled_QuickConnectUnavailable_False() => Assert.False(_quickConnectManager.IsEnabled); + [Theory] + [InlineData("", "DeviceId", "Client", "1.0.0")] + [InlineData("Device", "", "Client", "1.0.0")] + [InlineData("Device", "DeviceId", "", "1.0.0")] + [InlineData("Device", "DeviceId", "Client", "")] + public void TryConnect_InvalidAuthorizationInfo_ThrowsArgumentException(string device, string deviceId, string client, string version) + => Assert.Throws<ArgumentException>(() => _quickConnectManager.TryConnect( + new AuthorizationInfo + { + Device = device, + DeviceId = deviceId, + Client = client, + Version = version + })); + [Fact] public void TryConnect_QuickConnectUnavailable_ThrowsAuthenticationException() => Assert.Throws<AuthenticationException>(() => _quickConnectManager.TryConnect(_quickConnectAuthInfo)); @@ -64,6 +80,10 @@ namespace Jellyfin.Server.Implementations.Tests.QuickConnect => Assert.ThrowsAsync<AuthenticationException>(() => _quickConnectManager.AuthorizeRequest(Guid.Empty, string.Empty)); [Fact] + public void GetAuthorizedRequest_QuickConnectUnavailable_ThrowsAuthenticationException() + => Assert.Throws<AuthenticationException>(() => _quickConnectManager.GetAuthorizedRequest(string.Empty)); + + [Fact] public void IsEnabled_QuickConnectAvailable_True() { _config.QuickConnectAvailable = true; @@ -80,6 +100,20 @@ namespace Jellyfin.Server.Implementations.Tests.QuickConnect } [Fact] + public void CheckRequestStatus_UnknownSecret_ThrowsResourceNotFoundException() + { + _config.QuickConnectAvailable = true; + Assert.Throws<ResourceNotFoundException>(() => _quickConnectManager.CheckRequestStatus("Unknown secret")); + } + + [Fact] + public void GetAuthorizedRequest_UnknownSecret_ThrowsResourceNotFoundException() + { + _config.QuickConnectAvailable = true; + Assert.Throws<ResourceNotFoundException>(() => _quickConnectManager.GetAuthorizedRequest("Unknown secret")); + } + + [Fact] public async Task AuthorizeRequest_QuickConnectAvailable_Success() { _config.QuickConnectAvailable = true; diff --git a/tests/Jellyfin.Server.Implementations.Tests/Sorting/AiredEpisodeOrderComparerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Sorting/AiredEpisodeOrderComparerTests.cs index e94c509d7..59d82678e 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Sorting/AiredEpisodeOrderComparerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Sorting/AiredEpisodeOrderComparerTests.cs @@ -1,6 +1,4 @@ using System; -using System.Collections; -using System.Collections.Generic; using Emby.Server.Implementations.Sorting; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -13,7 +11,7 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting { [Theory] [ClassData(typeof(EpisodeBadData))] - public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem x, BaseItem y) + public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem? x, BaseItem? y) { var cmp = new AiredEpisodeOrderComparer(); Assert.Throws<ArgumentNullException>(() => cmp.Compare(x, y)); @@ -29,171 +27,138 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting Assert.Equal(-expected, cmp.Compare(y, x)); } - private class EpisodeBadData : IEnumerable<object?[]> + private class EpisodeBadData : TheoryData<BaseItem?, BaseItem?> { - public IEnumerator<object?[]> GetEnumerator() + public EpisodeBadData() { - yield return new object?[] { null, new Episode() }; - yield return new object?[] { new Episode(), null }; + Add(null, new Episode()); + Add(new Episode(), null); } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } - private class EpisodeTestData : IEnumerable<object?[]> + private class EpisodeTestData : TheoryData<BaseItem, BaseItem, int> { - public IEnumerator<object?[]> GetEnumerator() + public EpisodeTestData() { - yield return new object?[] - { + Add( new Movie(), new Movie(), - 0 - }; - yield return new object?[] - { + 0); + + Add( new Movie(), new Episode(), - 1 - }; + 1); + // Good cases - yield return new object?[] - { + Add( new Episode(), new Episode(), - 0 - }; - yield return new object?[] - { + 0); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, - 0 - }; - yield return new object?[] - { + 0); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 2 }, new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, - 1 - }; - yield return new object?[] - { + 1); + + Add( new Episode { ParentIndexNumber = 2, IndexNumber = 1 }, new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, - 1 - }; + 1); + // Good Specials - yield return new object?[] - { + Add( new Episode { ParentIndexNumber = 0, IndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1 }, - 0 - }; - yield return new object?[] - { + 0); + + Add( new Episode { ParentIndexNumber = 0, IndexNumber = 2 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1 }, - 1 - }; + 1); // Specials to Episodes - yield return new object?[] - { + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1 }, - 1 - }; - yield return new object?[] - { + 1); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 2 }, - 1 - }; - yield return new object?[] - { + 1); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 2 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1 }, - 1 - }; + 1); - yield return new object?[] - { + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 2 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1 }, - 1 - }; - yield return new object?[] - { + 1); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 2 }, - 1 - }; + 1); - yield return new object?[] - { + Add( new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1 }, new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, - 1 - }; - yield return new object?[] - { + 1); + + Add( new Episode { ParentIndexNumber = 3, IndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1 }, - 1 - }; + 1); - yield return new object?[] - { + Add( new Episode { ParentIndexNumber = 3, IndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 }, - 1 - }; + 1); - yield return new object?[] - { + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1 }, - 1 - }; - yield return new object?[] - { + 1); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 2 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 }, - 1 - }; - yield return new object?[] - { + 1); + + Add( new Episode { ParentIndexNumber = 1 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 }, - 0 - }; - yield return new object?[] - { + 0); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 3 }, new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 }, - 1 - }; + 1); + // Premiere Date - yield return new object?[] - { + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) }, new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) }, - 0 - }; - yield return new object?[] - { + 0); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 11, 0, 0, 0) }, new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) }, - -1 - }; - yield return new object?[] - { + -1); + + Add( new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) }, new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 11, 0, 0, 0) }, - 1 - }; + 1); } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json new file mode 100644 index 000000000..015afeecc --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json @@ -0,0 +1 @@ +[{"headend":"CA00053","transport":"Cable","location":"Beverly Hills","lineups":[{"name":"Time Warner Cable - Cable","lineup":"USA-CA00053-DEFAULT","uri":"/20141201/lineups/USA-CA00053-DEFAULT"},{"name":"Time Warner Cable - Digital","lineup":"USA-CA00053-X","uri":"/20141201/lineups/USA-CA00053-X"}]},{"headend":"CA61222","transport":"Cable","location":"Beverly Hills","lineups":[{"name":"Mulholland Estates - Cable","lineup":"USA-CA61222-DEFAULT","uri":"/20141201/lineups/USA-CA61222-DEFAULT"}]},{"headend":"CA66511","transport":"Cable","location":"Los Angeles","lineups":[{"name":"AT&T U-verse TV - Digital","lineup":"USA-CA66511-X","uri":"/20141201/lineups/USA-CA66511-X"}]},{"headend":"CA67309","transport":"Cable","location":"Westchester","lineups":[{"name":"Time Warner Cable Sherman Oaks - Cable","lineup":"USA-CA67309-DEFAULT","uri":"/20141201/lineups/USA-CA67309-DEFAULT"},{"name":"Time Warner Cable Sherman Oaks - Digital","lineup":"USA-CA67309-X","uri":"/20141201/lineups/USA-CA67309-X"}]},{"headend":"CA67310","transport":"Cable","location":"Eagle Rock","lineups":[{"name":"Time Warner Cable City of Los Angeles - Cable","lineup":"USA-CA67310-DEFAULT","uri":"/20141201/lineups/USA-CA67310-DEFAULT"},{"name":"Time Warner Cable City of Los Angeles - Digital","lineup":"USA-CA67310-X","uri":"/20141201/lineups/USA-CA67310-X"}]},{"headend":"DISH803","transport":"Satellite","location":"Los Angeles","lineups":[{"name":"DISH Los Angeles - Satellite","lineup":"USA-DISH803-DEFAULT","uri":"/20141201/lineups/USA-DISH803-DEFAULT"}]},{"headend":"DITV803","transport":"Satellite","location":"Los Angeles","lineups":[{"name":"DIRECTV Los Angeles - Satellite","lineup":"USA-DITV803-DEFAULT","uri":"/20141201/lineups/USA-DITV803-DEFAULT"}]},{"headend":"90210","transport":"Antenna","location":"90210","lineups":[{"name":"Antenna","lineup":"USA-OTA-90210","uri":"/20141201/lineups/USA-OTA-90210"}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json new file mode 100644 index 000000000..072089470 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json @@ -0,0 +1 @@ +{"map":[{"stationID":"24326","channel":"001","providerCallsign":"BBC ONE South","logicalChannelNumber":"1","matchType":"providerCallsign"},{"stationID":"17154","channel":"002","providerCallsign":"BBC TWO","logicalChannelNumber":"2","matchType":"providerCallsign"}]} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json new file mode 100644 index 000000000..032a84e59 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json @@ -0,0 +1 @@ +{"code":0,"serverID":"20141201.web.1","datetime":"2015-04-17T14:22:17Z","lineups":[{"lineup":"GBR-0001317-DEFAULT","name":"Freeview - Carlton - LWT (Southeast)","transport":"DVB-T","location":"London","uri":"/20141201/lineups/GBR-0001317-DEFAULT"},{"lineup":"USA-IL57303-X","name":"Comcast Waukegan/Lake Forest Area - Digital","transport":"Cable","location":"Lake Forest","uri":"/20141201/lineups/USA-IL57303-X"},{"lineup":"USA-NY67791-X","name":"Verizon Fios Queens - Digital","transport":"Cable","location":"Fresh Meadows","uri":"/20141201/lineups/USA-NY67791-X"},{"lineup":"USA-OTA-60030","name":"Local Over the Air Broadcast","transport":"Antenna","location":"60030","uri":"/20141201/lineups/USA-OTA-60030"},{"lineup":"USA-WI61859-DEFAULT","name":"DELETED LINEUP","isDeleted":true}]} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json new file mode 100644 index 000000000..78166f09a --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json @@ -0,0 +1 @@ +[{"programID":"SH00712240","data":[{"width":"135","height":"180","uri":"assets/p282288_b_v2_aa.jpg","size":"Sm","aspect":"3x4","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"720","height":"540","uri":"assets/p282288_b_h6_aa.jpg","size":"Lg","aspect":"4x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"960","height":"1440","uri":"assets/p282288_b_v8_aa.jpg","size":"Ms","aspect":"2x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"180","height":"135","uri":"assets/p282288_b_h5_aa.jpg","size":"Sm","aspect":"4x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json new file mode 100644 index 000000000..fe2a94436 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json @@ -0,0 +1 @@ +[{"programID":"EP000000060003","titles":[{"title120":"'Allo 'Allo!"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"A disguised British Intelligence officer is sent to help the airmen."}]},"originalAirDate":"1985-11-04","genres":["Sitcom"],"episodeTitle150":"The Poloceman Cometh","metadata":[{"Gracenote":{"season":2,"episode":3}}],"cast":[{"personId":"383774","nameId":"392649","name":"Gorden Kaye","role":"Actor","billingOrder":"01"},{"personId":"246840","nameId":"250387","name":"Carmen Silvera","role":"Actor","billingOrder":"02"},{"personId":"376955","nameId":"385830","name":"Rose Hill","role":"Actor","billingOrder":"03"},{"personId":"259773","nameId":"263340","name":"Vicki Michelle","role":"Actor","billingOrder":"04"},{"personId":"353113","nameId":"361987","name":"Kirsten Cooke","role":"Actor","billingOrder":"05"},{"personId":"77787","nameId":"77787","name":"Richard Marner","role":"Actor","billingOrder":"06"},{"personId":"230921","nameId":"234193","name":"Guy Siner","role":"Actor","billingOrder":"07"},{"personId":"374934","nameId":"383809","name":"Kim Hartman","role":"Actor","billingOrder":"08"},{"personId":"369151","nameId":"378026","name":"Richard Gibson","role":"Actor","billingOrder":"09"},{"personId":"343690","nameId":"352564","name":"Arthur Bostrom","role":"Actor","billingOrder":"10"},{"personId":"352557","nameId":"361431","name":"John D. Collins","role":"Actor","billingOrder":"11"},{"personId":"605275","nameId":"627734","name":"Nicholas Frankau","role":"Actor","billingOrder":"12"},{"personId":"373394","nameId":"382269","name":"Jack Haig","role":"Actor","billingOrder":"13"}],"crew":[{"personId":"354407","nameId":"363281","name":"David Croft","role":"Director","billingOrder":"01"},{"personId":"354407","nameId":"363281","name":"David Croft","role":"Writer","billingOrder":"02"},{"personId":"105145","nameId":"105145","name":"Jeremy Lloyd","role":"Writer","billingOrder":"03"}],"showType":"Series","hasImageArtwork":true,"md5":"Jo5NKxoo44xRvBCAq8QT2A"},{"programID":"EP000000510142","titles":[{"title120":"A Different World"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"Whitley and Dwayne tell new students about their honeymoon in Los Angeles."}]},"originalAirDate":"1992-09-24","genres":["Sitcom"],"episodeTitle150":"Honeymoon in L.A.","metadata":[{"Gracenote":{"season":6,"episode":1}}],"cast":[{"personId":"700","nameId":"700","name":"Jasmine Guy","role":"Actor","billingOrder":"01"},{"personId":"729","nameId":"729","name":"Kadeem Hardison","role":"Actor","billingOrder":"02"},{"personId":"120","nameId":"120","name":"Darryl M. Bell","role":"Actor","billingOrder":"03"},{"personId":"1729","nameId":"1729","name":"Cree Summer","role":"Actor","billingOrder":"04"},{"personId":"217","nameId":"217","name":"Charnele Brown","role":"Actor","billingOrder":"05"},{"personId":"1811","nameId":"1811","name":"Glynn Turman","role":"Actor","billingOrder":"06"},{"personId":"1232","nameId":"1232","name":"Lou Myers","role":"Actor","billingOrder":"07"},{"personId":"1363","nameId":"1363","name":"Jada Pinkett","role":"Guest Star","billingOrder":"08"},{"personId":"222967","nameId":"225536","name":"Ajai Sanders","role":"Guest Star","billingOrder":"09"},{"personId":"181744","nameId":"183292","name":"Karen Malina White","role":"Guest Star","billingOrder":"10"},{"personId":"305017","nameId":"318897","name":"Patrick Y. Malone","role":"Guest Star","billingOrder":"11"},{"personId":"9841","nameId":"9841","name":"Bumper Robinson","role":"Guest Star","billingOrder":"12"},{"personId":"426422","nameId":"435297","name":"Sister Souljah","role":"Guest Star","billingOrder":"13"},{"personId":"25","nameId":"25","name":"Debbie Allen","role":"Guest Star","billingOrder":"14"},{"personId":"668","nameId":"668","name":"Gilbert Gottfried","role":"Guest Star","billingOrder":"15"}],"showType":"Series","hasImageArtwork":true,"md5":"P5kz0QmCeYxIA+yL0H4DWw"}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json new file mode 100644 index 000000000..5ef1bfb1c --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json @@ -0,0 +1 @@ +[{"stationID":"20454","date":["2015-03-13","2015-03-17"]},{"stationID":"10021","date":["2015-03-12","2015-03-13"]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json new file mode 100644 index 000000000..4a97e5517 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json @@ -0,0 +1 @@ +[{"stationID":"20454","programs":[{"programID":"SH005371070000","airDateTime":"2015-03-03T00:00:00Z","duration":1800,"md5":"Sy8HEMBPcuiAx3FBukUhKQ","new":true,"audioProperties":["stereo","cc"],"videoProperties":["hdtv"]},{"programID":"EP000014577244","airDateTime":"2015-03-03T00:30:00Z","duration":1800,"md5":"25DNXVXO192JI7Y9vSW9lQ","new":true,"audioProperties":["stereo","cc"],"videoProperties":["hdtv"]}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json new file mode 100644 index 000000000..e5fb64a6f --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json @@ -0,0 +1 @@ +{"code":0,"message":"OK","serverID":"AWS-SD-web.1","datetime":"2016-08-23T13:55:25Z","token":"f3fca79989cafe7dead71beefedc812b"} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json new file mode 100644 index 000000000..b66a4ed0c --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json @@ -0,0 +1 @@ +{"response":"SERVICE_OFFLINE","code":3000,"serverID":"20141201.web.1","message":"Server offline for maintenance.","datetime":"2015-04-23T00:03:32Z","token":"CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE"} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/empty.zip b/tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/empty.zip Binary files differnew file mode 100644 index 000000000..15628e26b --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/empty.zip diff --git a/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs index 70acbfc40..7abd2e685 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs @@ -40,7 +40,8 @@ namespace Jellyfin.Server.Implementations.Tests.Updates _fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true - }).Inject(http); + }); + _fixture.Inject(http); _installationManager = _fixture.Create<InstallationManager>(); } @@ -78,5 +79,32 @@ namespace Jellyfin.Server.Implementations.Tests.Updates packages = _installationManager.FilterPackages(packages, id: new Guid("a4df60c5-6ab4-412a-8f79-2cab93fb2bc5")).ToArray(); Assert.Single(packages); } + + [Fact] + public async Task InstallPackage_InvalidChecksum_ThrowsInvalidDataException() + { + var packageInfo = new InstallationInfo() + { + Name = "Test", + SourceUrl = "https://repo.jellyfin.org/releases/plugin/empty/empty.zip", + Checksum = "InvalidChecksum" + }; + + await Assert.ThrowsAsync<InvalidDataException>(() => _installationManager.InstallPackage(packageInfo, CancellationToken.None)).ConfigureAwait(false); + } + + [Fact] + public async Task InstallPackage_Valid_Success() + { + var packageInfo = new InstallationInfo() + { + Name = "Test", + SourceUrl = "https://repo.jellyfin.org/releases/plugin/empty/empty.zip", + Checksum = "11b5b2f1a9ebc4f66d6ef19018543361" + }; + + var ex = await Record.ExceptionAsync(() => _installationManager.InstallPackage(packageInfo, CancellationToken.None)).ConfigureAwait(false); + Assert.Null(ex); + } } } |
