Files
Just.Railway/Raliway.Tests/Errors/Serialization_RoundTrip.cs
T
just e8ae93799e
.NET Test / .NET tests (push) Failing after 2m5s
error tests expansion
2026-07-12 18:06:53 +04:00

227 lines
7.1 KiB
C#

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));
}
}
}