aboutsummaryrefslogtreecommitdiff
path: root/tests/Jellyfin.Common.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Jellyfin.Common.Tests')
-rw-r--r--tests/Jellyfin.Common.Tests/Crc32Tests.cs33
-rw-r--r--tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs185
-rw-r--r--tests/Jellyfin.Common.Tests/Extensions/CopyToExtensionsTests.cs40
-rw-r--r--tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj9
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs52
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs1
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs1
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs27
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs39
-rw-r--r--tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs36
-rw-r--r--tests/Jellyfin.Common.Tests/PasswordHashTests.cs31
-rw-r--r--tests/Jellyfin.Common.Tests/Providers/ProviderIdParserTests.cs85
12 files changed, 485 insertions, 54 deletions
diff --git a/tests/Jellyfin.Common.Tests/Crc32Tests.cs b/tests/Jellyfin.Common.Tests/Crc32Tests.cs
new file mode 100644
index 000000000..e95a2867f
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Crc32Tests.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Text;
+using MediaBrowser.Common;
+using Xunit;
+
+namespace Jellyfin.Common.Tests
+{
+ public static class Crc32Tests
+ {
+ [Fact]
+ public static void Compute_Empty_Zero()
+ {
+ Assert.Equal<uint>(0, Crc32.Compute(Array.Empty<byte>()));
+ }
+
+ [Theory]
+ [InlineData(0x414fa339, "The quick brown fox jumps over the lazy dog")]
+ public static void Compute_Valid_Success(uint expected, string data)
+ {
+ Assert.Equal(expected, Crc32.Compute(Encoding.UTF8.GetBytes(data)));
+ }
+
+ [Theory]
+ [InlineData(0x414fa339, "54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F67")]
+ [InlineData(0x190a55ad, "0000000000000000000000000000000000000000000000000000000000000000")]
+ [InlineData(0xff6cab0b, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")]
+ [InlineData(0x91267e8a, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")]
+ public static void Compute_ValidHex_Success(uint expected, string data)
+ {
+ Assert.Equal(expected, Crc32.Compute(Convert.FromHexString(data)));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs b/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs
new file mode 100644
index 000000000..e6c325bac
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Cryptography;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Cryptography
+{
+ public static class PasswordHashTests
+ {
+ [Fact]
+ public static void Ctor_Null_ThrowsArgumentNullException()
+ {
+ Assert.Throws<ArgumentNullException>(() => new PasswordHash(null!, Array.Empty<byte>()));
+ }
+
+ [Fact]
+ public static void Ctor_Empty_ThrowsArgumentException()
+ {
+ Assert.Throws<ArgumentException>(() => new PasswordHash(string.Empty, Array.Empty<byte>()));
+ }
+
+ public static IEnumerable<object[]> Parse_Valid_TestData()
+ {
+ // Id
+ yield return new object[]
+ {
+ "$PBKDF2",
+ new PasswordHash("PBKDF2", Array.Empty<byte>())
+ };
+
+ // Id + parameter
+ yield return new object[]
+ {
+ "$PBKDF2$iterations=1000",
+ new PasswordHash(
+ "PBKDF2",
+ Array.Empty<byte>(),
+ Array.Empty<byte>(),
+ new Dictionary<string, string>()
+ {
+ { "iterations", "1000" },
+ })
+ };
+
+ // Id + parameters
+ yield return new object[]
+ {
+ "$PBKDF2$iterations=1000,m=120",
+ new PasswordHash(
+ "PBKDF2",
+ Array.Empty<byte>(),
+ Array.Empty<byte>(),
+ new Dictionary<string, string>()
+ {
+ { "iterations", "1000" },
+ { "m", "120" }
+ })
+ };
+
+ // Id + hash
+ yield return new object[]
+ {
+ "$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
+ new PasswordHash(
+ "PBKDF2",
+ Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"),
+ Array.Empty<byte>(),
+ new Dictionary<string, string>())
+ };
+
+ // Id + salt + hash
+ yield return new object[]
+ {
+ "$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
+ new PasswordHash(
+ "PBKDF2",
+ Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"),
+ Convert.FromHexString("69F420"),
+ new Dictionary<string, string>())
+ };
+
+ // Id + parameter + hash
+ yield return new object[]
+ {
+ "$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
+ new PasswordHash(
+ "PBKDF2",
+ Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"),
+ Array.Empty<byte>(),
+ new Dictionary<string, string>()
+ {
+ { "iterations", "1000" }
+ })
+ };
+
+ // Id + parameters + hash
+ yield return new object[]
+ {
+ "$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
+ new PasswordHash(
+ "PBKDF2",
+ Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"),
+ Array.Empty<byte>(),
+ new Dictionary<string, string>()
+ {
+ { "iterations", "1000" },
+ { "m", "120" }
+ })
+ };
+
+ // Id + parameters + salt + hash
+ yield return new object[]
+ {
+ "$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
+ new PasswordHash(
+ "PBKDF2",
+ Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"),
+ Convert.FromHexString("69F420"),
+ new Dictionary<string, string>()
+ {
+ { "iterations", "1000" },
+ { "m", "120" }
+ })
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Valid_TestData))]
+ public static void Parse_Valid_Success(string passwordHashString, PasswordHash expected)
+ {
+ var passwordHash = PasswordHash.Parse(passwordHashString);
+ Assert.Equal(expected.Id, passwordHash.Id);
+ Assert.Equal(expected.Parameters, passwordHash.Parameters);
+ Assert.Equal(expected.Salt.ToArray(), passwordHash.Salt.ToArray());
+ Assert.Equal(expected.Hash.ToArray(), passwordHash.Hash.ToArray());
+ Assert.Equal(expected.ToString(), passwordHash.ToString());
+ }
+
+ [Theory]
+ [InlineData("$PBKDF2")]
+ [InlineData("$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")]
+ [InlineData("$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")]
+ [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")]
+ [InlineData("$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")]
+ [InlineData("$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")]
+ [InlineData("$PBKDF2$iterations=1000,m=120")]
+ public static void ToString_Roundtrip_Success(string passwordHash)
+ {
+ Assert.Equal(passwordHash, PasswordHash.Parse(passwordHash).ToString());
+ }
+
+ [Fact]
+ public static void Parse_Null_ThrowsArgumentException()
+ {
+ Assert.Throws<ArgumentException>(() => PasswordHash.Parse(null));
+ }
+
+ [Fact]
+ public static void Parse_Empty_ThrowsArgumentException()
+ {
+ Assert.Throws<ArgumentException>(() => PasswordHash.Parse(string.Empty));
+ }
+
+ [Theory]
+ [InlineData("$")] // No id
+ [InlineData("$$")] // Empty segments
+ [InlineData("PBKDF2$")] // Doesn't start with $
+ [InlineData("$PBKDF2$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty segment
+ [InlineData("$PBKDF2$iterations=1000$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty salt segment
+ [InlineData("$PBKDF2$iterations=1000$69F420$")] // Empty hash segment
+ [InlineData("$PBKDF2$=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter
+ [InlineData("$PBKDF2$=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter
+ [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter
+ [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Ends on $
+ [InlineData("$PBKDF2$iterations=$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Extra segment
+ [InlineData("$PBKDF2$iterations=$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$anotherone")] // Extra segment
+ [InlineData("$PBKDF2$iterations=$invalidstalt$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid salt
+ [InlineData("$PBKDF2$iterations=$69F420$invalid hash")] // Invalid hash
+ [InlineData("$PBKDF2$69F420$")] // Empty hash
+ public static void Parse_InvalidFormat_ThrowsFormatException(string passwordHash)
+ {
+ Assert.Throws<FormatException>(() => PasswordHash.Parse(passwordHash));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Extensions/CopyToExtensionsTests.cs b/tests/Jellyfin.Common.Tests/Extensions/CopyToExtensionsTests.cs
new file mode 100644
index 000000000..9903409fa
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Extensions/CopyToExtensionsTests.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Extensions;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Extensions
+{
+ public static class CopyToExtensionsTests
+ {
+ public static IEnumerable<object[]> CopyTo_Valid_Correct_TestData()
+ {
+ yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 0, new[] { 0, 1, 2, 3, 4, 5 } };
+ yield return new object[] { new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 2, new[] { 5, 4, 0, 1, 2, 0 } };
+ }
+
+ [Theory]
+ [MemberData(nameof(CopyTo_Valid_Correct_TestData))]
+ public static void CopyTo_Valid_Correct<T>(IReadOnlyList<T> source, IList<T> destination, int index, IList<T> expected)
+ {
+ source.CopyTo(destination, index);
+ Assert.Equal(expected, destination);
+ }
+
+ public static IEnumerable<object[]> CopyTo_Invalid_ThrowsArgumentOutOfRangeException_TestData()
+ {
+ yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, -1 };
+ yield return new object[] { new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 6 };
+ yield return new object[] { new[] { 0, 1, 2 }, Array.Empty<int>(), 0 };
+ yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0 }, 0 };
+ yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 1 };
+ }
+
+ [Theory]
+ [MemberData(nameof(CopyTo_Invalid_ThrowsArgumentOutOfRangeException_TestData))]
+ public static void CopyTo_Invalid_ThrowsArgumentOutOfRangeException<T>(IReadOnlyList<T> source, IList<T> destination, int index)
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => source.CopyTo(destination, index));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
index 278f34109..8018b2966 100644
--- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
+++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
@@ -10,10 +10,12 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
+ <AnalysisMode>AllEnabledByDefault</AnalysisMode>
+ <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.0.3" />
@@ -21,7 +23,6 @@
<!-- 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" />
@@ -32,8 +33,4 @@
<ProjectReference Include="../../MediaBrowser.Providers/MediaBrowser.Providers.csproj" />
</ItemGroup>
- <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
- <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
-
</Project>
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs
index 0d2bdd1af..ca300401d 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs
+++ b/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs
@@ -1,4 +1,5 @@
-using System.Text.Json;
+using System;
+using System.Text.Json;
using System.Text.Json.Serialization;
using Jellyfin.Common.Tests.Models;
using MediaBrowser.Model.Session;
@@ -9,6 +10,27 @@ namespace Jellyfin.Common.Tests.Json
public static class JsonCommaDelimitedArrayTests
{
[Fact]
+ public static void Deserialize_String_Null_Success()
+ {
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": null }", options);
+ Assert.Null(value?.Value);
+ }
+
+ [Fact]
+ public static void Deserialize_Empty_Success()
+ {
+ var desiredValue = new GenericBodyArrayModel<string>
+ {
+ Value = Array.Empty<string>()
+ };
+
+ var options = new JsonSerializerOptions();
+ var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": """" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
public static void Deserialize_String_Valid_Success()
{
var desiredValue = new GenericBodyArrayModel<string>
@@ -49,6 +71,34 @@ namespace Jellyfin.Common.Tests.Json
}
[Fact]
+ public static void Deserialize_GenericCommandType_EmptyEntry_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_Invalid_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,TotallyNotAVallidCommand,MoveDown"" }", options);
+ Assert.Equal(desiredValue.Value, value?.Value);
+ }
+
+ [Fact]
public static void Deserialize_GenericCommandType_Space_Valid_Success()
{
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs
index 1e1cde957..dbfad3c2f 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs
+++ b/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs
@@ -1,5 +1,4 @@
using System;
-using System.Globalization;
using System.Text.Json;
using MediaBrowser.Common.Json.Converters;
using Xunit;
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs
index 22bc7afb9..cb3b66c4c 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs
+++ b/tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs
@@ -1,5 +1,4 @@
using System;
-using System.Globalization;
using System.Text.Json;
using MediaBrowser.Common.Json.Converters;
using Xunit;
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs
index faed086a1..efe8063a0 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs
+++ b/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs
@@ -39,6 +39,15 @@ namespace Jellyfin.Common.Tests.Json
}
[Theory]
+ [InlineData("\"8\"", 8)]
+ [InlineData("8", 8)]
+ public void Deserialize_NullableInt_Success(string input, int? expected)
+ {
+ var result = JsonSerializer.Deserialize<int?>(input, _options);
+ Assert.Equal(result, expected);
+ }
+
+ [Theory]
[InlineData("\"N/A\"")]
[InlineData("null")]
public void Deserialization_To_Nullable_String_Shoud_Be_Null(string input)
@@ -48,21 +57,11 @@ namespace Jellyfin.Common.Tests.Json
}
[Theory]
- [InlineData("\"8\"", 8)]
- [InlineData("8", 8)]
- public void Deserialize_Int_Success(string input, int expected)
- {
- var result = JsonSerializer.Deserialize<int>(input, _options);
- Assert.Equal(result, expected);
- }
-
- [Fact]
- public void Deserialize_Normal_String_Success()
+ [InlineData("\"Jellyfin\"", "Jellyfin")]
+ public void Deserialize_Normal_String_Success(string input, string expected)
{
- const string Input = "\"Jellyfin\"";
- const string Expected = "Jellyfin";
- var result = JsonSerializer.Deserialize<string>(Input, _options);
- Assert.Equal(Expected, result);
+ var result = JsonSerializer.Deserialize<string?>(input, _options);
+ Assert.Equal(expected, result);
}
[Fact]
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs
new file mode 100644
index 000000000..fd77694b3
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs
@@ -0,0 +1,39 @@
+using System.Text.Json;
+using MediaBrowser.Common.Json.Converters;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Json
+{
+ public class JsonStringConverterTests
+ {
+ private readonly JsonSerializerOptions _jsonSerializerOptions
+ = new ()
+ {
+ Converters =
+ {
+ new JsonStringConverter()
+ }
+ };
+
+ [Theory]
+ [InlineData("\"test\"", "test")]
+ [InlineData("123", "123")]
+ [InlineData("123.45", "123.45")]
+ [InlineData("true", "true")]
+ [InlineData("false", "false")]
+ public void Deserialize_String_Valid_Success(string input, string output)
+ {
+ var deserialized = JsonSerializer.Deserialize<string>(input, _jsonSerializerOptions);
+ Assert.Equal(deserialized, output);
+ }
+
+ [Fact]
+ public void Deserialize_Int32asInt32_Valid_Success()
+ {
+ const string? input = "123";
+ const int output = 123;
+ var deserialized = JsonSerializer.Deserialize<int>(input, _jsonSerializerOptions);
+ Assert.Equal(deserialized, output);
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs
new file mode 100644
index 000000000..f2cefdbf8
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Text.Json;
+using MediaBrowser.Common.Json.Converters;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Json
+{
+ public class JsonVersionConverterTests
+ {
+ private readonly JsonSerializerOptions _options;
+
+ public JsonVersionConverterTests()
+ {
+ _options = new JsonSerializerOptions();
+ _options.Converters.Add(new JsonVersionConverter());
+ }
+
+ [Fact]
+ public void Deserialize_Version_Success()
+ {
+ var input = "\"1.025.222\"";
+ var output = new Version(1, 25, 222);
+ var deserializedInput = JsonSerializer.Deserialize<Version>(input, _options);
+ Assert.Equal(output, deserializedInput);
+ }
+
+ [Fact]
+ public void Serialize_Version_Success()
+ {
+ var input = new Version(1, 09, 59);
+ var output = "\"1.9.59\"";
+ var serializedInput = JsonSerializer.Serialize(input, _options);
+ Assert.Equal(output, serializedInput);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/PasswordHashTests.cs b/tests/Jellyfin.Common.Tests/PasswordHashTests.cs
deleted file mode 100644
index c4422bd10..000000000
--- a/tests/Jellyfin.Common.Tests/PasswordHashTests.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using MediaBrowser.Common;
-using MediaBrowser.Common.Cryptography;
-using Xunit;
-
-namespace Jellyfin.Common.Tests
-{
- public class PasswordHashTests
- {
- [Theory]
- [InlineData(
- "$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
- "PBKDF2",
- "",
- "62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")]
- public void ParseTest(string passwordHash, string id, string salt, string hash)
- {
- var pass = PasswordHash.Parse(passwordHash);
- Assert.Equal(id, pass.Id);
- Assert.Equal(salt, Convert.ToHexString(pass.Salt));
- Assert.Equal(hash, Convert.ToHexString(pass.Hash));
- }
-
- [Theory]
- [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")]
- public void ToStringTest(string passwordHash)
- {
- Assert.Equal(passwordHash, PasswordHash.Parse(passwordHash).ToString());
- }
- }
-}
diff --git a/tests/Jellyfin.Common.Tests/Providers/ProviderIdParserTests.cs b/tests/Jellyfin.Common.Tests/Providers/ProviderIdParserTests.cs
new file mode 100644
index 000000000..ef9d31cc1
--- /dev/null
+++ b/tests/Jellyfin.Common.Tests/Providers/ProviderIdParserTests.cs
@@ -0,0 +1,85 @@
+using System;
+using MediaBrowser.Common.Providers;
+using Xunit;
+
+namespace Jellyfin.Common.Tests.Providers
+{
+ public class ProviderIdParserTests
+ {
+ [Theory]
+ [InlineData("tt1234567", "tt1234567")]
+ [InlineData("tt12345678", "tt12345678")]
+ [InlineData("https://www.imdb.com/title/tt1234567", "tt1234567")]
+ [InlineData("https://www.imdb.com/title/tt12345678", "tt12345678")]
+ [InlineData(@"multiline\nhttps://www.imdb.com/title/tt1234567", "tt1234567")]
+ [InlineData(@"multiline\nhttps://www.imdb.com/title/tt12345678", "tt12345678")]
+ [InlineData("tt1234567tt7654321", "tt1234567")]
+ [InlineData("tt12345678tt7654321", "tt12345678")]
+ [InlineData("tt123456789", "tt12345678")]
+ public void FindImdbId_Valid_Success(string text, string expected)
+ {
+ Assert.True(ProviderIdParsers.TryFindImdbId(text, out ReadOnlySpan<char> parsedId));
+ Assert.Equal(expected, parsedId.ToString());
+ }
+
+ [Theory]
+ [InlineData("tt123456")]
+ [InlineData("https://www.imdb.com/title/tt123456")]
+ [InlineData("Jellyfin")]
+ public void FindImdbId_Invalid_Success(string text)
+ {
+ Assert.False(ProviderIdParsers.TryFindImdbId(text, out _));
+ }
+
+ [Theory]
+ [InlineData("https://www.themoviedb.org/movie/30287-fallo", "30287")]
+ [InlineData("themoviedb.org/movie/30287", "30287")]
+ public void FindTmdbMovieId_Valid_Success(string text, string expected)
+ {
+ Assert.True(ProviderIdParsers.TryFindTmdbMovieId(text, out ReadOnlySpan<char> parsedId));
+ Assert.Equal(expected, parsedId.ToString());
+ }
+
+ [Theory]
+ [InlineData("https://www.themoviedb.org/movie/fallo-30287")]
+ [InlineData("https://www.themoviedb.org/tv/1668-friends")]
+ public void FindTmdbMovieId_Invalid_Success(string text)
+ {
+ Assert.False(ProviderIdParsers.TryFindTmdbMovieId(text, out _));
+ }
+
+ [Theory]
+ [InlineData("https://www.themoviedb.org/tv/1668-friends", "1668")]
+ [InlineData("themoviedb.org/tv/1668", "1668")]
+ public void FindTmdbSeriesId_Valid_Success(string text, string expected)
+ {
+ Assert.True(ProviderIdParsers.TryFindTmdbSeriesId(text, out ReadOnlySpan<char> parsedId));
+ Assert.Equal(expected, parsedId.ToString());
+ }
+
+ [Theory]
+ [InlineData("https://www.themoviedb.org/tv/friends-1668")]
+ [InlineData("https://www.themoviedb.org/movie/30287-fallo")]
+ public void FindTmdbSeriesId_Invalid_Success(string text)
+ {
+ Assert.False(ProviderIdParsers.TryFindTmdbSeriesId(text, out _));
+ }
+
+ [Theory]
+ [InlineData("https://www.thetvdb.com/?tab=series&id=121361", "121361")]
+ [InlineData("thetvdb.com/?tab=series&id=121361", "121361")]
+ public void FindTvdbId_Valid_Success(string text, string expected)
+ {
+ Assert.True(ProviderIdParsers.TryFindTvdbId(text, out ReadOnlySpan<char> parsedId));
+ Assert.Equal(expected, parsedId.ToString());
+ }
+
+ [Theory]
+ [InlineData("thetvdb.com/?tab=series&id=Jellyfin121361")]
+ [InlineData("https://www.themoviedb.org/tv/1668-friends")]
+ public void FindTvdbId_Invalid_Success(string text)
+ {
+ Assert.False(ProviderIdParsers.TryFindTvdbId(text, out _));
+ }
+ }
+}