mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-03 22:38:30 +01:00
Merge branch 'master' into tests11
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Branding;
|
||||
@@ -5,11 +7,11 @@ using Xunit;
|
||||
|
||||
namespace Jellyfin.Api.Tests
|
||||
{
|
||||
public sealed class BrandingServiceTests : IClassFixture<JellyfinApplicationFactory>
|
||||
public sealed class BrandingControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
|
||||
public BrandingServiceTests(JellyfinApplicationFactory factory)
|
||||
public BrandingControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
@@ -24,8 +26,9 @@ namespace Jellyfin.Api.Tests
|
||||
var response = await client.GetAsync("/Branding/Configuration");
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType?.ToString());
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
var responseBody = await response.Content.ReadAsStreamAsync();
|
||||
_ = await JsonSerializer.DeserializeAsync<BrandingOptions>(responseBody);
|
||||
}
|
||||
@@ -42,8 +45,9 @@ namespace Jellyfin.Api.Tests
|
||||
var response = await client.GetAsync(url);
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal("text/css; charset=utf-8", response.Content.Headers.ContentType?.ToString());
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
Assert.Equal("text/css", response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models;
|
||||
using MediaBrowser.Common.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Api.Tests.Controllers
|
||||
{
|
||||
public sealed class DashboardControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOpions = JsonDefaults.GetOptions();
|
||||
|
||||
public DashboardControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDashboardConfigurationPage_NonExistingPage_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("web/ConfigurationPage?name=ThisPageDoesntExists").ConfigureAwait(false);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDashboardConfigurationPage_ExistingPage_CorrectPage()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/web/ConfigurationPage?name=TestPlugin").ConfigureAwait(false);
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
Assert.Equal(MediaTypeNames.Text.Html, response.Content.Headers.ContentType?.MediaType);
|
||||
StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Api.Tests.TestPage.html")!);
|
||||
Assert.Equal(await response.Content.ReadAsStringAsync(), reader.ReadToEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDashboardConfigurationPage_BrokenPage_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/web/ConfigurationPage?name=BrokenPage").ConfigureAwait(false);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetConfigurationPages_NoParams_AllConfigurationPages()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/web/ConfigurationPages").ConfigureAwait(false);
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
|
||||
var res = await response.Content.ReadAsStreamAsync();
|
||||
_ = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(res, _jsonOpions);
|
||||
// TODO: check content
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetConfigurationPages_True_MainMenuConfigurationPages()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/web/ConfigurationPages?enableInMainMenu=true").ConfigureAwait(false);
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
|
||||
var res = await response.Content.ReadAsStreamAsync();
|
||||
var data = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(res, _jsonOpions);
|
||||
Assert.Empty(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
<PackageReference Include="Moq" Version="4.16.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -41,4 +41,8 @@
|
||||
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="TestPage.html" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Jellyfin.Api.Tests
|
||||
_disposableComponents.Add(loggerFactory);
|
||||
|
||||
// Create the app host and initialize it
|
||||
var appHost = new CoreAppHost(
|
||||
var appHost = new TestAppHost(
|
||||
appPaths,
|
||||
loggerFactory,
|
||||
commandLineOpts,
|
||||
@@ -93,7 +93,7 @@ namespace Jellyfin.Api.Tests
|
||||
var testServer = base.CreateServer(builder);
|
||||
|
||||
// Finish initializing the app host
|
||||
var appHost = (CoreAppHost)testServer.Services.GetRequiredService<IApplicationHost>();
|
||||
var appHost = (TestAppHost)testServer.Services.GetRequiredService<IApplicationHost>();
|
||||
appHost.ServiceProvider = testServer.Services;
|
||||
appHost.InitializeServices().GetAwaiter().GetResult();
|
||||
appHost.RunStartupTasksAsync().GetAwaiter().GetResult();
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,28 +37,28 @@ namespace Jellyfin.Api.Tests
|
||||
EnableIPV6 = ip6
|
||||
};
|
||||
|
||||
var result = match + ',';
|
||||
var result = match + ",";
|
||||
ForwardedHeadersOptions options = new ForwardedHeadersOptions();
|
||||
|
||||
// Need this here as ::1 and 127.0.0.1 are in them by default.
|
||||
options.KnownProxies.Clear();
|
||||
options.KnownNetworks.Clear();
|
||||
|
||||
ApiServiceCollectionExtensions.AddProxyAddresses(settings, hostList.Split(","), options);
|
||||
ApiServiceCollectionExtensions.AddProxyAddresses(settings, hostList.Split(','), options);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var item in options.KnownProxies)
|
||||
{
|
||||
sb.Append(item);
|
||||
sb.Append(',');
|
||||
sb.Append(item)
|
||||
.Append(',');
|
||||
}
|
||||
|
||||
foreach (var item in options.KnownNetworks)
|
||||
{
|
||||
sb.Append(item.Prefix);
|
||||
sb.Append('/');
|
||||
sb.Append(item.PrefixLength.ToString(CultureInfo.InvariantCulture));
|
||||
sb.Append(',');
|
||||
sb.Append(item.Prefix)
|
||||
.Append('/')
|
||||
.Append(item.PrefixLength.ToString(CultureInfo.InvariantCulture))
|
||||
.Append(',');
|
||||
}
|
||||
|
||||
Assert.Equal(sb.ToString(), result);
|
||||
|
||||
51
tests/Jellyfin.Api.Tests/TestAppHost.cs
Normal file
51
tests/Jellyfin.Api.Tests/TestAppHost.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Emby.Server.Implementations;
|
||||
using Jellyfin.Server;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Api.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of the abstract <see cref="ApplicationHost" /> class.
|
||||
/// </summary>
|
||||
public class TestAppHost : CoreAppHost
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TestAppHost" /> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationPaths">The <see cref="ServerApplicationPaths" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="collection">The <see cref="IServiceCollection"/> to be used by the <see cref="CoreAppHost"/>.</param>
|
||||
public TestAppHost(
|
||||
IServerApplicationPaths applicationPaths,
|
||||
ILoggerFactory loggerFactory,
|
||||
IStartupOptions options,
|
||||
IFileSystem fileSystem,
|
||||
IServiceCollection collection)
|
||||
: base(
|
||||
applicationPaths,
|
||||
loggerFactory,
|
||||
options,
|
||||
fileSystem,
|
||||
collection)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IEnumerable<Assembly> GetAssembliesWithPartsInternal()
|
||||
{
|
||||
foreach (var a in base.GetAssembliesWithPartsInternal())
|
||||
{
|
||||
yield return a;
|
||||
}
|
||||
|
||||
yield return typeof(TestPlugin).Assembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
tests/Jellyfin.Api.Tests/TestPage.html
Normal file
9
tests/Jellyfin.Api.Tests/TestPage.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TestPlugin</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>This is a Test Page.</h1>
|
||||
</body>
|
||||
</html>
|
||||
43
tests/Jellyfin.Api.Tests/TestPlugin.cs
Normal file
43
tests/Jellyfin.Api.Tests/TestPlugin.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Model.Plugins;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Jellyfin.Api.Tests
|
||||
{
|
||||
public class TestPlugin : BasePlugin<BasePluginConfiguration>, IHasWebPages
|
||||
{
|
||||
public TestPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||
: base(applicationPaths, xmlSerializer)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public static TestPlugin? Instance { get; private set; }
|
||||
|
||||
public override Guid Id => new Guid("2d350a13-0bf7-4b61-859c-d5e601b5facf");
|
||||
|
||||
public override string Name => nameof(TestPlugin);
|
||||
|
||||
public override string Description => "Server test Plugin.";
|
||||
|
||||
public IEnumerable<PluginPageInfo> GetPages()
|
||||
{
|
||||
yield return new PluginPageInfo
|
||||
{
|
||||
Name = Name,
|
||||
EmbeddedResourcePath = GetType().Namespace + ".TestPage.html"
|
||||
};
|
||||
|
||||
yield return new PluginPageInfo
|
||||
{
|
||||
Name = "BrokenPage",
|
||||
EmbeddedResourcePath = GetType().Namespace + ".foobar"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Common.Tests.Extensions
|
||||
{
|
||||
public class StringExtensionsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("", 'q', "")]
|
||||
[InlineData("Banana split", ' ', "Banana")]
|
||||
[InlineData("Banana split", 'q', "Banana split")]
|
||||
public void LeftPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult)
|
||||
{
|
||||
var result = str.AsSpan().LeftPart(needle).ToString();
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", "", "")]
|
||||
[InlineData("", "q", "")]
|
||||
[InlineData("Banana split", "", "")]
|
||||
[InlineData("Banana split", " ", "Banana")]
|
||||
[InlineData("Banana split test", " split", "Banana")]
|
||||
public void LeftPart_ValidArgsWithoutStringComparison_Correct(string str, string needle, string expectedResult)
|
||||
{
|
||||
var result = str.AsSpan().LeftPart(needle).ToString();
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", "", StringComparison.Ordinal, "")]
|
||||
[InlineData("Banana split", " ", StringComparison.Ordinal, "Banana")]
|
||||
[InlineData("Banana split test", " split", StringComparison.Ordinal, "Banana")]
|
||||
[InlineData("Banana split test", " Split", StringComparison.Ordinal, "Banana split test")]
|
||||
[InlineData("Banana split test", " Splït", StringComparison.InvariantCultureIgnoreCase, "Banana split test")]
|
||||
public void LeftPart_ValidArgs_Correct(string str, string needle, StringComparison stringComparison, string expectedResult)
|
||||
{
|
||||
var result = str.AsSpan().LeftPart(needle, stringComparison).ToString();
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code Analyzers -->
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code Analyzers -->
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code Analyzers -->
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code Analyzers -->
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using MediaBrowser.MediaEncoding.Subtitles;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.MediaEncoding.Subtitles.Tests
|
||||
@@ -14,25 +15,15 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
|
||||
{
|
||||
using (var stream = File.OpenRead("Test Data/example.ass"))
|
||||
{
|
||||
var parsed = new AssParser().Parse(stream, CancellationToken.None);
|
||||
var parsed = new AssParser(new NullLogger<AssParser>()).Parse(stream, CancellationToken.None);
|
||||
Assert.Single(parsed.TrackEvents);
|
||||
var trackEvent = parsed.TrackEvents[0];
|
||||
|
||||
Assert.Equal("1", trackEvent.Id);
|
||||
Assert.Equal(TimeSpan.Parse("00:00:01.18", CultureInfo.InvariantCulture).Ticks, trackEvent.StartPositionTicks);
|
||||
Assert.Equal(TimeSpan.Parse("00:00:06.85", CultureInfo.InvariantCulture).Ticks, trackEvent.EndPositionTicks);
|
||||
Assert.Equal("Like an Angel with pity on nobody\r\nThe second line in subtitle", trackEvent.Text);
|
||||
Assert.Equal("{\\pos(400,570)}Like an Angel with pity on nobody" + Environment.NewLine + "The second line in subtitle", trackEvent.Text);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseFieldHeaders_Valid_Success()
|
||||
{
|
||||
const string Line = "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
|
||||
var headers = AssParser.ParseFieldHeaders(Line);
|
||||
Assert.Equal(1, headers["Start"]);
|
||||
Assert.Equal(2, headers["End"]);
|
||||
Assert.Equal(9, headers["Text"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
|
||||
Assert.Equal("1", trackEvent1.Id);
|
||||
Assert.Equal(TimeSpan.Parse("00:02:17.440", CultureInfo.InvariantCulture).Ticks, trackEvent1.StartPositionTicks);
|
||||
Assert.Equal(TimeSpan.Parse("00:02:20.375", CultureInfo.InvariantCulture).Ticks, trackEvent1.EndPositionTicks);
|
||||
Assert.Equal("Senator, we're making\r\nour final approach into Coruscant.", trackEvent1.Text);
|
||||
Assert.Equal("Senator, we're making" + Environment.NewLine + "our final approach into Coruscant.", trackEvent1.Text);
|
||||
|
||||
var trackEvent2 = parsed.TrackEvents[1];
|
||||
Assert.Equal("2", trackEvent2.Id);
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using MediaBrowser.MediaEncoding.Subtitles;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.MediaEncoding.Tests
|
||||
namespace Jellyfin.MediaEncoding.Subtitles.Tests
|
||||
{
|
||||
public class SsaParserTests
|
||||
{
|
||||
// commonly shared invariant value between tests, assumes default format order
|
||||
private const string InvariantDialoguePrefix = "[Events]\nDialogue: ,0:00:00.00,0:00:00.01,,,,,,,";
|
||||
|
||||
private SsaParser parser = new SsaParser();
|
||||
private readonly SsaParser _parser = new SsaParser(new NullLogger<AssParser>());
|
||||
|
||||
[Theory]
|
||||
[InlineData("[EvEnTs]\nDialogue: ,0:00:00.00,0:00:00.01,,,,,,,text", "text")] // label casing insensitivity
|
||||
[InlineData("[Events]\n,0:00:00.00,0:00:00.01,,,,,,,labelless dialogue", "labelless dialogue")] // no "Dialogue:" label, it is optional
|
||||
[InlineData("[Events]\nFormat: Text, Start, End, Layer, Effect, Style\nDialogue: reordered text,0:00:00.00,0:00:00.01", "reordered text")] // reordered formats
|
||||
// TODO: Fix upstream
|
||||
// [InlineData("[Events]\nFormat: Text, Start, End, Layer, Effect, Style\nDialogue: reordered text,0:00:00.00,0:00:00.01", "reordered text")] // reordered formats
|
||||
[InlineData(InvariantDialoguePrefix + "Cased TEXT", "Cased TEXT")] // preserve text casing
|
||||
[InlineData(InvariantDialoguePrefix + " text ", " text ")] // do not trim text
|
||||
[InlineData(InvariantDialoguePrefix + "text, more text", "text, more text")] // append excess dialogue values (> 10) to text
|
||||
[InlineData(InvariantDialoguePrefix + "start {\\fnFont Name}text{\\fn} end", "start <font face=\"Font Name\">text</font> end")] // font name
|
||||
[InlineData(InvariantDialoguePrefix + "start {\\fs10}text{\\fs} end", "start <font size=\"10\">text</font> end")] // font size
|
||||
[InlineData(InvariantDialoguePrefix + "start {\\c&H112233}text{\\c} end", "start <font color=\"#332211\">text</font> end")] // color
|
||||
[InlineData(InvariantDialoguePrefix + "start {\\1c&H112233}text{\\1c} end", "start <font color=\"#332211\">text</font> end")] // primay color
|
||||
[InlineData(InvariantDialoguePrefix + "start {\\fnFont Name}text1 {\\fs10}text2{\\fs}{\\fn} {\\1c&H112233}text3{\\1c} end", "start <font face=\"Font Name\">text1 <font size=\"10\">text2</font></font> <font color=\"#332211\">text3</font> end")] // nested formatting
|
||||
// TODO: Fix upstream
|
||||
// [InlineData(InvariantDialoguePrefix + "start {\\1c&H112233}text{\\1c} end", "start <font color=\"#332211\">text</font> end")] // primay color
|
||||
// [InlineData(InvariantDialoguePrefix + "start {\\fnFont Name}text1 {\\fs10}text2{\\fs}{\\fn} {\\1c&H112233}text3{\\1c} end", "start <font face=\"Font Name\">text1 <font size=\"10\">text2</font></font> <font color=\"#332211\">text3</font> end")] // nested formatting
|
||||
public void Parse(string ssa, string expectedText)
|
||||
{
|
||||
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa)))
|
||||
{
|
||||
SubtitleTrackInfo subtitleTrackInfo = parser.Parse(stream, CancellationToken.None);
|
||||
SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, CancellationToken.None);
|
||||
SubtitleTrackEvent actual = subtitleTrackInfo.TrackEvents[0];
|
||||
Assert.Equal(expectedText, actual.Text);
|
||||
}
|
||||
@@ -43,7 +48,7 @@ namespace Jellyfin.MediaEncoding.Tests
|
||||
{
|
||||
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa)))
|
||||
{
|
||||
SubtitleTrackInfo subtitleTrackInfo = parser.Parse(stream, CancellationToken.None);
|
||||
SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, CancellationToken.None);
|
||||
|
||||
Assert.Equal(expectedSubtitleTrackEvents.Count, subtitleTrackInfo.TrackEvents.Count);
|
||||
|
||||
@@ -52,9 +57,10 @@ namespace Jellyfin.MediaEncoding.Tests
|
||||
SubtitleTrackEvent expected = expectedSubtitleTrackEvents[i];
|
||||
SubtitleTrackEvent actual = subtitleTrackInfo.TrackEvents[i];
|
||||
|
||||
Assert.Equal(expected.Id, actual.Id);
|
||||
Assert.Equal(expected.Text, actual.Text);
|
||||
Assert.Equal(expected.StartPositionTicks, actual.StartPositionTicks);
|
||||
Assert.Equal(expected.EndPositionTicks, actual.EndPositionTicks);
|
||||
Assert.Equal(expected.Text, actual.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,26 +77,39 @@ namespace Jellyfin.MediaEncoding.Tests
|
||||
",
|
||||
new List<SubtitleTrackEvent>
|
||||
{
|
||||
new SubtitleTrackEvent
|
||||
new SubtitleTrackEvent("1", "dialogue1")
|
||||
{
|
||||
StartPositionTicks = 11800000,
|
||||
EndPositionTicks = 18500000,
|
||||
Text = "dialogue1"
|
||||
EndPositionTicks = 18500000
|
||||
},
|
||||
new SubtitleTrackEvent
|
||||
new SubtitleTrackEvent("2", "dialogue2")
|
||||
{
|
||||
StartPositionTicks = 21800000,
|
||||
EndPositionTicks = 28500000,
|
||||
Text = "dialogue2"
|
||||
EndPositionTicks = 28500000
|
||||
},
|
||||
new SubtitleTrackEvent
|
||||
new SubtitleTrackEvent("3", "dialogue3")
|
||||
{
|
||||
StartPositionTicks = 31800000,
|
||||
EndPositionTicks = 38500000,
|
||||
Text = "dialogue3"
|
||||
EndPositionTicks = 38500000
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_Valid_Success()
|
||||
{
|
||||
using (var stream = File.OpenRead("Test Data/example.ssa"))
|
||||
{
|
||||
var parsed = _parser.Parse(stream, CancellationToken.None);
|
||||
Assert.Single(parsed.TrackEvents);
|
||||
var trackEvent = parsed.TrackEvents[0];
|
||||
|
||||
Assert.Equal("1", trackEvent.Id);
|
||||
Assert.Equal(TimeSpan.Parse("00:00:01.18", CultureInfo.InvariantCulture).Ticks, trackEvent.StartPositionTicks);
|
||||
Assert.Equal(TimeSpan.Parse("00:00:06.85", CultureInfo.InvariantCulture).Ticks, trackEvent.EndPositionTicks);
|
||||
Assert.Equal("{\\pos(400,570)}Like an angel with pity on nobody", trackEvent.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
tests/Jellyfin.MediaEncoding.Tests/Test Data/example.ssa
Normal file
20
tests/Jellyfin.MediaEncoding.Tests/Test Data/example.ssa
Normal file
@@ -0,0 +1,20 @@
|
||||
[Script Info]
|
||||
; This is a Sub Station Alpha v4 script.
|
||||
; For Sub Station Alpha info and downloads,
|
||||
; go to http://www.eswat.demon.co.uk/
|
||||
Title: Neon Genesis Evangelion - Episode 26 (neutral Spanish)
|
||||
Original Script: RoRo
|
||||
Script Updated By: version 2.8.01
|
||||
ScriptType: v4.00
|
||||
Collisions: Normal
|
||||
PlayResY: 600
|
||||
PlayDepth: 0
|
||||
Timer: 100,0000
|
||||
|
||||
[V4 Styles]
|
||||
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding
|
||||
Style: DefaultVCD, Arial,28,11861244,11861244,11861244,-2147483640,-1,0,1,1,2,2,30,30,30,0,0
|
||||
|
||||
[Events]
|
||||
Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
||||
Dialogue: Marked=0,0:00:01.18,0:00:06.85,DefaultVCD, NTP,0000,0000,0000,,{\pos(400,570)}Like an angel with pity on nobody
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Model.Tests.Entities
|
||||
{
|
||||
public class ProviderIdsExtensionsTests
|
||||
{
|
||||
private const string ExampleImdbId = "tt0113375";
|
||||
|
||||
[Fact]
|
||||
public void GetProviderId_NullInstance_ThrowsArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => ProviderIdsExtensions.GetProviderId(null!, MetadataProvider.Imdb));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProviderId_NullName_ThrowsArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => ProviderIdsExtensionsTestsObject.Empty.GetProviderId(null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProviderId_NotFoundName_Null()
|
||||
{
|
||||
Assert.Null(ProviderIdsExtensionsTestsObject.Empty.GetProviderId(MetadataProvider.Imdb));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProviderId_NullProvider_Null()
|
||||
{
|
||||
var nullProvider = new ProviderIdsExtensionsTestsObject()
|
||||
{
|
||||
ProviderIds = null!
|
||||
};
|
||||
|
||||
Assert.Null(nullProvider.GetProviderId(MetadataProvider.Imdb));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetProviderId_NotFoundName_False()
|
||||
{
|
||||
Assert.False(ProviderIdsExtensionsTestsObject.Empty.TryGetProviderId(MetadataProvider.Imdb, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetProviderId_NullProvider_False()
|
||||
{
|
||||
var nullProvider = new ProviderIdsExtensionsTestsObject()
|
||||
{
|
||||
ProviderIds = null!
|
||||
};
|
||||
|
||||
Assert.False(nullProvider.TryGetProviderId(MetadataProvider.Imdb, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProviderId_FoundName_Id()
|
||||
{
|
||||
var provider = new ProviderIdsExtensionsTestsObject();
|
||||
provider.ProviderIds[MetadataProvider.Imdb.ToString()] = ExampleImdbId;
|
||||
|
||||
Assert.Equal(ExampleImdbId, provider.GetProviderId(MetadataProvider.Imdb));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetProviderId_FoundName_True()
|
||||
{
|
||||
var provider = new ProviderIdsExtensionsTestsObject();
|
||||
provider.ProviderIds[MetadataProvider.Imdb.ToString()] = ExampleImdbId;
|
||||
|
||||
Assert.True(provider.TryGetProviderId(MetadataProvider.Imdb, out var id));
|
||||
Assert.Equal(ExampleImdbId, id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetProviderId_NullInstance_ThrowsArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => ProviderIdsExtensions.SetProviderId(null!, MetadataProvider.Imdb, ExampleImdbId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetProviderId_Null_Remove()
|
||||
{
|
||||
var provider = new ProviderIdsExtensionsTestsObject();
|
||||
provider.SetProviderId(MetadataProvider.Imdb, null!);
|
||||
Assert.Empty(provider.ProviderIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetProviderId_EmptyName_Remove()
|
||||
{
|
||||
var provider = new ProviderIdsExtensionsTestsObject();
|
||||
provider.ProviderIds[MetadataProvider.Imdb.ToString()] = ExampleImdbId;
|
||||
provider.SetProviderId(MetadataProvider.Imdb, string.Empty);
|
||||
Assert.Empty(provider.ProviderIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetProviderId_NonEmptyId_Success()
|
||||
{
|
||||
var provider = new ProviderIdsExtensionsTestsObject();
|
||||
provider.SetProviderId(MetadataProvider.Imdb, ExampleImdbId);
|
||||
Assert.Single(provider.ProviderIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetProviderId_NullProvider_Success()
|
||||
{
|
||||
var nullProvider = new ProviderIdsExtensionsTestsObject()
|
||||
{
|
||||
ProviderIds = null!
|
||||
};
|
||||
|
||||
nullProvider.SetProviderId(MetadataProvider.Imdb, ExampleImdbId);
|
||||
Assert.Single(nullProvider.ProviderIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetProviderId_NullProviderAndEmptyName_Success()
|
||||
{
|
||||
var nullProvider = new ProviderIdsExtensionsTestsObject()
|
||||
{
|
||||
ProviderIds = null!
|
||||
};
|
||||
|
||||
nullProvider.SetProviderId(MetadataProvider.Imdb, string.Empty);
|
||||
Assert.Null(nullProvider.ProviderIds);
|
||||
}
|
||||
|
||||
private class ProviderIdsExtensionsTestsObject : IHasProviderIds
|
||||
{
|
||||
public static readonly ProviderIdsExtensionsTestsObject Empty = new ProviderIdsExtensionsTestsObject();
|
||||
|
||||
public Dictionary<string, string> ProviderIds { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code Analyzers -->
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
<PackageReference Include="Moq" Version="4.16.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<PackageReference Include="Moq" Version="4.16.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code Analyzers -->
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<PackageReference Include="Moq" Version="4.16.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code Analyzers -->
|
||||
|
||||
Reference in New Issue
Block a user