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) } } // cty.dat marks non-DXCC entities (Sicily *IT9, African Italy *IG9) with a // leading '*'; the parser must fold those into their parent DXCC entity // "Italy" while leaving real DXCC entities — Sardinia (IS0), no '*' — alone. func TestCanonicalEntityNames(t *testing.T) { const cty = `Italy: 15: 28: EU: 42.82: -12.58: -1.0: I: I,IK,IZ; African Italy: 33: 37: AF: 35.67: -12.67: -1.0: *IG9: IG9,IH9; Sardinia: 15: 28: EU: 40.15: -9.27: -1.0: IS0: IM0,IS,IW0U,IW0V; Sicily: 15: 28: EU: 37.50: -14.00: -1.0: *IT9: IT9,IW9; ` db, err := Load(strings.NewReader(cty)) if err != nil { t.Fatalf("load: %v", err) } cases := map[string]string{ "IW9EZO": "Italy", // Sicily (*IT9) → Italy "IT9CLY": "Italy", "IG9A": "Italy", // African Italy (*IG9) → Italy "IK0ABC": "Italy", "IS0XYZ": "Sardinia", // real DXCC entity — must stay Sardinia "IM0ABC": "Sardinia", } for call, want := range cases { m, ok := db.Lookup(call) if !ok { t.Errorf("%s: no match", call) continue } if m.Entity.Name != want { t.Errorf("%s: country = %q, want %q", call, m.Entity.Name, want) } } // African Italy keeps its own zones/continent even though it reports // Italy as the entity. if m, _ := db.Lookup("IG9A"); m.CQZone != 33 || m.Continent != "AF" { t.Errorf("IG9A: got CQ=%d cont=%s, want 33/AF", m.CQZone, m.Continent) } if EntityDXCC("Sicily") != 248 { t.Errorf("EntityDXCC(Sicily) = %d, want 248 (Italy)", EntityDXCC("Sicily")) } if EntityDXCC("Sardinia") != 225 { t.Errorf("EntityDXCC(Sardinia) = %d, want 225", EntityDXCC("Sardinia")) } } 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) } } }