aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs2
-rw-r--r--tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs30
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj2
-rw-r--r--tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs88
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs13
-rw-r--r--tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs (renamed from tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs)4
-rw-r--r--tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs159
-rw-r--r--tests/Jellyfin.Naming.Tests/Common/NamingOptionsTest.cs1
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs11
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs124
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/StackTests.cs100
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs228
-rw-r--r--tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs268
-rw-r--r--tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs31
-rw-r--r--tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs160
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs17
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs232
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs12
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/LiveTv/RecordingHelperTests.cs4
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs3
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs7
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs15
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/MediaStructureControllerTests.cs11
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs10
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs15
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj2
-rw-r--r--tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj2
27 files changed, 867 insertions, 684 deletions
diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
index cd03958b6..6f5c0ed0c 100644
--- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
+++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
@@ -132,6 +132,8 @@ namespace Jellyfin.Api.Tests.Auth
authorizationInfo.User.AddDefaultPreferences();
authorizationInfo.User.SetPermission(PermissionKind.IsAdministrator, isAdmin);
authorizationInfo.IsApiKey = false;
+ authorizationInfo.HasToken = true;
+ authorizationInfo.Token = "fake-token";
_jellyfinAuthServiceMock.Setup(
a => a.Authenticate(
diff --git a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
index 4ba7e1d2f..c4640bd22 100644
--- a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
+++ b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
@@ -55,35 +55,5 @@ namespace Jellyfin.Api.Tests.Helpers
return data;
}
-
- [Fact]
- public static void GetItemTypeStrings_Empty_Empty()
- {
- Assert.Empty(RequestHelpers.GetItemTypeStrings(Array.Empty<BaseItemKind>()));
- }
-
- [Fact]
- public static void GetItemTypeStrings_Valid_Success()
- {
- BaseItemKind[] input =
- {
- BaseItemKind.AggregateFolder,
- BaseItemKind.Audio,
- BaseItemKind.BasePluginFolder,
- BaseItemKind.CollectionFolder
- };
-
- string[] expected =
- {
- "AggregateFolder",
- "Audio",
- "BasePluginFolder",
- "CollectionFolder"
- };
-
- var res = RequestHelpers.GetItemTypeStrings(input);
-
- Assert.Equal(expected, res);
- }
}
}
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index 2aced0669..bcbe9c1be 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -15,7 +15,7 @@
<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.0" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
diff --git a/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs
new file mode 100644
index 000000000..463e17ad3
--- /dev/null
+++ b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs
@@ -0,0 +1,88 @@
+using System;
+using MediaBrowser.Controller.BaseItemManager;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Model.Configuration;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Controller.Tests
+{
+ public class BaseItemManagerTests
+ {
+ [Theory]
+ [InlineData(typeof(Book), "LibraryEnabled", true)]
+ [InlineData(typeof(Book), "LibraryDisabled", false)]
+ [InlineData(typeof(MusicArtist), "Enabled", true)]
+ [InlineData(typeof(MusicArtist), "ServerDisabled", false)]
+ public void IsMetadataFetcherEnabled_ChecksOptions_ReturnsExpected(Type itemType, string fetcherName, bool expected)
+ {
+ BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!;
+
+ var libraryOptions = new LibraryOptions
+ {
+ TypeOptions = new[]
+ {
+ new TypeOptions
+ {
+ Type = "Book",
+ MetadataFetchers = new[] { "LibraryEnabled" }
+ }
+ }
+ };
+
+ var serverConfiguration = new ServerConfiguration();
+ foreach (var typeConfig in serverConfiguration.MetadataOptions)
+ {
+ typeConfig.DisabledMetadataFetchers = new[] { "ServerDisabled" };
+ }
+
+ var serverConfigurationManager = new Mock<IServerConfigurationManager>();
+ serverConfigurationManager.Setup(scm => scm.Configuration)
+ .Returns(serverConfiguration);
+
+ var baseItemManager = new BaseItemManager(serverConfigurationManager.Object);
+ var actual = baseItemManager.IsMetadataFetcherEnabled(item, libraryOptions, fetcherName);
+
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(typeof(Book), "LibraryEnabled", true)]
+ [InlineData(typeof(Book), "LibraryDisabled", false)]
+ [InlineData(typeof(MusicArtist), "Enabled", true)]
+ [InlineData(typeof(MusicArtist), "ServerDisabled", false)]
+ public void IsImageFetcherEnabled_ChecksOptions_ReturnsExpected(Type itemType, string fetcherName, bool expected)
+ {
+ BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!;
+
+ var libraryOptions = new LibraryOptions
+ {
+ TypeOptions = new[]
+ {
+ new TypeOptions
+ {
+ Type = "Book",
+ ImageFetchers = new[] { "LibraryEnabled" }
+ }
+ }
+ };
+
+ var serverConfiguration = new ServerConfiguration();
+ foreach (var typeConfig in serverConfiguration.MetadataOptions)
+ {
+ typeConfig.DisabledImageFetchers = new[] { "ServerDisabled" };
+ }
+
+ var serverConfigurationManager = new Mock<IServerConfigurationManager>();
+ serverConfigurationManager.Setup(scm => scm.Configuration)
+ .Returns(serverConfiguration);
+
+ var baseItemManager = new BaseItemManager(serverConfigurationManager.Object);
+ var actual = baseItemManager.IsImageFetcherEnabled(item, libraryOptions, fetcherName);
+
+ Assert.Equal(expected, actual);
+ }
+ }
+}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
index 4504924cb..0fc8724b6 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
@@ -18,6 +18,19 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private readonly ProbeResultNormalizer _probeResultNormalizer = new ProbeResultNormalizer(new NullLogger<EncoderValidatorTests>(), null);
+ [Theory]
+ [InlineData("2997/125", 23.976f)]
+ [InlineData("1/50", 0.02f)]
+ [InlineData("25/1", 25f)]
+ [InlineData("120/1", 120f)]
+ [InlineData("1704753000/71073479", 23.98578237601117f)]
+ [InlineData("0/0", null)]
+ [InlineData("1/1000", 0.001f)]
+ [InlineData("1/90000", 1.1111111E-05f)]
+ [InlineData("1/48000", 2.0833333E-05f)]
+ public void GetFrameRate_Success(string value, float? expected)
+ => Assert.Equal(expected, ProbeResultNormalizer.GetFrameRate(value));
+
[Fact]
public void GetMediaInfo_MetaData_Success()
{
diff --git a/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs b/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs
index bfece97b6..6948280a3 100644
--- a/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs
+++ b/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
-using MediaBrowser.Common.Cryptography;
+using MediaBrowser.Model.Cryptography;
using Xunit;
-namespace Jellyfin.Common.Tests.Cryptography
+namespace Jellyfin.Model.Tests.Cryptography
{
public static class PasswordHashTests
{
diff --git a/tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs b/tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs
new file mode 100644
index 000000000..cbab455f0
--- /dev/null
+++ b/tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs
@@ -0,0 +1,159 @@
+using MediaBrowser.Model.Net;
+using Xunit;
+
+namespace Jellyfin.Model.Tests.Net
+{
+ public class MimeTypesTests
+ {
+ [Theory]
+ [InlineData(".dll", "application/octet-stream")]
+ [InlineData(".log", "text/plain")]
+ [InlineData(".srt", "application/x-subrip")]
+ [InlineData(".html", "text/html; charset=UTF-8")]
+ [InlineData(".htm", "text/html; charset=UTF-8")]
+ [InlineData(".7z", "application/x-7z-compressed")]
+ [InlineData(".azw", "application/vnd.amazon.ebook")]
+ [InlineData(".azw3", "application/vnd.amazon.ebook")]
+ [InlineData(".eot", "application/vnd.ms-fontobject")]
+ [InlineData(".epub", "application/epub+zip")]
+ [InlineData(".json", "application/json")]
+ [InlineData(".mobi", "application/x-mobipocket-ebook")]
+ [InlineData(".opf", "application/oebps-package+xml")]
+ [InlineData(".pdf", "application/pdf")]
+ [InlineData(".rar", "application/vnd.rar")]
+ [InlineData(".ttml", "application/ttml+xml")]
+ [InlineData(".wasm", "application/wasm")]
+ [InlineData(".xml", "application/xml")]
+ [InlineData(".zip", "application/zip")]
+ [InlineData(".bmp", "image/bmp")]
+ [InlineData(".gif", "image/gif")]
+ [InlineData(".ico", "image/vnd.microsoft.icon")]
+ [InlineData(".jpg", "image/jpeg")]
+ [InlineData(".jpeg", "image/jpeg")]
+ [InlineData(".png", "image/png")]
+ [InlineData(".svg", "image/svg+xml")]
+ [InlineData(".svgz", "image/svg+xml")]
+ [InlineData(".tbn", "image/jpeg")]
+ [InlineData(".tif", "image/tiff")]
+ [InlineData(".tiff", "image/tiff")]
+ [InlineData(".webp", "image/webp")]
+ [InlineData(".ttf", "font/ttf")]
+ [InlineData(".woff", "font/woff")]
+ [InlineData(".woff2", "font/woff2")]
+ [InlineData(".ass", "text/x-ssa")]
+ [InlineData(".ssa", "text/x-ssa")]
+ [InlineData(".css", "text/css")]
+ [InlineData(".csv", "text/csv")]
+ [InlineData(".edl", "text/plain")]
+ [InlineData(".txt", "text/plain")]
+ [InlineData(".vtt", "text/vtt")]
+ [InlineData(".3gp", "video/3gpp")]
+ [InlineData(".3g2", "video/3gpp2")]
+ [InlineData(".asf", "video/x-ms-asf")]
+ [InlineData(".avi", "video/x-msvideo")]
+ [InlineData(".flv", "video/x-flv")]
+ [InlineData(".mp4", "video/mp4")]
+ [InlineData(".m4v", "video/x-m4v")]
+ [InlineData(".mpegts", "video/mp2t")]
+ [InlineData(".mpg", "video/mpeg")]
+ [InlineData(".mkv", "video/x-matroska")]
+ [InlineData(".mov", "video/quicktime")]
+ [InlineData(".ogv", "video/ogg")]
+ [InlineData(".ts", "video/mp2t")]
+ [InlineData(".webm", "video/webm")]
+ [InlineData(".wmv", "video/x-ms-wmv")]
+ [InlineData(".aac", "audio/aac")]
+ [InlineData(".ac3", "audio/ac3")]
+ [InlineData(".ape", "audio/x-ape")]
+ [InlineData(".dsf", "audio/dsf")]
+ [InlineData(".dsp", "audio/dsp")]
+ [InlineData(".flac", "audio/flac")]
+ [InlineData(".m4a", "audio/mp4")]
+ [InlineData(".m4b", "audio/m4b")]
+ [InlineData(".mid", "audio/midi")]
+ [InlineData(".midi", "audio/midi")]
+ [InlineData(".mp3", "audio/mpeg")]
+ [InlineData(".oga", "audio/ogg")]
+ [InlineData(".ogg", "audio/ogg")]
+ [InlineData(".opus", "audio/ogg")]
+ [InlineData(".vorbis", "audio/vorbis")]
+ [InlineData(".wav", "audio/wav")]
+ [InlineData(".webma", "audio/webm")]
+ [InlineData(".wma", "audio/x-ms-wma")]
+ [InlineData(".wv", "audio/x-wavpack")]
+ [InlineData(".xsp", "audio/xsp")]
+ public void GetMimeType_Valid_ReturnsCorrectResult(string input, string expectedResult)
+ {
+ Assert.Equal(expectedResult, MimeTypes.GetMimeType(input, null));
+ }
+
+ [Theory]
+ [InlineData("application/epub+zip", ".epub")]
+ [InlineData("application/json", ".json")]
+ [InlineData("application/oebps-package+xml", ".opf")]
+ [InlineData("application/pdf", ".pdf")]
+ [InlineData("application/ttml+xml", ".ttml")]
+ [InlineData("application/vnd.amazon.ebook", ".azw")]
+ [InlineData("application/vnd.ms-fontobject", ".eot")]
+ [InlineData("application/vnd.rar", ".rar")]
+ [InlineData("application/wasm", ".wasm")]
+ [InlineData("application/x-7z-compressed", ".7z")]
+ [InlineData("application/x-cbz", ".cbz")]
+ [InlineData("application/x-javascript", ".js")]
+ [InlineData("application/x-mobipocket-ebook", ".mobi")]
+ [InlineData("application/x-mpegURL", ".m3u8")]
+ [InlineData("application/x-subrip", ".srt")]
+ [InlineData("application/xml", ".xml")]
+ [InlineData("application/zip", ".zip")]
+ [InlineData("audio/aac", ".aac")]
+ [InlineData("audio/ac3", ".ac3")]
+ [InlineData("audio/dsf", ".dsf")]
+ [InlineData("audio/dsp", ".dsp")]
+ [InlineData("audio/flac", ".flac")]
+ [InlineData("audio/m4b", ".m4b")]
+ [InlineData("audio/mp4", ".m4a")]
+ [InlineData("audio/vorbis", ".vorbis")]
+ [InlineData("audio/wav", ".wav")]
+ [InlineData("audio/x-aac", ".aac")]
+ [InlineData("audio/x-ape", ".ape")]
+ [InlineData("audio/x-ms-wma", ".wma")]
+ [InlineData("audio/x-wavpack", ".wv")]
+ [InlineData("audio/xsp", ".xsp")]
+ [InlineData("font/ttf", ".ttf")]
+ [InlineData("font/woff", ".woff")]
+ [InlineData("font/woff2", ".woff2")]
+ [InlineData("image/bmp", ".bmp")]
+ [InlineData("image/gif", ".gif")]
+ [InlineData("image/jpeg", ".jpg")]
+ [InlineData("image/png", ".png")]
+ [InlineData("image/svg+xml", ".svg")]
+ [InlineData("image/tiff", ".tif")]
+ [InlineData("image/vnd.microsoft.icon", ".ico")]
+ [InlineData("image/webp", ".webp")]
+ [InlineData("image/x-png", ".png")]
+ [InlineData("text/css", ".css")]
+ [InlineData("text/csv", ".csv")]
+ [InlineData("text/plain", ".txt")]
+ [InlineData("text/rtf", ".rtf")]
+ [InlineData("text/vtt", ".vtt")]
+ [InlineData("text/x-ssa", ".ssa")]
+ [InlineData("video/3gpp", ".3gp")]
+ [InlineData("video/3gpp2", ".3g2")]
+ [InlineData("video/mp2t", ".ts")]
+ [InlineData("video/mp4", ".mp4")]
+ [InlineData("video/ogg", ".ogv")]
+ [InlineData("video/quicktime", ".mov")]
+ [InlineData("video/vnd.mpeg.dash.mpd", ".mpd")]
+ [InlineData("video/webm", ".webm")]
+ [InlineData("video/x-flv", ".flv")]
+ [InlineData("video/x-m4v", ".m4v")]
+ [InlineData("video/x-matroska", ".mkv")]
+ [InlineData("video/x-ms-asf", ".asf")]
+ [InlineData("video/x-ms-wmv", ".wmv")]
+ [InlineData("video/x-msvideo", ".avi")]
+ public void ToExtension_Valid_ReturnsCorrectResult(string input, string expectedResult)
+ {
+ Assert.Equal(expectedResult, MimeTypes.ToExtension(input));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Naming.Tests/Common/NamingOptionsTest.cs b/tests/Jellyfin.Naming.Tests/Common/NamingOptionsTest.cs
index 3892d00f6..58aaed023 100644
--- a/tests/Jellyfin.Naming.Tests/Common/NamingOptionsTest.cs
+++ b/tests/Jellyfin.Naming.Tests/Common/NamingOptionsTest.cs
@@ -10,7 +10,6 @@ namespace Jellyfin.Naming.Tests.Common
{
var options = new NamingOptions();
- Assert.NotEmpty(options.VideoFileStackingRegexes);
Assert.NotEmpty(options.CleanDateTimeRegexes);
Assert.NotEmpty(options.CleanStringRegexes);
Assert.NotEmpty(options.EpisodeWithoutSeasonRegexes);
diff --git a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
index d13e89cee..8dd637559 100644
--- a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
@@ -81,9 +81,7 @@ namespace Jellyfin.Naming.Tests.Video
private void Test(string input, ExtraType? expectedType)
{
- var parser = GetExtraTypeParser(_videoOptions);
-
- var extraType = parser.GetExtraInfo(input).ExtraType;
+ var extraType = ExtraResolver.GetExtraInfo(input, _videoOptions).ExtraType;
Assert.Equal(expectedType, extraType);
}
@@ -93,14 +91,9 @@ namespace Jellyfin.Naming.Tests.Video
{
var rule = new ExtraRule(ExtraType.Unknown, ExtraRuleType.Regex, @"([eE]x(tra)?\.\w+)", MediaType.Video);
var options = new NamingOptions { VideoExtraRules = new[] { rule } };
- var res = GetExtraTypeParser(options).GetExtraInfo("extra.mp4");
+ var res = ExtraResolver.GetExtraInfo("extra.mp4", options);
Assert.Equal(rule, res.Rule);
}
-
- private ExtraResolver GetExtraTypeParser(NamingOptions videoOptions)
- {
- return new ExtraResolver(videoOptions);
- }
}
}
diff --git a/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs b/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs
index d02f8ae92..9a9a57be4 100644
--- a/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs
@@ -23,15 +23,11 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
- Assert.Single(result[0].Extras);
+ Assert.Single(result.Where(v => v.ExtraType == null));
+ Assert.Single(result.Where(v => v.ExtraType != null));
}
[Fact]
@@ -46,15 +42,11 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
- Assert.Single(result[0].Extras);
+ Assert.Single(result.Where(v => v.ExtraType == null));
+ Assert.Single(result.Where(v => v.ExtraType != null));
Assert.Equal(2, result[0].AlternateVersions.Count);
}
@@ -68,11 +60,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
@@ -94,15 +82,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(7, result.Count);
- Assert.Empty(result[0].Extras);
Assert.Empty(result[0].AlternateVersions);
}
@@ -122,15 +105,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
- Assert.Empty(result[0].Extras);
Assert.Equal(7, result[0].AlternateVersions.Count);
}
@@ -151,15 +129,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(9, result.Count);
- Assert.Empty(result[0].Extras);
Assert.Empty(result[0].AlternateVersions);
}
@@ -176,15 +149,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(5, result.Count);
- Assert.Empty(result[0].Extras);
Assert.Empty(result[0].AlternateVersions);
}
@@ -203,15 +171,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(5, result.Count);
- Assert.Empty(result[0].Extras);
Assert.Empty(result[0].AlternateVersions);
}
@@ -231,15 +194,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
- Assert.Empty(result[0].Extras);
Assert.Equal(7, result[0].AlternateVersions.Count);
Assert.False(result[0].AlternateVersions[2].Is3D);
Assert.True(result[0].AlternateVersions[3].Is3D);
@@ -262,15 +220,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
- Assert.Empty(result[0].Extras);
Assert.Equal(7, result[0].AlternateVersions.Count);
Assert.False(result[0].AlternateVersions[3].Is3D);
Assert.True(result[0].AlternateVersions[4].Is3D);
@@ -287,11 +240,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(2, result.Count);
@@ -312,15 +261,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(7, result.Count);
- Assert.Empty(result[0].Extras);
Assert.Empty(result[0].AlternateVersions);
}
@@ -339,15 +283,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(5, result.Count);
- Assert.Empty(result[0].Extras);
Assert.Empty(result[0].AlternateVersions);
}
@@ -361,15 +300,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
- Assert.Empty(result[0].Extras);
Assert.Single(result[0].AlternateVersions);
}
@@ -383,15 +317,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
- Assert.Empty(result[0].Extras);
Assert.Single(result[0].AlternateVersions);
}
@@ -405,15 +334,10 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
- Assert.Empty(result[0].Extras);
Assert.Single(result[0].AlternateVersions);
}
@@ -427,11 +351,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(2, result.Count);
@@ -440,7 +360,7 @@ namespace Jellyfin.Naming.Tests.Video
[Fact]
public void TestEmptyList()
{
- var result = VideoListResolver.Resolve(new List<FileSystemMetadata>(), _namingOptions).ToList();
+ var result = VideoListResolver.Resolve(new List<VideoFileInfo>(), _namingOptions).ToList();
Assert.Empty(result);
}
diff --git a/tests/Jellyfin.Naming.Tests/Video/StackTests.cs b/tests/Jellyfin.Naming.Tests/Video/StackTests.cs
index 8794d3ebe..368c3592e 100644
--- a/tests/Jellyfin.Naming.Tests/Video/StackTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/StackTests.cs
@@ -22,9 +22,7 @@ namespace Jellyfin.Naming.Tests.Video
"Bad Boys (2006)-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Single(result);
TestStackInfo(result[0], "Bad Boys (2006)", 4);
@@ -39,9 +37,7 @@ namespace Jellyfin.Naming.Tests.Video
"Bad Boys (2007).mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -55,9 +51,7 @@ namespace Jellyfin.Naming.Tests.Video
"Bad Boys 2007.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -71,9 +65,7 @@ namespace Jellyfin.Naming.Tests.Video
"300 (2007).mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -87,9 +79,7 @@ namespace Jellyfin.Naming.Tests.Video
"300 2007.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -103,9 +93,7 @@ namespace Jellyfin.Naming.Tests.Video
"Star Trek 2- The wrath of khan.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -119,9 +107,7 @@ namespace Jellyfin.Naming.Tests.Video
"Red Riding in the Year of Our Lord 1974 (2009).mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -135,16 +121,14 @@ namespace Jellyfin.Naming.Tests.Video
"d:/movies/300 2006 part2.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Single(result);
TestStackInfo(result[0], "300 2006", 2);
}
[Fact]
- public void TestDirtyNames()
+ public void ResolveFiles_GivenPartInMiddleOfName_ReturnsNoStack()
{
var files = new[]
{
@@ -155,16 +139,13 @@ namespace Jellyfin.Naming.Tests.Video
"Bad Boys (2006)-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
- Assert.Single(result);
- TestStackInfo(result[0], "Bad Boys (2006).stv.unrated.multi.1080p.bluray.x264-rough", 4);
+ Assert.Empty(result);
}
[Fact]
- public void TestNumberedFiles()
+ public void ResolveFiles_FileNamesWithMissingPartType_ReturnsNoStack()
{
var files = new[]
{
@@ -175,9 +156,7 @@ namespace Jellyfin.Naming.Tests.Video
"Bad Boys (2006)-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -194,9 +173,7 @@ namespace Jellyfin.Naming.Tests.Video
"300 (2006)-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Single(result);
TestStackInfo(result[0], "300 (2006)", 4);
@@ -214,9 +191,7 @@ namespace Jellyfin.Naming.Tests.Video
"Bad Boys (2006)-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Single(result);
TestStackInfo(result[0], "Bad Boys (2006)", 3);
@@ -238,9 +213,7 @@ namespace Jellyfin.Naming.Tests.Video
"300 (2006)-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Equal(2, result.Count);
TestStackInfo(result[1], "Bad Boys (2006)", 4);
@@ -256,9 +229,7 @@ namespace Jellyfin.Naming.Tests.Video
"blah blah - cd 2"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveDirectories(files).ToList();
+ var result = StackResolver.ResolveDirectories(files, _namingOptions).ToList();
Assert.Single(result);
TestStackInfo(result[0], "blah blah", 2);
@@ -275,9 +246,7 @@ namespace Jellyfin.Naming.Tests.Video
"300-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Single(result);
@@ -297,9 +266,7 @@ namespace Jellyfin.Naming.Tests.Video
"Avengers part3.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Equal(2, result.Count);
@@ -328,9 +295,7 @@ namespace Jellyfin.Naming.Tests.Video
"300-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Equal(3, result.Count);
@@ -354,9 +319,7 @@ namespace Jellyfin.Naming.Tests.Video
"300 (2006)-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Single(result);
@@ -375,9 +338,7 @@ namespace Jellyfin.Naming.Tests.Video
new FileSystemMetadata { FullName = "300 (2006) part1", IsDirectory = true }
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files).ToList();
+ var result = StackResolver.Resolve(files, _namingOptions).ToList();
Assert.Equal(2, result.Count);
TestStackInfo(result[0], "300 (2006)", 3);
@@ -397,9 +358,7 @@ namespace Jellyfin.Naming.Tests.Video
"Harry Potter and the Deathly Hallows 4.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Empty(result);
}
@@ -414,9 +373,7 @@ namespace Jellyfin.Naming.Tests.Video
"Neverland (2011)[720p][PG][Voted 6.5][Family-Fantasy]part2.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveFiles(files).ToList();
+ var result = StackResolver.ResolveFiles(files, _namingOptions).ToList();
Assert.Single(result);
Assert.Equal(2, result[0].Files.Count);
@@ -432,9 +389,7 @@ namespace Jellyfin.Naming.Tests.Video
@"M:/Movies (DVD)/Movies (Musical)/The Sound of Music/The Sound of Music (1965) (Disc 02)"
};
- var resolver = GetResolver();
-
- var result = resolver.ResolveDirectories(files).ToList();
+ var result = StackResolver.ResolveDirectories(files, _namingOptions).ToList();
Assert.Single(result);
Assert.Equal(2, result[0].Files.Count);
@@ -445,10 +400,5 @@ namespace Jellyfin.Naming.Tests.Video
Assert.Equal(fileCount, stack.Files.Count);
Assert.Equal(name, stack.Name);
}
-
- private StackResolver GetResolver()
- {
- return new StackResolver(_namingOptions);
- }
}
}
diff --git a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
index 9e0776c3c..b76187842 100644
--- a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
@@ -2,6 +2,7 @@ using System;
using System.Linq;
using Emby.Naming.Common;
using Emby.Naming.Video;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using Xunit;
@@ -41,23 +42,28 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Equal(5, result.Count);
+ Assert.Equal(11, result.Count);
var batman = result.FirstOrDefault(x => string.Equals(x.Name, "Batman", StringComparison.Ordinal));
Assert.NotNull(batman);
Assert.Equal(3, batman!.Files.Count);
- Assert.Equal(3, batman!.Extras.Count);
var harry = result.FirstOrDefault(x => string.Equals(x.Name, "Harry Potter and the Deathly Hallows", StringComparison.Ordinal));
Assert.NotNull(harry);
Assert.Equal(4, harry!.Files.Count);
- Assert.Equal(2, harry!.Extras.Count);
+
+ Assert.False(result[2].ExtraType.HasValue);
+
+ Assert.Equal(ExtraType.Trailer, result[3].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[4].ExtraType);
+ Assert.Equal(ExtraType.DeletedScene, result[5].ExtraType);
+ Assert.Equal(ExtraType.Sample, result[6].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[7].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[8].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[9].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[10].ExtraType);
}
[Fact]
@@ -70,11 +76,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
@@ -90,14 +92,12 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(2, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
}
[Fact]
@@ -110,14 +110,12 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(2, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
}
[Fact]
@@ -131,34 +129,51 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(3, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[2].ExtraType);
}
[Fact]
- public void TestDifferentNames()
+ public void Resolve_SameNameAndYear_ReturnsSingleItem()
{
var files = new[]
{
"Looper (2012)-trailer.mkv",
+ "Looper 2012-trailer.mkv",
"Looper.2012.bluray.720p.x264.mkv"
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(3, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[2].ExtraType);
+ }
+
+ [Fact]
+ public void Resolve_TrailerMatchesFolderName_ReturnsSingleItem()
+ {
+ var files = new[]
+ {
+ "/movies/Looper (2012)/Looper (2012)-trailer.mkv",
+ "/movies/Looper (2012)/Looper.bluray.720p.x264.mkv"
+ };
+
+ var result = VideoListResolver.Resolve(
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
+ _namingOptions).ToList();
+
+ Assert.Equal(2, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
}
[Fact]
@@ -175,11 +190,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(5, result.Count);
@@ -195,11 +206,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = true,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
@@ -216,11 +223,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = true,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(2, result.Count);
@@ -233,39 +236,18 @@ namespace Jellyfin.Naming.Tests.Video
{
@"No (2012) part1.mp4",
@"No (2012) part2.mp4",
- @"No (2012) part1-trailer.mp4"
- };
-
- var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
- _namingOptions).ToList();
-
- Assert.Single(result);
- }
-
- [Fact]
- public void TestStackedWithTrailer2()
- {
- var files = new[]
- {
- @"No (2012) part1.mp4",
- @"No (2012) part2.mp4",
+ @"No (2012) part1-trailer.mp4",
@"No (2012)-trailer.mp4"
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(3, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[2].ExtraType);
}
[Fact]
@@ -276,18 +258,18 @@ namespace Jellyfin.Naming.Tests.Video
@"/Movies/Top Gun (1984)/movie.mp4",
@"/Movies/Top Gun (1984)/Top Gun (1984)-trailer.mp4",
@"/Movies/Top Gun (1984)/Top Gun (1984)-trailer2.mp4",
- @"trailer.mp4"
+ @"/Movies/trailer.mp4"
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(4, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[2].ExtraType);
+ Assert.Equal(ExtraType.Trailer, result[3].ExtraType);
}
[Fact]
@@ -302,11 +284,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(2, result.Count);
@@ -321,11 +299,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
@@ -340,11 +314,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
@@ -360,11 +330,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Single(result);
@@ -380,11 +346,7 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
Assert.Equal(2, result.Count);
@@ -396,40 +358,34 @@ namespace Jellyfin.Naming.Tests.Video
var files = new[]
{
@"/Server/Despicable Me/Despicable Me (2010).mkv",
- @"/Server/Despicable Me/movie-trailer.mkv"
+ @"/Server/Despicable Me/trailer.mkv"
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(2, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
}
[Fact]
- public void TestTrailerFalsePositives()
+ public void Resolve_TrailerInTrailersFolder_ReturnsCorrectExtraType()
{
var files = new[]
{
- @"/Server/Despicable Me/Skyscraper (2018) - Big Game Spot.mkv",
- @"/Server/Despicable Me/Skyscraper (2018) - Trailer.mkv",
- @"/Server/Despicable Me/Baywatch (2017) - Big Game Spot.mkv",
- @"/Server/Despicable Me/Baywatch (2017) - Trailer.mkv"
+ @"/Server/Despicable Me/Despicable Me (2010).mkv",
+ @"/Server/Despicable Me/trailers/some title.mkv"
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Equal(4, result.Count);
+ Assert.Equal(2, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
}
[Fact]
@@ -442,20 +398,18 @@ namespace Jellyfin.Naming.Tests.Video
};
var result = VideoListResolver.Resolve(
- files.Select(i => new FileSystemMetadata
- {
- IsDirectory = false,
- FullName = i
- }).ToList(),
+ files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
_namingOptions).ToList();
- Assert.Single(result);
+ Assert.Equal(2, result.Count);
+ Assert.False(result[0].ExtraType.HasValue);
+ Assert.Equal(ExtraType.Trailer, result[1].ExtraType);
}
[Fact]
public void TestDirectoryStack()
{
- var stack = new FileStack();
+ var stack = new FileStack(string.Empty, false, Array.Empty<string>());
Assert.False(stack.ContainsFile("XX", true));
}
}
diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs
index b194e3885..558321810 100644
--- a/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs
+++ b/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -5,11 +6,14 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.MediaInfo;
+using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
@@ -17,200 +21,136 @@ namespace Jellyfin.Providers.Tests.MediaInfo
{
public class EmbeddedImageProviderTests
{
- private static TheoryData<BaseItem> GetSupportedImages_UnsupportedBaseItems_ReturnsEmpty_TestData()
- {
- return new ()
- {
- new AudioBook(),
- new BoxSet(),
- new Series(),
- new Season(),
- };
- }
-
[Theory]
- [MemberData(nameof(GetSupportedImages_UnsupportedBaseItems_ReturnsEmpty_TestData))]
- public void GetSupportedImages_UnsupportedBaseItems_ReturnsEmpty(BaseItem item)
+ [InlineData(typeof(AudioBook))]
+ [InlineData(typeof(BoxSet))]
+ [InlineData(typeof(Series))]
+ [InlineData(typeof(Season))]
+ [InlineData(typeof(Episode), ImageType.Primary)]
+ [InlineData(typeof(Movie), ImageType.Logo, ImageType.Backdrop, ImageType.Primary)]
+ public void GetSupportedImages_AnyBaseItem_ReturnsExpected(Type type, params ImageType[] expected)
{
- var embeddedImageProvider = GetEmbeddedImageProvider(null);
- Assert.Empty(embeddedImageProvider.GetSupportedImages(item));
- }
-
- private static TheoryData<BaseItem, IEnumerable<ImageType>> GetSupportedImages_SupportedBaseItems_ReturnsPopulated_TestData()
- {
- return new TheoryData<BaseItem, IEnumerable<ImageType>>
- {
- { new Episode(), new List<ImageType> { ImageType.Primary } },
- { new Movie(), new List<ImageType> { ImageType.Logo, ImageType.Backdrop, ImageType.Primary } },
- };
- }
-
- [Theory]
- [MemberData(nameof(GetSupportedImages_SupportedBaseItems_ReturnsPopulated_TestData))]
- public void GetSupportedImages_SupportedBaseItems_ReturnsPopulated(BaseItem item, IEnumerable<ImageType> expected)
- {
- var embeddedImageProvider = GetEmbeddedImageProvider(null);
+ BaseItem item = (BaseItem)Activator.CreateInstance(type)!;
+ var embeddedImageProvider = new EmbeddedImageProvider(Mock.Of<IMediaSourceManager>(), Mock.Of<IMediaEncoder>(), new NullLogger<EmbeddedImageProvider>());
var actual = embeddedImageProvider.GetSupportedImages(item);
Assert.Equal(expected.OrderBy(i => i.ToString()), actual.OrderBy(i => i.ToString()));
}
[Fact]
- public async void GetImage_InputWithNoStreams_ReturnsNoImage()
+ public async void GetImage_NoStreams_ReturnsNoImage()
{
- var embeddedImageProvider = GetEmbeddedImageProvider(null);
+ var input = new Movie();
- var input = GetMovie(new List<MediaAttachment>(), new List<MediaStream>());
+ var mediaSourceManager = GetMediaSourceManager(input, new List<MediaAttachment>(), new List<MediaStream>());
+ var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, null, new NullLogger<EmbeddedImageProvider>());
var actual = await embeddedImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
Assert.NotNull(actual);
Assert.False(actual.HasImage);
}
- [Fact]
- public async void GetImage_InputWithUnlabeledAttachments_ReturnsNoImage()
+ [Theory]
+ [InlineData("chapter", null, 1, ImageType.Chapter, null)] // unexpected type, nothing found
+ [InlineData("unmatched", null, 1, ImageType.Primary, null)] // doesn't default on no match
+ [InlineData("clearlogo.png", null, 1, ImageType.Logo, ImageFormat.Png)] // extract extension from name
+ [InlineData("backdrop", "image/bmp", 2, ImageType.Backdrop, ImageFormat.Bmp)] // extract extension from mimetype
+ [InlineData("poster", null, 3, ImageType.Primary, ImageFormat.Jpg)] // default extension to jpg
+ public async void GetImage_Attachment_ReturnsCorrectSelection(string filename, string mimetype, int targetIndex, ImageType type, ImageFormat? expectedFormat)
{
- var embeddedImageProvider = GetEmbeddedImageProvider(null);
-
- // add an attachment without a filename - has a list to look through but finds nothing
- var input = GetMovie(
- new List<MediaAttachment> { new () },
- new List<MediaStream>());
-
- var actual = await embeddedImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
- Assert.NotNull(actual);
- Assert.False(actual.HasImage);
- }
+ var attachments = new List<MediaAttachment>();
+ string pathPrefix = "path";
+ for (int i = 1; i <= targetIndex; i++)
+ {
+ var name = i == targetIndex ? filename : "unmatched";
+ attachments.Add(new ()
+ {
+ FileName = name,
+ MimeType = mimetype,
+ Index = i
+ });
+ }
- [Fact]
- public async void GetImage_InputWithLabeledAttachments_ReturnsCorrectSelection()
- {
- // first tests file extension detection, second uses mimetype, third defaults to jpg
- MediaAttachment sampleAttachment1 = new () { FileName = "clearlogo.png", Index = 1 };
- MediaAttachment sampleAttachment2 = new () { FileName = "backdrop", MimeType = "image/bmp", Index = 2 };
- MediaAttachment sampleAttachment3 = new () { FileName = "poster", Index = 3 };
- string targetPath1 = "path1.png";
- string targetPath2 = "path2.bmp";
- string targetPath3 = "path2.jpg";
+ var input = new Movie();
var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), 1, ".png", CancellationToken.None))
- .Returns(Task.FromResult(targetPath1));
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), 2, ".bmp", CancellationToken.None))
- .Returns(Task.FromResult(targetPath2));
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), 3, ".jpg", CancellationToken.None))
- .Returns(Task.FromResult(targetPath3));
- var embeddedImageProvider = GetEmbeddedImageProvider(mediaEncoder.Object);
-
- var input = GetMovie(
- new List<MediaAttachment> { sampleAttachment1, sampleAttachment2, sampleAttachment3 },
- new List<MediaStream>());
-
- var actualLogo = await embeddedImageProvider.GetImage(input, ImageType.Logo, CancellationToken.None);
- Assert.NotNull(actualLogo);
- Assert.True(actualLogo.HasImage);
- Assert.Equal(targetPath1, actualLogo.Path);
- Assert.Equal(ImageFormat.Png, actualLogo.Format);
-
- var actualBackdrop = await embeddedImageProvider.GetImage(input, ImageType.Backdrop, CancellationToken.None);
- Assert.NotNull(actualBackdrop);
- Assert.True(actualBackdrop.HasImage);
- Assert.Equal(targetPath2, actualBackdrop.Path);
- Assert.Equal(ImageFormat.Bmp, actualBackdrop.Format);
-
- var actualPrimary = await embeddedImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
- Assert.NotNull(actualPrimary);
- Assert.True(actualPrimary.HasImage);
- Assert.Equal(targetPath3, actualPrimary.Path);
- Assert.Equal(ImageFormat.Jpg, actualPrimary.Format);
- }
-
- [Fact]
- public async void GetImage_InputWithUnlabeledEmbeddedImages_BackdropReturnsNoImage()
- {
- var embeddedImageProvider = GetEmbeddedImageProvider(null);
+ mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), It.IsAny<int>(), It.IsAny<ImageFormat>(), It.IsAny<CancellationToken>()))
+ .Returns<string, string, MediaSourceInfo, MediaStream, int, ImageFormat, CancellationToken>((_, _, _, _, index, ext, _) => Task.FromResult(pathPrefix + index + "." + ext));
+ var mediaSourceManager = GetMediaSourceManager(input, attachments, new List<MediaStream>());
+ var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<EmbeddedImageProvider>());
- var input = GetMovie(
- new List<MediaAttachment>(),
- new List<MediaStream> { new () { Type = MediaStreamType.EmbeddedImage } });
-
- var actual = await embeddedImageProvider.GetImage(input, ImageType.Backdrop, CancellationToken.None);
+ var actual = await embeddedImageProvider.GetImage(input, type, CancellationToken.None);
Assert.NotNull(actual);
- Assert.False(actual.HasImage);
+ if (expectedFormat == null)
+ {
+ Assert.False(actual.HasImage);
+ }
+ else
+ {
+ Assert.True(actual.HasImage);
+ Assert.Equal(pathPrefix + targetIndex + "." + expectedFormat, actual.Path, StringComparer.OrdinalIgnoreCase);
+ Assert.Equal(expectedFormat, actual.Format);
+ }
}
- [Fact]
- public async void GetImage_InputWithUnlabeledEmbeddedImages_PrimaryReturnsImage()
+ [Theory]
+ [InlineData("chapter", null, 1, ImageType.Chapter, null)] // unexpected type, nothing found
+ [InlineData(null, null, 1, ImageType.Backdrop, null)] // no label, can only find primary
+ [InlineData(null, null, 1, ImageType.Primary, ImageFormat.Jpg)] // no label, finds primary
+ [InlineData("backdrop", null, 2, ImageType.Backdrop, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
+ [InlineData("cover", null, 2, ImageType.Primary, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
+ [InlineData(null, "mjpeg", 1, ImageType.Primary, ImageFormat.Jpg)]
+ [InlineData(null, "png", 1, ImageType.Primary, ImageFormat.Png)]
+ [InlineData(null, "gif", 1, ImageType.Primary, ImageFormat.Gif)]
+ public async void GetImage_Embedded_ReturnsCorrectSelection(string label, string? codec, int targetIndex, ImageType type, ImageFormat? expectedFormat)
{
- MediaStream sampleStream = new () { Type = MediaStreamType.EmbeddedImage, Index = 1 };
- string targetPath = "path";
-
+ var streams = new List<MediaStream>();
+ for (int i = 1; i <= targetIndex; i++)
+ {
+ var comment = i == targetIndex ? label : "unmatched";
+ streams.Add(new ()
+ {
+ Type = MediaStreamType.EmbeddedImage,
+ Index = i,
+ Comment = comment,
+ Codec = codec
+ });
+ }
+
+ var input = new Movie();
+
+ var pathPrefix = "path";
var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), sampleStream, 1, ".jpg", CancellationToken.None))
- .Returns(Task.FromResult(targetPath));
- var embeddedImageProvider = GetEmbeddedImageProvider(mediaEncoder.Object);
-
- var input = GetMovie(
- new List<MediaAttachment>(),
- new List<MediaStream> { sampleStream });
-
- var actual = await embeddedImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
+ mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), It.IsAny<int>(), It.IsAny<ImageFormat>(), It.IsAny<CancellationToken>()))
+ .Returns<string, string, MediaSourceInfo, MediaStream, int, ImageFormat, CancellationToken>((_, _, _, stream, index, ext, _) =>
+ {
+ Assert.Equal(streams[index - 1], stream);
+ return Task.FromResult(pathPrefix + index + "." + ext);
+ });
+ var mediaSourceManager = GetMediaSourceManager(input, new List<MediaAttachment>(), streams);
+ var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<EmbeddedImageProvider>());
+
+ var actual = await embeddedImageProvider.GetImage(input, type, CancellationToken.None);
Assert.NotNull(actual);
- Assert.True(actual.HasImage);
- Assert.Equal(targetPath, actual.Path);
- Assert.Equal(ImageFormat.Jpg, actual.Format);
- }
-
- [Fact]
- public async void GetImage_InputWithLabeledEmbeddedImages_ReturnsCorrectSelection()
- {
- // primary is second stream to ensure it's not defaulting, backdrop is first
- MediaStream sampleStream1 = new () { Type = MediaStreamType.EmbeddedImage, Index = 1, Comment = "backdrop" };
- MediaStream sampleStream2 = new () { Type = MediaStreamType.EmbeddedImage, Index = 2, Comment = "cover" };
- string targetPath1 = "path1.jpg";
- string targetPath2 = "path2.jpg";
-
- var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), sampleStream1, 1, ".jpg", CancellationToken.None))
- .Returns(Task.FromResult(targetPath1));
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), sampleStream2, 2, ".jpg", CancellationToken.None))
- .Returns(Task.FromResult(targetPath2));
- var embeddedImageProvider = GetEmbeddedImageProvider(mediaEncoder.Object);
-
- var input = GetMovie(
- new List<MediaAttachment>(),
- new List<MediaStream> { sampleStream1, sampleStream2 });
-
- var actualPrimary = await embeddedImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
- Assert.NotNull(actualPrimary);
- Assert.True(actualPrimary.HasImage);
- Assert.Equal(targetPath2, actualPrimary.Path);
- Assert.Equal(ImageFormat.Jpg, actualPrimary.Format);
-
- var actualBackdrop = await embeddedImageProvider.GetImage(input, ImageType.Backdrop, CancellationToken.None);
- Assert.NotNull(actualBackdrop);
- Assert.True(actualBackdrop.HasImage);
- Assert.Equal(targetPath1, actualBackdrop.Path);
- Assert.Equal(ImageFormat.Jpg, actualBackdrop.Format);
- }
-
- private static EmbeddedImageProvider GetEmbeddedImageProvider(IMediaEncoder? mediaEncoder)
- {
- return new EmbeddedImageProvider(mediaEncoder);
+ if (expectedFormat == null)
+ {
+ Assert.False(actual.HasImage);
+ }
+ else
+ {
+ Assert.True(actual.HasImage);
+ Assert.Equal(pathPrefix + targetIndex + "." + expectedFormat, actual.Path, StringComparer.OrdinalIgnoreCase);
+ Assert.Equal(expectedFormat, actual.Format);
+ }
}
- private static Movie GetMovie(List<MediaAttachment> mediaAttachments, List<MediaStream> mediaStreams)
+ private static IMediaSourceManager GetMediaSourceManager(BaseItem item, List<MediaAttachment> mediaAttachments, List<MediaStream> mediaStreams)
{
- // Mocking IMediaSourceManager GetMediaAttachments and GetMediaStreams instead of mocking Movie works, but
- // has concurrency problems between this and VideoImageProviderTests due to BaseItem.MediaSourceManager
- // being static
- var movie = new Mock<Movie>();
-
- movie.Setup(item => item.GetMediaSources(It.IsAny<bool>()))
- .Returns(new List<MediaSourceInfo> { new () { MediaAttachments = mediaAttachments } } );
- movie.Setup(item => item.GetMediaStreams())
+ var mediaSourceManager = new Mock<IMediaSourceManager>(MockBehavior.Strict);
+ mediaSourceManager.Setup(i => i.GetMediaAttachments(item.Id))
+ .Returns(mediaAttachments);
+ mediaSourceManager.Setup(i => i.GetMediaStreams(It.Is<MediaStreamQuery>(q => q.ItemId == item.Id && q.Type == MediaStreamType.EmbeddedImage)))
.Returns(mediaStreams);
-
- return movie.Object;
+ return mediaSourceManager.Object;
}
}
}
diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs
index c289a7112..33da277e3 100644
--- a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs
+++ b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs
@@ -80,6 +80,37 @@ namespace Jellyfin.Providers.Tests.MediaInfo
}
}
+ [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 streams = new List<MediaStream>();
+ var expected = CreateMediaStream(file, codec, language, 0, isForced, isDefault);
+
+ new SubtitleResolver(Mock.Of<ILocalizationManager>()).AddExternalSubtitleStreams(streams, videoPath, 0, new[] { file });
+
+ 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);
+ }
+
private static MediaStream CreateMediaStream(string path, string codec, string? language, int index, bool isForced = false, bool isDefault = false)
{
return new ()
diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs
index 0f51a2b8f..839925dd1 100644
--- a/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs
+++ b/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs
@@ -2,8 +2,11 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -16,85 +19,56 @@ namespace Jellyfin.Providers.Tests.MediaInfo
{
public class VideoImageProviderTests
{
- [Fact]
- public async void GetImage_InputIsPlaceholder_ReturnsNoImage()
+ private static TheoryData<Video> GetImage_UnsupportedInput_ReturnsNoImage_TestData()
{
- var videoImageProvider = GetVideoImageProvider(null);
-
- var input = new Movie
+ return new ()
{
- IsPlaceHolder = true
- };
-
- var actual = await videoImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
- Assert.NotNull(actual);
- Assert.False(actual.HasImage);
- }
+ new Movie { IsPlaceHolder = true },
- [Fact]
- public async void GetImage_NoDefaultVideoStream_ReturnsNoImage()
- {
- var videoImageProvider = GetVideoImageProvider(null);
+ new Movie { DefaultVideoStreamIndex = null },
- var input = new Movie
- {
- DefaultVideoStreamIndex = null
+ // set a default index but don't put anything there (invalid input, but provider shouldn't break)
+ new Movie { DefaultVideoStreamIndex = 0 }
};
-
- var actual = await videoImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
- Assert.NotNull(actual);
- Assert.False(actual.HasImage);
}
- [Fact]
- public async void GetImage_DefaultSetButNoVideoStream_ReturnsNoImage()
+ [Theory]
+ [MemberData(nameof(GetImage_UnsupportedInput_ReturnsNoImage_TestData))]
+ public async void GetImage_UnsupportedInput_ReturnsNoImage(Video input)
{
- var videoImageProvider = GetVideoImageProvider(null);
-
- // set a default index but don't put anything there (invalid input, but provider shouldn't break)
- var input = GetMovie(0, null, new List<MediaStream>());
+ var mediaSourceManager = GetMediaSourceManager(input, null, new List<MediaStream>());
+ var videoImageProvider = new VideoImageProvider(mediaSourceManager, Mock.Of<IMediaEncoder>(), new NullLogger<VideoImageProvider>());
var actual = await videoImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
Assert.NotNull(actual);
Assert.False(actual.HasImage);
}
- [Fact]
- public async void GetImage_DefaultSetMultipleVideoStreams_ReturnsDefaultStreamImage()
+ [Theory]
+ [InlineData(1, 1)] // default not first stream
+ [InlineData(5, 0)] // default out of valid range
+ public async void GetImage_DefaultVideoStreams_ReturnsCorrectStreamImage(int defaultIndex, int targetIndex)
{
- MediaStream firstStream = new () { Type = MediaStreamType.Video, Index = 0 };
- MediaStream targetStream = new () { Type = MediaStreamType.Video, Index = 1 };
- string targetPath = "path.jpg";
+ var input = new Movie { DefaultVideoStreamIndex = defaultIndex };
+ string targetPath = "path.jpg";
+ var mediaStreams = new List<MediaStream>();
var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), firstStream, It.IsAny<Video3DFormat?>(), It.IsAny<TimeSpan?>(), CancellationToken.None))
- .Returns(Task.FromResult("wrong stream called!"));
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), targetStream, It.IsAny<Video3DFormat?>(), It.IsAny<TimeSpan?>(), CancellationToken.None))
- .Returns(Task.FromResult(targetPath));
- var videoImageProvider = GetVideoImageProvider(mediaEncoder.Object);
- var input = GetMovie(1, targetStream, new List<MediaStream> { firstStream, targetStream } );
-
- var actual = await videoImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
- Assert.NotNull(actual);
- Assert.True(actual.HasImage);
- Assert.Equal(targetPath, actual.Path);
- Assert.Equal(ImageFormat.Jpg, actual.Format);
- }
+ for (int i = 0; i <= targetIndex; i++)
+ {
+ var mediaStream = new MediaStream { Type = MediaStreamType.Video, Index = i };
+ mediaStreams.Add(mediaStream);
- [Fact]
- public async void GetImage_InvalidDefaultSingleVideoStream_ReturnsFirstVideoStreamImage()
- {
- MediaStream targetStream = new () { Type = MediaStreamType.Video, Index = 0 };
- string targetPath = "path.jpg";
+ var path = i == targetIndex ? targetPath : "wrong stream called!";
+ mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), mediaStream, It.IsAny<Video3DFormat?>(), It.IsAny<TimeSpan?>(), It.IsAny<CancellationToken>()))
+ .Returns(Task.FromResult(path));
+ }
- var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), targetStream, It.IsAny<Video3DFormat?>(), It.IsAny<TimeSpan?>(), CancellationToken.None))
- .Returns(Task.FromResult(targetPath));
- var videoImageProvider = GetVideoImageProvider(mediaEncoder.Object);
+ var defaultStream = defaultIndex < mediaStreams.Count ? mediaStreams[targetIndex] : null;
+ var mediaSourceManager = GetMediaSourceManager(input, defaultStream, mediaStreams);
- // provide query results for default (empty) and all streams (populated)
- var input = GetMovie(5, null, new List<MediaStream> { targetStream });
+ var videoImageProvider = new VideoImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<VideoImageProvider>());
var actual = await videoImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
Assert.NotNull(actual);
@@ -103,10 +77,19 @@ namespace Jellyfin.Providers.Tests.MediaInfo
Assert.Equal(ImageFormat.Jpg, actual.Format);
}
- [Fact]
- public async void GetImage_NoTimeSpanSet_CallsEncoderWithDefaultTime()
+ [Theory]
+ [InlineData(null, 10)] // default time
+ [InlineData(500, 50)] // calculated time
+ public async void GetImage_TimeSpan_SelectsCorrectTime(int? runTimeSeconds, long expectedSeconds)
{
MediaStream targetStream = new () { Type = MediaStreamType.Video, Index = 0 };
+ var input = new Movie
+ {
+ DefaultVideoStreamIndex = 0,
+ RunTimeTicks = runTimeSeconds * TimeSpan.TicksPerSecond
+ };
+
+ var mediaSourceManager = GetMediaSourceManager(input, targetStream, new List<MediaStream> { targetStream });
// use a callback to catch the actual value
// provides more information on failure than verifying a specific input was called on the mock
@@ -115,62 +98,29 @@ namespace Jellyfin.Providers.Tests.MediaInfo
mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), It.IsAny<Video3DFormat?>(), It.IsAny<TimeSpan?>(), CancellationToken.None))
.Callback<string, string, MediaSourceInfo, MediaStream, Video3DFormat?, TimeSpan?, CancellationToken>((_, _, _, _, _, timeSpan, _) => actualTimeSpan = timeSpan)
.Returns(Task.FromResult("path"));
- var videoImageProvider = GetVideoImageProvider(mediaEncoder.Object);
- var input = GetMovie(0, targetStream, new List<MediaStream> { targetStream });
+ var videoImageProvider = new VideoImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<VideoImageProvider>());
// not testing return, just verifying what gets requested for time span
await videoImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
- Assert.Equal(TimeSpan.FromSeconds(10), actualTimeSpan);
+ Assert.Equal(TimeSpan.FromSeconds(expectedSeconds), actualTimeSpan);
}
- [Fact]
- public async void GetImage_TimeSpanSet_CallsEncoderWithCalculatedTime()
+ private static IMediaSourceManager GetMediaSourceManager(Video item, MediaStream? defaultStream, List<MediaStream> mediaStreams)
{
- MediaStream targetStream = new () { Type = MediaStreamType.Video, Index = 0 };
-
- TimeSpan? actualTimeSpan = null;
- var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
- mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), It.IsAny<Video3DFormat?>(), It.IsAny<TimeSpan?>(), CancellationToken.None))
- .Callback<string, string, MediaSourceInfo, MediaStream, Video3DFormat?, TimeSpan?, CancellationToken>((_, _, _, _, _, timeSpan, _) => actualTimeSpan = timeSpan)
- .Returns(Task.FromResult("path"));
- var videoImageProvider = GetVideoImageProvider(mediaEncoder.Object);
-
- var input = GetMovie(0, targetStream, new List<MediaStream> { targetStream });
- input.RunTimeTicks = 5000;
-
- // not testing return, just verifying what gets requested for time span
- await videoImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
-
- Assert.Equal(TimeSpan.FromTicks(500), actualTimeSpan);
- }
-
- private static VideoImageProvider GetVideoImageProvider(IMediaEncoder? mediaEncoder)
- {
- // strict to ensure this isn't accidentally used where a prepared mock is intended
- mediaEncoder ??= new Mock<IMediaEncoder>(MockBehavior.Strict).Object;
- return new VideoImageProvider(mediaEncoder, new NullLogger<VideoImageProvider>());
- }
-
- private static Movie GetMovie(int defaultVideoStreamIndex, MediaStream? defaultStream, List<MediaStream> mediaStreams)
- {
- // Mocking IMediaSourceManager GetMediaStreams instead of mocking Movie works, but has concurrency problems
- // between this and EmbeddedImageProviderTests due to BaseItem.MediaSourceManager being static
- var movie = new Mock<Movie>
+ var defaultStreamList = new List<MediaStream>();
+ if (defaultStream != null)
{
- Object =
- {
- DefaultVideoStreamIndex = defaultVideoStreamIndex
- }
- };
+ defaultStreamList.Add(defaultStream);
+ }
- movie.Setup(item => item.GetDefaultVideoStream())
- .Returns(defaultStream!);
- movie.Setup(item => item.GetMediaStreams())
+ var mediaSourceManager = new Mock<IMediaSourceManager>(MockBehavior.Strict);
+ mediaSourceManager.Setup(i => i.GetMediaStreams(It.Is<MediaStreamQuery>(q => q.ItemId == item.Id && q.Index == item.DefaultVideoStreamIndex)))
+ .Returns(defaultStreamList);
+ mediaSourceManager.Setup(i => i.GetMediaStreams(It.Is<MediaStreamQuery>(q => q.ItemId == item.Id && q.Type == MediaStreamType.Video)))
.Returns(mediaStreams);
-
- return movie.Object;
+ return mediaSourceManager.Object;
}
}
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs
index c393742eb..362c3216f 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,7 +61,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library
private class EpisodeResolverMock : EpisodeResolver
{
- public EpisodeResolverMock(ILibraryManager libraryManager) : base(libraryManager)
+ public EpisodeResolverMock(NamingOptions namingOptions) : base(namingOptions)
{
}
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..b29426d85
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs
@@ -0,0 +1,232 @@
+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;
+using Emby.Server.Implementations.Library.Resolvers.Audio;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+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");
+ _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 GenericVideoResolver<Video>(fixture.Create<NamingOptions>()), 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(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
+ }
+ });
+
+ _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
+ }
+ });
+
+ _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
+ }
+ });
+
+ var files = paths.Select(p => new FileSystemMetadata
+ {
+ FullName = p,
+ Name = Path.GetFileName(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(6, extras.Count);
+ Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
+ Assert.Equal(ExtraType.Trailer, extras[1].ExtraType);
+ Assert.Equal(ExtraType.BehindTheScenes, extras[2].ExtraType);
+ Assert.Equal(ExtraType.Sample, extras[3].ExtraType);
+ Assert.Equal(ExtraType.ThemeSong, extras[4].ExtraType);
+ Assert.Equal(ExtraType.ThemeSong, extras[5].ExtraType);
+ }
+
+ [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("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("trailer", extras[0].FileNameWithoutExtension);
+ Assert.Equal("/movies/Up/trailer.mkv", extras[0].Path);
+ }
+
+ [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("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/PathExtensionsTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
index c5cc056f5..54a63a5f2 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
@@ -11,6 +11,18 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[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 [tmdbid=618355][imdbid=tt10985510]", "imdbid", "tt10985510")]
+ [InlineData("Superman: Red Son [tmdbid=618355][imdbid=tt10985510]", "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)]
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 976afe195..09aec82b0 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/RecordingHelperTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/RecordingHelperTests.cs
@@ -61,7 +61,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
{
Name = "The Big Bang Theory",
IsProgramSeries = true,
- OriginalAirDate = new DateTime(2018, 12, 6)
+ OriginalAirDate = new DateTime(2018, 12, 6, 0, 0, 0, DateTimeKind.Local)
});
data.Add(
@@ -70,7 +70,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
{
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"
});
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs
index 09c4bd100..7abd2e685 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs
@@ -6,9 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.AutoMoq;
-using Emby.Server.Implementations.Archiving;
using Emby.Server.Implementations.Updates;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.Updates;
using Moq;
using Moq.Protected;
@@ -44,7 +42,6 @@ namespace Jellyfin.Server.Implementations.Tests.Updates
ConfigureMembers = true
});
_fixture.Inject(http);
- _fixture.Inject<IZipClient>(new ZipClient());
_installationManager = _fixture.Create<InstallationManager>();
}
diff --git a/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs b/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs
index 4ea05397d..21131eb97 100644
--- a/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs
@@ -1,8 +1,8 @@
using System;
using System.Net;
using System.Net.Http;
+using System.Net.Http.Json;
using System.Net.Http.Headers;
-using System.Net.Mime;
using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Models.StartupDtos;
@@ -26,14 +26,13 @@ namespace Jellyfin.Server.Integration.Tests
using var completeResponse = await client.PostAsync("/Startup/Complete", new ByteArrayContent(Array.Empty<byte>())).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.NoContent, completeResponse.StatusCode);
- using var content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(
+ using var content = JsonContent.Create(
new AuthenticateUserByName()
{
Username = user!.Name,
Pw = user.Password,
},
- jsonOptions));
- content.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
+ options: jsonOptions);
content.Headers.Add("X-Emby-Authorization", DummyAuthHeader);
using var authResponse = await client.PostAsync("/Users/AuthenticateByName", content).ConfigureAwait(false);
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs
index 4421ced72..5d7b0e874 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs
@@ -1,8 +1,7 @@
using System;
using System.Linq;
using System.Net;
-using System.Net.Http;
-using System.Net.Http.Headers;
+using System.Net.Http.Json;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
@@ -62,9 +61,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
Name = "ThisProfileDoesNotExist"
};
- using var content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(deviceProfile, _jsonOptions));
- content.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- using var getResponse = await client.PostAsync("/Dlna/Profiles/" + NonExistentProfile, content).ConfigureAwait(false);
+ using var getResponse = await client.PostAsJsonAsync("/Dlna/Profiles/" + NonExistentProfile, deviceProfile, _jsonOptions).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode);
}
@@ -80,9 +77,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
Name = "ThisProfileIsNew"
};
- using var content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(deviceProfile, _jsonOptions));
- content.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- using var getResponse = await client.PostAsync("/Dlna/Profiles", content).ConfigureAwait(false);
+ using var getResponse = await client.PostAsJsonAsync("/Dlna/Profiles", deviceProfile, _jsonOptions).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.NoContent, getResponse.StatusCode);
}
@@ -120,9 +115,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
Id = _newDeviceProfileId
};
- using var content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(updatedProfile, _jsonOptions));
- content.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- using var getResponse = await client.PostAsync("/Dlna/Profiles", content).ConfigureAwait(false);
+ using var getResponse = await client.PostAsJsonAsync("/Dlna/Profiles", updatedProfile, _jsonOptions).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.NoContent, getResponse.StatusCode);
}
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/MediaStructureControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/MediaStructureControllerTests.cs
index 19d8381ea..24251013c 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/MediaStructureControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/MediaStructureControllerTests.cs
@@ -1,8 +1,7 @@
using System;
using System.Net;
using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Net.Mime;
+using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Models.LibraryStructureDto;
@@ -71,9 +70,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
Path = "/this/path/doesnt/exist"
};
- using var postContent = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(data, _jsonOptions));
- postContent.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- var response = await client.PostAsync("Library/VirtualFolders/Paths", postContent).ConfigureAwait(false);
+ var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths", data, _jsonOptions).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
@@ -90,9 +87,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
PathInfo = new MediaPathInfo("test")
};
- using var postContent = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(data, _jsonOptions));
- postContent.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- var response = await client.PostAsync("Library/VirtualFolders/Paths/Update", postContent).ConfigureAwait(false);
+ var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths/Update", data, _jsonOptions).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
index 9c0fc72f6..e72dacfe0 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
@@ -1,7 +1,7 @@
using System;
using System.Net;
using System.Net.Http;
-using System.Net.Http.Headers;
+using System.Net.Http.Json;
using System.Net.Mime;
using System.Text.Json;
using System.Threading.Tasks;
@@ -36,9 +36,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
PreferredMetadataLanguage = "nl"
};
- using var postContent = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(config, _jsonOptions));
- postContent.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- using var postResponse = await client.PostAsync("/Startup/Configuration", postContent).ConfigureAwait(false);
+ using var postResponse = await client.PostAsJsonAsync("/Startup/Configuration", config, _jsonOptions).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.NoContent, postResponse.StatusCode);
using var getResponse = await client.GetAsync("/Startup/Configuration").ConfigureAwait(false);
@@ -80,9 +78,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
Password = "NewPassword"
};
- using var postContent = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions));
- postContent.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- var postResponse = await client.PostAsync("/Startup/User", postContent).ConfigureAwait(false);
+ var postResponse = await client.PostAsJsonAsync("/Startup/User", user, _jsonOptions).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.NoContent, postResponse.StatusCode);
var getResponse = await client.GetAsync("/Startup/User").ConfigureAwait(false);
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
index 8866ab53c..588e25a82 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
@@ -3,8 +3,7 @@ using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Net.Mime;
+using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Models.UserDtos;
@@ -31,18 +30,10 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
}
private Task<HttpResponseMessage> CreateUserByName(HttpClient httpClient, CreateUserByName request)
- {
- using var postContent = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(request, _jsonOpions));
- postContent.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- return httpClient.PostAsync("Users/New", postContent);
- }
+ => httpClient.PostAsJsonAsync("Users/New", request, _jsonOpions);
private Task<HttpResponseMessage> UpdateUserPassword(HttpClient httpClient, Guid userId, UpdateUserPassword request)
- {
- using var postContent = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(request, _jsonOpions));
- postContent.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json);
- return httpClient.PostAsync("Users/" + userId.ToString("N", CultureInfo.InvariantCulture) + "/Password", postContent);
- }
+ => httpClient.PostAsJsonAsync("Users/" + userId.ToString("N", CultureInfo.InvariantCulture) + "/Password", request, _jsonOpions);
[Fact]
[Priority(-1)]
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 5b884cddf..a59900b02 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
+++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
@@ -9,7 +9,7 @@
<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.0" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
index 29d7646a6..ada9034df 100644
--- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
+++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
@@ -10,7 +10,7 @@
<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.0" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />