1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#!/usr/bin/env python3
"""Unit tests for ax25_codec (RFC 1171 FCS + libax25 address rules)."""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from ax25_codec import ( # noqa: E402
ax25_build_ui,
ax25_crc,
ax25_crc_valid,
ax25_encode_address,
ax25_parse_ui,
format_callsign,
parse_callsign,
validate_callsign,
)
def test_rfc1171_crc_vector() -> None:
body = bytes(range(256))
crc = ax25_crc(body)
frame = body + bytes((crc & 0xFF, crc >> 8))
assert ax25_crc_valid(frame)
assert crc == 0x303C
def test_address_roundtrip() -> None:
raw = ax25_encode_address("DG1ABC", 7, last=True)
frame = ax25_build_ui("DG1ABC-7", "CQ", b"73")
parsed = ax25_parse_ui(frame)
assert parsed == ("DG1ABC-7", "CQ", b"73")
def test_format_callsign_omit_zero_ssid() -> None:
assert format_callsign("DG1ABC", 0) == "DG1ABC"
assert format_callsign("CB", 0) == "CB"
def test_parse_callsign_legacy() -> None:
assert parse_callsign("DK0WC-7") == ("DK0WC", 7)
assert parse_callsign("bad-ssid") == ("BAD", 0)
def test_validate_callsign_strict() -> None:
assert validate_callsign("CB-0") == ("CB", 0)
assert validate_callsign("N0CALL-15") == ("N0CALL", 15)
try:
validate_callsign("CB_0")
raise AssertionError("expected ValueError")
except ValueError:
pass
def test_ui_frame_without_fcs() -> None:
frame = ax25_build_ui("DG1ABC", "QST", b"hi")
body = frame[:-2]
parsed = ax25_parse_ui(body)
assert parsed == ("DG1ABC", "QST", b"hi")
def test_invalid_callsign_build() -> None:
try:
ax25_build_ui("BAD_CALL", "CQ", b"x")
raise AssertionError("expected ValueError")
except ValueError:
pass
def test_non_ui_rejected() -> None:
frame = ax25_build_ui("A", "B", b"x")
frame = bytearray(frame)
frame[14] = 0x00 # not UI control
assert ax25_parse_ui(bytes(frame)) is None
def main() -> int:
tests = [
test_rfc1171_crc_vector,
test_address_roundtrip,
test_format_callsign_omit_zero_ssid,
test_parse_callsign_legacy,
test_validate_callsign_strict,
test_ui_frame_without_fcs,
test_invalid_callsign_build,
test_non_ui_rejected,
]
for fn in tests:
fn()
print("OK: ax25_codec unit tests")
return 0
if __name__ == "__main__":
sys.exit(main())
|