using System.Text.Json; using Mbproxy.Admin; using Shouldly; using Xunit; namespace Mbproxy.Tests.Admin; /// /// Locks the SignalR payload wire shape. The hub serialises detail / fleet payloads /// with a camelCase property policy (see AdminEndpointHost's AddJsonProtocol), /// and the dashboard JS reads camelCase field names — so a regression to the naming /// policy would silently break every field on the live feed with no other failing test. /// [Trait("Category", "Unit")] public sealed class DebugDtoSerializationTests { // The exact policy AdminEndpointHost configures on the hub's PayloadSerializerOptions. private static readonly JsonSerializerOptions HubOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; [Fact] public void PlcDetailResponse_SerializesWithCamelCaseFieldNames() { var detail = new PlcDetailResponse( Plc: null, Debug: new PlcDebugSnapshot( CaptureArmed: true, Tags: [new TagValueDto( Address: 100, Width: 16, Name: "Left AirSP", HasValue: true, Direction: "read", RawHex: "0x1234", DecodedValue: 1234, UpdatedAtUtc: "2026-05-16T00:00:00Z", AgeSeconds: 1.5)])); string json = JsonSerializer.Serialize(detail, HubOptions); // Case.Sensitive throughout — Shouldly's string contains defaults to // case-insensitive, which would not distinguish camelCase from PascalCase. json.ShouldContain("\"captureArmed\"", Case.Sensitive); json.ShouldContain("\"decodedValue\"", Case.Sensitive); json.ShouldContain("\"updatedAtUtc\"", Case.Sensitive); json.ShouldNotContain("\"CaptureArmed\"", Case.Sensitive); json.ShouldNotContain("\"DecodedValue\"", Case.Sensitive); } }