From 915855e422cec59e26d35ca4faff01068443d661 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 5 Jun 2021 13:32:22 +0200 Subject: [PATCH 1/2] Add property based testing --- MediaBrowser.Model/Extensions/StringHelper.cs | 2 +- .../Jellyfin.Common.Tests.csproj | 1 + .../Json/JsonBoolNumberTests.cs | 33 ++++++---- .../Json/JsonStringConverterTests.cs | 15 +++-- .../Extensions/StringHelperTests.cs | 14 +++++ .../Jellyfin.Model.Tests.csproj | 1 + .../Jellyfin.Networking.Tests/IPHostTests.cs | 53 ++++++++++++++++ .../IPNetAddressTests.cs | 49 +++++++++++++++ .../Jellyfin.Networking.Tests.csproj | 1 + .../NetworkParseTests.cs | 60 ------------------- 10 files changed, 149 insertions(+), 80 deletions(-) create mode 100644 tests/Jellyfin.Networking.Tests/IPHostTests.cs create mode 100644 tests/Jellyfin.Networking.Tests/IPNetAddressTests.cs diff --git a/MediaBrowser.Model/Extensions/StringHelper.cs b/MediaBrowser.Model/Extensions/StringHelper.cs index 2d9a6c4dbc..d6a712a8e7 100644 --- a/MediaBrowser.Model/Extensions/StringHelper.cs +++ b/MediaBrowser.Model/Extensions/StringHelper.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Model.Extensions return str; } - if (char.IsUpper(str[0])) + if (!char.IsLower(str[0])) { return str; } diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index fc50cfeb50..546b2487e8 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -19,6 +19,7 @@ + diff --git a/tests/Jellyfin.Common.Tests/Json/JsonBoolNumberTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonBoolNumberTests.cs index 9ded01f2b1..7629d9912c 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonBoolNumberTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonBoolNumberTests.cs @@ -1,34 +1,45 @@ -using System.Text.Json; +using System.Globalization; +using System.Text.Json; +using FsCheck; +using FsCheck.Xunit; using MediaBrowser.Common.Json.Converters; using Xunit; namespace Jellyfin.Common.Tests.Json { - public static class JsonBoolNumberTests + public class JsonBoolNumberTests { + private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions() + { + Converters = + { + new JsonBoolNumberConverter() + } + }; + [Theory] [InlineData("1", true)] [InlineData("0", false)] [InlineData("2", true)] [InlineData("true", true)] [InlineData("false", false)] - public static void Deserialize_Number_Valid_Success(string input, bool? output) + public void Deserialize_Number_Valid_Success(string input, bool? output) { - var options = new JsonSerializerOptions(); - options.Converters.Add(new JsonBoolNumberConverter()); - var value = JsonSerializer.Deserialize(input, options); + var value = JsonSerializer.Deserialize(input, _jsonOptions); Assert.Equal(value, output); } [Theory] [InlineData(true, "true")] [InlineData(false, "false")] - public static void Serialize_Bool_Success(bool input, string output) + public void Serialize_Bool_Success(bool input, string output) { - var options = new JsonSerializerOptions(); - options.Converters.Add(new JsonBoolNumberConverter()); - var value = JsonSerializer.Serialize(input, options); + var value = JsonSerializer.Serialize(input, _jsonOptions); Assert.Equal(value, output); } + + [Property] + public Property Deserialize_NonZeroInt_True(NonZeroInt input) + => JsonSerializer.Deserialize(input.ToString(), _jsonOptions).ToProperty(); } -} \ No newline at end of file +} diff --git a/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs b/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs index fd77694b30..2b23c6705b 100644 --- a/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs +++ b/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs @@ -6,14 +6,13 @@ namespace Jellyfin.Common.Tests.Json { public class JsonStringConverterTests { - private readonly JsonSerializerOptions _jsonSerializerOptions - = new () + private readonly JsonSerializerOptions _jsonSerializerOptions = new () + { + Converters = { - Converters = - { - new JsonStringConverter() - } - }; + new JsonStringConverter() + } + }; [Theory] [InlineData("\"test\"", "test")] @@ -36,4 +35,4 @@ namespace Jellyfin.Common.Tests.Json Assert.Equal(deserialized, output); } } -} \ No newline at end of file +} diff --git a/tests/Jellyfin.Model.Tests/Extensions/StringHelperTests.cs b/tests/Jellyfin.Model.Tests/Extensions/StringHelperTests.cs index 5864a05094..0a4e060df6 100644 --- a/tests/Jellyfin.Model.Tests/Extensions/StringHelperTests.cs +++ b/tests/Jellyfin.Model.Tests/Extensions/StringHelperTests.cs @@ -1,3 +1,6 @@ +using System; +using FsCheck; +using FsCheck.Xunit; using MediaBrowser.Model.Extensions; using Xunit; @@ -10,9 +13,20 @@ namespace Jellyfin.Model.Tests.Extensions [InlineData("banana", "Banana")] [InlineData("Banana", "Banana")] [InlineData("ä", "Ä")] + [InlineData("\027", "\027")] public void StringHelper_ValidArgs_Success(string input, string expectedResult) { Assert.Equal(expectedResult, StringHelper.FirstToUpper(input)); } + + [Property] + public Property FirstToUpper_RandomArg_Correct(NonEmptyString input) + { + var result = StringHelper.FirstToUpper(input.Item); + + // We check IsLower instead of IsUpper because both return false for non-letters + return (!char.IsLower(result[0])).Label("First char is uppercase") + .And(input.Item.Length == 1 || result[1..].Equals(input.Item[1..], StringComparison.Ordinal)).Label("Remaining chars are unmodified"); + } } } diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj index 79b34163da..40c51e5248 100644 --- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj +++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj @@ -14,6 +14,7 @@ + diff --git a/tests/Jellyfin.Networking.Tests/IPHostTests.cs b/tests/Jellyfin.Networking.Tests/IPHostTests.cs new file mode 100644 index 0000000000..ec3a1300c8 --- /dev/null +++ b/tests/Jellyfin.Networking.Tests/IPHostTests.cs @@ -0,0 +1,53 @@ +using FsCheck; +using FsCheck.Xunit; +using MediaBrowser.Common.Net; +using Xunit; + +namespace Jellyfin.Networking.Tests +{ + public static class IPHostTests + { + /// + /// Checks IP address formats. + /// + /// IP Address. + [Theory] + [InlineData("127.0.0.1")] + [InlineData("127.0.0.1:123")] + [InlineData("localhost")] + [InlineData("localhost:1345")] + [InlineData("www.google.co.uk")] + [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517")] + [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517/56")] + [InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]:124")] + [InlineData("fe80::7add:12ff:febb:c67b%16")] + [InlineData("[fe80::7add:12ff:febb:c67b%16]:123")] + [InlineData("fe80::7add:12ff:febb:c67b%16:123")] + [InlineData("[fe80::7add:12ff:febb:c67b%16]")] + [InlineData("192.168.1.2/255.255.255.0")] + [InlineData("192.168.1.2/24")] + public static void TryParse_ValidHostStrings_True(string address) + => Assert.True(IPHost.TryParse(address, out _)); + + [Property] + public static Property TryParse_IPv4Address_True(IPv4Address address) + => IPHost.TryParse(address.Item.ToString(), out _).ToProperty(); + + [Property] + public static Property TryParse_IPv6Address_True(IPv6Address address) + => IPHost.TryParse(address.Item.ToString(), out _).ToProperty(); + + /// + /// All should be invalid address strings. + /// + /// Invalid address strings. + [Theory] + [InlineData("256.128.0.0.0.1")] + [InlineData("127.0.0.1#")] + [InlineData("localhost!")] + [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517:1231")] + [InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517:1231]")] + public static void TryParse_InvalidAddressString_False(string address) + => Assert.False(IPHost.TryParse(address, out _)); + } +} diff --git a/tests/Jellyfin.Networking.Tests/IPNetAddressTests.cs b/tests/Jellyfin.Networking.Tests/IPNetAddressTests.cs new file mode 100644 index 0000000000..aa2dbc57a2 --- /dev/null +++ b/tests/Jellyfin.Networking.Tests/IPNetAddressTests.cs @@ -0,0 +1,49 @@ +using FsCheck; +using FsCheck.Xunit; +using MediaBrowser.Common.Net; +using Xunit; + +namespace Jellyfin.Networking.Tests +{ + public static class IPNetAddressTests + { + /// + /// Checks IP address formats. + /// + /// IP Address. + [Theory] + [InlineData("127.0.0.1")] + [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517")] + [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517/56")] + [InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]")] + [InlineData("fe80::7add:12ff:febb:c67b%16")] + [InlineData("[fe80::7add:12ff:febb:c67b%16]:123")] + [InlineData("fe80::7add:12ff:febb:c67b%16:123")] + [InlineData("[fe80::7add:12ff:febb:c67b%16]")] + [InlineData("192.168.1.2/255.255.255.0")] + [InlineData("192.168.1.2/24")] + public static void TryParse_ValidIPStrings_True(string address) + => Assert.True(IPNetAddress.TryParse(address, out _)); + + [Property] + public static Property TryParse_IPv4Address_True(IPv4Address address) + => IPNetAddress.TryParse(address.Item.ToString(), out _).ToProperty(); + + [Property] + public static Property TryParse_IPv6Address_True(IPv6Address address) + => IPNetAddress.TryParse(address.Item.ToString(), out _).ToProperty(); + + /// + /// All should be invalid address strings. + /// + /// Invalid address strings. + [Theory] + [InlineData("256.128.0.0.0.1")] + [InlineData("127.0.0.1#")] + [InlineData("localhost!")] + [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517:1231")] + [InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517:1231]")] + public static void TryParse_InvalidAddressString_False(string address) + => Assert.False(IPNetAddress.TryParse(address, out _)); + } +} diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj index 4abc83c5ec..97bf673ae6 100644 --- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj +++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj @@ -19,6 +19,7 @@ + diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs index 671b8598de..97c14d463b 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs @@ -56,66 +56,6 @@ namespace Jellyfin.Networking.Tests Assert.Equal(nm.GetInternalBindAddresses().AsString(), value); } - /// - /// Checks IP address formats. - /// - /// IP Address. - [Theory] - [InlineData("127.0.0.1")] - [InlineData("127.0.0.1:123")] - [InlineData("localhost")] - [InlineData("localhost:1345")] - [InlineData("www.google.co.uk")] - [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517")] - [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517/56")] - [InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]:124")] - [InlineData("fe80::7add:12ff:febb:c67b%16")] - [InlineData("[fe80::7add:12ff:febb:c67b%16]:123")] - [InlineData("fe80::7add:12ff:febb:c67b%16:123")] - [InlineData("[fe80::7add:12ff:febb:c67b%16]")] - [InlineData("192.168.1.2/255.255.255.0")] - [InlineData("192.168.1.2/24")] - public void ValidHostStrings(string address) - { - Assert.True(IPHost.TryParse(address, out _)); - } - - /// - /// Checks IP address formats. - /// - /// IP Address. - [Theory] - [InlineData("127.0.0.1")] - [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517")] - [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517/56")] - [InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]")] - [InlineData("fe80::7add:12ff:febb:c67b%16")] - [InlineData("[fe80::7add:12ff:febb:c67b%16]:123")] - [InlineData("fe80::7add:12ff:febb:c67b%16:123")] - [InlineData("[fe80::7add:12ff:febb:c67b%16]")] - [InlineData("192.168.1.2/255.255.255.0")] - [InlineData("192.168.1.2/24")] - public void ValidIPStrings(string address) - { - Assert.True(IPNetAddress.TryParse(address, out _)); - } - - /// - /// All should be invalid address strings. - /// - /// Invalid address strings. - [Theory] - [InlineData("256.128.0.0.0.1")] - [InlineData("127.0.0.1#")] - [InlineData("localhost!")] - [InlineData("fd23:184f:2029:0:3139:7386:67d7:d517:1231")] - [InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517:1231]")] - public void InvalidAddressString(string address) - { - Assert.False(IPNetAddress.TryParse(address, out _)); - Assert.False(IPHost.TryParse(address, out _)); - } - /// /// Test collection parsing. /// From ce434ebc7a564ce0fc07f9a2b5f16c0ca3da404f Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sun, 6 Jun 2021 19:30:43 +0200 Subject: [PATCH 2/2] Add comment --- MediaBrowser.Model/Extensions/StringHelper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Model/Extensions/StringHelper.cs b/MediaBrowser.Model/Extensions/StringHelper.cs index d6a712a8e7..77cbef00f5 100644 --- a/MediaBrowser.Model/Extensions/StringHelper.cs +++ b/MediaBrowser.Model/Extensions/StringHelper.cs @@ -17,6 +17,7 @@ namespace MediaBrowser.Model.Extensions return str; } + // We check IsLower instead of IsUpper because both return false for non-letters if (!char.IsLower(str[0])) { return str;