The award editor offered five confirmation sources and Def's own doc comment named five, but confirmed() had cases for three. "qrzcom" and "custom" fell through the switch, so ticking either marked nothing as confirmed — the exact failure the GrantCodes comment in this struct warns about: a checkbox that does nothing is worse than no checkbox, because it is trusted. QRZ.com reads qrzcom_qso_download_status, not the upload one: uploading a QSO is us telling QRZ about it, which confirms nothing. Custom names a field. Rather than a checkbox per external source, the Def gains ConfirmField + ConfirmValue: any QSO field or ADIF extras key, and optionally the comma-separated values that count. That one shape covers the three cases asked for — the OpsLog card marker (APP_OPSLOG_QSL_RCVD), an arbitrary ADIF tag, and a tag stamped by an imported club list — because all three end up as a field on the QSO. An empty ConfirmValue means any non-empty content confirms: the OpsLog marker stores the date the card arrived, not a Y/N flag. A custom source naming NO field confirms nothing, deliberately — the opposite default would silently mark a whole logbook confirmed.
67 lines
2.6 KiB
Go
67 lines
2.6 KiB
Go
package award
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"hamlog/internal/qso"
|
|
)
|
|
|
|
// Every source the editor offers must actually do something. "qrzcom" and
|
|
// "custom" were listed in the UI and in Def's doc comment but had no case in the
|
|
// switch, so ticking either marked nothing as confirmed — a checkbox that is
|
|
// trusted and silently inert.
|
|
func TestConfirmedSources(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
q qso.QSO
|
|
d Def
|
|
sources []string
|
|
want bool
|
|
}{
|
|
{"lotw", qso.QSO{LOTWRcvd: "Y"}, Def{}, []string{"lotw"}, true},
|
|
{"qsl", qso.QSO{QSLRcvd: "Y"}, Def{}, []string{"qsl"}, true},
|
|
{"eqsl", qso.QSO{EQSLRcvd: "Y"}, Def{}, []string{"eqsl"}, true},
|
|
|
|
// QRZ confirms on the DOWNLOAD status. The upload one is us telling QRZ
|
|
// about the QSO, which is not a confirmation of anything.
|
|
{"qrz download", qso.QSO{QRZComDownloadStatus: "Y"}, Def{}, []string{"qrzcom"}, true},
|
|
{"qrz upload only", qso.QSO{QRZComUploadStatus: "Y"}, Def{}, []string{"qrzcom"}, false},
|
|
|
|
// Custom, no value required: any non-empty value counts. This is the
|
|
// OpsLog card case — the marker holds a timestamp, not a flag.
|
|
{"custom any value",
|
|
qso.QSO{Extras: map[string]string{"APP_OPSLOG_QSL_RCVD": "2026-08-09T01:00:00Z"}},
|
|
Def{ConfirmField: "APP_OPSLOG_QSL_RCVD"}, []string{"custom"}, true},
|
|
{"custom field empty",
|
|
qso.QSO{Extras: map[string]string{"APP_OPSLOG_QSL_RCVD": ""}},
|
|
Def{ConfirmField: "APP_OPSLOG_QSL_RCVD"}, []string{"custom"}, false},
|
|
|
|
// Custom with an explicit value list, matched case-insensitively.
|
|
{"custom value match",
|
|
qso.QSO{Extras: map[string]string{"APP_CLUB_CONF": "v"}},
|
|
Def{ConfirmField: "APP_CLUB_CONF", ConfirmValue: "Y,V"}, []string{"custom"}, true},
|
|
{"custom value mismatch",
|
|
qso.QSO{Extras: map[string]string{"APP_CLUB_CONF": "N"}},
|
|
Def{ConfirmField: "APP_CLUB_CONF", ConfirmValue: "Y,V"}, []string{"custom"}, false},
|
|
|
|
// A custom source naming no field must confirm NOTHING — never everything.
|
|
{"custom without a field",
|
|
qso.QSO{Extras: map[string]string{"APP_OPSLOG_QSL_RCVD": "x"}},
|
|
Def{}, []string{"custom"}, false},
|
|
|
|
// Known QSO fields resolve too, not just extras.
|
|
{"custom on a known field", qso.QSO{State: "TX"},
|
|
Def{ConfirmField: "state", ConfirmValue: "TX"}, []string{"custom"}, true},
|
|
|
|
// Any source in the list is enough.
|
|
{"first source misses, second hits", qso.QSO{EQSLRcvd: "Y"}, Def{},
|
|
[]string{"lotw", "eqsl"}, true},
|
|
{"no source set", qso.QSO{LOTWRcvd: "Y"}, Def{}, nil, false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := Confirmed(&c.q, c.d, c.sources); got != c.want {
|
|
t.Errorf("%s: Confirmed = %v, want %v", c.name, got, c.want)
|
|
}
|
|
}
|
|
}
|