aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs1
-rw-r--r--tests/Jellyfin.Api.Tests/BrandingServiceTests.cs (renamed from tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs)2
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj15
-rw-r--r--tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs (renamed from tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs)12
-rw-r--r--tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs225
-rw-r--r--tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs17
-rw-r--r--tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs42
-rw-r--r--tests/Jellyfin.Api.Tests/TestHelpers.cs2
-rw-r--r--tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj4
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs92
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedIReadOnlyListTests.cs92
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs32
-rw-r--r--tests/Jellyfin.Common.Tests/Models/GenericBodyArrayModel.cs20
-rw-r--r--tests/Jellyfin.Common.Tests/Models/GenericBodyIReadOnlyListModel.cs19
-rw-r--r--tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj4
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs7
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs26
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs3
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj4
-rw-r--r--tests/Jellyfin.Naming.Tests/AudioBook/AudioBookFileInfoTests.cs30
-rw-r--r--tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs90
-rw-r--r--tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs64
-rw-r--r--tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj4
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs4
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs16
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs18
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj9
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/IgnorePatternsTests.cs3
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs1
-rw-r--r--tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj34
-rw-r--r--tests/jellyfin-tests.ruleset4
31 files changed, 802 insertions, 94 deletions
diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
index 4ea5094b6..33534abd2 100644
--- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
+++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
@@ -128,6 +128,7 @@ namespace Jellyfin.Api.Tests.Auth
var authorizationInfo = _fixture.Create<AuthorizationInfo>();
authorizationInfo.User = _fixture.Create<User>();
authorizationInfo.User.SetPermission(PermissionKind.IsAdministrator, isAdmin);
+ authorizationInfo.IsApiKey = false;
_jellyfinAuthServiceMock.Setup(
a => a.Authenticate(
diff --git a/tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs b/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
index 5d7f7765c..6fc287420 100644
--- a/tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs
+++ b/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Model.Branding;
using Xunit;
-namespace MediaBrowser.Api.Tests
+namespace Jellyfin.Api.Tests
{
public sealed class BrandingServiceTests : IClassFixture<JellyfinApplicationFactory>
{
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index f77eba376..0236f2ac1 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -13,15 +13,16 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="AutoFixture" Version="4.13.0" />
- <PackageReference Include="AutoFixture.AutoMoq" Version="4.12.0" />
- <PackageReference Include="AutoFixture.Xunit2" Version="4.12.0" />
- <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.6" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
+ <PackageReference Include="AutoFixture" Version="4.14.0" />
+ <PackageReference Include="AutoFixture.AutoMoq" Version="4.14.0" />
+ <PackageReference Include="AutoFixture.Xunit2" Version="4.14.0" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.9" />
+ <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.9" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
- <PackageReference Include="Moq" Version="4.14.5" />
+ <PackageReference Include="Moq" Version="4.14.7" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
index c39ed07de..bd3d35687 100644
--- a/tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs
+++ b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Logging;
-namespace MediaBrowser.Api.Tests
+namespace Jellyfin.Api.Tests
{
/// <summary>
/// Factory for bootstrapping the Jellyfin application in memory for functional end to end tests.
@@ -47,8 +47,7 @@ namespace MediaBrowser.Api.Tests
// Specify the startup command line options
var commandLineOpts = new StartupOptions
{
- NoWebClient = true,
- NoAutoRunWebApp = true
+ NoWebClient = true
};
// Use a temporary directory for the application paths
@@ -72,6 +71,7 @@ namespace MediaBrowser.Api.Tests
var startupConfig = Program.CreateAppConfiguration(commandLineOpts, appPaths);
ILoggerFactory loggerFactory = new SerilogLoggerFactory();
+ var serviceCollection = new ServiceCollection();
_disposableComponents.Add(loggerFactory);
// Create the app host and initialize it
@@ -80,10 +80,10 @@ namespace MediaBrowser.Api.Tests
loggerFactory,
commandLineOpts,
new ManagedFileSystem(loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
- new NetworkManager(loggerFactory.CreateLogger<NetworkManager>()));
+ new NetworkManager(loggerFactory.CreateLogger<NetworkManager>()),
+ serviceCollection);
_disposableComponents.Add(appHost);
- var serviceCollection = new ServiceCollection();
- appHost.Init(serviceCollection);
+ appHost.Init();
// Configure the web host builder
Program.ConfigureWebHostBuilder(builder, appHost, serviceCollection, commandLineOpts, startupConfig, appPaths);
diff --git a/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs b/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs
new file mode 100644
index 000000000..89c7d62f7
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Threading.Tasks;
+using Jellyfin.Api.ModelBinders;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.Extensions.Primitives;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.ModelBinders
+{
+ public sealed class CommaDelimitedArrayModelBinderTests
+ {
+ [Fact]
+ public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedStringArrayQuery()
+ {
+ var queryParamName = "test";
+ var queryParamValues = new[] { "lol", "xd" };
+ var queryParamString = "lol,xd";
+ var queryParamType = typeof(string[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ Assert.True(bindingContextMock.Object.Result.IsModelSet);
+ Assert.Equal((string[])bindingContextMock.Object.Result.Model, queryParamValues);
+ }
+
+ [Fact]
+ public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedIntArrayQuery()
+ {
+ var queryParamName = "test";
+ var queryParamValues = new[] { 42, 0 };
+ var queryParamString = "42,0";
+ var queryParamType = typeof(int[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ Assert.True(bindingContextMock.Object.Result.IsModelSet);
+ Assert.Equal((int[])bindingContextMock.Object.Result.Model, queryParamValues);
+ }
+
+ [Fact]
+ public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedEnumArrayQuery()
+ {
+ var queryParamName = "test";
+ var queryParamValues = new[] { TestType.How, TestType.Much };
+ var queryParamString = "How,Much";
+ var queryParamType = typeof(TestType[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ Assert.True(bindingContextMock.Object.Result.IsModelSet);
+ Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
+ }
+
+ [Fact]
+ public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedEnumArrayQueryWithDoubleCommas()
+ {
+ var queryParamName = "test";
+ var queryParamValues = new[] { TestType.How, TestType.Much };
+ var queryParamString = "How,,Much";
+ var queryParamType = typeof(TestType[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ Assert.True(bindingContextMock.Object.Result.IsModelSet);
+ Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
+ }
+
+ [Fact]
+ public async Task BindModelAsync_CorrectlyBindsValidEnumArrayQuery()
+ {
+ var queryParamName = "test";
+ var queryParamValues = new[] { TestType.How, TestType.Much };
+ var queryParamString1 = "How";
+ var queryParamString2 = "Much";
+ var queryParamType = typeof(TestType[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues>
+ {
+ { queryParamName, new StringValues(new[] { queryParamString1, queryParamString2 }) },
+ }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ Assert.True(bindingContextMock.Object.Result.IsModelSet);
+ Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
+ }
+
+ [Fact]
+ public async Task BindModelAsync_CorrectlyBindsEmptyEnumArrayQuery()
+ {
+ var queryParamName = "test";
+ var queryParamValues = Array.Empty<TestType>();
+ var queryParamType = typeof(TestType[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues>
+ {
+ { queryParamName, new StringValues(value: null) },
+ }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ Assert.True(bindingContextMock.Object.Result.IsModelSet);
+ Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
+ }
+
+ [Fact]
+ public async Task BindModelAsync_ThrowsIfCommaDelimitedEnumArrayQueryIsInvalid()
+ {
+ var queryParamName = "test";
+ var queryParamString = "🔥,😢";
+ var queryParamType = typeof(TestType[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ Func<Task> act = async () => await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ await Assert.ThrowsAsync<FormatException>(act);
+ }
+
+ [Fact]
+ public async Task BindModelAsync_ThrowsIfCommaDelimitedEnumArrayQueryIsInvalid2()
+ {
+ var queryParamName = "test";
+ var queryParamString1 = "How";
+ var queryParamString2 = "😱";
+ var queryParamType = typeof(TestType[]);
+
+ var modelBinder = new CommaDelimitedArrayModelBinder();
+
+ var valueProvider = new QueryStringValueProvider(
+ new BindingSource(string.Empty, string.Empty, false, false),
+ new QueryCollection(new Dictionary<string, StringValues>
+ {
+ { queryParamName, new StringValues(new[] { queryParamString1, queryParamString2 }) },
+ }),
+ CultureInfo.InvariantCulture);
+ var bindingContextMock = new Mock<ModelBindingContext>();
+ bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
+ bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
+ bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
+ bindingContextMock.SetupProperty(b => b.Result);
+
+ Func<Task> act = async () => await modelBinder.BindModelAsync(bindingContextMock.Object);
+
+ await Assert.ThrowsAsync<FormatException>(act);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs b/tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs
new file mode 100644
index 000000000..544a74637
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Jellyfin.Api.Tests.ModelBinders
+{
+ public enum TestType
+ {
+#pragma warning disable SA1602 // Enumeration items should be documented
+ How,
+ Much,
+ Is,
+ The,
+ Fish
+#pragma warning restore SA1602 // Enumeration items should be documented
+ }
+}
diff --git a/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs b/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs
new file mode 100644
index 000000000..3a85b5514
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs
@@ -0,0 +1,42 @@
+using System.IO;
+using System.Reflection;
+using System.Text.Json;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Branding;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Jellyfin.Api.Tests
+{
+ public sealed class OpenApiSpecTests : IClassFixture<JellyfinApplicationFactory>
+ {
+ private readonly JellyfinApplicationFactory _factory;
+ private readonly ITestOutputHelper _outputHelper;
+
+ public OpenApiSpecTests(JellyfinApplicationFactory factory, ITestOutputHelper outputHelper)
+ {
+ _factory = factory;
+ _outputHelper = outputHelper;
+ }
+
+ [Fact]
+ public async Task GetSpec_ReturnsCorrectResponse()
+ {
+ // Arrange
+ var client = _factory.CreateClient();
+
+ // Act
+ var response = await client.GetAsync("/api-docs/openapi.json");
+
+ // Assert
+ response.EnsureSuccessStatusCode();
+ Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
+
+ // Write out for publishing
+ var responseBody = await response.Content.ReadAsStringAsync();
+ string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json"));
+ _outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath);
+ File.WriteAllText(outputPath, responseBody);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Api.Tests/TestHelpers.cs b/tests/Jellyfin.Api.Tests/TestHelpers.cs
index a4dd4e409..c4ce39885 100644
--- a/tests/Jellyfin.Api.Tests/TestHelpers.cs
+++ b/tests/Jellyfin.Api.Tests/TestHelpers.cs
@@ -45,7 +45,7 @@ namespace Jellyfin.Api.Tests
{
new Claim(ClaimTypes.Role, role),
new Claim(ClaimTypes.Name, "jellyfin"),
- new Claim(InternalClaimTypes.UserId, Guid.Empty.ToString("N", CultureInfo.InvariantCulture)),
+ new Claim(InternalClaimTypes.UserId, Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)),
new Claim(InternalClaimTypes.DeviceId, Guid.Empty.ToString("N", CultureInfo.InvariantCulture)),
new Claim(InternalClaimTypes.Device, "test"),
new Claim(InternalClaimTypes.Client, "test"),
diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
index 746474044..e3f87d29b 100644
--- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
+++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
@@ -13,9 +13,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs
new file mode 100644
index 000000000..0d2bdd1af
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs
@@ -0,0 +1,92 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Jellyfin.Common.Tests.Models;
+using MediaBrowser.Model.Session;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Json
+{
+ public static class JsonCommaDelimitedArrayTests
+ {
+ [Fact]
+ public static void Deserialize_String_Valid_Success()
+ {
+ var desiredValue = new GenericBodyArrayModel<string>
+ {
+ Value = new[] { "a", "b", "c" }
+ };
+
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": ""a,b,c"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_String_Space_Valid_Success()
+ {
+ var desiredValue = new GenericBodyArrayModel<string>
+ {
+ Value = new[] { "a", "b", "c" }
+ };
+
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": ""a, b, c"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_GenericCommandType_Valid_Success()
+ {
+ var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
+ {
+ Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ };
+
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonStringEnumConverter());
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,MoveDown"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_GenericCommandType_Space_Valid_Success()
+ {
+ var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
+ {
+ Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ };
+
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonStringEnumConverter());
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp, MoveDown"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_String_Array_Valid_Success()
+ {
+ var desiredValue = new GenericBodyArrayModel<string>
+ {
+ Value = new[] { "a", "b", "c" }
+ };
+
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": [""a"",""b"",""c""] }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_GenericCommandType_Array_Valid_Success()
+ {
+ var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
+ {
+ Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ };
+
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonStringEnumConverter());
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedIReadOnlyListTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedIReadOnlyListTests.cs
new file mode 100644
index 000000000..34ad9bac7
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedIReadOnlyListTests.cs
@@ -0,0 +1,92 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Jellyfin.Common.Tests.Models;
+using MediaBrowser.Model.Session;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Json
+{
+ public static class JsonCommaDelimitedIReadOnlyListTests
+ {
+ [Fact]
+ public static void Deserialize_String_Valid_Success()
+ {
+ var desiredValue = new GenericBodyIReadOnlyListModel<string>
+ {
+ Value = new[] { "a", "b", "c" }
+ };
+
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": ""a,b,c"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_String_Space_Valid_Success()
+ {
+ var desiredValue = new GenericBodyIReadOnlyListModel<string>
+ {
+ Value = new[] { "a", "b", "c" }
+ };
+
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": ""a, b, c"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_GenericCommandType_Valid_Success()
+ {
+ var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
+ {
+ Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ };
+
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonStringEnumConverter());
+ var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,MoveDown"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_GenericCommandType_Space_Valid_Success()
+ {
+ var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
+ {
+ Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ };
+
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonStringEnumConverter());
+ var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp, MoveDown"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_String_Array_Valid_Success()
+ {
+ var desiredValue = new GenericBodyIReadOnlyListModel<string>
+ {
+ Value = new[] { "a", "b", "c" }
+ };
+
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": [""a"",""b"",""c""] }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_GenericCommandType_Array_Valid_Success()
+ {
+ var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
+ {
+ Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ };
+
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonStringEnumConverter());
+ var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs
new file mode 100644
index 000000000..d9e66d677
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Text.Json;
+using MediaBrowser.Common.Json.Converters;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Extensions
+{
+ public static class JsonGuidConverterTests
+ {
+ [Fact]
+ public static void Deserialize_Valid_Success()
+ {
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonGuidConverter());
+ Guid value = JsonSerializer.Deserialize<Guid>(@"""a852a27afe324084ae66db579ee3ee18""", options);
+ Assert.Equal(new Guid("a852a27afe324084ae66db579ee3ee18"), value);
+
+ value = JsonSerializer.Deserialize<Guid>(@"""e9b2dcaa-529c-426e-9433-5e9981f27f2e""", options);
+ Assert.Equal(new Guid("e9b2dcaa-529c-426e-9433-5e9981f27f2e"), value);
+ }
+
+ [Fact]
+ public static void Roundtrip_Valid_Success()
+ {
+ var options = new JsonSerializerOptions();
+ options.Converters.Add(new JsonGuidConverter());
+ Guid guid = new Guid("a852a27afe324084ae66db579ee3ee18");
+ string value = JsonSerializer.Serialize(guid, options);
+ Assert.Equal(guid, JsonSerializer.Deserialize<Guid>(value, options));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Models/GenericBodyArrayModel.cs b/tests/Jellyfin.Common.Tests/Models/GenericBodyArrayModel.cs
new file mode 100644
index 000000000..276e1bfbe
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Models/GenericBodyArrayModel.cs
@@ -0,0 +1,20 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Text.Json.Serialization;
+using MediaBrowser.Common.Json.Converters;
+
+namespace Jellyfin.Common.Tests.Models
+{
+ /// <summary>
+ /// The generic body model.
+ /// </summary>
+ /// <typeparam name="T">The value type.</typeparam>
+ public class GenericBodyArrayModel<T>
+ {
+ /// <summary>
+ /// Gets or sets the value.
+ /// </summary>
+ [SuppressMessage("Microsoft.Performance", "CA1819:Properties should not return arrays", MessageId = "Value", Justification = "Imported from ServiceStack")]
+ [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ public T[] Value { get; set; } = default!;
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Models/GenericBodyIReadOnlyListModel.cs b/tests/Jellyfin.Common.Tests/Models/GenericBodyIReadOnlyListModel.cs
new file mode 100644
index 000000000..627454b25
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Models/GenericBodyIReadOnlyListModel.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+using MediaBrowser.Common.Json.Converters;
+
+namespace Jellyfin.Common.Tests.Models
+{
+ /// <summary>
+ /// The generic body <c>IReadOnlyList</c> model.
+ /// </summary>
+ /// <typeparam name="T">The value type.</typeparam>
+ public class GenericBodyIReadOnlyListModel<T>
+ {
+ /// <summary>
+ /// Gets or sets the value.
+ /// </summary>
+ [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ public IReadOnlyList<T> Value { get; set; } = default!;
+ }
+}
diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
index 1559f70ab..5de02a29b 100644
--- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
+++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
@@ -13,9 +13,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
index 9eb601edf..39fd8afda 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
@@ -13,15 +13,18 @@ namespace Jellyfin.MediaEncoding.Tests
[ClassData(typeof(GetFFmpegVersionTestData))]
public void GetFFmpegVersionTest(string versionOutput, Version? version)
{
- Assert.Equal(version, EncoderValidator.GetFFmpegVersion(versionOutput));
+ var val = new EncoderValidator(new NullLogger<EncoderValidatorTests>());
+ Assert.Equal(version, val.GetFFmpegVersion(versionOutput));
}
[Theory]
+ [InlineData(EncoderValidatorTestsData.FFmpegV431Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV43Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV421Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV42Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV414Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV404Output, true)]
+ [InlineData(EncoderValidatorTestsData.FFmpegGitUnknownOutput2, true)]
[InlineData(EncoderValidatorTestsData.FFmpegGitUnknownOutput, false)]
public void ValidateVersionInternalTest(string versionOutput, bool valid)
{
@@ -33,11 +36,13 @@ namespace Jellyfin.MediaEncoding.Tests
{
public IEnumerator<object?[]> GetEnumerator()
{
+ yield return new object?[] { EncoderValidatorTestsData.FFmpegV431Output, new Version(4, 3, 1) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV43Output, new Version(4, 3) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4) };
+ yield return new object?[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput2, new Version(4, 0) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput, null };
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs
index f5ff3d723..9f5bef9a8 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs
@@ -2,6 +2,18 @@ namespace Jellyfin.MediaEncoding.Tests
{
internal static class EncoderValidatorTestsData
{
+ public const string FFmpegV431Output = @"ffmpeg version n4.3.1 Copyright (c) 2000-2020 the FFmpeg developers
+built with gcc 10.1.0 (GCC)
+configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-avisynth --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librav1e --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3
+libavutil 56. 51.100 / 56. 51.100
+libavcodec 58. 91.100 / 58. 91.100
+libavformat 58. 45.100 / 58. 45.100
+libavdevice 58. 10.100 / 58. 10.100
+libavfilter 7. 85.100 / 7. 85.100
+libswscale 5. 7.100 / 5. 7.100
+libswresample 3. 7.100 / 3. 7.100
+libpostproc 55. 7.100 / 55. 7.100";
+
public const string FFmpegV43Output = @"ffmpeg version 4.3 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
configuration: --prefix=/usr/lib/jellyfin-ffmpeg --target-os=linux --disable-doc --disable-ffplay --disable-shared --disable-libxcb --disable-vdpau --disable-sdl2 --disable-xlib --enable-gpl --enable-version3 --enable-static --enable-libfontconfig --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libx264 --enable-libx265 --enable-libzvbi --arch=amd64 --enable-amf --enable-nvenc --enable-nvdec --enable-vaapi --enable-opencl
@@ -63,7 +75,7 @@ libswscale 5. 1.100 / 5. 1.100
libswresample 3. 1.100 / 3. 1.100
libpostproc 55. 1.100 / 55. 1.100";
- public const string FFmpegGitUnknownOutput = @"ffmpeg version N-94303-g7cb4f8c962 Copyright (c) 2000-2019 the FFmpeg developers
+ public const string FFmpegGitUnknownOutput2 = @"ffmpeg version N-94303-g7cb4f8c962 Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 9.1.1 (GCC) 20190716
configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
libavutil 56. 30.100 / 56. 30.100
@@ -74,5 +86,17 @@ libavfilter 7. 56.101 / 7. 56.101
libswscale 5. 4.101 / 5. 4.101
libswresample 3. 4.100 / 3. 4.100
libpostproc 55. 4.100 / 55. 4.100";
+
+ public const string FFmpegGitUnknownOutput = @"ffmpeg version N-45325-gb173e0353-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2018 the FFmpeg developers
+built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
+configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-6 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gray --enable-libfribidi --enable-libass --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libzimg
+libavutil 56. 9.100 / 56. 9.100
+libavcodec 58. 14.100 / 58. 14.100
+libavformat 58. 10.100 / 58. 10.100
+libavdevice 58. 2.100 / 58. 2.100
+libavfilter 7. 13.100 / 7. 13.100
+libswscale 5. 0.102 / 5. 0.102
+libswresample 3. 0.101 / 3. 0.101
+libpostproc 55. 0.100 / 55. 0.100";
}
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs
index 2032f6cec..c39ef0ce9 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs
@@ -1,6 +1,7 @@
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
+using MediaBrowser.Common.Json;
using MediaBrowser.MediaEncoding.Probing;
using Xunit;
@@ -15,7 +16,7 @@ namespace Jellyfin.MediaEncoding.Tests
var path = Path.Join("Test Data", fileName);
using (var stream = File.OpenRead(path))
{
- await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream).ConfigureAwait(false);
+ await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream, JsonDefaults.GetOptions()).ConfigureAwait(false);
}
}
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
index e1a089547..3ac60819b 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
@@ -19,9 +19,9 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
diff --git a/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookFileInfoTests.cs b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookFileInfoTests.cs
new file mode 100644
index 000000000..a214bc57c
--- /dev/null
+++ b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookFileInfoTests.cs
@@ -0,0 +1,30 @@
+using Emby.Naming.AudioBook;
+using Xunit;
+
+namespace Jellyfin.Naming.Tests.AudioBook
+{
+ public class AudioBookFileInfoTests
+ {
+ [Fact]
+ public void CompareTo_Same_Success()
+ {
+ var info = new AudioBookFileInfo();
+ Assert.Equal(0, info.CompareTo(info));
+ }
+
+ [Fact]
+ public void CompareTo_Null_Success()
+ {
+ var info = new AudioBookFileInfo();
+ Assert.Equal(1, info.CompareTo(null));
+ }
+
+ [Fact]
+ public void CompareTo_Empty_Success()
+ {
+ var info1 = new AudioBookFileInfo();
+ var info2 = new AudioBookFileInfo();
+ Assert.Equal(0, info1.CompareTo(info2));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs
new file mode 100644
index 000000000..1084e20bd
--- /dev/null
+++ b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs
@@ -0,0 +1,90 @@
+using System.Linq;
+using Emby.Naming.AudioBook;
+using Emby.Naming.Common;
+using MediaBrowser.Model.IO;
+using Xunit;
+
+namespace Jellyfin.Naming.Tests.AudioBook
+{
+ public class AudioBookListResolverTests
+ {
+ private readonly NamingOptions _namingOptions = new NamingOptions();
+
+ [Fact]
+ public void TestStackAndExtras()
+ {
+ // No stacking here because there is no part/disc/etc
+ var files = new[]
+ {
+ "Harry Potter and the Deathly Hallows/Part 1.mp3",
+ "Harry Potter and the Deathly Hallows/Part 2.mp3",
+ "Harry Potter and the Deathly Hallows/book.nfo",
+
+ "Batman/Chapter 1.mp3",
+ "Batman/Chapter 2.mp3",
+ "Batman/Chapter 3.mp3",
+ };
+
+ var resolver = GetResolver();
+
+ var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ {
+ IsDirectory = false,
+ FullName = i
+ })).ToList();
+
+ Assert.Equal(2, result[0].Files.Count);
+ // Assert.Empty(result[0].Extras); FIXME: AudioBookListResolver should resolve extra files properly
+ Assert.Equal("Harry Potter and the Deathly Hallows", result[0].Name);
+
+ Assert.Equal(3, result[1].Files.Count);
+ Assert.Empty(result[1].Extras);
+ Assert.Equal("Batman", result[1].Name);
+ }
+
+ [Fact]
+ public void TestWithMetadata()
+ {
+ var files = new[]
+ {
+ "Harry Potter and the Deathly Hallows/Chapter 1.ogg",
+ "Harry Potter and the Deathly Hallows/Harry Potter and the Deathly Hallows.nfo"
+ };
+
+ var resolver = GetResolver();
+
+ var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ {
+ IsDirectory = false,
+ FullName = i
+ }));
+
+ Assert.Single(result);
+ }
+
+ [Fact]
+ public void TestWithExtra()
+ {
+ var files = new[]
+ {
+ "Harry Potter and the Deathly Hallows/Chapter 1.mp3",
+ "Harry Potter and the Deathly Hallows/Harry Potter and the Deathly Hallows trailer.mp3"
+ };
+
+ var resolver = GetResolver();
+
+ var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ {
+ IsDirectory = false,
+ FullName = i
+ })).ToList();
+
+ Assert.Single(result);
+ }
+
+ private AudioBookListResolver GetResolver()
+ {
+ return new AudioBookListResolver(_namingOptions);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs
new file mode 100644
index 000000000..673289436
--- /dev/null
+++ b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using Emby.Naming.AudioBook;
+using Emby.Naming.Common;
+using Xunit;
+
+namespace Jellyfin.Naming.Tests.AudioBook
+{
+ public class AudioBookResolverTests
+ {
+ private readonly NamingOptions _namingOptions = new NamingOptions();
+
+ public static IEnumerable<object[]> GetResolveFileTestData()
+ {
+ yield return new object[]
+ {
+ new AudioBookFileInfo()
+ {
+ Path = @"/server/AudioBooks/Larry Potter/Larry Potter.mp3",
+ Container = "mp3",
+ }
+ };
+ yield return new object[]
+ {
+ new AudioBookFileInfo()
+ {
+ Path = @"/server/AudioBooks/Berry Potter/Chapter 1 .ogg",
+ Container = "ogg",
+ ChapterNumber = 1
+ }
+ };
+ yield return new object[]
+ {
+ new AudioBookFileInfo()
+ {
+ Path = @"/server/AudioBooks/Nerry Potter/Part 3 - Chapter 2.mp3",
+ Container = "mp3",
+ ChapterNumber = 2,
+ PartNumber = 3
+ }
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(GetResolveFileTestData))]
+ public void Resolve_ValidFileName_Success(AudioBookFileInfo expectedResult)
+ {
+ var result = new AudioBookResolver(_namingOptions).Resolve(expectedResult.Path);
+
+ Assert.NotNull(result);
+ Assert.Equal(result!.Path, expectedResult.Path);
+ Assert.Equal(result!.Container, expectedResult.Container);
+ Assert.Equal(result!.ChapterNumber, expectedResult.ChapterNumber);
+ Assert.Equal(result!.PartNumber, expectedResult.PartNumber);
+ Assert.Equal(result!.IsDirectory, expectedResult.IsDirectory);
+ }
+
+ [Fact]
+ public void Resolve_EmptyFileName_ArgumentException()
+ {
+ Assert.Throws<ArgumentException>(() => new AudioBookResolver(_namingOptions).Resolve(string.Empty));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
index 0e9e91563..37d0a9929 100644
--- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
+++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
@@ -13,9 +13,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
diff --git a/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs b/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs
index 917d8fb3a..ed971eed7 100644
--- a/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/CleanDateTimeTests.cs
@@ -47,6 +47,10 @@ namespace Jellyfin.Naming.Tests.Video
// FIXME: [InlineData("Robin Hood [Multi-Subs] [2018].mkv", "Robin Hood", 2018)]
[InlineData(@"3.Days.to.Kill.2014.720p.BluRay.x264.YIFY.mkv", "3.Days.to.Kill", 2014)] // In this test case, running CleanDateTime first produces no date, so it will attempt to run CleanString first and then CleanDateTime again
[InlineData("3 days to kill (2005).mkv", "3 days to kill", 2005)]
+ [InlineData("My Movie 2013.12.09", "My Movie 2013.12.09", null)]
+ [InlineData("My Movie 2013-12-09", "My Movie 2013-12-09", null)]
+ [InlineData("My Movie 20131209", "My Movie 20131209", null)]
+ [InlineData("My Movie 2013-12-09 2013", "My Movie 2013-12-09", 2013)]
public void CleanDateTimeTest(string input, string expectedName, int? expectedYear)
{
input = Path.GetFileName(input);
diff --git a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
index a2722a175..8dfb8f859 100644
--- a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs
@@ -44,14 +44,14 @@ namespace Jellyfin.Naming.Tests.Video
}
[Theory]
- [InlineData(ExtraType.BehindTheScenes, "behind the scenes" )]
- [InlineData(ExtraType.DeletedScene, "deleted scenes" )]
- [InlineData(ExtraType.Interview, "interviews" )]
- [InlineData(ExtraType.Scene, "scenes" )]
- [InlineData(ExtraType.Sample, "samples" )]
- [InlineData(ExtraType.Clip, "shorts" )]
- [InlineData(ExtraType.Clip, "featurettes" )]
- [InlineData(ExtraType.Unknown, "extras" )]
+ [InlineData(ExtraType.BehindTheScenes, "behind the scenes")]
+ [InlineData(ExtraType.DeletedScene, "deleted scenes")]
+ [InlineData(ExtraType.Interview, "interviews")]
+ [InlineData(ExtraType.Scene, "scenes")]
+ [InlineData(ExtraType.Sample, "samples")]
+ [InlineData(ExtraType.Clip, "shorts")]
+ [InlineData(ExtraType.Clip, "featurettes")]
+ [InlineData(ExtraType.Unknown, "extras")]
public void TestDirectories(ExtraType type, string dirName)
{
Test(dirName + "/300.mp4", type, _videoOptions);
diff --git a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs
deleted file mode 100644
index 39bd94b59..000000000
--- a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Emby.Server.Implementations.HttpServer;
-using Xunit;
-
-namespace Jellyfin.Server.Implementations.Tests.HttpServer
-{
- public class ResponseFilterTests
- {
- [Theory]
- [InlineData(null, null)]
- [InlineData("", "")]
- [InlineData("This is a clean string.", "This is a clean string.")]
- [InlineData("This isn't \n\ra clean string.", "This isn't a clean string.")]
- public void RemoveControlCharacters_ValidArgs_Correct(string? input, string? result)
- {
- Assert.Equal(result, ResponseFilter.RemoveControlCharacters(input));
- }
- }
-}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
index 03187f4b9..05323490e 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -14,11 +14,12 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="AutoFixture" Version="4.13.0" />
- <PackageReference Include="AutoFixture.AutoMoq" Version="4.12.0" />
- <PackageReference Include="Moq" Version="4.14.5" />
+ <PackageReference Include="AutoFixture" Version="4.14.0" />
+ <PackageReference Include="AutoFixture.AutoMoq" Version="4.14.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
+ <PackageReference Include="Moq" Version="4.14.7" />
<PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/IgnorePatternsTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/IgnorePatternsTests.cs
index b4e6db8f3..09eb22328 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/IgnorePatternsTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/IgnorePatternsTests.cs
@@ -30,8 +30,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[InlineData("/media/movies/.@__thumb/foo-bar-thumbnail.png", true)]
[InlineData("/media/music/Foo B.A.R./epic.flac", false)]
[InlineData("/media/music/Foo B.A.R", false)]
- // This test is pending an upstream fix: https://github.com/dazinator/DotNet.Glob/issues/78
- // [InlineData("/media/music/Foo B.A.R.", false)]
+ [InlineData("/media/music/Foo B.A.R.", false)]
public void PathIgnored(string path, bool expected)
{
Assert.Equal(expected, IgnorePatterns.ShouldIgnore(path));
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
index c771f5f4a..6d768af89 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
@@ -10,6 +10,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[InlineData("Superman: Red Son [imdbid=tt10985510]", "imdbid", "tt10985510")]
[InlineData("Superman: Red Son - tt10985510", "imdbid", "tt10985510")]
[InlineData("Superman: Red Son", "imdbid", null)]
+ [InlineData("Superman: Red Son", "something", null)]
public void GetAttributeValue_ValidArgs_Correct(string input, string attribute, string? expectedResult)
{
Assert.Equal(expectedResult, PathExtensions.GetAttributeValue(input, attribute));
diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj
deleted file mode 100644
index a4ef10648..000000000
--- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj
+++ /dev/null
@@ -1,34 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>netcoreapp3.1</TargetFramework>
- <IsPackable>false</IsPackable>
- <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
- <Nullable>enable</Nullable>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.6" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
- <PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
- <PackageReference Include="coverlet.collector" Version="1.3.0" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\..\Jellyfin.Server\Jellyfin.Server.csproj" />
- </ItemGroup>
-
- <!-- Code Analyzers -->
- <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
- <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
- <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
- <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
- <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
- </ItemGroup>
-
- <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
- <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
-
-</Project>
diff --git a/tests/jellyfin-tests.ruleset b/tests/jellyfin-tests.ruleset
index 5a113e955..e2abaf5bb 100644
--- a/tests/jellyfin-tests.ruleset
+++ b/tests/jellyfin-tests.ruleset
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<RuleSet Name="Rules for MediaBrowser.Api.Tests" Description="Code analysis rules for MediaBrowser.Api.Tests.csproj" ToolsVersion="14.0">
+<RuleSet Name="Rules for Jellyfin.Api.Tests" Description="Code analysis rules for Jellyfin.Api.Tests.csproj" ToolsVersion="14.0">
<!-- Include the solution default RuleSet. The rules in this file will override the defaults. -->
<Include Path="../jellyfin.ruleset" Action="Default" />
@@ -17,6 +17,6 @@
<!-- CA2007: Consider calling ConfigureAwait on the awaited task -->
<Rule Id="CA2007" Action="None" />
<!-- CA2234: Pass system uri objects instead of strings -->
- <Rule Id="CA2234" Action="Info" />
+ <Rule Id="CA2234" Action="Info" />
</Rules>
</RuleSet>