Project · Testing
JSON request boundary lab
Check the actual local serializer and independent domain validation against explicit input fixtures. No remote service or full runner is simulated.
All C# source files below are loaded together in the playground. Files written by a run live in its virtual directory.
Program.cs
var checks = BoundaryChecks.Run();
foreach (var check in checks) Console.WriteLine($"{check.Name}:{(check.Passed ? "PASS" : "FAIL")}");
Console.WriteLine($"passed:{checks.Count(check => check.Passed)}/{checks.Count}");
return checks.All(check => check.Passed) ? 0 : 1;
Domain/Request.cs
public sealed record Request(string Code, int Quantity);
public sealed record DecodeResult(bool Success, Request? Value, string Error);
Domain/QuantityRules.cs
public static class QuantityRules
{
public static bool Allowed(int quantity) => quantity >= 1 && quantity <= 5;
}
Adapters/JsonRequestCodec.cs
using System.Text.Json;
public static class JsonRequestCodec
{
private sealed record RequestDto(string? Code, int Quantity);
private static readonly JsonSerializerOptions Options = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
public static DecodeResult Decode(string json)
{
RequestDto? data;
try { data = JsonSerializer.Deserialize<RequestDto>(json, Options); }
catch (JsonException) { return new(false, null, "representation"); }
if (data is null) return new(false, null, "shape");
if (string.IsNullOrWhiteSpace(data.Code)) return new(false, null, "code");
if (!QuantityRules.Allowed(data.Quantity)) return new(false, null, "quantity");
return new(true, new Request(data.Code, data.Quantity), "");
}
}
Checks/CheckResult.cs
public sealed record CheckResult(string Name, bool Passed);
Checks/BoundaryChecks.cs
public static class BoundaryChecks
{
private sealed record Case(string Name, string Json, bool ExpectedSuccess, string ExpectedCode, int ExpectedQuantity, string ExpectedError);
public static List<CheckResult> Run()
{
var cases = new[]
{
new Case("valid", "{\"code\":\"A1\",\"quantity\":2}", true, "A1", 2, ""),
new Case("malformed", "{", false, "", 0, "representation"),
new Case("blank-code", "{\"code\":\"\",\"quantity\":2}", false, "", 0, "code"),
new Case("missing-quantity", "{\"code\":\"A1\"}", false, "", 0, "quantity"),
new Case("excess", "{\"code\":\"A1\",\"quantity\":6}", false, "", 0, "quantity"),
new Case("null-root", "null", false, "", 0, "shape"),
new Case("quoted-quantity", "{\"code\":\"A1\",\"quantity\":\"2\"}", false, "", 0, "representation"),
new Case("exact-limit", "{\"code\":\"A1\",\"quantity\":5}", true, "A1", 5, "")
};
var results = new List<CheckResult>();
foreach (var item in cases)
{
DecodeResult actual = JsonRequestCodec.Decode(item.Json);
bool correct = actual.Success == item.ExpectedSuccess && actual.Error == item.ExpectedError;
if (item.ExpectedSuccess) correct &= actual.Value?.Code == item.ExpectedCode && actual.Value?.Quantity == item.ExpectedQuantity;
else correct &= actual.Value is null;
results.Add(new(item.Name, correct));
}
return results;
}
}
JsonBoundaryLab.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>