24afa04a4c
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
81 lines
3.1 KiB
Python
81 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Unit tests for repeaters.py (pure: no network, no radio). `python3 -m unittest`."""
|
|
import unittest
|
|
|
|
import repeaters
|
|
|
|
|
|
class TestNormalizeCsv(unittest.TestCase):
|
|
ROW = {
|
|
"Output Freq": "147.300000", "Input Freq": "147.90000", "Offset": "+",
|
|
"Uplink Tone": "131.8", "Downlink Tone": "131.8", "Call": "W4ABC",
|
|
"Location": "Fairfax", "County": "Fairfax", "State": "Virginia",
|
|
"Modes": "FM ", "Digital Access": "",
|
|
}
|
|
|
|
def test_core_fields(self):
|
|
r = repeaters.normalize_csv(self.ROW, 7)
|
|
self.assertEqual(r["callsign"], "W4ABC")
|
|
self.assertAlmostEqual(r["output_mhz"], 147.300)
|
|
self.assertEqual(r["rank"], 7)
|
|
self.assertEqual(r["location"], "Fairfax, VA")
|
|
|
|
def test_offset_sign_and_magnitude(self):
|
|
r = repeaters.normalize_csv(self.ROW, 0)
|
|
self.assertEqual(r["duplex"], "+")
|
|
self.assertAlmostEqual(r["offset_mhz"], 0.600, places=4)
|
|
|
|
def test_negative_offset(self):
|
|
row = dict(self.ROW, **{"Input Freq": "146.700000", "Offset": "-"})
|
|
self.assertEqual(repeaters.normalize_csv(row, 0)["duplex"], "-")
|
|
|
|
def test_simplex(self):
|
|
row = dict(self.ROW, **{"Input Freq": "147.300000", "Offset": ""})
|
|
self.assertEqual(repeaters.normalize_csv(row, 0)["duplex"], "simplex")
|
|
|
|
def test_tone(self):
|
|
r = repeaters.normalize_csv(self.ROW, 0)
|
|
self.assertAlmostEqual(r["tone_hz"], 131.8)
|
|
self.assertEqual(r["tone_mode"], "ctcss")
|
|
|
|
def test_no_tone(self):
|
|
row = dict(self.ROW); row["Uplink Tone"] = ""
|
|
r = repeaters.normalize_csv(row, 0)
|
|
self.assertIsNone(r["tone_hz"])
|
|
self.assertEqual(r["tone_mode"], "none")
|
|
|
|
def test_pure_dstar_is_dv(self):
|
|
row = dict(self.ROW, **{"Modes": "DSTAR "})
|
|
self.assertEqual(repeaters.normalize_csv(row, 0)["mode"], "DV")
|
|
|
|
def test_fm_dstar_is_fm(self):
|
|
row = dict(self.ROW, **{"Modes": "FM DSTAR "})
|
|
self.assertEqual(repeaters.normalize_csv(row, 0)["mode"], "FM")
|
|
|
|
|
|
class TestSearch(unittest.TestCase):
|
|
RECS = [
|
|
{"callsign": "NEAR", "location": "Fairfax, VA", "mode": "FM", "rank": 0},
|
|
{"callsign": "MID", "location": "Bethesda, MD", "mode": "DV", "rank": 5},
|
|
{"callsign": "FAR", "location": "Norfolk, VA", "mode": "FM", "rank": 50},
|
|
]
|
|
|
|
def test_rank_order_preserved(self):
|
|
out = repeaters.search(self.RECS, "", 10)
|
|
self.assertEqual([r["callsign"] for r in out], ["NEAR", "MID", "FAR"])
|
|
|
|
def test_text_filter_callsign_and_location(self):
|
|
self.assertEqual(len(repeaters.search(self.RECS, "norfolk", 10)), 1)
|
|
self.assertEqual(repeaters.search(self.RECS, "far", 10)[0]["callsign"], "FAR")
|
|
|
|
def test_filter_is_case_insensitive(self):
|
|
self.assertEqual(repeaters.search(self.RECS, "BETHESDA", 10)[0]["callsign"], "MID")
|
|
|
|
def test_limit(self):
|
|
self.assertEqual(len(repeaters.search(self.RECS, "", 2)), 2)
|
|
|
|
|
|
class TestLoad(unittest.TestCase):
|
|
def test_missing_file_returns_empty(self):
|
|
self.assertEqual(repeaters.load("/no/such/file.json"), [])
|