#!/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"), [])