From 55c4545b02579a90f7387011551b2ea9a38e1284 Mon Sep 17 00:00:00 2001 From: Corniel Nobel Date: Tue, 13 Feb 2024 15:52:52 +0100 Subject: [PATCH] When deserializing from JSON numeric nodes, the constraints of the ID should be taken into account. --- .../Qowaiv.Specs/Identifiers/ID_Cast_specs.cs | 5 --- .../Identifiers/Id_for_Int32_specs.cs | 38 +++++++++++++++---- .../Identifiers/Id_for_Int64_specs.cs | 30 +++++++++++++++ src/Qowaiv/Identifiers/Int32IdBehavior.cs | 16 +++----- src/Qowaiv/Identifiers/Int64IdBehavior.cs | 10 ++--- .../Json/Identifiers/IdJsonConverter.cs | 14 +++---- 6 files changed, 78 insertions(+), 35 deletions(-) diff --git a/specs/Qowaiv.Specs/Identifiers/ID_Cast_specs.cs b/specs/Qowaiv.Specs/Identifiers/ID_Cast_specs.cs index 554090e0..d9e01922 100644 --- a/specs/Qowaiv.Specs/Identifiers/ID_Cast_specs.cs +++ b/specs/Qowaiv.Specs/Identifiers/ID_Cast_specs.cs @@ -84,10 +84,5 @@ public void non_GUID_string_to_GUID() public void long_to_GUID() => ((object)123546L).Invoking(id => (CustomGuid)id) .Should().Throw(); - - [Test] - public void invalid_JSON_input() - => (-1L).Invoking(Int64Id.FromJson) - .Should().Throw(); } diff --git a/specs/Qowaiv.Specs/Identifiers/Id_for_Int32_specs.cs b/specs/Qowaiv.Specs/Identifiers/Id_for_Int32_specs.cs index b03b7ac6..8e219e3d 100644 --- a/specs/Qowaiv.Specs/Identifiers/Id_for_Int32_specs.cs +++ b/specs/Qowaiv.Specs/Identifiers/Id_for_Int32_specs.cs @@ -49,6 +49,37 @@ public void System_Text_JSON_deserialization(object json, Int32Id svo) [TestCase("12345678", 12345678L)] public void System_Text_JSON_serialization(Int32Id svo, object json) => JsonTester.Write_System_Text_JSON(svo).Should().Be(json); + + [TestCase(-2)] + [TestCase(17)] + [TestCase("17")] + [TestCase(int.MaxValue + 1L)] + public void taking_constrains_into_account(object json) + { + json.Invoking(JsonTester.Read_System_Text_JSON>) + .Should().Throw() + .WithMessage("Not a valid identifier."); + } + + private sealed class ForEven : Int32IdBehavior + { + public override bool TryCreate(object? obj, out object? id) + { + if(obj is int even && even % 2 == 0) + { + id = even; + return true; + } + { + id = null; + return false; + } + } + + public override bool TryParse(string? str, out object? id) + => TryCreate(int.TryParse(str, out int even) ? even : null, out id); + } + #endif [TestCase("", "")] [TestCase(12345678L, 12345678)] @@ -60,13 +91,6 @@ public void convention_based_deserialization(object json, Int32Id svo) [TestCase("12345678", 12345678L)] public void convention_based_serialization(Int32Id svo, object json) => JsonTester.Write(svo).Should().Be(json); - - [TestCase("Invalid input", typeof(FormatException))] - [TestCase(long.MaxValue, typeof(InvalidCastException))] - public void throws_for_invalid_json(object json, Type exceptionType) - => json.Invoking(JsonTester.Read) - .Should().Throw() - .Which.Should().BeOfType(exceptionType); } public class Supports_type_conversion diff --git a/specs/Qowaiv.Specs/Identifiers/Id_for_Int64_specs.cs b/specs/Qowaiv.Specs/Identifiers/Id_for_Int64_specs.cs index 3c63a7fb..a0b8fdfa 100644 --- a/specs/Qowaiv.Specs/Identifiers/Id_for_Int64_specs.cs +++ b/specs/Qowaiv.Specs/Identifiers/Id_for_Int64_specs.cs @@ -48,7 +48,37 @@ public void System_Text_JSON_deserialization(object json, Int64Id svo) [TestCase(123456789L, "123456789")] public void System_Text_JSON_serialization(Int64Id svo, object json) => JsonTester.Write_System_Text_JSON(svo).Should().Be(json); + + [TestCase(-2)] + [TestCase(17)] + [TestCase("17")] + public void taking_constrains_into_account(object json) + { + json.Invoking(JsonTester.Read_System_Text_JSON>) + .Should().Throw() + .WithMessage("Not a valid identifier."); + } + + private sealed class ForEven : Int64IdBehavior + { + public override bool TryCreate(object? obj, out object? id) + { + if (obj is long even && even % 2 == 0) + { + id = even; + return true; + } + { + id = null; + return false; + } + } + + public override bool TryParse(string? str, out object? id) + => TryCreate(long.TryParse(str, out long even) ? even : null, out id); + } #endif + [TestCase("", null)] [TestCase(123456789L, 123456789L)] [TestCase("123456789", 123456789L)] diff --git a/src/Qowaiv/Identifiers/Int32IdBehavior.cs b/src/Qowaiv/Identifiers/Int32IdBehavior.cs index f60f78b5..7dac52c4 100644 --- a/src/Qowaiv/Identifiers/Int32IdBehavior.cs +++ b/src/Qowaiv/Identifiers/Int32IdBehavior.cs @@ -37,18 +37,12 @@ public override byte[] ToByteArray(object? obj) /// [Pure] - public override object? FromJson(long obj) + public override object? FromJson(long obj) => obj switch { - if (obj == 0) - { - return null; - } - else if (obj > 0 && obj <= int.MaxValue) - { - return (int)obj; - } - else throw Exceptions.InvalidCast(typeof(int), typeof(Id<>).MakeGenericType(GetType())); - } + 0 => null, + _ when obj > 0 && obj <= int.MaxValue && TryCreate(obj, out var created) && created is int id => id, + _ => throw Unparsable.ForValue(obj.ToString(), "Not a valid identifier.", typeof(Id<>).MakeGenericType(GetType())), + }; /// [Pure] diff --git a/src/Qowaiv/Identifiers/Int64IdBehavior.cs b/src/Qowaiv/Identifiers/Int64IdBehavior.cs index 62d859dd..30257a4a 100644 --- a/src/Qowaiv/Identifiers/Int64IdBehavior.cs +++ b/src/Qowaiv/Identifiers/Int64IdBehavior.cs @@ -39,12 +39,12 @@ public override string ToString(object? obj, string? format, IFormatProvider? fo /// [Pure] - public sealed override object? FromJson(long obj) + public sealed override object? FromJson(long obj) => obj switch { - if (obj == 0) return null; - else if (obj > 0) return obj; - else throw Exceptions.InvalidCast(typeof(long), typeof(Id<>).MakeGenericType(GetType())); - } + 0 => null, + _ when obj > 0 && TryCreate(obj, out var created) && created is long id => id, + _ => throw Unparsable.ForValue(obj.ToString(), "Not a valid identifier.", typeof(Id<>).MakeGenericType(GetType())), + }; /// [Pure] diff --git a/src/Qowaiv/Json/Identifiers/IdJsonConverter.cs b/src/Qowaiv/Json/Identifiers/IdJsonConverter.cs index 9d8ea8db..1fd5e5cf 100644 --- a/src/Qowaiv/Json/Identifiers/IdJsonConverter.cs +++ b/src/Qowaiv/Json/Identifiers/IdJsonConverter.cs @@ -48,8 +48,12 @@ JsonTokenType.True or } catch (Exception x) { - if (x is JsonException) throw; - else throw new JsonException(x.Message, x); + var inner = x; + while (inner is TargetInvocationException && inner.InnerException is { }) + { + inner = inner.InnerException; + } + throw new JsonException(inner.Message, inner); } } @@ -77,17 +81,13 @@ public override void Write(Utf8JsonWriter writer, Id value, JsonSeria } } -#if NET6_0_OR_GREATER - /// - public override Id ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) +- public override Id ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => Id.FromJson(reader.GetString()); /// public override void WriteAsPropertyName(Utf8JsonWriter writer, Id value, JsonSerializerOptions options) => writer.WritePropertyName(value.ToJson()?.ToString() ?? string.Empty); - -#endif } [Pure]