using Nonemm.Contests.Rules; using Nonemm.Core; using Nonemm.Formats.Adif; namespace Nonemm.Formats.Tests; public class AdifTests { private static readonly StationInfo Me = new() { Callsign = "DL1ABC" }; private static Qso Contact() => new() { Id = Qso.NewId(), TimestampUtc = new DateTime(2026, 5, 30, 12, 34, 56, DateTimeKind.Utc), Call = Callsign.Parse("JA1XYZ"), Frequency = Frequency.FromKilohertz(14_025), Mode = Modes.Cw, ContestName = "CQWW", SentReport = "599", ReceivedReport = "579", Zone = 25, ReceivedNumber = 34, }; [Fact] public void ContactSurvivesAWriteAndRead() { string text = new AdifWriter(Me).Write([Contact()]); Qso read = AdifReader.Read(text).Single(); Assert.Equal("JA1XYZ", read.Call.Text); Assert.Equal(new DateTime(2026, 5, 30, 12, 34, 56, DateTimeKind.Utc), read.TimestampUtc); Assert.Equal(14_025_000, read.Frequency.Hertz); Assert.Equal(Modes.Cw, read.Mode); Assert.Equal("579", read.ReceivedReport); Assert.Equal(25, read.Zone); Assert.Equal(34, read.ReceivedNumber); Assert.Equal("CQWW", read.ContestName); } private static Qso Traffic() => new WaeQtc( Callsign.Parse("JA1XYZ"), IsSent: true, Series: 3, CountInSeries: 10, TimeUtc: "1435", Call: Callsign.Parse("DL9XYZ"), Number: 42, OwnNumber: 7) .ApplyTo(Contact() with { TimestampUtc = new DateTime(2026, 5, 30, 12, 40, 0, DateTimeKind.Utc) }); /// ADIF has no QTC record, so the plain export leaves the traffic out, the /// way N1MM does. [Fact] public void TrafficIsLeftOutUnlessItIsAskedFor() { string text = new AdifWriter(Me).Write([Contact() with { Exchange1 = WaeQtc.Contact }, Traffic()]); Qso read = Assert.Single(AdifReader.Read(text)); Assert.Equal("JA1XYZ", read.Call.Text); // the row kind comes back, so a contact read into a WAE log is still // a contact rather than a row of no kind at all Assert.Equal(WaeQtc.Contact, read.Exchange1); Assert.DoesNotContain("APP_NONEMM_QTC", text, StringComparison.Ordinal); } /// Asked for, the traffic goes in fields of our own and comes back as the /// same QTC, so a WAE log survives the round trip whole. [Fact] public void TrafficSurvivesAWriteAndRead() { string text = new AdifWriter(Me).Write([Contact(), Traffic()], withQtcTraffic: true); IReadOnlyList read = AdifReader.Read(text); Assert.Equal(2, read.Count); Qso row = read.Single(WaeQtc.IsQtc); Assert.Equal(new WaeQtc( Callsign.Parse("JA1XYZ"), true, 3, 10, "1435", Callsign.Parse("DL9XYZ"), 42, 7), WaeQtc.From(row)); Assert.Equal(new DateTime(2026, 5, 30, 12, 40, 0, DateTimeKind.Utc), row.TimestampUtc); Assert.Equal(Bands.Band20M, row.Band); } /// The report columns of a QTC row hold the time and callsign of the /// contact being reported, so writing them as a report and a serial number /// would tell another program something untrue. [Fact] public void TrafficDoesNotWriteTheReportFields() { string text = new AdifWriter(Me).Write([Traffic()], withQtcTraffic: true); Assert.DoesNotContain("JA1XYZ 20260530 123456 CW "; Assert.False(WaeQtc.IsQtc(AdifReader.Read(text).Single())); } [Fact] public void HeaderIsSkipped() { const string text = "Exported by something\r\n3.1.4 \r\n" + "JA1XYZ 20260530 123456 CW "; Assert.Equal("JA1XYZ", AdifReader.Read(text).Single().Call.Text); } [Fact] public void RecordWithNoCallIsDropped() { const string text = "\r\n20260530 \r\nJA1XYZ "; Assert.Single(AdifReader.Read(text)); } [Fact] public void BandStandsInWhenThereIsNoFrequency() { const string text = "\r\nJA1XYZ 20m "; Assert.Equal(Bands.Band20M, AdifReader.Read(text).Single().Band); } }