using Nonemm.Core; namespace Nonemm.Spotting.Tests; public class BandmapTests { private static readonly DateTime Now = new(2026, 5, 30, 12, 0, 0, DateTimeKind.Utc); private static Spot At(string call, double kilohertz, DateTime? at = null) => new(Callsign.Parse(call), Frequency.FromKilohertz(kilohertz), at ?? Now, SpotSource.Cluster); [Fact] public void SpotsComeBackInFrequencyOrder() { Bandmap map = new(); map.Add(At("DL1ABC", 14_100)); map.Add(At("JA1XYZ", 14_010)); Assert.Equal(["JA1XYZ", "DL1ABC"], map.On(Bands.Band20M).Select(s => s.Call.Text)); } [Fact] public void AStationThatMovesKeepsOneEntryOnItsBand() { Bandmap map = new(); map.Add(At("DL1ABC", 14_010)); map.Add(At("DL1ABC", 14_020)); Spot only = Assert.Single(map.On(Bands.Band20M)); Assert.Equal(14_020_000, only.Frequency.Hertz); } [Fact] public void TheSameStationOnAnotherBandIsASeparateEntry() { Bandmap map = new(); map.Add(At("DL1ABC", 14_010)); map.Add(At("DL1ABC", 7_010)); Assert.Equal(2, map.All().Count); } [Fact] public void SpotsOlderThanAnHourAreDropped() { DateTime arriving = Now.AddHours(-2); Bandmap map = new(clock: () => arriving); map.Add(At("DL1ABC", 14_010)); arriving = Now.AddMinutes(-5); map.Add(At("JA1XYZ", 14_020)); map.DropOlderThan(Now); Assert.Equal("JA1XYZ", Assert.Single(map.All()).Call.Text); } /// Nodes get their clocks wrong and replay their backlog on connect. Age is /// counted from when the spot arrived, so a spot stamped hours ago still /// shows for the hour after it turned up. [Fact] public void ASpotStampedLongAgoIsKeptIfItOnlyJustArrived() { Bandmap map = new(clock: () => Now); map.Add(At("DL1ABC", 14_010, Now.AddHours(-4))); map.DropOlderThan(Now); Assert.Single(map.All()); } [Fact] public void ARespottedStationStartsItsHourAgain() { DateTime arriving = Now.AddMinutes(-50); Bandmap map = new(clock: () => arriving); map.Add(At("DL1ABC", 14_010)); arriving = Now; map.Add(At("DL1ABC", 14_012)); map.DropOlderThan(Now.AddMinutes(30)); Assert.Single(map.All()); } /// N1MM's Mark button leaves this where the radio is, to say the frequency /// is busy. [Fact] public void AMarkIsLabelledWithTheTimeAndIsNotAStation() { Spot mark = Spot.Mark( Frequency.FromKilohertz(14_030), new DateTime(2026, 1, 1, 22, 31, 5, DateTimeKind.Utc)); Assert.Equal("BUSY@22:31:05", mark.Call.Text); Assert.False(mark.IsStation); } [Fact] public void TheNearestSpotInsideTheWindowIsFound() { Bandmap map = new(); map.Add(At("DL1ABC", 14_010)); map.Add(At("JA1XYZ", 14_050)); Assert.Equal( "DL1ABC", map.Near(Frequency.FromKilohertz(14_010.2), Frequency.FromKilohertz(0.5))?.Call.Text); Assert.Null(map.Near(Frequency.FromKilohertz(14_030), Frequency.FromKilohertz(0.5))); } }