using KArtSell.Modules.ModelOperations.Domain; namespace KArtSell.ModelOperations.UnitTests; public sealed class ScheduleOccurrencePlannerTests { [Fact] public void Daily_anchor_does_not_drift_to_dispatch_time() { var scheduled = new DateTimeOffset(2026, 8, 1, 1, 0, 0, TimeSpan.Zero); var next = ScheduleOccurrencePlanner.GetNextDueAt(scheduled, "DAILY", "LATEST_ONLY", 1, scheduled.AddHours(10)); Assert.Equal(scheduled.AddDays(1), next); } [Fact] public void Missed_occurrences_are_skipped_without_dispatch_storm() { var scheduled = new DateTimeOffset(2026, 7, 1, 1, 0, 0, TimeSpan.Zero); var next = ScheduleOccurrencePlanner.GetNextDueAt(scheduled, "DAILY", "LATEST_ONLY", 1, new DateTimeOffset(2026, 8, 1, 4, 0, 0, TimeSpan.Zero)); Assert.True(next > new DateTimeOffset(2026, 8, 1, 4, 0, 0, TimeSpan.Zero)); Assert.Equal(1, next.Hour); } [Fact] public void All_with_limit_dispatches_only_the_most_recent_configured_occurrences() { var scheduled = new DateTimeOffset(2026, 8, 1, 1, 0, 0, TimeSpan.Zero); var plan = ScheduleOccurrencePlanner.Plan(scheduled, "DAILY", "ALL_WITH_LIMIT", 2, new DateTimeOffset(2026, 8, 4, 4, 0, 0, TimeSpan.Zero)); Assert.Equal([scheduled.AddDays(2), scheduled.AddDays(3)], plan.OccurrencesToDispatch); Assert.Equal(scheduled.AddDays(4), plan.NextDueAt); } [Fact] public void Skip_missed_advances_without_dispatching_a_stale_occurrence() { var scheduled = new DateTimeOffset(2026, 8, 1, 1, 0, 0, TimeSpan.Zero); var plan = ScheduleOccurrencePlanner.Plan(scheduled, "DAILY", "SKIP_MISSED", 1, new DateTimeOffset(2026, 8, 3, 4, 0, 0, TimeSpan.Zero)); Assert.Empty(plan.OccurrencesToDispatch); Assert.Equal(scheduled.AddDays(3), plan.NextDueAt); } }