using Nonemm.Contests; using Nonemm.Contests.Rules; using Nonemm.Core; using Nonemm.Core.Country; using Nonemm.Storage; namespace Nonemm.Session.Tests; /// What a contact from another station of a multi-operator entry does to this /// log. public class NetworkedContactsTests { 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; """; private static readonly StationInfo Me = new() { Callsign = "DL1ABC", CqZone = 14, ItuZone = 28, Continent = "EU", CountryPrefix = "DL", }; private static readonly DateTime Start = new(2026, 1, 1, 12, 0, 0, DateTimeKind.Utc); private static (ContestSession Session, FakeLogStore Store) Station() { FakeLogStore store = new(); ContestInstance instance = store.AddContest(new ContestInstance { ContestNumber = 0, ContestName = "CQWW", }); return ( new ContestSession( store, new CqWorldWide(ModeCategory.Cw), instance, Me, CountryFile.Parse(Countries)), store); } private static Qso Arriving(string call, int minute, int zone = 25) => new() { Id = $"{call}-{minute}", TimestampUtc = Start.AddMinutes(minute), Call = Callsign.Parse(call), Frequency = Frequency.FromKilohertz(14_030), Mode = Modes.Cw, ContestName = "CQWW", SentReport = "599", ReceivedReport = "599", Zone = zone, // what the sending station worked out, which is not trusted Points = 99, IsMultiplier1 = true, }; /// A contact worked at this station, which `Add` scores from the rules like /// any other. private static Qso WorkHere(ContestSession session, string call, int minute, int zone = 25) => session.Add(Arriving(call, minute, zone) with { Id = Qso.NewId(), ContestNumber = session.Instance.ContestNumber, }); [Fact] public void AContactFromAnotherStationIsLoggedAndScoredHere() { (ContestSession session, _) = Station(); Assert.True(session.AddFromNetwork(Arriving("JA1XYZ", 1))); Qso stored = Assert.Single(session.Log.Qsos); Assert.Equal("JA1XYZ", stored.Call.Text); Assert.Equal(3, stored.Points); Assert.False(stored.IsOriginal); Assert.Equal(session.Instance.ContestNumber, stored.ContestNumber); } [Fact] public void ItDoesNotGoBackOutToTheOtherStations() { (ContestSession session, _) = Station(); int sent = 0; session.Logged += (_, _) => sent++; session.AddFromNetwork(Arriving("JA1XYZ", 1)); Assert.Equal(0, sent); } [Fact] public void TheSameContactArrivingTwiceIsTakenOnce() { (ContestSession session, _) = Station(); session.AddFromNetwork(Arriving("JA1XYZ", 1)); Assert.False(session.AddFromNetwork(Arriving("JA1XYZ", 1))); Assert.Single(session.Log.Qsos); } /// The station that worked it first keeps the multiplier, however late the /// message about it turns up. [Fact] public void AContactThatArrivesLateStillTakesTheMultiplierItWorkedFirst() { (ContestSession session, _) = Station(); WorkHere(session, "JA9ZZZ", minute: 5); session.AddFromNetwork(Arriving("JA1XYZ", minute: 1)); Assert.True(session.Log.Qsos[0].IsMultiplier1); Assert.False(session.Log.Qsos[1].IsMultiplier1); Assert.Equal("JA1XYZ", session.Log.Qsos[0].Call.Text); } [Fact] public void WhatIsBeingTypedIsLeftAlone() { (ContestSession session, _) = Station(); OperatingPosition position = new(session); position.Entry.Call = "G4AB"; position.Entry.Set(ExchangeSlot.Zone, "14"); session.AddFromNetwork(Arriving("JA1XYZ", 1)); Assert.Equal("G4AB", position.Entry.Call); Assert.Equal("14", position.Entry.ValueOf(ExchangeSlot.Zone)); } [Fact] public void AnEditFromAnotherStationIsAppliedById() { (ContestSession session, _) = Station(); session.AddFromNetwork(Arriving("JA1XYZ", 1)); Assert.True(session.ReplaceFromNetwork( Arriving("JA1XYZ", 1) with { Zone = 24 }, "JA1XYZ", Start.AddMinutes(1))); Assert.Equal(24, Assert.Single(session.Log.Qsos).Zone); } /// N1MM does not know our ids, so a message from N1MM is matched on the /// call and time the contact had before the edit. [Fact] public void AnEditWithNoIdIsMatchedOnTheOldCallAndTime() { (ContestSession session, _) = Station(); Qso worked = WorkHere(session, "JA1XYZ", minute: 1); Assert.True(session.ReplaceFromNetwork( Arriving("JA1XYY", 1) with { Id = "" }, "JA1XYZ", worked.TimestampUtc)); Qso changed = Assert.Single(session.Log.Qsos); Assert.Equal("JA1XYY", changed.Call.Text); Assert.Equal(worked.Id, changed.Id); } [Fact] public void AnEditToAContactWeDoNotHoldIsRefused() { (ContestSession session, _) = Station(); Assert.False(session.ReplaceFromNetwork(Arriving("JA1XYZ", 1), "JA1XYZ", Start)); Assert.Empty(session.Log.Qsos); } [Fact] public void ADeleteFromAnotherStationRemovesTheContactAndRescores() { (ContestSession session, FakeLogStore store) = Station(); session.AddFromNetwork(Arriving("JA1XYZ", 1)); WorkHere(session, "JA9ZZZ", minute: 5); Assert.True(session.DeleteFromNetwork("JA1XYZ-1", "JA1XYZ", Start.AddMinutes(1))); Qso left = Assert.Single(session.Log.Qsos); Assert.Equal("JA9ZZZ", left.Call.Text); Assert.True(left.IsMultiplier1); Assert.Single(store.Qsos(session.Instance.ContestNumber)); } [Fact] public void ADeleteOfAContactWeDoNotHoldIsRefused() { (ContestSession session, _) = Station(); Assert.False(session.DeleteFromNetwork("nothing", "JA1XYZ", Start)); } }