chore: release v0.25.9
This commit is contained in:
@@ -195,10 +195,7 @@ func (m *Manager) Lookup(ctx context.Context, callsign string) (Result, error) {
|
||||
// operator was looking the call up for, and it came back empty while
|
||||
// the same lookup without the suffix answered perfectly.
|
||||
if !saysNothingAboutLocation(call) {
|
||||
r.Country, r.Continent = "", ""
|
||||
r.CQZ, r.ITUZ, r.DXCC = 0, 0, 0
|
||||
r.Lat, r.Lon = 0, 0
|
||||
r.Grid, r.State, r.County = "", "", ""
|
||||
clearHomeLocation(&r)
|
||||
}
|
||||
fillFromDXCC(&r, dxcc) // entity/zones/lat-lon from the FULL (slashed) call
|
||||
normalizeNames(&r)
|
||||
@@ -378,6 +375,17 @@ func titleCase(s string) string {
|
||||
// the DXCC number since QRZ's value is wrong and we don't have an entity
|
||||
// → DXCC# table yet.
|
||||
// Returns true if any field was filled.
|
||||
// clearHomeLocation drops the fields that say WHERE a callbook record's operator
|
||||
// lives, and keeps the ones that say WHO they are — name, address, QSL route.
|
||||
// A portable operator's cards still go to the home address, so that address is
|
||||
// not wrong; their county is.
|
||||
func clearHomeLocation(r *Result) {
|
||||
r.Country, r.Continent = "", ""
|
||||
r.CQZ, r.ITUZ, r.DXCC = 0, 0, 0
|
||||
r.Lat, r.Lon = 0, 0
|
||||
r.Grid, r.State, r.County = "", "", ""
|
||||
}
|
||||
|
||||
func fillFromDXCC(r *Result, dxcc DXCCResolver) bool {
|
||||
if dxcc == nil {
|
||||
return false
|
||||
@@ -387,6 +395,33 @@ func fillFromDXCC(r *Result, dxcc DXCCResolver) bool {
|
||||
return false
|
||||
}
|
||||
filled := false
|
||||
|
||||
// A subdivision belongs to an ENTITY, so a record describing one entity has
|
||||
// nothing to say about a station operating from another.
|
||||
//
|
||||
// TI8/W2RE came back as a Costa Rica contact in Dutchess County, New York, on
|
||||
// square FN31 — W2RE's home details, from a QRZ page that carries the home
|
||||
// mailing address as most portable pages do. CNTY is *defined* as a US
|
||||
// county, so that is not a cosmetic slip: it is a US county award credit
|
||||
// recorded against a Costa Rica QSO, and a distance and beam heading computed
|
||||
// from a square 3,600 km from where the station actually is.
|
||||
//
|
||||
// The home-call fallback above already clears these, but it only runs when NO
|
||||
// provider had the slashed form. An operator with a page for their portable
|
||||
// call never reached it. Cleared here instead, where the operating entity is
|
||||
// known — which also heals rows already in the cache, since every cache hit
|
||||
// comes back through here.
|
||||
//
|
||||
// Same-entity portables (F4BPO/P, W2RE/2) are untouched: the entities match,
|
||||
// and there the home details ARE where the operator is.
|
||||
if dxccNum != 0 && strings.ContainsRune(r.Callsign, '/') && !saysNothingAboutLocation(r.Callsign) {
|
||||
if home := homeCall(r.Callsign); home != "" && home != r.Callsign {
|
||||
if homeNum, _, _, _, _, _, _, homeOK := dxcc.Resolve(home); homeOK && homeNum != 0 && homeNum != dxccNum {
|
||||
clearHomeLocation(r)
|
||||
filled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if country != "" {
|
||||
r.Country = country
|
||||
filled = true
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package lookup
|
||||
|
||||
import "testing"
|
||||
|
||||
// fakeDXCC resolves a handful of calls, enough to stand in for cty.dat.
|
||||
type fakeDXCC map[string]struct {
|
||||
num int
|
||||
country string
|
||||
cont string
|
||||
cqz, ituz int
|
||||
lat, lon float64
|
||||
}
|
||||
|
||||
func (f fakeDXCC) Resolve(call string) (int, string, string, int, int, float64, float64, bool) {
|
||||
e, ok := f[call]
|
||||
if !ok {
|
||||
return 0, "", "", 0, 0, 0, 0, false
|
||||
}
|
||||
return e.num, e.country, e.cont, e.cqz, e.ituz, e.lat, e.lon, true
|
||||
}
|
||||
|
||||
func testDXCC() fakeDXCC {
|
||||
return fakeDXCC{
|
||||
// Costa Rica, as cty.dat reads the OPERATING call.
|
||||
"TI8/W2RE": {num: 308, country: "Costa Rica", cont: "NA", cqz: 7, ituz: 11, lat: 9.9, lon: -84.1},
|
||||
// The home call: United States.
|
||||
"W2RE": {num: 291, country: "United States", cont: "NA", cqz: 5, ituz: 8, lat: 39.8, lon: -98.5},
|
||||
// A same-entity portable: still France either way.
|
||||
"F4BPO/P": {num: 227, country: "France", cont: "EU", cqz: 14, ituz: 27, lat: 46.2, lon: 2.2},
|
||||
"F4BPO": {num: 227, country: "France", cont: "EU", cqz: 14, ituz: 27, lat: 46.2, lon: 2.2},
|
||||
}
|
||||
}
|
||||
|
||||
// A callbook record for a portable call routinely carries the operator's HOME
|
||||
// address — most QRZ pages for a portable call do — and a subdivision belongs to
|
||||
// an entity. Carrying the home county across an entity change is not cosmetic:
|
||||
// CNTY is defined as a US county, so TI8/W2RE was coming out as a Costa Rica
|
||||
// contact credited to Dutchess County, New York, with the distance and beam
|
||||
// heading taken from a square 3,600 km from where the station actually was.
|
||||
func TestPortableInAnotherEntityDropsTheHomeSubdivision(t *testing.T) {
|
||||
r := Result{
|
||||
Callsign: "TI8/W2RE",
|
||||
Name: "Raymond", // who they are — kept
|
||||
QTH: "Poughquag",
|
||||
Address: "499 Pleasant Ridge Road", // cards still go there — kept
|
||||
State: "NY",
|
||||
County: "Dutchess",
|
||||
Grid: "FN31",
|
||||
Lat: 41.6, Lon: -73.7,
|
||||
DXCC: 291,
|
||||
}
|
||||
fillFromDXCC(&r, testDXCC())
|
||||
|
||||
if r.County != "" {
|
||||
t.Errorf("county = %q, want empty — a US county on a Costa Rica QSO is a false award credit", r.County)
|
||||
}
|
||||
if r.State != "" {
|
||||
t.Errorf("state = %q, want empty — a subdivision of the entity that is not being worked", r.State)
|
||||
}
|
||||
if r.Grid != "" {
|
||||
t.Errorf("grid = %q, want empty — it is the home square, 3,600 km from the operation", r.Grid)
|
||||
}
|
||||
// The entity and its centroid take over, so distance and bearing mean
|
||||
// something again.
|
||||
if r.DXCC != 308 || r.Country != "Costa Rica" {
|
||||
t.Errorf("entity = %d %q, want 308 Costa Rica", r.DXCC, r.Country)
|
||||
}
|
||||
if r.Lat != 9.9 || r.Lon != -84.1 {
|
||||
t.Errorf("lat/lon = %v/%v, want the Costa Rica centroid — the home coordinates must not survive", r.Lat, r.Lon)
|
||||
}
|
||||
// Who they are, and where their cards go, is unchanged.
|
||||
if r.Name != "Raymond" || r.Address != "499 Pleasant Ridge Road" {
|
||||
t.Errorf("name/address were cleared (%q / %q) — a portable operator's post still reaches home", r.Name, r.Address)
|
||||
}
|
||||
}
|
||||
|
||||
// The other half of the rule: a portable WITHIN the same entity is at home as
|
||||
// far as the entity is concerned, and its details must survive untouched.
|
||||
func TestSameEntityPortableKeepsItsLocation(t *testing.T) {
|
||||
r := Result{
|
||||
Callsign: "F4BPO/P",
|
||||
State: "77", County: "Seine-et-Marne", Grid: "JN18cs",
|
||||
Lat: 48.8, Lon: 2.4, DXCC: 227,
|
||||
}
|
||||
fillFromDXCC(&r, testDXCC())
|
||||
|
||||
if r.Grid != "JN18cs" || r.County != "Seine-et-Marne" || r.State != "77" {
|
||||
t.Errorf("a same-entity portable lost its location: grid=%q county=%q state=%q", r.Grid, r.County, r.State)
|
||||
}
|
||||
if r.Lat != 48.8 || r.Lon != 2.4 {
|
||||
t.Errorf("lat/lon = %v/%v — the precise home position was replaced by the entity centroid", r.Lat, r.Lon)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user