fix(client-shared): resolve Medium code-review findings (Client.Shared-001, -002, -007, -008)

Client.Shared-001: lowered the OnAlarmEventNotification early-return guard
from <6 to <1; per-index field guards already default missing fields safely.
Client.Shared-002: GetRedundancyInfoAsync replaces unguarded unboxing casts
with StatusCode.IsGood + Convert.ToInt32/ToByte, defaulting on bad reads.
Client.Shared-007: alarm fallback Task.Run guards on ReferenceEquals(session,
_session) and drops stale alarms on ObjectDisposedException after failover.
Client.Shared-008: WriteValueAsync rejects type inference from bad/null reads;
ValueConverter wraps parse failures in a descriptive FormatException.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-22 08:11:23 -04:00
parent aa142f6dd4
commit 7e54e1e4a0
5 changed files with 267 additions and 30 deletions

View File

@@ -97,14 +97,43 @@ public class ValueConverterTests
}
[Fact]
public void ConvertValue_InvalidInt_Throws()
public void ConvertValue_InvalidInt_ThrowsWithDescription()
{
Should.Throw<FormatException>(() => ValueConverter.ConvertValue("notanint", 0));
var ex = Should.Throw<FormatException>(() => ValueConverter.ConvertValue("notanint", 0));
ex.Message.ShouldContain("Int32");
ex.Message.ShouldContain("notanint");
}
[Fact]
public void ConvertValue_Overflow_Throws()
public void ConvertValue_Overflow_ThrowsFormatException()
{
Should.Throw<OverflowException>(() => ValueConverter.ConvertValue("256", (byte)0));
// OverflowException is now wrapped in a descriptive FormatException
var ex = Should.Throw<FormatException>(() => ValueConverter.ConvertValue("256", (byte)0));
ex.InnerException.ShouldBeOfType<OverflowException>();
}
// --- Client.Shared-008: Boolean aliases ---
[Theory]
[InlineData("1", true)]
[InlineData("0", false)]
[InlineData("yes", true)]
[InlineData("no", false)]
[InlineData("YES", true)]
[InlineData("NO", false)]
[InlineData("true", true)]
[InlineData("false", false)]
[InlineData("True", true)]
[InlineData("False", false)]
public void ConvertValue_Bool_AcceptsNumericAndWordAliases(string input, bool expected)
{
ValueConverter.ConvertValue(input, true).ShouldBe(expected);
}
[Fact]
public void ConvertValue_InvalidBool_ThrowsDescriptiveFormatException()
{
var ex = Should.Throw<FormatException>(() => ValueConverter.ConvertValue("maybe", false));
ex.Message.ShouldContain("Boolean");
}
}