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:
+61
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user