fix(qsl): every confirmation service has a default, and the wiki explains them
HAMLOG.online was added after most profiles were configured, so it had no entry in the shipped defaults and no stored value either: it came back blank, and blank is not a status anybody chose. Every service now starts the same way — the sent side at R, the received side at N — and a blank left by a service that did not exist when the operator last saved is filled in from that. A status they chose themselves is untouched. Two tests hold the line: no sent side may default to Y, and no field may be left without a default. Y means "already sent", so it makes the uploader skip the contact for ever — an operator with eQSL Sent at Y had a logbook that never reached eQSL, and the only trace was one line in the application log. Wiki, both from operator reports: QSL Management opens with Confirmations — what the page actually is (the status stamped on every new QSO, not an action), what each status does, and the warning about Y in the plainest words available, because it fails silently and by design. Digital Modes and GridTracker is new. Unicast and multicast explained from the operating problem rather than the networking: one letterbox that two programs watch, against a broadcast everyone can tune to. It carries the real evidence — two starts of one station an hour apart, decodes in the second and none in the first, the only difference being whether GridTracker or OpsLog reached port 2237 first — then the settings for WSJT-X, JTDX, MSHV, GridTracker and OpsLog, the 127.0.0.1-in-the-group-box mistake, what to do if unicast is unavoidable, and how to check it from the log. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The sent side must never start at Y.
|
||||
//
|
||||
// Y means "already sent", so the uploader skips the contact for ever. An
|
||||
// operator whose eQSL default was Y had a logbook that never reached eQSL and
|
||||
// nothing on screen to explain it — the log said "not eligible, EQSLSent
|
||||
// already Y" and that is the only place it was ever said.
|
||||
func TestNoConfirmationDefaultsToAlreadySent(t *testing.T) {
|
||||
d := defaultQSLDefaults()
|
||||
v := reflect.ValueOf(d)
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
name := v.Type().Field(i).Name
|
||||
val := strings.ToUpper(strings.TrimSpace(v.Field(i).String()))
|
||||
if val == "Y" {
|
||||
t.Errorf("%s defaults to Y — every new QSO would be skipped by its uploader for ever", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Every field has a default. A service added without one comes back blank,
|
||||
// which is not a status anybody chose — HAMLOG.online arrived that way and
|
||||
// every existing profile got nothing for it.
|
||||
func TestEveryConfirmationHasADefault(t *testing.T) {
|
||||
d := defaultQSLDefaults()
|
||||
v := reflect.ValueOf(d)
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if strings.TrimSpace(v.Field(i).String()) == "" {
|
||||
t.Errorf("%s has no default — add it to defaultQSLDefaults", v.Type().Field(i).Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A profile saved before a service existed has no value stored for it, and
|
||||
// gets the shipped one rather than a blank.
|
||||
func TestStoredBlanksAreFilledFromTheDefaults(t *testing.T) {
|
||||
// What an old profile looks like: the services it knew about are set, the
|
||||
// ones added later are empty.
|
||||
stored := QSLDefaults{
|
||||
QSLSent: "N", QSLRcvd: "N",
|
||||
EQSLSent: "R", EQSLRcvd: "N",
|
||||
LOTWSent: "R", LOTWRcvd: "N",
|
||||
ClublogStatus: "R", ClublogCfm: "N", HRDLogStatus: "R",
|
||||
QRZComStatus: "R", QRZComCfm: "N",
|
||||
}
|
||||
got := fillMissingQSLDefaults(stored)
|
||||
if got.HamlogStatus != "R" || got.HamlogCfm != "N" || got.HamqthStatus != "R" {
|
||||
t.Errorf("services added later were left blank: hamlog=%q/%q hamqth=%q",
|
||||
got.HamlogStatus, got.HamlogCfm, got.HamqthStatus)
|
||||
}
|
||||
// And a value the operator DID choose is untouched.
|
||||
chosen := QSLDefaults{QSLSent: "I", EQSLSent: "N"}
|
||||
filled := fillMissingQSLDefaults(chosen)
|
||||
if filled.QSLSent != "I" || filled.EQSLSent != "N" {
|
||||
t.Errorf("a chosen status was overwritten: %q / %q", filled.QSLSent, filled.EQSLSent)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user