uaf.git

uaf

~
git clone https://github.com/debuman/uaf.git

tests/test_scanner.py (4242B)

      1 """Tests for ap_scanner.scanner — ChannelHopper schedule + ScannerEngine logic."""
      2 
      3 from unittest.mock import patch
      4 
      5 from ap_scanner.scanner import ChannelHopper, ScannerEngine
      6 
      7 
      8 # --- ChannelHopper._build_schedule ---
      9 
     10 class TestBuildSchedule:
     11     """Tests for ChannelHopper._build_schedule weighted scheduling."""
     12 
     13     def _make_hopper(self, channels):
     14         """Create a ChannelHopper without starting any threads."""
     15         with patch.object(ChannelHopper, "_get_mac", return_value="00:00:00:00:00:00"):
     16             return ChannelHopper("wlan0", channels)
     17 
     18     def test_primary_channels_appear_first(self):
     19         """Channels 1, 6, 11 should be the first entries for quick discovery."""
     20         hopper = self._make_hopper([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
     21         sched = hopper._schedule
     22         # First three entries should be the primary channels
     23         assert sched[0] in {1, 6, 11}
     24         assert sched[1] in {1, 6, 11}
     25         assert sched[2] in {1, 6, 11}
     26 
     27     def test_primary_channels_visited_more(self):
     28         """Primary channels (1, 6, 11) should appear more than once."""
     29         hopper = self._make_hopper(list(range(1, 14)))
     30         sched = hopper._schedule
     31         for ch in (1, 6, 11):
     32             assert sched.count(ch) >= 2, f"Channel {ch} should appear >= 2 times"
     33 
     34     def test_only_primary_channels(self):
     35         """With only primary channels, schedule still works."""
     36         hopper = self._make_hopper([1, 6, 11])
     37         sched = hopper._schedule
     38         assert len(sched) > 0
     39         assert set(sched) == {1, 6, 11}
     40 
     41     def test_no_primary_channels(self):
     42         """With no primary channels (5GHz only), schedule is a plain list."""
     43         hopper = self._make_hopper([36, 40, 44, 48])
     44         sched = hopper._schedule
     45         assert sched == [36, 40, 44, 48]
     46 
     47     def test_empty_channels(self):
     48         """Empty channel list produces empty schedule."""
     49         hopper = self._make_hopper([])
     50         assert hopper._schedule == []
     51 
     52     def test_single_channel(self):
     53         """Single non-primary channel produces single-entry schedule."""
     54         hopper = self._make_hopper([36])
     55         assert hopper._schedule == [36]
     56 
     57     def test_single_primary_channel(self):
     58         """Single primary channel appears twice (prepended + tail)."""
     59         hopper = self._make_hopper([6])
     60         sched = hopper._schedule
     61         assert 6 in sched
     62         assert len(sched) >= 1
     63 
     64     def test_5ghz_schedule_unchanged(self):
     65         """5GHz-only channels should maintain order (no reordering)."""
     66         channels = [36, 40, 44, 48, 52, 56, 60, 64]
     67         hopper = self._make_hopper(channels)
     68         assert hopper._schedule == channels
     69 
     70     def test_mixed_channels_all_present(self):
     71         """All channels from input are present in the schedule."""
     72         channels = [1, 6, 11, 36, 40, 44, 48]
     73         hopper = self._make_hopper(channels)
     74         sched = hopper._schedule
     75         for ch in channels:
     76             assert ch in sched, f"Channel {ch} missing from schedule"
     77 
     78 
     79 # --- ScannerEngine AP tracking ---
     80 
     81 class TestScannerEngineAPUpdate:
     82     """Tests for AP update logic in _on_packet."""
     83 
     84     def test_access_points_returns_copy(self):
     85         """access_points property should return a copy, not the internal dict."""
     86         with patch.object(ChannelHopper, "_get_mac", return_value="00:00:00:00:00:00"):
     87             engine = ScannerEngine("wlan0", [1, 6, 11])
     88         aps1 = engine.access_points
     89         aps2 = engine.access_points
     90         assert aps1 is not aps2
     91 
     92     def test_clear_removes_all_aps(self):
     93         """clear() should remove all discovered APs."""
     94         from datetime import datetime
     95         from ap_scanner.models import AccessPoint
     96 
     97         with patch.object(ChannelHopper, "_get_mac", return_value="00:00:00:00:00:00"):
     98             engine = ScannerEngine("wlan0", [1, 6, 11])
     99         # Manually inject an AP
    100         ap = AccessPoint(
    101             bssid="AA:BB:CC:DD:EE:FF", ssid="Test", channel=6,
    102             rssi=-50, encryption="WPA2", cipher="CCMP", auth="PSK",
    103             band="2.4GHz", wifi_standard="n",
    104         )
    105         engine._aps["AA:BB:CC:DD:EE:FF"] = ap
    106         assert len(engine.access_points) == 1
    107         engine.clear()
    108         assert len(engine.access_points) == 0