239 lines
7.3 KiB
C#
239 lines
7.3 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 EmptyError_serializes_to_null()
|
|
{
|
|
// Given
|
|
var error = Error.Empty;
|
|
|
|
// When
|
|
var json = JsonSerializer.Serialize(error);
|
|
|
|
// Then
|
|
json.ShouldBe("null");
|
|
}
|
|
|
|
[Fact]
|
|
public void EmptyError_filtered_from_ManyErrors_serialization()
|
|
{
|
|
// Given
|
|
var real = Error.New("real_error");
|
|
var errors = Error.Many(Error.Empty, real);
|
|
|
|
// When
|
|
var json = JsonSerializer.Serialize(errors);
|
|
|
|
// Then
|
|
json.ShouldNotContain("empty");
|
|
json.ShouldContain("real_error");
|
|
}
|
|
|
|
[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));
|
|
}
|
|
}
|
|
}
|