use crate::message::{
CallsignHashTable, GridField, Ft8Message, NonstdExtra, pack77, unpack77,
};
use crate::message::callsign::{pack_basecall, pack28, unpack28};
use crate::message::grid::{packgrid, unpackgrid};
use crate::message::free_text::{encode_free_text, decode_free_text};
#[test]
fn pack_basecall_long() {
let n = pack_basecall("W9XYZ").expect("W9XYZ should be a valid basecall");
assert_eq!(n, 6_493_904);
}
#[test]
fn pack_basecall_roundtrip() {
for call in &["W9XYZ", "KD9ABC", "VE3XYZ", "G0ABC"] {
let n = pack_basecall(call).unwrap_or_else(|| panic!("{} should be valid", call));
let _ = n; }
}
#[test]
fn unpack28_special_tokens() {
let ht = CallsignHashTable::new();
assert_eq!(unpack28(0, false, 1, &ht).unwrap(), "DE");
assert_eq!(unpack28(1, false, 1, &ht).unwrap(), "QRZ");
assert_eq!(unpack28(2, false, 1, &ht).unwrap(), "CQ");
}
#[test]
fn pack28_roundtrip_standard() {
let mut ht = CallsignHashTable::new();
for call in &["W9XYZ", "KD9ABC", "VE3XYZ"] {
let mut ip = false;
let n28 = pack28(call, &mut ht, &mut ip).expect(call);
let back = unpack28(n28, ip, 1, &ht).expect("unpack28 failed");
assert_eq!(&back, call, "Roundtrip failed for {}", call);
}
}
#[test]
fn pack28_cq_tokens() {
let mut ht = CallsignHashTable::new();
let mut ip = false;
let n = pack28("CQ 123", &mut ht, &mut ip).expect("CQ 123");
let back = unpack28(n, ip, 1, &ht).expect("unpack CQ 123");
assert_eq!(back, "CQ 123");
let n = pack28("CQ DX", &mut ht, &mut ip).expect("CQ DX");
let back = unpack28(n, ip, 1, &ht).expect("unpack CQ DX");
assert_eq!(back, "CQ DX");
}
#[test]
fn packgrid_grid_roundtrip() {
for g in &["FN31", "AA00", "RR99"] {
let raw = packgrid(g);
let gf = unpackgrid(raw & 0x7FFF, (raw & 0x8000) != 0);
assert_eq!(gf, GridField::Grid(g.to_string()), "Roundtrip failed for {}", g);
}
}
#[test]
fn packgrid_report_roundtrip() {
let cases: &[(&str, GridField)] = &[
("+07", GridField::Report(7)),
("-12", GridField::Report(-12)),
("R-05", GridField::RReport(-5)),
];
for (s, expected) in cases {
let raw = packgrid(s);
let gf = unpackgrid(raw & 0x7FFF, (raw & 0x8000) != 0);
assert_eq!(&gf, expected, "Roundtrip failed for '{}'", s);
}
}
#[test]
fn packgrid_tokens() {
let raw = packgrid("RRR");
assert_eq!(unpackgrid(raw & 0x7FFF, false), GridField::RRR);
let raw = packgrid("RR73");
assert_eq!(unpackgrid(raw & 0x7FFF, false), GridField::RR73);
let raw = packgrid("73");
assert_eq!(unpackgrid(raw & 0x7FFF, false), GridField::Seventy3);
let raw = packgrid("");
assert_eq!(unpackgrid(raw & 0x7FFF, false), GridField::None);
}
#[test]
fn free_text_roundtrip() {
let cases = &["CQ DX", "HELLO WORLD", "TNX 73 GL", "73", ""];
for &text in cases {
let encoded = encode_free_text(text)
.unwrap_or_else(|| panic!("encode failed for '{}'", text));
let decoded = decode_free_text(&encoded);
assert_eq!(decoded, text.trim_end(), "Free text roundtrip failed for '{}'", text);
}
}
#[test]
fn free_text_max_length() {
let text = "ABCDEFGHIJKLM";
assert_eq!(text.len(), 13);
let enc = encode_free_text(text).expect("13-char text should encode");
let dec = decode_free_text(&enc);
assert_eq!(dec, text);
}
#[test]
fn free_text_too_long() {
assert!(encode_free_text("ABCDEFGHIJKLMN").is_none());
}
#[test]
fn pack77_type1_roundtrip() {
let mut ht = CallsignHashTable::new();
let msg = Ft8Message::Standard {
call_to: "KD9ABC".to_string(),
call_de: "W9XYZ".to_string(),
extra: GridField::Grid("FN31".to_string()),
};
let payload = pack77(&msg, &mut ht).expect("pack77 type1");
let decoded = unpack77(&payload, &ht);
assert_eq!(decoded, msg);
}
#[test]
fn pack77_type1_report() {
let mut ht = CallsignHashTable::new();
let msg = Ft8Message::Standard {
call_to: "KD9ABC".to_string(),
call_de: "W9XYZ".to_string(),
extra: GridField::Report(-7),
};
let payload = pack77(&msg, &mut ht).expect("pack77 report");
let decoded = unpack77(&payload, &ht);
assert_eq!(decoded, msg);
}
#[test]
fn pack77_type1_rr73() {
let mut ht = CallsignHashTable::new();
let msg = Ft8Message::Standard {
call_to: "CQ".to_string(),
call_de: "W9XYZ".to_string(),
extra: GridField::RR73,
};
let payload = pack77(&msg, &mut ht).expect("pack77 rr73");
let decoded = unpack77(&payload, &ht);
assert_eq!(decoded, msg);
}
#[test]
fn pack77_free_text_roundtrip() {
let mut ht = CallsignHashTable::new();
for text in &["CQ DX", "HELLO WORLD", "73"] {
let msg = Ft8Message::FreeText(text.to_string());
let payload = pack77(&msg, &mut ht).expect("pack77 free text");
let decoded = unpack77(&payload, &ht);
assert_eq!(decoded, msg, "Free text roundtrip failed for '{}'", text);
}
}
#[test]
fn pack77_telemetry_roundtrip() {
let mut ht = CallsignHashTable::new();
let data = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11];
let msg = Ft8Message::Telemetry(data);
let payload = pack77(&msg, &mut ht).expect("pack77 telemetry");
let decoded = unpack77(&payload, &ht);
assert_eq!(decoded, msg);
}
#[test]
fn pack77_type4_roundtrip() {
let mut ht = CallsignHashTable::new();
ht.save("W9XYZ");
let msg = Ft8Message::NonStd {
call_to: "W9XYZ".to_string(),
call_de: "KD9ABC/R".to_string(),
extra: NonstdExtra::RRR,
};
let payload = pack77(&msg, &mut ht).expect("pack77 type4");
let decoded = unpack77(&payload, &ht);
match decoded {
Ft8Message::NonStd { call_to, call_de, extra } => {
assert!(call_to.contains("W9XYZ") || call_to == "<W9XYZ>",
"Expected W9XYZ in call_to, got {}", call_to);
assert_eq!(call_de, "KD9ABC/R");
assert_eq!(extra, NonstdExtra::RRR);
}
other => panic!("Expected NonStd, got {:?}", other),
}
}