CW and digital spots time out after 10 minutes and phone spots after 30 by default, both settings on the telnet Filters tab. The mode comes from the band plan; a frequency it has no boundaries for counts as phone. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
122 lines
3.6 KiB
C#
122 lines
3.6 KiB
C#
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 EachSpotLivesAsLongAsItsOwnLifetime()
|
|
{
|
|
Bandmap map = new(clock: () => Now)
|
|
{
|
|
LifetimeFor = spot => TimeSpan.FromMinutes(spot.Frequency.Kilohertz < 14_100 ? 10 : 30),
|
|
};
|
|
map.Add(At("DL1ABC", 14_025));
|
|
map.Add(At("JA1XYZ", 14_200));
|
|
|
|
map.DropOlderThan(Now.AddMinutes(15));
|
|
|
|
Assert.Equal(["JA1XYZ"], map.All().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)));
|
|
}
|
|
}
|