using Nonemm.Core; namespace Nonemm.Contests.Tests; /// The `…BandChange…` settings: what counts as a change, and over what stretch /// of time the changes are counted. public class BandChangeRulesTests { private static readonly DateTime Start = new(2026, 5, 30, 12, 0, 0, DateTimeKind.Utc); private static Qso At(int minutes, double kilohertz, Mode? mode = null, int seconds = 0) => TestLog.Contact("OM3XYZ", kilohertz, mode: mode) with { TimestampUtc = Start.AddMinutes(minutes).AddSeconds(seconds), }; [Fact] public void EachMoveToAnotherBandIsOneChange() => Assert.Equal( 2, new BandChangeRules(8).CountedIn( [At(0, 14_025), At(5, 7_040), At(10, 7_045), At(15, 14_030)], Start.AddMinutes(20))); /// The count is per clock hour unless the file says otherwise, so a change /// made in the hour before does not count against this one. [Fact] public void ChangesMadeInAnEarlierHourAreNotCounted() => Assert.Equal( 1, new BandChangeRules(8).CountedIn( [At(0, 14_025), At(5, 7_040), At(65, 14_025)], Start.AddMinutes(70))); [Fact] public void CountingPerContestKeepsEveryChange() => Assert.Equal( 2, new BandChangeRules(8, PerContest: true).CountedIn( [At(0, 14_025), At(5, 7_040), At(65, 14_025)], Start.AddMinutes(70))); /// `CountBandChangesPerPeriod` counts the hour up to now rather than the /// clock hour. [Fact] public void CountingPerPeriodLooksBackAnHour() => Assert.Equal( 1, new BandChangeRules(8, PerPeriod: true).CountedIn( [At(0, 14_025), At(5, 7_040), At(65, 14_025)], Start.AddMinutes(70))); /// `CountBandOrModeChange` counts a move to another mode on the same band. [Fact] public void ModeChangesCountWhenTheContestSaysSo() => Assert.Equal( 1, new BandChangeRules(8, CountsModeChanges: true).CountedIn( [At(0, 14_025), At(5, 14_250, Modes.Usb)], Start.AddMinutes(10))); /// The stay runs from the minute after the contact that changed band, so a /// change at 12:05:40 with a ten-minute stay has five minutes left at /// 12:11. N1MM starts it the same way. [Fact] public void TheStayCountsDownFromTheMinuteAfterTheChange() { BandChangeRules rules = new(8, MinimumStay: TimeSpan.FromMinutes(10)); Assert.Equal( TimeSpan.FromMinutes(5), rules.StayLeft([At(0, 14_025), At(5, 7_040, seconds: 40)], Start.AddMinutes(11))); } [Fact] public void TheStayIsUpOnceTheTimeHasPassed() => Assert.Equal( TimeSpan.Zero, new BandChangeRules(8, MinimumStay: TimeSpan.FromMinutes(10)).StayLeft( [At(0, 14_025), At(5, 7_040)], Start.AddMinutes(30))); /// A log that has stayed on one band has nothing to count down. [Fact] public void NothingCountsDownUntilTheStationChangesBand() => Assert.Equal( TimeSpan.Zero, new BandChangeRules(8, MinimumStay: TimeSpan.FromMinutes(10)).StayLeft( [At(0, 14_025), At(5, 14_030)], Start.AddMinutes(6))); [Fact] public void AContestThatAsksForNoStayHasNoTimer() { Assert.False(new BandChangeRules(8).HasStayTimer); Assert.True(new BandChangeRules(8, MinimumStay: TimeSpan.FromMinutes(10)).HasStayTimer); } [Fact] public void AContestWithNoLimitCountsNothing() => Assert.False(BandChangeRules.None.IsCounted); }