Files
Nonemm/tests/Nonemm.Session.Tests/AvailableStationsTests.cs
ericek111 d375d86466 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>
2026-08-27 23:01:11 +00:00

171 lines
5.8 KiB
C#

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);
}
}