fix(stats): confirmed outranks worked in the band/mode matrix
Reported by VK4DX with the case that names itself: YB confirmed on 20m digital, painted blue, because one unconfirmed YB station had also been worked on that slot. The ladder ran call_c > call_w > dxcc_c > dxcc_w, so a callsign worked and not confirmed beat an entity CONFIRMED on the same band and mode. The grid answers 'what do I still need here', and a confirmed entity needs nothing whoever was worked afterwards — so the order is now call_c > dxcc_c > call_w > dxcc_w. Two things made it easy to get wrong, and both are fixed rather than merely corrected. The code was a run of assignments where the later test silently overwrote the earlier, so 'call worked' erased 'entity confirmed'; it now takes the maximum. And the rule lived inside a scan loop where nothing could reach it, so it is lifted into bandStatusCode with a table test — including this exact case, and one that fails if anybody reorders the constants.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package qso
|
||||
|
||||
import "testing"
|
||||
|
||||
// The colour of a matrix cell is a claim about what the operator still needs,
|
||||
// and it was wrong for several releases: a callsign worked and not confirmed
|
||||
// outranked an entity CONFIRMED on the same band and mode, so a slot that was
|
||||
// finished showed as unfinished.
|
||||
//
|
||||
// Reported by VK4DX with the case that names itself: YB confirmed on 20m
|
||||
// digital, shown blue, because one unconfirmed YB station had also been worked
|
||||
// there.
|
||||
func TestBandStatusConfirmedOutranksWorked(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
callWorked, callConfirmed, entityConfirm bool
|
||||
want string
|
||||
}{
|
||||
{"entity worked only", false, false, false, "dxcc_w"},
|
||||
{"this call worked, nothing confirmed", true, false, false, "call_w"},
|
||||
// The regression, in one line.
|
||||
{"entity confirmed, this call worked but not confirmed", true, false, true, "dxcc_c"},
|
||||
{"entity confirmed, this call not worked here", false, false, true, "dxcc_c"},
|
||||
{"this call confirmed", true, true, true, "call_c"},
|
||||
// A confirmed contact with this call implies it was worked, but the flags
|
||||
// arrive from separate SQL aggregates and nothing guarantees the pair.
|
||||
{"call confirmed without the worked flag", false, true, true, "call_c"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
got := bandStatusNames[bandStatusCode(c.callWorked, c.callConfirmed, c.entityConfirm)]
|
||||
if got != c.want {
|
||||
t.Errorf("bandStatusCode(worked=%v, callConf=%v, entityConf=%v) = %s, want %s",
|
||||
c.callWorked, c.callConfirmed, c.entityConfirm, got, c.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The ladder itself, stated once: every confirmed code must beat every worked
|
||||
// code. A future edit that reorders the constants fails here rather than in a
|
||||
// screenshot from an operator.
|
||||
func TestBandStatusLadderPutsConfirmedAbove(t *testing.T) {
|
||||
for _, worked := range []int{stDxccW, stCallW} {
|
||||
for _, confirmed := range []int{stDxccC, stCallC} {
|
||||
if confirmed <= worked {
|
||||
t.Errorf("%s (%d) does not outrank %s (%d)",
|
||||
bandStatusNames[confirmed], confirmed, bandStatusNames[worked], worked)
|
||||
}
|
||||
}
|
||||
}
|
||||
if stCallC <= stDxccC {
|
||||
t.Error("call_c must outrank dxcc_c: the callsign is the more specific claim")
|
||||
}
|
||||
if stCallW <= stDxccW {
|
||||
t.Error("call_w must outrank dxcc_w for the same reason")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user