review(Driver.Modbus.Addressing): fix misleading byte-order hint + drop dead overflow guard

Re-review at 7286d320. -010 (Low): TryParseByteOrder no longer lists REAL/DINT/UINT as type
codes (gave wrong 'field 2' advice -> second parse error); generic byte-order error instead.
-011 (Low): remove unreachable offsetWithinBank>ushort.MaxValue guard (DecodeOctalVAddress
caps at 0xFFFF). + TDD.
This commit is contained in:
Joseph Doherty
2026-06-19 11:34:35 -04:00
parent 6853a0430f
commit b5f6cdfdb9
4 changed files with 161 additions and 14 deletions
@@ -256,4 +256,65 @@ public sealed class ModbusAddressEdgeCaseTests
error.ShouldNotBeNullOrEmpty();
error!.ShouldContain("byte order", Case.Insensitive);
}
// ── Driver.Modbus.Addressing-010: isKnownTypeCode lists non-type-codes (REAL/DINT/UINT) ─
//
// TryParseByteOrder's isKnownTypeCode heuristic listed "REAL", "DINT", and "UINT" as
// "known type codes" but those strings are NOT valid type codes in TryParseType. Following
// the advice "type belongs in field 2 (e.g. '40001:REAL')" would lead to a second error
// "Unknown type code 'REAL'", misdirecting the user. The list must be restricted to the
// actual 4-letter valid type code: BOOL.
/// <summary>Verifies that REAL in the byte-order slot gives a generic byte-order error, not false type-code advice.</summary>
[Theory]
[InlineData("40001:F:REAL")]
[InlineData("40001:F:DINT")]
[InlineData("40001:F:UINT")]
public void ByteOrderSlot_NonTypeCode_Strings_Give_Generic_ByteOrder_Error(string addr)
{
// "REAL", "DINT", "UINT" look like PLC type names but are NOT valid type codes in this
// parser. They should produce the generic "Unknown byte order" message, not a misleading
// "type belongs in field 2" hint that would lead the user to another failure.
var ok = ModbusAddressParser.TryParse(addr, out _, out var error);
ok.ShouldBeFalse();
error.ShouldNotBeNullOrEmpty();
// Must NOT claim these are type codes — following that advice produces another error.
error!.ShouldNotContain("type code", Case.Insensitive);
// Must mention the valid byte orders so the user knows what field 3 accepts.
error.ShouldContain("ABCD", Case.Insensitive);
}
/// <summary>Verifies that BOOL in the byte-order slot still gives the helpful type-code hint.</summary>
[Fact]
public void ByteOrderSlot_BOOL_Gives_TypeCode_Hint()
{
// BOOL IS a valid type code — the hint "type belongs in field 2 (e.g. '40001:BOOL')"
// is correct advice since '40001:BOOL' does parse successfully.
var ok = ModbusAddressParser.TryParse("40001:F:BOOL", out _, out var error);
ok.ShouldBeFalse();
error.ShouldNotBeNullOrEmpty();
error!.ShouldContain("field 2", Case.Insensitive);
}
// ── Driver.Modbus.Addressing-011: dead overflow check in VMemoryToPdu ──────────────────
//
// VMemoryToPdu's "offsetWithinBank > ushort.MaxValue" guard is unreachable: DecodeOctalVAddress
// already caps octalValue at ushort.MaxValue (0xFFFF), so offsetWithinBank can never exceed
// 0xFFFF - SystemVMemoryOctalBase (0x4100) = 0xBEFF = 48895, which is always < ushort.MaxValue.
// The real overflow guard lives in SystemVMemoryToPdu (pdu > ushort.MaxValue) and is reachable
// when SystemVMemoryToPdu is called directly with a large offset. These tests pin the boundary
// and confirm the overflow is caught by SystemVMemoryToPdu, not the outer check.
/// <summary>Verifies that VMemoryToPdu correctly maps the last valid system-bank V-address.</summary>
[Fact]
public void VMemoryToPdu_max_system_bank_address_maps_correctly()
{
// The largest V-address whose octal-decoded value fits in ushort (0xFFFF = 65535 octal) is
// V177777 (octal). octalValue = 0xFFFF. offsetWithinBank = 0xFFFF - 0x4100 = 0xBEFF.
// pdu = 0x2100 + 0xBEFF = 0xDFFF = 57343 which is < 0xFFFF — does not overflow.
// The "offsetWithinBank > ushort.MaxValue" check in VMemoryToPdu never fires for V-addresses
// reachable through the parser (DecodeOctalVAddress caps at 0xFFFF).
var result = DirectLogicAddress.VMemoryToPdu("V177777");
result.ShouldBe((ushort)(DirectLogicAddress.SystemVMemoryBasePdu + (0xFFFF - DirectLogicAddress.SystemVMemoryOctalBase)));
}
}