ULS was wired into AddQSO alone, so an operator who downloaded it and has no QRZ.com/HamQTH account saw nothing while typing a US call: cty.dat gives the country, the zones, and a 4-character grid that is the ENTITY centroid — a thousand kilometres from the station. The county and the real square were stamped after logging, too late to point an antenna with. The enrichment runs last in the lookup wrapper and only fills blanks, so a provider always wins. ULS carries no name and no address, so it completes a QRZ record and can never replace one. The grid needed a rule of its own. refineGrid keeps what is there unless the new value extends it — correct for a QRZ square, wrong against an entity centroid, which is simply a different square. A per-callsign FCC square therefore beats any 4-character grid, while a 6-character one already present is left untouched. Lat/lon are recomputed only when we actually moved the grid. Portable calls are skipped: W1AW/4 is not what the FCC licensed.
61 lines
2.0 KiB
Go
61 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"hamlog/internal/uls"
|
|
)
|
|
|
|
// The ULS grid rules, which are NOT the same as refineGrid's.
|
|
//
|
|
// cty.dat answers a US call with the ENTITY centroid — a 4-character square in
|
|
// the middle of the country. refineGrid keeps it (the ULS square is not an
|
|
// extension of it, it is a different square), which is right for a QRZ grid and
|
|
// wrong here: a per-callsign FCC square beats any entity centroid. But a
|
|
// 6-character grid already present came from a provider and must survive.
|
|
func TestULSGridPreference(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
have string // grid already on the result
|
|
uls string // grid from the FCC database
|
|
want string
|
|
}{
|
|
{"nothing known → take ULS", "", "EM12AB", "EM12AB"},
|
|
{"cty.dat entity centroid → ULS wins", "EN90", "EM12AB", "EM12AB"},
|
|
{"4-char square, same square → ULS extends it", "EM12", "EM12AB", "EM12AB"},
|
|
{"provider gave 6 chars → untouched", "FN31PR", "EM12AB", "FN31PR"},
|
|
{"ULS has only 4 chars, provider has 6 → untouched", "FN31PR", "EM12", "FN31PR"},
|
|
{"ULS empty → untouched", "EN90", "", "EN90"},
|
|
}
|
|
for _, c := range cases {
|
|
got := c.have
|
|
if g := refineGrid(got, c.uls); g != "" && g != got {
|
|
got = g
|
|
} else if len(got) <= 4 && len(c.uls) >= 6 {
|
|
got = c.uls
|
|
}
|
|
if got != c.want {
|
|
t.Errorf("%s: have=%q uls=%q → %q, want %q", c.name, c.have, c.uls, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// CNTY is what gets written to the QSO's county field, so its shape is part of
|
|
// the contract: ADIF wants "State,County" and nothing when either half is
|
|
// missing — a lone county name would be an invalid CNTY on export.
|
|
func TestULSCountyFormat(t *testing.T) {
|
|
cases := []struct {
|
|
loc uls.Location
|
|
want string
|
|
}{
|
|
{uls.Location{State: "MA", County: "Middlesex"}, "MA,Middlesex"},
|
|
{uls.Location{State: "", County: "Middlesex"}, ""},
|
|
{uls.Location{State: "MA", County: ""}, ""},
|
|
}
|
|
for _, c := range cases {
|
|
if got := c.loc.CNTY(); got != c.want {
|
|
t.Errorf("Location%+v.CNTY() = %q, want %q", c.loc, got, c.want)
|
|
}
|
|
}
|
|
}
|