uaf.git

uaf

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

tests/test_display.py (5517B)

      1 """Tests for ap_scanner.display."""
      2 
      3 from ap_scanner.display import Display, _display_width, _pad_to_width, _truncate_to_width
      4 
      5 
      6 # --- _display_width ---
      7 
      8 def test_display_width_ascii():
      9     assert _display_width("hello") == 5
     10 
     11 
     12 def test_display_width_cjk():
     13     # CJK characters are 2 cells wide each
     14     assert _display_width("\u5317\u4eac") == 4  # 北京
     15 
     16 
     17 def test_display_width_mixed():
     18     assert _display_width("AB\u5317\u4eac") == 6  # 2 ASCII + 2 CJK
     19 
     20 
     21 def test_display_width_empty():
     22     assert _display_width("") == 0
     23 
     24 
     25 # --- _truncate_to_width ---
     26 
     27 def test_truncate_no_change():
     28     assert _truncate_to_width("short", 10) == "short"
     29 
     30 
     31 def test_truncate_long_ascii():
     32     result = _truncate_to_width("a" * 30, 10)
     33     assert _display_width(result) <= 11  # 10 + ellipsis
     34 
     35 
     36 def test_truncate_cjk():
     37     # 5 CJK chars = 10 cells, truncate to 7
     38     result = _truncate_to_width("\u5317\u4eac\u4e0a\u6d77\u5e7f", 7)
     39     assert _display_width(result) <= 8  # truncated + ellipsis
     40 
     41 
     42 # --- _pad_to_width ---
     43 
     44 def test_pad_to_width_shorter():
     45     result = _pad_to_width("hi", 10)
     46     assert _display_width(result) == 10
     47 
     48 
     49 def test_pad_to_width_exact():
     50     result = _pad_to_width("12345", 5)
     51     assert result == "12345"
     52 
     53 
     54 def test_pad_to_width_cjk():
     55     # 2 CJK chars = 4 cells, pad to 10
     56     result = _pad_to_width("\u5317\u4eac", 10)
     57     assert _display_width(result) == 10
     58     assert result.endswith(" " * 6)
     59 
     60 
     61 # --- Display class ---
     62 
     63 def test_cycle_sort():
     64     d = Display()
     65     assert d.sort_field == "rssi"
     66     d.cycle_sort()
     67     assert d.sort_field == "channel"
     68     d.cycle_sort()
     69     assert d.sort_field == "essid"
     70     d.cycle_sort()
     71     assert d.sort_field == "enc"
     72     d.cycle_sort()
     73     assert d.sort_field == "rssi"  # wraps around
     74 
     75 
     76 def test_cycle_band():
     77     d = Display()
     78     assert d.band_filter is None
     79 
     80     result = d.cycle_band()
     81     assert result == "2.4GHz"
     82     assert d.band_filter == "2.4GHz"
     83 
     84     result = d.cycle_band()
     85     assert result == "5GHz"
     86 
     87     result = d.cycle_band()
     88     assert result == "6GHz"
     89     assert d.band_filter == "6GHz"
     90 
     91     result = d.cycle_band()
     92     assert result == "all"
     93     assert d.band_filter is None
     94 
     95 
     96 def test_set_sort_valid():
     97     d = Display()
     98     d.set_sort("channel")
     99     assert d.sort_field == "channel"
    100 
    101 
    102 def test_set_sort_invalid():
    103     d = Display()
    104     d.set_sort("nonexistent")
    105     assert d.sort_field == "rssi"  # unchanged
    106 
    107 
    108 # --- Selection mode ---
    109 
    110 def test_selection_mode_toggle():
    111     d = Display()
    112     assert d._selection_mode is False
    113     d.enter_selection_mode()
    114     assert d._selection_mode is True
    115     assert d._selected_index == 0
    116     d.exit_selection_mode()
    117     assert d._selection_mode is False
    118     assert d._selected_index == 0
    119 
    120 
    121 def test_move_selection_bounds():
    122     d = Display()
    123     d.enter_selection_mode()
    124     # Move down within bounds
    125     d.move_selection(1, 5)
    126     assert d._selected_index == 1
    127     d.move_selection(1, 5)
    128     assert d._selected_index == 2
    129     # Move past end — should clamp
    130     d.move_selection(10, 5)
    131     assert d._selected_index == 4
    132     # Move past start — should clamp to 0
    133     d.move_selection(-10, 5)
    134     assert d._selected_index == 0
    135 
    136 
    137 def test_move_selection_empty():
    138     d = Display()
    139     d.enter_selection_mode()
    140     d.move_selection(1, 0)
    141     assert d._selected_index == 0
    142 
    143 
    144 def test_get_sorted_filtered(sample_ap, open_ap):
    145     d = Display()
    146     aps = {sample_ap.bssid: sample_ap, open_ap.bssid: open_ap}
    147     result = d.get_sorted_filtered(aps)
    148     assert len(result) == 2
    149     # Default sort by rssi descending: -42 > -73
    150     assert result[0].bssid == sample_ap.bssid
    151 
    152 
    153 def test_get_sorted_filtered_band(sample_ap, open_ap):
    154     d = Display()
    155     d.band_filter = "5GHz"
    156     aps = {sample_ap.bssid: sample_ap, open_ap.bssid: open_ap}
    157     result = d.get_sorted_filtered(aps)
    158     # Both are 2.4GHz, so filtering to 5GHz returns nothing
    159     assert len(result) == 0
    160 
    161 
    162 # --- Overlay title padding fix ---
    163 
    164 def test_overlay_title_width():
    165     """Verify overlay title line does not exceed border width (bug fix)."""
    166     from ap_scanner.display import _display_width
    167 
    168     box_width = 72
    169     title = "ACTIVE SCAN: TestNet (AA:BB:CC:DD:EE:FF)"
    170     title_line = f"| {title}"
    171     pad = box_width - 3 - _display_width(title)
    172     title_line += " " * max(0, pad) + "|"
    173 
    174     border = "+" + "-" * (box_width - 2) + "+"
    175 
    176     assert _display_width(title_line) == _display_width(border), (
    177         f"title_line width ({_display_width(title_line)}) != "
    178         f"border width ({_display_width(border)})"
    179     )
    180 
    181 
    182 def test_overlay_content_line_width():
    183     """Verify overlay content lines match border width."""
    184     from ap_scanner.display import _display_width, _truncate_to_width
    185 
    186     box_width = 72
    187     line = "Assigned IP:  192.168.1.100"
    188     display_line = _truncate_to_width(line, box_width - 4)
    189     pad = box_width - 2 - _display_width(display_line) - 1
    190     row = f"| {display_line}" + " " * max(0, pad) + "|"
    191 
    192     border = "+" + "-" * (box_width - 2) + "+"
    193 
    194     assert _display_width(row) == _display_width(border)
    195 
    196 
    197 def test_overlay_title_width_cjk():
    198     """Overlay title with CJK characters must not exceed border width."""
    199     from ap_scanner.display import _display_width
    200 
    201     box_width = 72
    202     title = "\u5317\u4eac\u7f51\u7edc (AA:BB:CC:DD:EE:FF)"  # 北京网络
    203     title_line = f"| {title}"
    204     pad = box_width - 3 - _display_width(title)
    205     title_line += " " * max(0, pad) + "|"
    206 
    207     border = "+" + "-" * (box_width - 2) + "+"
    208 
    209     assert _display_width(title_line) == _display_width(border)