using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common.Tests; public sealed class LiveWritePreparerTests { private static readonly DateTime T = new DateTime(2026, 10, 9, 8, 0, 0, DateTimeKind.Utc).AddTicks(1234567); [Fact] public void Prepare_truncates_to_microseconds_before_dedup_when_resolution_is_10() { // The brief's example used AddTicks(3), but …567 + 3 = …570 crosses into the NEXT microsecond; +2 (…569) stays // in the same one (…560), which is the case the test means to pin. var t = T; var rows = LiveWritePreparer.Prepare([new(t, HistorianValue.FromDouble(1), 0), new(t.AddTicks(2), HistorianValue.FromDouble(2), 0)], () => t, 10); rows.Count.ShouldBe(1); rows[0].TimeUtc.Ticks.ShouldBe(t.Ticks - t.Ticks % 10); rows[0].Value.Number.ShouldBe(1); } [Fact] public void Resolution_1_keeps_100ns_ticks_distinct() { var rows = LiveWritePreparer.Prepare([new(T, HistorianValue.FromDouble(1), 0), new(T.AddTicks(3), HistorianValue.FromDouble(2), 0)], () => T); rows.Select(r => r.TimeUtc.Ticks).ShouldBe([T.Ticks, T.Ticks + 3]); } [Fact] public void Truncation_also_applies_to_the_clock_and_the_result_is_utc() { var rows = LiveWritePreparer.Prepare([new(null, HistorianValue.FromDouble(1), 0)], () => T, 10); rows[0].TimeUtc.ShouldBe(new DateTime(T.Ticks - 7, DateTimeKind.Utc)); rows[0].TimeUtc.Kind.ShouldBe(DateTimeKind.Utc); } }