Grid: RI0FA transmitted QN35 all evening and was logged with its licence holder's home square. WSJT-X's logged ADIF usually carries no GRIDSQUARE, so the lookup was the only source left — and QRZ/HamQTH describe where an operator LIVES, which for an expedition is the wrong side of the planet. The square heard on the air is now applied before the lookup runs, so refineGrid has something to defend. It still upgrades a 4-character square to a 6-character one from the same field, and still refuses a finer square from a different field. SPE: decodeCSV marks the client connected on every frame it parses, and the poll goroutine can be mid-read while PowerOff runs. The frame from a second ago landed after PowerOff had marked the amp offline and put it straight back, which is why OFF had to be pressed twice. Frames are ignored for three seconds after the off key goes out — the window is opened before the key is sent, so nothing already travelling can beat it. Time bounded rather than latched: an amp switched back on at its own front panel has to reappear without being told.
48 lines
1.7 KiB
Go
48 lines
1.7 KiB
Go
package main
|
|
|
|
import "testing"
|
|
|
|
// A CQ in FT8 carries the operator's square and it is where they are NOW.
|
|
// QRZ and HamQTH describe where they LIVE, which for an expedition is the
|
|
// wrong side of the planet — RI0FA transmitted QN35 all evening and was logged
|
|
// with its licence-holder's home square.
|
|
//
|
|
// refineGrid is the referee. What it must never do is let a directory value
|
|
// replace one heard on the air.
|
|
func TestRefineGridKeepsWhatWasHeardOnAir(t *testing.T) {
|
|
for _, tc := range []struct{ have, found, want string }{
|
|
// The expedition case: heard QN35, directory says the home square.
|
|
{"QN35", "KO85", "QN35"},
|
|
// Nothing heard: the directory is all there is.
|
|
{"", "KO85", "KO85"},
|
|
// A finer square from the SAME field is an upgrade, not a contradiction.
|
|
{"QN35", "QN35SL", "QN35SL"},
|
|
// A finer square from a DIFFERENT field is a contradiction — refuse it.
|
|
{"QN35", "KO85AB", "QN35"},
|
|
// Case and padding must not decide anything.
|
|
{" qn35 ", "KO85", "QN35"},
|
|
{"QN35", "", "QN35"},
|
|
} {
|
|
if got := refineGrid(tc.have, tc.found); got != tc.want {
|
|
t.Errorf("refineGrid(%q, %q) = %q, want %q", tc.have, tc.found, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// And the ordering that makes it work: the decoded grid has to be applied
|
|
// BEFORE the lookup, or refineGrid has nothing to defend.
|
|
func TestDecodedGridWinsOverTheDirectory(t *testing.T) {
|
|
a := &App{}
|
|
a.rememberDecodeGrid("RI0FA", "QN35", "decode")
|
|
|
|
grid := "" // WSJT-X's ADIF carried no GRIDSQUARE, which is the usual case
|
|
if g := a.lookupDecodeGrid("RI0FA"); g != "" {
|
|
grid = refineGrid(grid, g)
|
|
}
|
|
grid = refineGrid(grid, "KO85") // then the lookup answers with the home square
|
|
|
|
if grid != "QN35" {
|
|
t.Errorf("logged grid = %q, want QN35 — the square the station actually sent", grid)
|
|
}
|
|
}
|