Skip to content

Commit

Permalink
When deserializing from JSON numeric nodes, the constraints of the ID…
Browse files Browse the repository at this point in the history
… should be taken into account.
  • Loading branch information
Corniel committed Feb 13, 2024
1 parent d6ce00f commit 55c4545
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 35 deletions.
5 changes: 0 additions & 5 deletions specs/Qowaiv.Specs/Identifiers/ID_Cast_specs.cs
Expand Up @@ -84,10 +84,5 @@ public void non_GUID_string_to_GUID()
public void long_to_GUID()
=> ((object)123546L).Invoking(id => (CustomGuid)id)
.Should().Throw<InvalidCastException>();

[Test]
public void invalid_JSON_input()
=> (-1L).Invoking(Int64Id.FromJson)
.Should().Throw<InvalidCastException>();
}

38 changes: 31 additions & 7 deletions specs/Qowaiv.Specs/Identifiers/Id_for_Int32_specs.cs
Expand Up @@ -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<Id<ForEven>>)
.Should().Throw<System.Text.Json.JsonException>()
.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)]
Expand All @@ -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<Int32Id>)
.Should().Throw<Exception>()
.Which.Should().BeOfType(exceptionType);
}

public class Supports_type_conversion
Expand Down
30 changes: 30 additions & 0 deletions specs/Qowaiv.Specs/Identifiers/Id_for_Int64_specs.cs
Expand Up @@ -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<Id<ForEven>>)
.Should().Throw<System.Text.Json.JsonException>()
.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)]
Expand Down
16 changes: 5 additions & 11 deletions src/Qowaiv/Identifiers/Int32IdBehavior.cs
Expand Up @@ -37,18 +37,12 @@ public override byte[] ToByteArray(object? obj)

/// <inheritdoc/>
[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())),
};

/// <inheritdoc/>
[Pure]
Expand Down
10 changes: 5 additions & 5 deletions src/Qowaiv/Identifiers/Int64IdBehavior.cs
Expand Up @@ -39,12 +39,12 @@ public override string ToString(object? obj, string? format, IFormatProvider? fo

/// <inheritdoc/>
[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())),
};

/// <inheritdoc/>
[Pure]
Expand Down
14 changes: 7 additions & 7 deletions src/Qowaiv/Json/Identifiers/IdJsonConverter.cs
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -77,17 +81,13 @@ public override void Write(Utf8JsonWriter writer, Id<TBehavior> value, JsonSeria
}
}

#if NET6_0_OR_GREATER

/// <inheritdoc />
public override Id<TBehavior> ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- public override Id<TBehavior> ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

Check failure on line 85 in src/Qowaiv/Json/Identifiers/IdJsonConverter.cs

View workflow job for this annotation

GitHub Actions / Build

Invalid token '-' in class, record, struct, or interface member declaration

Check failure on line 85 in src/Qowaiv/Json/Identifiers/IdJsonConverter.cs

View workflow job for this annotation

GitHub Actions / Build

Invalid token '-' in class, record, struct, or interface member declaration

Check failure on line 85 in src/Qowaiv/Json/Identifiers/IdJsonConverter.cs

View workflow job for this annotation

GitHub Actions / Build

Invalid token '-' in class, record, struct, or interface member declaration

Check failure on line 85 in src/Qowaiv/Json/Identifiers/IdJsonConverter.cs

View workflow job for this annotation

GitHub Actions / Build

Invalid token '-' in class, record, struct, or interface member declaration
=> Id<TBehavior>.FromJson(reader.GetString());

/// <inheritdoc />
public override void WriteAsPropertyName(Utf8JsonWriter writer, Id<TBehavior> value, JsonSerializerOptions options)
=> writer.WritePropertyName(value.ToJson()?.ToString() ?? string.Empty);

#endif
}

[Pure]
Expand Down

0 comments on commit 55c4545

Please sign in to comment.