Files
Nonemm/tests/Nonemm.Core.Tests/Calls/CallHistoryTests.cs
ericek111 76b57cee1d Carry out the call history section directives
A call history file is built from years of logs, so its section and
state columns carry old names, and the file says at the top what to do
about that. The four lines that say it were read and passed over.

All four are now carried out, in N1MM's order: !!MapOnSection!! stores
the old Ontario sections as ON, !!ValidateArrlSection!! drops a section
that is not one of N1MM's, !!GTA2GH_NT2TER!! stores GTA as GH and NT as
TER, and !!Validate50State!! keeps a state, turns a section into the
state it is in, or drops the value.

The section list is the one N1MM's call history reader validates
against, which is not the list its entry window offers: it holds the
retired GTA and NT, and leaves out ON. It sits beside the reader in
Nonemm.Core rather than with the contest lists, which are the entry
window's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
2026-08-31 14:21:02 +00:00

255 lines
7.3 KiB
C#

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