@@ -0,0 +1,226 @@
|
||||
namespace Raliway.Tests.Errors;
|
||||
|
||||
public class Serialization_RoundTrip
|
||||
{
|
||||
public class ExpectedError_Tests
|
||||
{
|
||||
[Fact]
|
||||
public void Round_trip_as_Error_preserves_Type_and_Message()
|
||||
{
|
||||
// Given
|
||||
Error original = Error.New("custom_type", "custom message");
|
||||
|
||||
// When
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then
|
||||
deserialized.ShouldBeOfType<ExpectedError>();
|
||||
deserialized!.Type.ShouldBe("custom_type");
|
||||
deserialized.Message.ShouldBe("custom message");
|
||||
deserialized.IsExpected.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Round_trip_as_ExpectedError_preserves_Type_and_Message()
|
||||
{
|
||||
// Given
|
||||
var original = new ExpectedError("custom_type", "custom message");
|
||||
|
||||
// When
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<ExpectedError>(json);
|
||||
|
||||
// Then
|
||||
deserialized!.Type.ShouldBe("custom_type");
|
||||
deserialized.Message.ShouldBe("custom message");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deserialize_single_object_as_Error_produces_ExpectedError()
|
||||
{
|
||||
// Given
|
||||
var json = """{"type":"foo","msg":"bar"}""";
|
||||
|
||||
// When
|
||||
var error = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then
|
||||
error.ShouldBeOfType<ExpectedError>();
|
||||
error!.Type.ShouldBe("foo");
|
||||
error.Message.ShouldBe("bar");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Unknown_properties_become_ExtensionData()
|
||||
{
|
||||
// Given
|
||||
var json = """{"type":"err","msg":"details","meta_key":"meta_value","flag":"1"}""";
|
||||
|
||||
// When
|
||||
var error = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then
|
||||
error.ShouldBeOfType<ExpectedError>();
|
||||
error!.ExtensionData["meta_key"].ShouldBe("meta_value");
|
||||
error.ExtensionData["flag"].ShouldBe("1");
|
||||
}
|
||||
}
|
||||
|
||||
public class ExceptionalError_Tests
|
||||
{
|
||||
[Fact]
|
||||
public void Round_trip_as_ExceptionalError_preserves_Type_and_Message()
|
||||
{
|
||||
// Given
|
||||
Error original = Error.New(new InvalidOperationException("boom"));
|
||||
|
||||
// When
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<ExceptionalError>(json);
|
||||
|
||||
// Then
|
||||
deserialized.ShouldBeOfType<ExceptionalError>();
|
||||
deserialized!.Type.ShouldBe("System.InvalidOperationException");
|
||||
deserialized.Message.ShouldBe("boom");
|
||||
deserialized.IsExceptional.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExceptionalError_serialized_then_deserialized_as_Error_becomes_ExpectedError()
|
||||
{
|
||||
// ErrorJsonConverter.Read always produces ExpectedError for JSON objects.
|
||||
|
||||
// Given
|
||||
Error original = Error.New(new InvalidOperationException("boom"));
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
|
||||
// When — deserialize as the base Error type
|
||||
var deserialized = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then — should NOT be an ExceptionalError (known bug)
|
||||
deserialized.ShouldBeOfType<ExpectedError>();
|
||||
deserialized!.Type.ShouldBe("System.InvalidOperationException");
|
||||
deserialized.Message.ShouldBe("boom");
|
||||
deserialized.IsExceptional.ShouldBeFalse();
|
||||
deserialized.IsExpected.ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
public class ManyErrors_Tests
|
||||
{
|
||||
[Fact]
|
||||
public void Round_trip_preserves_all_elements()
|
||||
{
|
||||
// Given
|
||||
Error original = Error.Many(
|
||||
Error.New("err1", "first error"),
|
||||
Error.New("err2", "second error"));
|
||||
|
||||
// When
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then
|
||||
deserialized.ShouldBeOfType<ManyErrors>();
|
||||
var many = (ManyErrors)deserialized!;
|
||||
many.Count.ShouldBe(2);
|
||||
many[0].Type.ShouldBe("err1");
|
||||
many[0].Message.ShouldBe("first error");
|
||||
many[1].Type.ShouldBe("err2");
|
||||
many[1].Message.ShouldBe("second error");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Round_trip_as_ManyErrors_preserves_elements()
|
||||
{
|
||||
// Given
|
||||
var original = new ManyErrors([
|
||||
Error.New("err1", "first"),
|
||||
Error.New("err2", "second")
|
||||
]);
|
||||
|
||||
// When
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<ManyErrors>(json);
|
||||
|
||||
// Then
|
||||
deserialized.ShouldBeOfType<ManyErrors>();
|
||||
deserialized!.Count.ShouldBe(2);
|
||||
deserialized[0].Type.ShouldBe("err1");
|
||||
deserialized[1].Type.ShouldBe("err2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Empty_ManyErrors_round_trip()
|
||||
{
|
||||
// Given
|
||||
Error original = Error.Many(Array.Empty<Error>());
|
||||
|
||||
// When
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then
|
||||
deserialized.ShouldBeOfType<ManyErrors>();
|
||||
deserialized!.IsEmpty.ShouldBeTrue();
|
||||
deserialized.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtensionData_round_trip_within_ManyErrors()
|
||||
{
|
||||
// Given
|
||||
Error original = Error.Many(
|
||||
Error.New("err", "msg", new Dictionary<string, string> { ["meta"] = "value" }),
|
||||
Error.New("err2", "msg2"));
|
||||
|
||||
// When
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then
|
||||
var many = (ManyErrors)deserialized!;
|
||||
many[0]["meta"].ShouldBe("value");
|
||||
}
|
||||
}
|
||||
|
||||
public class Null_Handling
|
||||
{
|
||||
[Fact]
|
||||
public void Deserialize_null_JSON_returns_null()
|
||||
{
|
||||
// Given
|
||||
var json = "null";
|
||||
|
||||
// When
|
||||
var result = JsonSerializer.Deserialize<Error>(json);
|
||||
|
||||
// Then
|
||||
result.ShouldBeNull();
|
||||
}
|
||||
}
|
||||
|
||||
public class Error_Handling
|
||||
{
|
||||
[Fact]
|
||||
public void Non_string_property_value_throws_JsonException()
|
||||
{
|
||||
// Given
|
||||
var json = """{"type":"err","msg":"ok","bad":42}""";
|
||||
|
||||
// When / Then
|
||||
Should.Throw<JsonException>(() => JsonSerializer.Deserialize<Error>(json));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Malformed_JSON_throws_JsonException()
|
||||
{
|
||||
// Given
|
||||
var json = "{not valid json at all";
|
||||
|
||||
// When / Then
|
||||
Should.Throw<JsonException>(() => JsonSerializer.Deserialize<Error>(json));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user