The # blocks in wl_cty.dat list CQ and ITU zones by call area and the first letter after the digit, written with the main prefix letters. A call now takes them whatever its own prefix letters are, so RA9Y and RM9I get what UA9Y gets, as in N1MM. A call whose own prefix rule gives a zone, and a whole-call entry, are left as they are. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
117 lines
3.7 KiB
C#
117 lines
3.7 KiB
C#
using Nonemm.Core;
|
|
using Nonemm.Core.Country;
|
|
|
|
namespace Nonemm.Core.Tests.Country;
|
|
|
|
public class CountryFileTests
|
|
{
|
|
private const string Sample = """
|
|
Sicily: 15: 28: EU: 37.50: -14.00: -1.0: *IT9:
|
|
IT9,IW9,ID9;
|
|
Italy: 15: 28: EU: 42.83: -12.83: -1.0: I:
|
|
I,IK,IZ,=IG9ABC;
|
|
United States: 05: 08: NA: 37.60: 91.87: 5.0: K:
|
|
K,W,N,K6(3)[6],=W1AW;
|
|
Fiji: 32: 56: OC: -17.78: -177.92: -12.0: 3D2:
|
|
3D2;
|
|
""";
|
|
|
|
private static readonly CountryFile File = CountryFile.Parse(Sample);
|
|
|
|
/// The publisher writes the issue date in as a callsign of its own. The
|
|
/// stations of a multi-operator entry compare it: two issues score the same
|
|
/// contact differently.
|
|
[Fact]
|
|
public void TheIssueDateIsRead() =>
|
|
Assert.Equal(
|
|
"20260826",
|
|
CountryFile.Parse(Sample.Replace("3D2;", "3D2,=VER20260826;")).Version);
|
|
|
|
[Fact]
|
|
public void AFileWithNoIssueDateHasNoVersion() =>
|
|
Assert.Equal("", File.Version);
|
|
|
|
[Fact]
|
|
public void LongestPrefixWins() =>
|
|
Assert.Equal("IT9", File.Find("IT9ABC")?.Entity.PrimaryPrefix);
|
|
|
|
[Fact]
|
|
public void ShorterPrefixStillMatches() =>
|
|
Assert.Equal("I", File.Find("IK2XYZ")?.Entity.PrimaryPrefix);
|
|
|
|
[Fact]
|
|
public void WaeOnlyEntitiesAreMarked() =>
|
|
Assert.True(File.Find("IT9ABC")?.Entity.IsWaeOnly);
|
|
|
|
[Fact]
|
|
public void WholeCallEntryBeatsThePrefix() =>
|
|
Assert.Equal("I", File.Find("IG9ABC")?.Entity.PrimaryPrefix);
|
|
|
|
[Fact]
|
|
public void PrefixOverrideChangesTheZone()
|
|
{
|
|
CountryLookup? found = File.Find("K6XYZ");
|
|
Assert.Equal(3, found?.CqZone);
|
|
Assert.Equal(6, found?.ItuZone);
|
|
}
|
|
|
|
[Fact]
|
|
public void PrefixWithoutOverrideKeepsTheEntityZone() =>
|
|
Assert.Equal(5, File.Find("W1XYZ")?.CqZone);
|
|
|
|
[Fact]
|
|
public void PortableStationIsLookedUpByItsPortablePrefix() =>
|
|
Assert.Equal("3D2", File.Find("3D2/K1ABC")?.Entity.PrimaryPrefix);
|
|
|
|
[Fact]
|
|
public void MaritimeMobileBelongsToNoEntity() =>
|
|
Assert.Null(File.Find("K1ABC/MM"));
|
|
|
|
[Fact]
|
|
public void LongitudeComesBackEastPositive() =>
|
|
Assert.Equal(-91.87, File.Find("W1XYZ")!.Longitude, 2);
|
|
|
|
[Fact]
|
|
public void UnknownCallHasNoEntity() =>
|
|
Assert.Null(File.Find("XX9ZZZ"));
|
|
|
|
[Theory]
|
|
[InlineData("")]
|
|
[InlineData("<html>404 not found</html>")]
|
|
public void TextThatIsNotACountryFileIsRejected(string text) =>
|
|
Assert.Throws<FormatException>(() => CountryFile.Parse(text));
|
|
|
|
private const string Russia = """
|
|
Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9:
|
|
# UA9: UA9H(18)[31],UA9J[20],
|
|
UA9Y(18)[31];
|
|
# UA0: UA0F(19)[34],UA0Z(19)[35];
|
|
R9,RA9,RM9,RZ9,RC0,UA9,UA0;
|
|
""";
|
|
|
|
/// The file lists zones by call area and the first letter after the digit
|
|
/// under UA, and N1MM applies them to every call of the entity.
|
|
[Theory]
|
|
[InlineData("UA9YA", 18, 31)]
|
|
[InlineData("RA9Y", 18, 31)]
|
|
[InlineData("RZ9YI", 18, 31)]
|
|
[InlineData("RM9J", 17, 20)]
|
|
[InlineData("RC0F", 19, 34)]
|
|
[InlineData("RA9A", 17, 30)]
|
|
public void TheZoneComesFromTheCallAreaListInTheFile(string call, int cq, int itu)
|
|
{
|
|
CountryLookup? found = CountryFile.Parse(Russia).Find(call);
|
|
|
|
Assert.Equal(cq, found?.CqZone);
|
|
Assert.Equal(itu, found?.ItuZone);
|
|
}
|
|
|
|
[Fact]
|
|
public void ACallWhoseOwnPrefixGivesAZoneIsNotChangedByTheList()
|
|
{
|
|
CountryFile file = CountryFile.Parse(Russia.Replace("RC0", "RC0(23)[40]"));
|
|
|
|
Assert.Equal(23, file.Find("RC0F")?.CqZone);
|
|
}
|
|
}
|