feat(history): full Part 13 aggregate set; unsupported-by-backend aggregates answer BadAggregateNotSupported (#285)
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
+17
-3
@@ -16,10 +16,24 @@ public sealed class AggregateModeMapperTests
|
||||
public void Maps_each_aggregate(HistoryAggregateType a, RetrievalMode expected)
|
||||
=> Assert.Equal(expected, AggregateModeMapper.ToRetrievalMode(a));
|
||||
|
||||
[Fact] // matrix guard: a new HistoryAggregateType member must fail here
|
||||
public void Every_aggregate_member_is_mapped()
|
||||
[Fact] // matrix guard: every member is either mapped or explicitly reported as not supported
|
||||
public void Every_aggregate_member_is_mapped_or_reports_not_supported()
|
||||
{
|
||||
var original = new[]
|
||||
{
|
||||
HistoryAggregateType.Average, HistoryAggregateType.Minimum, HistoryAggregateType.Maximum,
|
||||
HistoryAggregateType.Total, HistoryAggregateType.Count,
|
||||
};
|
||||
foreach (var a in Enum.GetValues<HistoryAggregateType>())
|
||||
_ = AggregateModeMapper.ToRetrievalMode(a); // must not throw for any defined member
|
||||
{
|
||||
if (original.Contains(a))
|
||||
_ = AggregateModeMapper.ToRetrievalMode(a);
|
||||
else
|
||||
Assert.Throws<HistoryAggregateNotSupportedException>(() => AggregateModeMapper.ToRetrievalMode(a));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Undefined_value_is_a_programming_error_not_a_not_supported()
|
||||
=> Assert.Throws<ArgumentOutOfRangeException>(() => AggregateModeMapper.ToRetrievalMode((HistoryAggregateType)9999));
|
||||
}
|
||||
|
||||
+14
-5
@@ -8,14 +8,23 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientHistoryTests
|
||||
{
|
||||
/// <summary>Every <see cref="HistoryAggregateType"/> member (#285: the full Part 13 set, not just five).</summary>
|
||||
public static IEnumerable<object[]> AllAggregates() =>
|
||||
Enum.GetValues<HistoryAggregateType>().Select(a => new object[] { a });
|
||||
|
||||
/// <summary>Every member maps to a DISTINCT aggregate NodeId (a copy/paste mapping would collide).</summary>
|
||||
[Fact]
|
||||
public void MapAggregateToNodeId_is_injective_over_the_whole_enum()
|
||||
{
|
||||
var ids = Enum.GetValues<HistoryAggregateType>().Select(OpcUaClientDriver.MapAggregateToNodeId).ToList();
|
||||
ids.Distinct().Count().ShouldBe(ids.Count);
|
||||
Enum.GetValues<HistoryAggregateType>().Length.ShouldBeGreaterThan(5);
|
||||
}
|
||||
|
||||
/// <summary>Verifies MapAggregateToNodeId returns standard Part 13 aggregate for every enum.</summary>
|
||||
/// <param name="agg">The history aggregate type to test.</param>
|
||||
[Theory]
|
||||
[InlineData(HistoryAggregateType.Average)]
|
||||
[InlineData(HistoryAggregateType.Minimum)]
|
||||
[InlineData(HistoryAggregateType.Maximum)]
|
||||
[InlineData(HistoryAggregateType.Total)]
|
||||
[InlineData(HistoryAggregateType.Count)]
|
||||
[MemberData(nameof(AllAggregates))]
|
||||
public void MapAggregateToNodeId_returns_standard_Part13_aggregate_for_every_enum(HistoryAggregateType agg)
|
||||
{
|
||||
var nodeId = OpcUaClientDriver.MapAggregateToNodeId(agg);
|
||||
|
||||
Reference in New Issue
Block a user