docs: backfill XML documentation across 756 files
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public members surfaced by commentchecker — resolves 5,847 of 5,869 issues (99.6%) across three /fixdocs passes.
This commit is contained in:
@@ -31,6 +31,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
MessageTemplate: msg,
|
||||
PredicateScriptSource: predicate);
|
||||
|
||||
/// <summary>Verifies that LoadAsync compiles the alarm predicate and subscribes to all referenced upstream tags.</summary>
|
||||
[Fact]
|
||||
public async Task Load_compiles_and_subscribes_to_referenced_upstreams()
|
||||
{
|
||||
@@ -45,6 +46,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
up.ActiveSubscriptionCount.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that compile failures across multiple alarms are aggregated into a single error.</summary>
|
||||
[Fact]
|
||||
public async Task Compile_failures_aggregated_into_one_error()
|
||||
{
|
||||
@@ -60,6 +62,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
ex.Message.ShouldContain("2 alarm(s) did not compile");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that an upstream tag change triggers predicate re-evaluation and emits an Activated event.</summary>
|
||||
[Fact]
|
||||
public async Task Upstream_change_re_evaluates_predicate_and_emits_Activated()
|
||||
{
|
||||
@@ -80,6 +83,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
eng.GetState("HighTemp")!.Active.ShouldBe(AlarmActiveState.Active);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that clearing an upstream tag value emits a Cleared event and transitions the alarm to Inactive.</summary>
|
||||
[Fact]
|
||||
public async Task Clearing_upstream_emits_Cleared_event()
|
||||
{
|
||||
@@ -100,6 +104,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
eng.GetState("HighTemp")!.Active.ShouldBe(AlarmActiveState.Inactive);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the message template resolves current tag values at the moment of alarm emission.</summary>
|
||||
[Fact]
|
||||
public async Task Message_template_resolves_tag_values_at_emission()
|
||||
{
|
||||
@@ -124,6 +129,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
events[0].Message.ShouldBe("Temp 150C exceeded limit 100C");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that AcknowledgeAsync records the operator user and persists the ack state to the store.</summary>
|
||||
[Fact]
|
||||
public async Task Ack_records_user_and_persists_to_store()
|
||||
{
|
||||
@@ -143,6 +149,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
persisted.Comments.Any(c => c.Kind == "Acknowledge" && c.User == "alice").ShouldBeTrue();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that startup recovery restores the persisted ack state but re-derives the active state from the live predicate.</summary>
|
||||
[Fact]
|
||||
public async Task Startup_recovery_preserves_ack_but_rederives_active_from_predicate()
|
||||
{
|
||||
@@ -190,6 +197,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
s.LastAckUser.ShouldBe("alice");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a shelved alarm transitions its internal state on activation but suppresses the Activated emission.</summary>
|
||||
[Fact]
|
||||
public async Task Shelved_active_transitions_state_but_suppresses_emission()
|
||||
{
|
||||
@@ -213,6 +221,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
"state still advances so startup recovery is consistent");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a runtime exception thrown by a predicate script leaves the alarm state unchanged and does not affect other alarms.</summary>
|
||||
[Fact]
|
||||
public async Task Predicate_runtime_exception_does_not_transition_state()
|
||||
{
|
||||
@@ -229,6 +238,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
eng.GetState("GoodScript")!.Active.ShouldBe(AlarmActiveState.Active);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a disabled alarm does not activate on predicate change and resumes normally after being re-enabled.</summary>
|
||||
[Fact]
|
||||
public async Task Disable_prevents_activation_until_re_enabled()
|
||||
{
|
||||
@@ -249,6 +259,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
await WaitForAsync(() => eng.GetState("HighTemp")!.Active == AlarmActiveState.Active);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that AddCommentAsync appends to the audit trail without changing the alarm's active or ack state.</summary>
|
||||
[Fact]
|
||||
public async Task AddComment_appends_to_audit_without_state_change()
|
||||
{
|
||||
@@ -266,6 +277,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
s.Comments[0].Kind.ShouldBe("AddComment");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that predicate scripts are forbidden from calling SetVirtualTag, and that the exception is isolated without state change.</summary>
|
||||
[Fact]
|
||||
public async Task Predicate_scripts_cannot_SetVirtualTag()
|
||||
{
|
||||
@@ -289,6 +301,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
eng.GetState("Bad")!.Active.ShouldBe(AlarmActiveState.Inactive);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that disposing the engine releases all upstream tag subscriptions.</summary>
|
||||
[Fact]
|
||||
public async Task Dispose_releases_upstream_subscriptions()
|
||||
{
|
||||
@@ -303,6 +316,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
up.ActiveSubscriptionCount.ShouldBe(0);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that concurrent reads of alarm state during dictionary mutations do not throw (regression for Core.ScriptedAlarms-001).</summary>
|
||||
[Fact]
|
||||
public async Task Concurrent_reads_during_mutation_do_not_throw(/* Core.ScriptedAlarms-001 */)
|
||||
{
|
||||
@@ -371,6 +385,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
// (1) Timed-shelve auto-expiry driven by the engine's shelving timer via an
|
||||
// injectable clock — the clock and scriptTimeout constructor parameters
|
||||
// exist for exactly this.
|
||||
/// <summary>Verifies that a timed shelve automatically expires when the engine's shelving check runs past the unshelve time.</summary>
|
||||
[Fact]
|
||||
public async Task TimedShelve_auto_expires_when_engine_shelving_check_runs(/* -012 (1) */)
|
||||
{
|
||||
@@ -407,6 +422,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
}
|
||||
|
||||
// (2a) ConfirmAsync end-to-end through the engine.
|
||||
/// <summary>Verifies that ConfirmAsync records the confirming user and emits a Confirmed event persisted to the store.</summary>
|
||||
[Fact]
|
||||
public async Task ConfirmAsync_records_user_and_emits_Confirmed(/* -012 (2) */)
|
||||
{
|
||||
@@ -433,6 +449,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
}
|
||||
|
||||
// (2b) TimedShelveAsync / UnshelveAsync end-to-end through the engine.
|
||||
/// <summary>Verifies that TimedShelveAsync shelves with a deadline and UnshelveAsync removes the shelve before the timer expires.</summary>
|
||||
[Fact]
|
||||
public async Task TimedShelveAsync_and_UnshelveAsync_round_trip(/* -012 (2) */)
|
||||
{
|
||||
@@ -460,6 +477,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
}
|
||||
|
||||
// (2c) EnableAsync end-to-end through the engine.
|
||||
/// <summary>Verifies that EnableAsync transitions the alarm back to Enabled state and emits an Enabled event.</summary>
|
||||
[Fact]
|
||||
public async Task EnableAsync_re_enables_after_disable(/* -012 (2) */)
|
||||
{
|
||||
@@ -482,6 +500,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
// (3) OnEvent subscriber-throws isolation — a bad subscriber must not crash
|
||||
// the engine or prevent subsequent alarm state transitions. The engine logs
|
||||
// the exception and continues operating; any later alarm changes still work.
|
||||
/// <summary>Verifies that an exception thrown by an OnEvent subscriber is isolated and does not crash the engine or prevent further state transitions.</summary>
|
||||
[Fact]
|
||||
public async Task OnEvent_subscriber_exception_does_not_crash_engine(/* -012 (3) */)
|
||||
{
|
||||
@@ -514,6 +533,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
|
||||
// (4) IAlarmStateStore.SaveAsync failure — in-memory state must remain at the
|
||||
// prior value after finding -007 fix (persist-before-update).
|
||||
/// <summary>Verifies that a store SaveAsync failure leaves the in-memory alarm state at its prior value (persist-before-update invariant, finding -007).</summary>
|
||||
[Fact]
|
||||
public async Task Store_save_failure_leaves_in_memory_state_unchanged(/* -012 (4) */)
|
||||
{
|
||||
@@ -544,6 +564,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
|
||||
// (5) Re-entrant LoadAsync — the old timer must not keep firing after a second
|
||||
// call (regression for finding -002: _shelvingTimer?.Dispose() fix).
|
||||
/// <summary>Verifies that a second LoadAsync call disposes the prior shelving timer so it does not keep firing after reload (regression for finding -002).</summary>
|
||||
[Fact]
|
||||
public async Task Second_LoadAsync_does_not_leak_old_timer(/* -012 (5) */)
|
||||
{
|
||||
@@ -576,6 +597,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
|
||||
// (6) Cold-start AreInputsReady guard — null value, Bad status, and Uncertain
|
||||
// status inputs are all handled correctly.
|
||||
/// <summary>Verifies that AreInputsReady blocks predicate evaluation when inputs have null values or Bad status codes, while Uncertain quality is accepted.</summary>
|
||||
[Fact]
|
||||
public async Task AreInputsReady_blocks_evaluation_for_null_and_bad_inputs(/* -012 (6) */)
|
||||
{
|
||||
@@ -612,6 +634,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
// (2) A subscriber that re-enters the engine (e.g. AcknowledgeAsync) must
|
||||
// not deadlock against _evalGate. Both regressions are covered here.
|
||||
// -------------------------------------------------------------------------
|
||||
/// <summary>Verifies that an OnEvent subscriber can call engine methods (e.g. AcknowledgeAsync) without deadlocking against the evaluation gate (regression for Core.ScriptedAlarms-003).</summary>
|
||||
[Fact]
|
||||
public async Task OnEvent_subscriber_can_call_back_into_engine_without_deadlock(/* -003 */)
|
||||
{
|
||||
@@ -663,6 +686,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Verifies that OnEvent emission occurs after the evaluation gate is released, so subscribers can re-enter the engine without deadlocking (regression for Core.ScriptedAlarms-003).</summary>
|
||||
[Fact]
|
||||
public void OnEvent_emission_happens_outside_evalGate(/* -003 */)
|
||||
{
|
||||
@@ -723,6 +747,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
// or shelving check started just before Dispose can keep running and write
|
||||
// to a (possibly disposed) store after the engine has returned.
|
||||
// -------------------------------------------------------------------------
|
||||
/// <summary>Verifies that Dispose blocks until in-flight background re-evaluation tasks complete, preventing the engine from outliving its store (regression for Core.ScriptedAlarms-006).</summary>
|
||||
[Fact]
|
||||
public async Task Dispose_drains_in_flight_reevaluation_tasks(/* -006 */)
|
||||
{
|
||||
@@ -768,6 +793,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
// resolution renders Uncertain as "{?}" so the operator sees the doubt
|
||||
// explicitly. The two policies are documented in docs/ScriptedAlarms.md.
|
||||
// -------------------------------------------------------------------------
|
||||
/// <summary>Verifies that Uncertain-quality inputs are accepted by the predicate but rendered as "{?}" in the operator-facing message template (Core.ScriptedAlarms-010).</summary>
|
||||
[Fact]
|
||||
public async Task Uncertain_quality_drives_predicate_but_renders_question_mark_in_message(/* -010 */)
|
||||
{
|
||||
@@ -815,6 +841,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
// (which still satisfies IReadOnlyList<AlarmComment> for existing
|
||||
// consumers).
|
||||
// -------------------------------------------------------------------------
|
||||
/// <summary>Verifies that the Comments collection is an ImmutableList, enabling O(log n) append and satisfying IReadOnlyList consumers (Core.ScriptedAlarms-008).</summary>
|
||||
[Fact]
|
||||
public async Task Comments_collection_uses_ImmutableList_for_efficient_append(/* -008 */)
|
||||
{
|
||||
@@ -836,6 +863,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
// propagated, not silently discarded. The class-level remarks promise a
|
||||
// diagnostic log line for no-op disabled-alarm evaluations.
|
||||
// -------------------------------------------------------------------------
|
||||
/// <summary>Verifies that TransitionResult.NoOp preserves the supplied diagnostic reason string for caller logging (Core.ScriptedAlarms-011).</summary>
|
||||
[Fact]
|
||||
public void TransitionResult_NoOp_propagates_reason(/* -011 */)
|
||||
{
|
||||
@@ -845,6 +873,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
"NoOp reason must be preserved on the TransitionResult so callers can log it");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that TransitionResult.None carries a null reason, distinguishing it from the NoOp factory (Core.ScriptedAlarms-011).</summary>
|
||||
[Fact]
|
||||
public void TransitionResult_None_carries_no_reason(/* -011 */)
|
||||
{
|
||||
@@ -875,20 +904,32 @@ public sealed class ScriptedAlarmEngineTests
|
||||
private sealed class FailOnSaveAlarmStateStore : IAlarmStateStore
|
||||
{
|
||||
private readonly InMemoryAlarmStateStore _inner = new();
|
||||
/// <summary>Gets or sets a value indicating whether the next SaveAsync call should throw a simulated failure.</summary>
|
||||
public bool FailSave { get; set; }
|
||||
|
||||
/// <summary>Loads an alarm condition state by ID from the inner store.</summary>
|
||||
/// <param name="alarmId">The ID of the alarm condition state to load.</param>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public Task<AlarmConditionState?> LoadAsync(string alarmId, CancellationToken ct)
|
||||
=> _inner.LoadAsync(alarmId, ct);
|
||||
|
||||
/// <summary>Loads all alarm condition states from the inner store.</summary>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public Task<IReadOnlyList<AlarmConditionState>> LoadAllAsync(CancellationToken ct)
|
||||
=> _inner.LoadAllAsync(ct);
|
||||
|
||||
/// <summary>Saves an alarm condition state, optionally throwing if FailSave is set.</summary>
|
||||
/// <param name="state">The alarm condition state to save.</param>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public Task SaveAsync(AlarmConditionState state, CancellationToken ct)
|
||||
{
|
||||
if (FailSave) throw new InvalidOperationException("Simulated store failure");
|
||||
return _inner.SaveAsync(state, ct);
|
||||
}
|
||||
|
||||
/// <summary>Removes an alarm condition state by ID from the inner store.</summary>
|
||||
/// <param name="alarmId">The ID of the alarm condition state to remove.</param>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public Task RemoveAsync(string alarmId, CancellationToken ct)
|
||||
=> _inner.RemoveAsync(alarmId, ct);
|
||||
}
|
||||
@@ -900,15 +941,25 @@ public sealed class ScriptedAlarmEngineTests
|
||||
private sealed class BlockingSaveAlarmStateStore : IAlarmStateStore
|
||||
{
|
||||
private readonly InMemoryAlarmStateStore _inner = new();
|
||||
/// <summary>Gets or sets a TaskCompletionSource that, when set, blocks the next SaveAsync until signalled.</summary>
|
||||
public TaskCompletionSource? BlockNextSave { get; set; }
|
||||
/// <summary>Gets a value indicating whether a SaveAsync call is currently blocked waiting on BlockNextSave.</summary>
|
||||
public bool SaveInProgress { get; private set; }
|
||||
|
||||
/// <summary>Loads an alarm condition state by ID from the inner store.</summary>
|
||||
/// <param name="alarmId">The ID of the alarm condition state to load.</param>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public Task<AlarmConditionState?> LoadAsync(string alarmId, CancellationToken ct)
|
||||
=> _inner.LoadAsync(alarmId, ct);
|
||||
|
||||
/// <summary>Loads all alarm condition states from the inner store.</summary>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public Task<IReadOnlyList<AlarmConditionState>> LoadAllAsync(CancellationToken ct)
|
||||
=> _inner.LoadAllAsync(ct);
|
||||
|
||||
/// <summary>Saves an alarm condition state, optionally blocking on BlockNextSave gate.</summary>
|
||||
/// <param name="state">The alarm condition state to save.</param>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public async Task SaveAsync(AlarmConditionState state, CancellationToken ct)
|
||||
{
|
||||
var gate = BlockNextSave;
|
||||
@@ -922,12 +973,16 @@ public sealed class ScriptedAlarmEngineTests
|
||||
await _inner.SaveAsync(state, ct).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>Removes an alarm condition state by ID from the inner store.</summary>
|
||||
/// <param name="alarmId">The ID of the alarm condition state to remove.</param>
|
||||
/// <param name="ct">A cancellation token.</param>
|
||||
public Task RemoveAsync(string alarmId, CancellationToken ct)
|
||||
=> _inner.RemoveAsync(alarmId, ct);
|
||||
}
|
||||
|
||||
// --- Core.ScriptedAlarms-009: per-alarm evaluation-scratch reuse ---
|
||||
|
||||
/// <summary>Verifies that re-evaluations reuse the same read cache dictionary instance instead of allocating a new one.</summary>
|
||||
[Fact]
|
||||
public async Task Reevaluation_reuses_the_same_read_cache_dictionary()
|
||||
{
|
||||
@@ -960,6 +1015,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
scratchAfterPush!["Temp"].Value.ShouldBe(150, "refill must update the existing dictionary in place");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that re-evaluations reuse the same predicate context instance across evaluations.</summary>
|
||||
[Fact]
|
||||
public async Task Reevaluation_reuses_the_same_predicate_context()
|
||||
{
|
||||
@@ -985,6 +1041,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
"the AlarmPredicateContext must be reused across evaluations (Core.ScriptedAlarms-009).");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that LoadAsync clears prior evaluation scratch so new alarms use fresh scratch.</summary>
|
||||
[Fact]
|
||||
public async Task LoadAsync_drops_the_prior_generations_scratch()
|
||||
{
|
||||
@@ -1018,6 +1075,7 @@ public sealed class ScriptedAlarmEngineTests
|
||||
|
||||
// --- Core.Scripting-016: engine routes compiles through CompiledScriptCache ---
|
||||
|
||||
/// <summary>Verifies that Dispose unloads the compiled predicate assembly via the script cache.</summary>
|
||||
[Fact]
|
||||
public void Dispose_unloads_compiled_predicate_assembly()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user