Show what is spotted and not worked yet
The Available Mults and Qs window: a column per band, the multipliers at the top of each column and then the stations that are only points. Clicking one puts the radio there with the call in the entry window, the same as the bandmap does. Every spot on the bandmap goes through ContestLog.Judge, and what comes back a dupe is dropped, so the colours and the ordering agree with every other window. A spot holds a callsign and a frequency and nothing else. For CQ WW that gives the country multiplier, which is derived from the call, but not the zone, which is what the other station sends. Where a call history file has an entry for the call its exchange is filled into the candidate first, so a published CQZone column brings the zone in and a Sect column makes Sweepstakes work at all. Filling the zone from the country file instead was rejected: it is wrong for every large country, and a multiplier that is not there is better than one that is not real. A spot has no mode either, so the candidate is judged in the mode the radio is in. In a mixed-mode contest that means the answer follows the operator. RadioPosition kept two private mappings — exchange value into a contact, and call history field into an exchange box — and both are needed here, so they move to ExchangeSlots and both callers share them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
170
tests/Nonemm.Session.Tests/AvailableStationsTests.cs
Normal file
170
tests/Nonemm.Session.Tests/AvailableStationsTests.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using Nonemm.Contests;
|
||||
using Nonemm.Contests.Rules;
|
||||
using Nonemm.Core;
|
||||
using Nonemm.Core.Calls;
|
||||
using Nonemm.Core.Country;
|
||||
using Nonemm.Spotting;
|
||||
using Nonemm.Storage;
|
||||
|
||||
namespace Nonemm.Session.Tests;
|
||||
|
||||
public class AvailableStationsTests
|
||||
{
|
||||
private const string Countries = """
|
||||
Germany: 14: 28: EU: 51.00: -10.00: -1.0: DL:
|
||||
DL,DK,DJ;
|
||||
Japan: 25: 45: AS: 36.40: -138.38: -9.0: JA:
|
||||
JA,JH,JR;
|
||||
United States: 05: 08: NA: 37.53: 91.67: 5.0: K:
|
||||
K,W,N;
|
||||
""";
|
||||
|
||||
private static readonly StationInfo Me = new()
|
||||
{
|
||||
Callsign = "DL1ABC",
|
||||
CqZone = 14,
|
||||
ItuZone = 28,
|
||||
Continent = "EU",
|
||||
CountryPrefix = "DL",
|
||||
};
|
||||
|
||||
private static readonly Frequency On20 = Frequency.FromKilohertz(14_030);
|
||||
|
||||
private static (RadioPosition Position, Bandmap Bandmap, AvailableStations Available) Station(
|
||||
Contest? contest = null,
|
||||
CallHistory? history = null)
|
||||
{
|
||||
FakeLogStore store = new();
|
||||
ContestInstance instance = store.AddContest(new ContestInstance
|
||||
{
|
||||
ContestNumber = 0,
|
||||
ContestName = "CQWW",
|
||||
});
|
||||
ContestSession session = new(
|
||||
store,
|
||||
contest ?? new CqWorldWide(ModeCategory.Cw),
|
||||
instance,
|
||||
Me,
|
||||
CountryFile.Parse(Countries),
|
||||
history);
|
||||
RadioPosition position = new(session);
|
||||
Bandmap bandmap = new();
|
||||
return (position, bandmap, new AvailableStations(position, bandmap));
|
||||
}
|
||||
|
||||
private static Spot At(string call, Frequency where) =>
|
||||
new(Callsign.Parse(call), where, DateTime.UtcNow, SpotSource.Cluster, "OK1TEST");
|
||||
|
||||
private static void Work(RadioPosition position, string call, string zone, Frequency where)
|
||||
{
|
||||
position.Tune(where);
|
||||
position.Entry.Call = call;
|
||||
position.Entry.Set(ExchangeSlot.ReceivedReport, "599");
|
||||
position.Entry.Set(ExchangeSlot.Zone, zone);
|
||||
position.LogContact();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ASpottedStationThatIsANewCountryIsAMultiplier()
|
||||
{
|
||||
(_, Bandmap bandmap, AvailableStations available) = Station();
|
||||
bandmap.Add(At("JA1XYZ", On20));
|
||||
|
||||
AvailableStation station = Assert.Single(available.All());
|
||||
Assert.True(station.IsMultiplier);
|
||||
Assert.Equal(Bands.Band20M, station.Band);
|
||||
Assert.Equal("JA", station.MultiplierText);
|
||||
}
|
||||
|
||||
/// CQ WW counts the zone the station sends, not the one the country file
|
||||
/// guesses, and a spot carries no exchange. So the zone shows only where
|
||||
/// the call history file published it.
|
||||
[Fact]
|
||||
public void TheCallHistoryZoneBringsInTheZoneMultiplier()
|
||||
{
|
||||
CallHistory history = CallHistory.Parse("""
|
||||
!!Order!!,Call,CQZone
|
||||
JA1XYZ,25
|
||||
""");
|
||||
(_, Bandmap bandmap, AvailableStations available) = Station(history: history);
|
||||
bandmap.Add(At("JA1XYZ", On20));
|
||||
|
||||
AvailableStation station = Assert.Single(available.All());
|
||||
Assert.Equal("25, JA", station.MultiplierText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStationAlreadyWorkedOnThatBandIsLeftOut()
|
||||
{
|
||||
(RadioPosition position, Bandmap bandmap, AvailableStations available) = Station();
|
||||
Work(position, "JA1XYZ", "25", On20);
|
||||
bandmap.Add(At("JA1XYZ", On20));
|
||||
|
||||
Assert.Empty(available.All());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TheSameStationOnAnotherBandIsStillWorthWorking()
|
||||
{
|
||||
(RadioPosition position, Bandmap bandmap, AvailableStations available) = Station();
|
||||
Work(position, "JA1XYZ", "25", On20);
|
||||
bandmap.Add(At("JA1XYZ", Frequency.FromKilohertz(7_030)));
|
||||
|
||||
AvailableStation station = Assert.Single(available.All());
|
||||
Assert.Equal(Bands.Band40M, station.Band);
|
||||
Assert.True(station.IsMultiplier);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStationThatBringsNoMultiplierIsStillOfferedForItsPoints()
|
||||
{
|
||||
(RadioPosition position, Bandmap bandmap, AvailableStations available) = Station();
|
||||
Work(position, "JA1XYZ", "25", On20);
|
||||
bandmap.Add(At("JA2ABC", On20));
|
||||
|
||||
AvailableStation station = Assert.Single(available.All());
|
||||
Assert.False(station.IsMultiplier);
|
||||
Assert.True(station.Verdict.Points > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipliersComeFirst()
|
||||
{
|
||||
(RadioPosition position, Bandmap bandmap, AvailableStations available) = Station();
|
||||
Work(position, "JA1XYZ", "25", On20);
|
||||
bandmap.Add(At("JA2ABC", Frequency.FromKilohertz(14_010)));
|
||||
bandmap.Add(At("W1AW", Frequency.FromKilohertz(14_040)));
|
||||
|
||||
Assert.Equal(
|
||||
["W1AW", "JA2ABC"],
|
||||
available.All().Select(s => s.Spot.Call.Text).ToList());
|
||||
}
|
||||
|
||||
/// A spot carries no exchange, so a section contest can only judge a
|
||||
/// spotted station where the call history file says what it sends.
|
||||
[Fact]
|
||||
public void TheCallHistoryFillsTheExchangeOfASpottedStation()
|
||||
{
|
||||
CallHistory history = CallHistory.Parse("""
|
||||
!!Order!!,Call,Sect
|
||||
W1AW,CT
|
||||
""");
|
||||
(_, Bandmap bandmap, AvailableStations available) =
|
||||
Station(new Sweepstakes(ModeCategory.Cw), history);
|
||||
bandmap.Add(At("W1AW", Frequency.FromKilohertz(14_080)));
|
||||
|
||||
AvailableStation station = Assert.Single(available.All());
|
||||
Assert.True(station.IsMultiplier);
|
||||
Assert.Equal("CT", station.MultiplierText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithNoCallHistoryASpottedStationOfASectionContestIsJustPoints()
|
||||
{
|
||||
(_, Bandmap bandmap, AvailableStations available) = Station(new Sweepstakes(ModeCategory.Cw));
|
||||
bandmap.Add(At("W1AW", Frequency.FromKilohertz(14_080)));
|
||||
|
||||
AvailableStation station = Assert.Single(available.All());
|
||||
Assert.False(station.IsMultiplier);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user