using Nonemm.Core.Calls; namespace Nonemm.Core.Tests.Calls; public class CallHistoryTests { [Fact] public void AFileWithNoOrderLineIsReadInTheDefaultOrder() { CallHistory history = CallHistory.Parse( "OM5M,Erik,JN88,,,,,,15,,100,15,28,notes"); CallHistoryEntry? found = history.Find("OM5M"); Assert.Equal("Erik", found?.Name); Assert.Equal("JN88", found?.GridSquare); Assert.Equal("15", found?.Exchange1); Assert.Equal("100", found?.Power); Assert.Equal(15, found?.CqZone); Assert.Equal(28, found?.ItuZone); } [Fact] public void AnOrderLineNamesTheColumns() { CallHistory history = CallHistory.Parse(""" !!Order!!,Call,Sect,Name W3LPL,MDC,Frank """); Assert.Equal("MDC", history.Find("W3LPL")?.Section); Assert.Equal("Frank", history.Find("W3LPL")?.Name); } [Fact] public void CommentsAndBlankLinesArePassedOver() { CallHistory history = CallHistory.Parse(""" # a comment # another !!Order!!,Call,Name OM5M,Erik """); Assert.Equal(1, history.Count); } /// N1MM takes semicolons in preference to commas, so user text holding a /// comma can still be read. [Fact] public void ALineWithSemicolonsIsSplitOnThose() { CallHistory history = CallHistory.Parse(""" !!Order!!;Call;Name;UserText OM5M;Erik;works 20m, mostly CW """); Assert.Equal("Erik", history.Find("OM5M")?.Name); Assert.Equal("works 20m, mostly CW", history.Find("OM5M")?.UserText); } [Fact] public void AnUnknownCallIsNotFound() => Assert.Null(CallHistory.Parse("OM5M,Erik").Find("JA1XYZ")); [Fact] public void TheCallIsMatchedWhateverCaseItIsTypedIn() => Assert.NotNull(CallHistory.Parse("om5m,Erik").Find("OM5M")); [Fact] public void AGridIsCutToFourCharactersWhenTheFileAsksForIt() { CallHistory history = CallHistory.Parse(""" !!FourCharGridSq!! !!Order!!,Call,Loc1 OM5M,JN88TG """); Assert.Equal("JN88", history.Find("OM5M")?.GridSquare); } [Fact] public void TheSecondGridIsDroppedWhenTheFileAsksForIt() { CallHistory history = CallHistory.Parse(""" !!NoLoc2AltGrid!! !!Order!!,Call,Loc1,Loc2 OM5M,JN88,JN99 """); Assert.Equal("", history.Find("OM5M")?.AlternateGridSquare); } [Fact] public void AnEmptySectionIsFilledFromTheStateWhenTheFileAsksForIt() { CallHistory history = CallHistory.Parse(""" !!MapStateToSect!! !!Order!!,Call,Sect,State K1TTT,,CT """); Assert.Equal("CT", history.Find("K1TTT")?.Section); } [Fact] public void AStateDoesNotOverwriteASectionThatIsThere() { CallHistory history = CallHistory.Parse(""" !!MapStateToSect!! !!Order!!,Call,Sect,State K1TTT,WMA,MA """); Assert.Equal("WMA", history.Find("K1TTT")?.Section); } /// The order can change part way through, because a file is often several /// files stuck together. [Fact] public void AnOrderLineOnlyAppliesToTheLinesAfterIt() { CallHistory history = CallHistory.Parse(""" !!Order!!,Call,Name OM5M,Erik !!Order!!,Call,Sect W3LPL,MDC """); Assert.Equal("Erik", history.Find("OM5M")?.Name); Assert.Equal("MDC", history.Find("W3LPL")?.Section); } [Fact] public void AlaterLineWinsForACallThatAppearsTwice() { CallHistory history = CallHistory.Parse(""" !!Order!!,Call,Name OM5M,Erik OM5M,Eric """); Assert.Equal("Eric", history.Find("OM5M")?.Name); Assert.Equal(1, history.Count); } [Fact] public void UserTextIsAddedToRatherThanReplaced() { CallHistory history = CallHistory.Parse(""" !!Order!!,Call,UserText OM5M,first OM5M,second """); Assert.Equal("first second", history.Find("OM5M")?.UserText); } [Fact] public void UserTextIsReplacedWhenTheFileAsksForIt() { CallHistory history = CallHistory.Parse(""" !!NoAppendUserText!! !!Order!!,Call,UserText OM5M,first OM5M,second """); Assert.Equal("second", history.Find("OM5M")?.UserText); } /// A directive must not be read as a callsign. [Fact] public void ADirectiveIsNotData() { CallHistory history = CallHistory.Parse(""" !!ValidateArrlSection!! !!Order!!,Call,Name OM5M,Erik """); Assert.Equal(1, history.Count); Assert.Null(history.Find("!!ValidateArrlSection!!")); } /// `!!MapOnSection!!`: the old Ontario sections are stored as `ON`. [Theory] [InlineData("ONN", "ON")] [InlineData("GTA", "ON")] [InlineData("EMA", "EMA")] public void MapOnSectionStoresTheOntarioSectionsAsOne(string section, string expected) => Assert.Equal( expected, Section("!!MapOnSection!!", section)); /// `!!ValidateArrlSection!!`: a section that is not one of N1MM's is /// dropped rather than stored. [Theory] [InlineData("EMA", "EMA")] [InlineData("XYZ", "")] [InlineData("ON", "")] public void ValidateArrlSectionDropsWhatIsNotASection(string section, string expected) => Assert.Equal(expected, Section("!!ValidateArrlSection!!", section)); /// `!!GTA2GH_NT2TER!!`: the two renamed sections. [Theory] [InlineData("GTA", "GH")] [InlineData("NT", "TER")] [InlineData("ONN", "ONN")] public void Gta2GhRenamesTheTwoSections(string section, string expected) => Assert.Equal(expected, Section("!!GTA2GH_NT2TER!!", section)); /// `!!Validate50State!!`: a state stays, a section becomes the state it is /// in, and anything else goes. [Theory] [InlineData("OH", "OH")] [InlineData("EMA", "MA")] [InlineData("SCV", "CA")] [InlineData("ONN", "")] [InlineData("XYZ", "")] public void Validate50StateKeepsOnlyStates(string state, string expected) => Assert.Equal( expected, CallHistory.Parse($""" !!Validate50State!! !!Order!!,Call,State OM5M,{state} """).Find("OM5M")?.State); /// Without the directive the column is stored as the file wrote it. [Fact] public void AFileThatAsksForNoCleanupIsStoredAsItIs() { CallHistoryEntry? found = CallHistory.Parse(""" !!Order!!,Call,Sect,State VE3ABC,ONN,XYZ """).Find("VE3ABC"); Assert.Equal("ONN", found?.Section); Assert.Equal("XYZ", found?.State); } private static string? Section(string directive, string section) => CallHistory.Parse($""" {directive} !!Order!!,Call,Sect VE3ABC,{section} """).Find("VE3ABC")?.Section; [Fact] public void ALineWithNoCallIsNotAnEntry() => Assert.Equal(0, CallHistory.Parse(",Erik,JN88").Count); }