7ace2cc602
Backend (Go 1.25 / Wails v2): - QSO storage on SQLite (modernc) with embedded migrations (0001..0005) - Streaming ADIF import (batch insert) + WorkedBefore per callsign and DXCC - Callsign lookup with QRZ.com + HamQTH providers (primary/failsafe routing) and SQLite-backed TTL cache - DXCC resolver from cty.dat (auto-download, longest-prefix-match) - Multi-profile operator identities (home/portable/SOTA/contest) — every QSO stamps MY_* from the active profile - CAT control via OmniRig COM on a single OS-locked goroutine, with bidirectional sync (freq/mode/band/split/VFOs) and Rig1/Rig2 hot-swap - Settings store (key/value), CAT debug log at %APPDATA%/HamLog/cat.log Frontend (React 18 + TypeScript + Tailwind v4 + shadcn-style): - Single-row entry strip with CAT-aware band/mode/freq, RST, Start/End UTC, per-field locks (band/mode/freq/start/end) for backdated QSOs - Topbar: live freq (MHz.kHz.Hz dotted), live UTC, band/mode/SPLIT badges, CAT pill with rig selector and clickable Azimuth pill (rotor TODO) - Settings tree: Profiles (Log4OM-style manager), Station Information (edits the active profile), unified Callsign Lookup with Test buttons, Bands/Modes lists, CAT - Worked-before matrix (band × mode × class) with new-DXCC highlighting - ADIF import from menu + Maintenance > Refresh cty.dat Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
1.9 KiB
Go
75 lines
1.9 KiB
Go
package dxcc
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const sampleCty = `Sov Mil Order of Malta: 15: 28: EU: 41.90: -12.43: -1.0: 1A:
|
|
1A;
|
|
Monaco: 14: 27: EU: 43.73: -7.40: -1.0: 3A:
|
|
3A;
|
|
France: 14: 27: EU: 46.00: -2.00: -1.0: F:
|
|
F,HW,HX,HY,TH,TM,TO,TP,TQ,TV,TX;
|
|
Germany: 14: 28: EU: 51.00: -10.00: -1.0: DL:
|
|
DA,DB,DC,DD,DE,DF,DG,DH,DI,DJ,DK,DL,DM,DN,DO,DP,DQ,DR;
|
|
United States: 05: 08: NA: 37.53: 91.67: 5.0: K:
|
|
=W1AW(5)[7],K,N,W,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK;
|
|
`
|
|
|
|
func TestLookup(t *testing.T) {
|
|
db, err := Load(strings.NewReader(sampleCty))
|
|
if err != nil {
|
|
t.Fatalf("load: %v", err)
|
|
}
|
|
cases := []struct {
|
|
call string
|
|
wantEnt string
|
|
}{
|
|
{"F4NIE", "France"},
|
|
{"F4BPO", "France"},
|
|
{"F4BPO/P", "France"},
|
|
{"DL/F4NIE", "Germany"},
|
|
{"DL5XYZ", "Germany"},
|
|
{"K1ABC", "United States"},
|
|
{"N0CALL", "United States"},
|
|
{"3A2MD", "Monaco"},
|
|
{"W1AW", "United States"}, // exact match wins
|
|
}
|
|
for _, c := range cases {
|
|
m, ok := db.Lookup(c.call)
|
|
if !ok {
|
|
t.Errorf("%s: no match", c.call)
|
|
continue
|
|
}
|
|
if m.Entity.Name != c.wantEnt {
|
|
t.Errorf("%s: got %q, want %q", c.call, m.Entity.Name, c.wantEnt)
|
|
}
|
|
}
|
|
|
|
// W1AW exact match has CQ override 5 and ITU override 7.
|
|
m, _ := db.Lookup("W1AW")
|
|
if m.CQZone != 5 || m.ITUZone != 7 {
|
|
t.Errorf("W1AW overrides: got CQ=%d ITU=%d, want 5/7", m.CQZone, m.ITUZone)
|
|
}
|
|
}
|
|
|
|
func TestNormalize(t *testing.T) {
|
|
cases := map[string]string{
|
|
"F4BPO": "F4BPO",
|
|
"f4bpo": "F4BPO",
|
|
" F4BPO ": "F4BPO",
|
|
"F4BPO/P": "F4BPO",
|
|
"F4BPO/MM": "F4BPO",
|
|
"F4BPO/5": "F4BPO",
|
|
"DL/F4BPO": "DL",
|
|
"F4BPO/W6": "W6",
|
|
"VK9/F4BPO": "VK9",
|
|
}
|
|
for in, want := range cases {
|
|
if got := normalizeCallsign(in); got != want {
|
|
t.Errorf("normalize(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|