Files
Nonemm/tests/Nonemm.Session.Tests/SkippedFieldTests.cs
T
erikbrockoandClaude Opus 5 b5d9f1e21c Name the All Asian multiplier after what it counts
The score window and the stored Contest.Multiplier1Name row both said
"Prefixes" for an Asian entrant, which counts DXCC entities.

Contest.MultiplierNames is now MultiplierNamesFor(StationInfo me), the
same shape as ExchangeFieldsFor. Every other contest returns the same
list it did before; All Asian returns "Countries" from Asia and
"Prefixes" from everywhere else. ContestDefinitions.For takes the
station as well, because that name is written to the log for N1MM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
2026-09-10 20:47:51 +00:00

135 lines
4.6 KiB
C#

using Nonemm.Contests;
using Nonemm.Core;
using Nonemm.Core.Country;
using Nonemm.Storage;
namespace Nonemm.Session.Tests;
/// A box the walk between the entry boxes steps over cannot be typed in, so it
/// must not be what holds a contact back either. CQ WW RTTY is the contest
/// that skips a box today, and its state box is not required; this is the rule
/// itself, so a contest that asks only some stations for a box cannot lock the
/// operator out of his own log.
public class SkippedFieldTests
{
private const string Countries = """
United States: 05: 08: NA: 37.60: 91.87: 5.0: K:
K,W,N,AA;
Japan: 25: 45: AS: 36.40: -138.38: -9.0: JA:
JA,JH,JR;
Germany: 14: 28: EU: 51.00: -10.00: -1.0: DL:
DL,DK;
""";
private static readonly StationInfo Me = new()
{
Callsign = "DL1ABC",
CountryPrefix = "DL",
Continent = "EU",
CqZone = 14,
};
private static OperatingPosition Position()
{
FakeLogStore store = new();
ContestInstance instance = store.AddContest(new ContestInstance
{
ContestNumber = 0,
ContestName = "STATEONLY",
});
return new OperatingPosition(new ContestSession(
store, new StateFromAmericansOnly(), instance, Me, CountryFile.Parse(Countries)));
}
private static OperatingPosition Working(string call)
{
OperatingPosition position = Position();
position.Entry.Call = call;
position.Entry.Set(ExchangeSlot.ReceivedReport, "599");
return position;
}
[Fact]
public void ABoxTheWalkStepsOverDoesNotHoldTheContactBack()
{
OperatingPosition position = Working("JA1XYZ");
Assert.True(position.IsEntryComplete);
Assert.Equal("JA1XYZ", position.LogContact().Call.Text);
}
[Fact]
public void ABoxTheStationIsAskedForStillHoldsTheContactBack()
{
OperatingPosition position = Working("K1ABC");
Assert.False(position.IsEntryComplete);
Assert.Throws<InvalidOperationException>(() => position.LogContact());
position.Entry.Set(ExchangeSlot.Section, "CT");
Assert.True(position.IsEntryComplete);
}
/// The cursor and the completeness check read the same rule. The report
/// boxes are filled in by the program, so with the state box stepped over
/// there is nothing left to type and the cursor stays on the callsign.
[Fact]
public void TheWalkStepsOverTheSameBox()
{
OperatingPosition japan = Working("JA1XYZ");
japan.Entry.FocusOn(0);
japan.MoveFocus(forward: true);
Assert.Equal(0, japan.Entry.Focus);
OperatingPosition america = Working("K1ABC");
america.Entry.FocusOn(0);
america.MoveFocus(forward: true);
Assert.Equal(
ExchangeSlot.Section,
america.Entry.Exchange[america.Entry.Focus - 1].Slot);
}
/// A contest that asks only American stations for a state, and marks the
/// box required — which is what the entry window used to lock up on.
private sealed class StateFromAmericansOnly : Contest
{
public string Name => "STATEONLY";
public string DisplayName => "State from Americans only";
public string CabrilloName => "STATE-ONLY";
public IReadOnlyList<ExchangeField> ExchangeFieldsFor(StationInfo me) =>
[
new ExchangeField("Snt", ExchangeSlot.SentReport, ExchangeFieldKind.Report, IsRequired: false),
new ExchangeField("Rcv", ExchangeSlot.ReceivedReport, ExchangeFieldKind.Report),
new ExchangeField("State", ExchangeSlot.Section, ExchangeFieldKind.Text),
];
public bool SkipsField(ExchangeField field, CountryLookup? their) =>
field.Slot == ExchangeSlot.Section && their?.Entity.PrimaryPrefix != "K";
public IReadOnlyList<string> MultiplierNamesFor(StationInfo me) => ["States"];
public DupeScope DupeScope => DupeScope.PerBand;
public bool HasSerialNumbers => false;
public IReadOnlyList<ModeCategory> Modes => [];
public string SentExchangeFor(StationInfo me) => me.State;
public int PointsFor(QsoContext qso) => 1;
public IReadOnlyList<Multiplier> MultipliersFor(QsoContext qso) => [];
public int TotalScore(ScoreTally tally, ContestEntry entry) => tally.Points;
public CabrilloExchange CabrilloExchange(Qso qso, StationInfo me, ContestEntry entry) =>
new([new CabrilloField(me.Callsign, 13)], [new CabrilloField(qso.Call.Text, 13)]);
}
}