using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Pages.Clusters.Drivers;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;
///
/// Regression guard for the systemic driver-config enum-serialization bug found 2026-06-19.
/// Every *DriverPage serialised enum config fields (e.g. S7 CpuType, Modbus
/// DataType/Region, AbCip PlcFamily) as JSON numbers because its
/// private static _jsonOpts had no . The driver
/// factories, however, deserialise into string-typed DTOs (+ lenient ParseEnum) and
/// throw when binding a JSON number to a string? — so an AdminUI-authored
/// config that contained any enum field produced a blob the driver could not parse, faulting
/// the driver on deploy. The fix makes every page serialise enums as strings (matching the
/// factory + the long-correct OpcUaClient template). This test fails if any driver page loses
/// its string-enum converter again.
///
public sealed class DriverPageJsonConverterTests
{
/// Every concrete *DriverPage in the AdminUI assembly that declares a
/// _jsonOpts config serializer.
private static IReadOnlyList DriverPageTypes { get; } =
typeof(S7DriverPage).Assembly.GetTypes()
.Where(t => t.Name.EndsWith("DriverPage", StringComparison.Ordinal) && !t.IsAbstract)
.Where(t => t.GetField("_jsonOpts", BindingFlags.NonPublic | BindingFlags.Static) is not null)
.OrderBy(t => t.Name)
.ToList();
/// xUnit theory source over the driver-page types discovered by reflection.
public static TheoryData DriverPagesWithJsonOpts()
{
var data = new TheoryData();
foreach (var t in DriverPageTypes)
data.Add(t);
return data;
}
/// Verifies every driver page's config serializer registers a string-enum converter so
/// enum config fields round-trip as strings (and the driver factory can parse the result).
/// A driver page component type discovered by reflection.
[Theory]
[MemberData(nameof(DriverPagesWithJsonOpts))]
public void Driver_page_json_options_register_string_enum_converter(Type pageType)
{
var field = pageType.GetField("_jsonOpts", BindingFlags.NonPublic | BindingFlags.Static);
var opts = (JsonSerializerOptions)field!.GetValue(null)!;
opts.Converters.OfType().ShouldNotBeEmpty(
$"{pageType.Name}._jsonOpts must register a JsonStringEnumConverter; otherwise AdminUI-authored " +
"enum config fields serialise as numbers and the string-typed driver factory throws on parse.");
}
/// Enforces that EVERY concrete *DriverPage routes config serialization through a
/// _jsonOpts field — otherwise a new page that serialised config a different way would slip
/// past the converter guard above. Also a floor check so a rename can't silently shrink the set.
[Fact]
public void Every_driver_page_uses_a_guarded_jsonOpts_serializer()
{
var allDriverPages = typeof(S7DriverPage).Assembly.GetTypes()
.Where(t => t.Name.EndsWith("DriverPage", StringComparison.Ordinal) && !t.IsAbstract)
.ToList();
allDriverPages.Count.ShouldBeGreaterThanOrEqualTo(9, "reflection should discover the full driver-page fleet");
DriverPageTypes.Count.ShouldBe(allDriverPages.Count,
"every *DriverPage must declare a _jsonOpts config serializer so the string-enum converter guard covers it");
}
}