using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common.Tests; /// EventContinuation, HistorianHealthCounters, ClampSeverity and the StoredSample quality clamp. public sealed class SharedHelperTests { [Fact] public void Event_continuation_is_ticks_pipe_event_id() { var t = new DateTime(2026, 10, 9, 8, 0, 0, DateTimeKind.Utc).AddTicks(1234567); EventContinuation.Encode(t, "abc").ShouldBe($"{t.Ticks.ToString(System.Globalization.CultureInfo.InvariantCulture)}|abc"); EventContinuation.Encode(new DateTime(42), "id").ShouldBe("42|id"); } [Theory] [InlineData(-5, 0)] [InlineData(700, 700)] [InlineData(70_000, 65_535)] public void Event_severity_is_clamped_to_ushort(int stored, int expected) => HistoricalEventRows.ClampSeverity(stored).ShouldBe((ushort)expected); [Fact] public void Health_counters_open_only_after_a_success_with_no_failure_since() { var h = new HistorianHealthCounters(); h.Snapshot().ProcessConnectionOpen.ShouldBeFalse(); h.RecordSuccess(); h.Snapshot().ProcessConnectionOpen.ShouldBeTrue(); h.RecordFailure(new InvalidOperationException("boom")); var s = h.Snapshot(); s.ProcessConnectionOpen.ShouldBeFalse(); s.EventConnectionOpen.ShouldBeFalse(); s.ConsecutiveFailures.ShouldBe(1); s.TotalQueries.ShouldBe(2); s.LastError.ShouldBe("InvalidOperationException: boom"); h.RecordSuccess(); h.Snapshot().ConsecutiveFailures.ShouldBe(0); h.Snapshot().ProcessConnectionOpen.ShouldBeTrue(); } [Fact] public void A_cancellation_is_not_a_health_failure() { var h = new HistorianHealthCounters(); h.RecordFailure(new OperationCanceledException()); h.RecordFailure(new TaskCanceledException()); var s = h.Snapshot(); s.TotalQueries.ShouldBe(0); s.TotalFailures.ShouldBe(0); s.LastError.ShouldBeNull(); } [Fact] public void A_stored_empty_sample_with_a_non_bad_status_is_served_BadNoData() { var t = DateTime.UnixEpoch; StoredSample.FromStored(t, HistorianValue.Empty, 0u).Status.ShouldBe(0x809B0000u); StoredSample.FromStored(t, HistorianValue.Empty, 0x40000000u).Status.ShouldBe(0x809B0000u); StoredSample.FromStored(t, HistorianValue.Empty, 0x80310000u).Status.ShouldBe(0x80310000u); StoredSample.FromStored(t, HistorianValue.FromDouble(1), 0x40000000u).Status.ShouldBe(0x40000000u); StoredSample.FromStored(t, HistorianValue.Empty, 0x80310000u).IsUsable.ShouldBeFalse(); StoredSample.FromStored(t, HistorianValue.FromDouble(1), 0x40000000u).IsGood.ShouldBeFalse(); } }