An operator's screenshot had it side by side: the Awards panel showed Morocco validated on five bands, and the band/mode matrix two inches above showed the entity as merely worked. ADIF's QSL_Rcvd enumeration has both Y and V — "received" and "verified" — and V is what a LoTW download writes for a confirmation the ARRL has validated. The award engine's isYes accepted "Y" or "V". Everything else in the app compared against 'Y' alone: the worked-before status grid, the slot statistics, the row colouring by QSL status, the awards QSO list, the call history badges. So the confirmations an operator cares most about were the ones that did not count. Now one definition per side, named so the next reader finds the other: qso.ConfirmedValues on the Go side, used by the queries themselves, and isQSLConfirmed in lib/qsl on the frontend, which rowColors and the panels call instead of testing the letter. The Go test drives the real query shape against a real database with a 'V' row — the constant being right is not the point, the queries using it is.
66 lines
2.0 KiB
Go
66 lines
2.0 KiB
Go
package qso
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"testing"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
// A LoTW confirmation the ARRL has validated arrives as V, not Y — ADIF's
|
|
// QSL_Rcvd enumeration has both. Every SQL query here compared against 'Y'
|
|
// alone, so the band/mode matrix showed an entity as merely worked while the
|
|
// Awards panel beside it showed the same entity validated on five bands.
|
|
//
|
|
// This drives the real queries against a real database rather than asserting on
|
|
// the constant: the constant being right is not the point, the queries using it
|
|
// is.
|
|
func TestConfirmedCountsVerifiedNotJustYes(t *testing.T) {
|
|
db, err := sql.Open("sqlite", "file:confirmedvalues?mode=memory&cache=shared")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
if _, err := db.Exec(`CREATE TABLE qso (
|
|
id INTEGER PRIMARY KEY, callsign TEXT, dxcc INTEGER, band TEXT, mode TEXT,
|
|
lotw_rcvd TEXT, qsl_rcvd TEXT, eqsl_rcvd TEXT)`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Two Morocco contacts: one verified through LoTW, one not confirmed at all.
|
|
if _, err := db.Exec(`INSERT INTO qso (callsign, dxcc, band, mode, lotw_rcvd, qsl_rcvd, eqsl_rcvd)
|
|
VALUES ('CN8ABC', 446, '30m', 'FT8', 'V', '', ''),
|
|
('CN8XYZ', 446, '20m', 'FT8', 'N', '', '')`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var confirmed30, confirmed20 int
|
|
q := `SELECT band, MAX(CASE WHEN lotw_rcvd IN ` + ConfirmedValues +
|
|
` OR qsl_rcvd IN ` + ConfirmedValues + ` OR eqsl_rcvd IN ` + ConfirmedValues +
|
|
` THEN 1 ELSE 0 END) FROM qso WHERE dxcc = 446 GROUP BY band`
|
|
rows, err := db.QueryContext(context.Background(), q)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var band string
|
|
var c int
|
|
if err := rows.Scan(&band, &c); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
switch band {
|
|
case "30m":
|
|
confirmed30 = c
|
|
case "20m":
|
|
confirmed20 = c
|
|
}
|
|
}
|
|
if confirmed30 != 1 {
|
|
t.Error("a LoTW 'V' (verified) was not counted as confirmed — the matrix would show the entity as merely worked")
|
|
}
|
|
if confirmed20 != 0 {
|
|
t.Error("an 'N' was counted as confirmed")
|
|
}
|
|
}
|