using System.Text.Json;
using System.Text.Json.Serialization;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Forms;
using ZB.MOM.WW.OtOpcUa.Driver.Modbus;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
///
/// Round-trip + enum-serialization guard for the Modbus driver (channel/protocol) form model.
/// Reproduces the historical driver-enum-serialization bug: enums MUST serialize as their name strings
/// (JsonStringEnumConverter) with camelCase keys, or the runtime factory faults on the numeric form.
///
public sealed class ModbusDriverFormModelTests
{
private static readonly JsonSerializerOptions JsonOpts = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
WriteIndented = false,
Converters = { new JsonStringEnumConverter() },
};
/// Review r1 n2: the lane's new form keys survive FromOptions → ToOptions, and their defaults keep
/// the historical wire (FC16, coalescing on at gap 8 only when the key is absent).
[Fact]
public void Form_round_trips_the_FC23_opt_in_and_coalescing_keys()
{
var form = new ModbusDriverForm.FormModel { UseFC23ForMultiRegisterWrites = true, DisableFC23 = true, DisableReadCoalescing = true, MaxReadGap = 0 };
var back = ModbusDriverForm.FormModel.FromOptions(form.ToOptions());
back.UseFC23ForMultiRegisterWrites.ShouldBeTrue();
back.DisableFC23.ShouldBeTrue();
back.DisableReadCoalescing.ShouldBeTrue();
back.MaxReadGap.ShouldBe(0);
var defaults = new ModbusDriverForm.FormModel().ToOptions();
defaults.UseFC23ForMultiRegisterWrites.ShouldBeFalse();
defaults.MaxReadGap.ShouldBe((ushort)8);
}
[Fact]
public void Round_trip_preserves_channel_fields_and_enum()
{
var form = new ModbusDriverForm.FormModel
{
Family = ModbusFamily.MELSEC,
MelsecSubFamily = MelsecFamily.Q_L_iQR,
TimeoutSeconds = 4,
MaxRegistersPerRead = 100,
WriteOnChangeOnly = true,
KeepAliveRetryCount = 5,
ReconnectBackoffMultiplier = 3.0,
ProbeAddress = 40,
};
var json = JsonSerializer.Serialize(form.ToOptions(), JsonOpts);
var back = ModbusDriverForm.FormModel.FromOptions(
JsonSerializer.Deserialize(json, JsonOpts)!);
back.Family.ShouldBe(ModbusFamily.MELSEC);
back.MelsecSubFamily.ShouldBe(MelsecFamily.Q_L_iQR);
back.TimeoutSeconds.ShouldBe(4);
back.MaxRegistersPerRead.ShouldBe(100);
back.WriteOnChangeOnly.ShouldBeTrue();
back.KeepAliveRetryCount.ShouldBe(5);
back.ReconnectBackoffMultiplier.ShouldBe(3.0);
back.ProbeAddress.ShouldBe(40);
}
[Fact]
public void Serialized_config_uses_camelCase_keys_and_enum_names()
{
var form = new ModbusDriverForm.FormModel { Family = ModbusFamily.MELSEC };
var json = JsonSerializer.Serialize(form.ToOptions(), JsonOpts);
json.ShouldContain("\"family\":\"MELSEC\""); // enum-as-name (not a number), camelCase key
json.ShouldNotContain("\"family\":0", Case.Sensitive); // never the numeric enum form
}
[Fact]
public void Round_trip_preserves_Transport_mode()
{
var form = new ModbusDriverForm.FormModel { Transport = ModbusTransportMode.RtuOverTcp };
var json = JsonSerializer.Serialize(form.ToOptions(), JsonOpts);
var back = ModbusDriverForm.FormModel.FromOptions(
JsonSerializer.Deserialize(json, JsonOpts)!);
back.Transport.ShouldBe(ModbusTransportMode.RtuOverTcp);
json.ShouldContain("\"transport\":\"RtuOverTcp\""); // name string, never a number
}
}