aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-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.csproj13
-rw-r--r--tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs (renamed from tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs)5
-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.Common.Tests/Jellyfin.Common.Tests.csproj4
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs32
-rw-r--r--tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj4
-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.cs57
-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.csproj7
-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
21 files changed, 530 insertions, 83 deletions
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..8a559b7b6 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -14,14 +14,15 @@
<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.AutoMoq" Version="4.13.0" />
+ <PackageReference Include="AutoFixture.Xunit2" Version="4.13.0" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.8" />
+ <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.8" />
+ <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.6" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
index 2029f88e9..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
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.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/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.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/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..83d44721c
--- /dev/null
+++ b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs
@@ -0,0 +1,57 @@
+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 ResolveFile_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);
+ }
+ }
+}
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..75b67f460 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -15,10 +15,11 @@
<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.AutoMoq" Version="4.13.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
+ <PackageReference Include="Moq" Version="4.14.6" />
<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/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>