package main import ( "testing" "hamlog/internal/autocall" ) // The entity's verdict is not the station's. // // From the air: on 10 m, where most countries are already in the log, the // engine refused twenty decodes out of twenty-one as "worked" — a watched // DXpedition calling CQ among them — because the ENTITY's status was read as // the station's. // allChased is the default: every orthogonal marker ticked. var allChased = chaseExtras{pota: true, grid: true, pfx: true, county: true, state: true} func TestCandidateWorkedIsTheCallsignNotTheEntity(t *testing.T) { d := autocall.Decode{Call: "J38DX", Band: "10m", Mode: "FT8", IsNew: true} // Grenada worked on 10 m FT8, this callsign never worked: nothing is needed // from it, and calling it is NOT a duplicate. c := candidateOf(d, SpotStatus{Status: "worked", WorkedSlot: false}, allChased) if c.Worked { t.Error("a station never worked was refused because its entity was") } if c.Need != autocall.NeedNone { t.Errorf("need = %v on a worked entity, want none", c.Need) } // The same callsign already in the log on this band and mode IS a duplicate. if c := candidateOf(d, SpotStatus{Status: "worked", WorkedSlot: true}, allChased); !c.Worked { t.Error("a callsign already worked on this band and mode was not flagged") } // And a real need still carries through, with the unconfirmed distinction. c = candidateOf(d, SpotStatus{Status: "new-band", UnconfStatus: true}, allChased) if c.Need != autocall.NeedBand || !c.Unconfirmed { t.Errorf("new-band unconfirmed came through as %v (unconf=%v)", c.Need, c.Unconfirmed) } } // A station whose ENTITY has nothing left to give can still be the reason the // operator is on the band: a WPX prefix, a county, a square, a park that has // never been worked. Reported from the air — auto-call sat through a // never-worked prefix calling CQ and did nothing. func TestOrthogonalMarkersAreWorthACall(t *testing.T) { d := autocall.Decode{Call: "BH2SWB", Band: "10m", Mode: "FT8", IsNew: true} worked := SpotStatus{Status: "worked"} for _, tc := range []struct { what string st SpotStatus want string }{ {"prefix", SpotStatus{Status: "worked", NewPfx: true}, "prefix"}, {"county", SpotStatus{Status: "worked", NewCounty: true}, "county"}, {"state", SpotStatus{Status: "worked", NewState: true}, "state"}, {"square", SpotStatus{Status: "worked", NewGrid: true}, "square"}, {"park", SpotStatus{Status: "worked", NewPOTA: true}, "park"}, } { c := candidateOf(d, tc.st, allChased) if c.Need != autocall.NeedExtra || c.Extra != tc.want { t.Errorf("%s: need=%v extra=%q, want extra %q", tc.what, c.Need, c.Extra, tc.want) } // And not when the operator does not chase that kind of thing: the // switch that withdraws the badge withdraws the call with it. if c := candidateOf(d, tc.st, chaseExtras{}); c.Need != autocall.NeedNone { t.Errorf("%s: called for a marker the operator does not chase", tc.what) } } // It is the LOWEST rung: a real need on the entity still says what it is. if c := candidateOf(d, SpotStatus{Status: "new-band", NewPfx: true}, allChased); c.Need != autocall.NeedBand { t.Errorf("need = %v — a new band that is also a new prefix is a new band", c.Need) } // Nothing anywhere is still nothing. if c := candidateOf(d, worked, allChased); c.Need != autocall.NeedNone { t.Errorf("need = %v on a station with nothing to gain", c.Need) } }