zapretgui/tests/test_strategy_scan_page_accessibility.py
2026-06-14 15:15:51 +03:00

354 lines
15 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import unittest
from types import SimpleNamespace
from unittest.mock import patch
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication
from qfluentwidgets import CaptionLabel, PushButton
from blockcheck import public as blockcheck_public
from blockcheck.ui.strategy_scan_page import StrategyScanPage
from blockcheck.ui.strategy_scan_page_results_workflow import (
apply_finished_scan,
apply_phase_change,
apply_strategy_started_progress,
)
from blockcheck.ui.strategy_scan_page_runtime_helpers import apply_language_plan_ui
class _BlockcheckFeatureStub:
build_selection_state = staticmethod(blockcheck_public.build_selection_state)
build_protocol_ui_plan = staticmethod(blockcheck_public.build_protocol_ui_plan)
build_udp_scope_hint_plan = staticmethod(blockcheck_public.build_udp_scope_hint_plan)
build_idle_interaction_plan = staticmethod(blockcheck_public.build_idle_interaction_plan)
build_running_interaction_plan = staticmethod(blockcheck_public.build_running_interaction_plan)
plan_scan_start = staticmethod(blockcheck_public.plan_scan_start)
class StrategyScanPageAccessibilityTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.app = QApplication.instance() or QApplication([])
def test_main_controls_are_named_for_screen_reader(self) -> None:
page = StrategyScanPage(
blockcheck_feature=_BlockcheckFeatureStub(),
create_strategy_scan_worker=lambda *_args, **_kwargs: None,
)
self.addCleanup(page.deleteLater)
self.assertEqual(page._protocol_combo.accessibleName(), "Протокол подбора стратегии, выбрано: TCP/HTTPS")
self.assertEqual(
page._protocol_combo.property("screenReaderStateText"),
"Протокол подбора стратегии, выбрано: TCP/HTTPS",
)
self.assertIn("тип соединения", page._protocol_combo.accessibleDescription())
self.assertEqual(page._games_scope_combo.accessibleName(), "Охват UDP, выбрано: Все ipset (по умолчанию)")
self.assertEqual(
page._games_scope_combo.property("screenReaderStateText"),
"Охват UDP, выбрано: Все ipset (по умолчанию)",
)
self.assertIn("UDP Games", page._games_scope_combo.accessibleDescription())
self.assertEqual(page._mode_combo.accessibleName(), "Режим подбора стратегии, выбрано: Быстрый (30)")
self.assertEqual(
page._mode_combo.property("screenReaderStateText"),
"Режим подбора стратегии, выбрано: Быстрый (30)",
)
self.assertIn("сколько стратегий", page._mode_combo.accessibleDescription())
self.assertEqual(page._target_input.accessibleName(), "Цель подбора стратегии")
self.assertEqual(page._target_input.property("screenReaderStateText"), "Цель подбора стратегии")
self.assertIn("домен или STUN-цель", page._target_input.accessibleDescription())
self.assertEqual(
page._games_scope_label.property("screenReaderStateText"),
"Поле подбора стратегии: Охват UDP:",
)
self.assertEqual(
page._target_label.property("screenReaderStateText"),
"Поле подбора стратегии: Цель:",
)
self.assertEqual(page._quick_domain_btn.accessibleName(), "Быстрый выбор цели")
self.assertEqual(page._quick_domain_btn.property("screenReaderStateText"), "Быстрый выбор цели")
self.assertEqual(
page._actions_title_label.property("screenReaderStateText"),
"Раздел подбора стратегии: Действия",
)
self.assertEqual(page._start_btn.accessibleName(), "Начать подбор стратегии")
self.assertEqual(page._start_btn.property("screenReaderStateText"), "Начать подбор стратегии")
self.assertEqual(page._stop_btn.accessibleName(), "Остановить подбор стратегии")
self.assertEqual(page._stop_btn.property("screenReaderStateText"), "Остановить подбор стратегии")
self.assertEqual(page._progress_bar.accessibleName(), "Ход подбора стратегии: не выполняется")
self.assertEqual(
page._progress_bar.property("screenReaderStateText"),
"Ход подбора стратегии: не выполняется",
)
self.assertIn("Показывает", page._progress_bar.accessibleDescription())
self.assertEqual(page._status_label.accessibleName(), "Статус подбора стратегии: Готово к сканированию")
self.assertEqual(page._table.accessibleName(), "Результаты подбора стратегии: пока нет результатов")
self.assertEqual(
page._table.property("screenReaderStateText"),
"Результаты подбора стратегии: пока нет результатов",
)
self.assertEqual(page._log_edit.accessibleName(), "Подробный лог подбора стратегии: пока нет записей")
self.assertEqual(
page._log_edit.property("screenReaderStateText"),
"Подробный лог подбора стратегии: пока нет записей",
)
self.assertEqual(page._expand_log_btn.accessibleName(), "Развернуть лог подбора стратегии")
self.assertEqual(
page._expand_log_btn.property("screenReaderStateText"),
"Развернуть лог подбора стратегии",
)
self.assertEqual(page._prepare_support_btn.accessibleName(), "Подготовить обращение по подбору стратегии")
self.assertEqual(
page._prepare_support_btn.property("screenReaderStateText"),
"Подготовить обращение по подбору стратегии",
)
self.assertEqual(
page._support_status_label.property("screenReaderStateText"),
"Статус обращения по подбору стратегии: нет статуса",
)
def test_protocol_combo_menu_items_are_named_for_screen_reader(self) -> None:
page = StrategyScanPage(
blockcheck_feature=_BlockcheckFeatureStub(),
create_strategy_scan_worker=lambda *_args, **_kwargs: None,
)
self.addCleanup(page.deleteLater)
create_menu = getattr(page._protocol_combo, "_create_accessible_combo_menu", None)
self.assertIsNotNone(create_menu)
menu = create_menu()
self.assertEqual(
menu.view.item(0).data(Qt.ItemDataRole.AccessibleTextRole),
"Протокол подбора стратегии: TCP/HTTPS, выбран",
)
self.assertEqual(
menu.view.item(1).data(Qt.ItemDataRole.AccessibleTextRole),
"Протокол подбора стратегии: STUN Voice (Discord/Telegram), не выбран",
)
def test_quick_target_menu_items_are_named_for_screen_reader(self) -> None:
page = StrategyScanPage(
blockcheck_feature=_BlockcheckFeatureStub(),
create_strategy_scan_worker=lambda *_args, **_kwargs: None,
)
self.addCleanup(page.deleteLater)
captured = []
with patch(
"blockcheck.ui.strategy_scan_page.exec_popup_menu",
side_effect=lambda menu, *_args, **_kwargs: captured.append(menu),
):
page._open_quick_targets_menu(
SimpleNamespace(
options=("discord.com", "youtube.com"),
current_value="youtube.com",
)
)
self.assertEqual(len(captured), 1)
menu = captured[0]
self.assertEqual(
menu.view.item(0).data(Qt.ItemDataRole.AccessibleTextRole),
"Быстрая цель: discord.com, не выбрана",
)
self.assertEqual(
menu.view.item(1).data(Qt.ItemDataRole.AccessibleTextRole),
"Быстрая цель: youtube.com, выбрана",
)
def test_runtime_status_updates_state_text_for_screen_reader(self) -> None:
label = CaptionLabel("Готово к сканированию")
apply_phase_change(status_label=label, phase="Проверяется стратегия TLS fake")
self.assertEqual(label.text(), "Проверяется стратегия TLS fake")
self.assertEqual(
label.property("screenReaderStateText"),
"Статус подбора стратегии: Проверяется стратегия TLS fake",
)
def test_progress_bar_reads_runtime_state_for_screen_reader(self) -> None:
progress_bar = _FakeProgressBar()
status_label = CaptionLabel()
apply_strategy_started_progress(
blockcheck_feature=_ProgressFeatureStub(),
strategy_name="TLS fake",
index=1,
total=3,
result_rows=[],
progress_bar=progress_bar,
status_label=status_label,
scan_cursor=1,
)
self.assertEqual(progress_bar.accessibleName(), "Ход подбора стратегии: выполняется")
self.assertEqual(progress_bar.property("screenReaderStateText"), "Ход подбора стратегии: выполняется")
apply_finished_scan(
blockcheck_feature=_ProgressFeatureStub(),
finish_plan=SimpleNamespace(
total_available=3,
total_count=3,
status_text="Подбор завершён",
support_status_code="ready_after_error",
cancelled=False,
),
reset_ui=lambda: None,
scan_protocol="tcp",
progress_bar=progress_bar,
status_label=status_label,
set_support_status=lambda _text: None,
parent_widget=None,
)
self.assertEqual(progress_bar.accessibleName(), "Ход подбора стратегии: не выполняется")
self.assertEqual(progress_bar.property("screenReaderStateText"), "Ход подбора стратегии: не выполняется")
def test_run_start_restores_empty_result_and_log_screen_reader_states(self) -> None:
from ui.accessibility import set_state_text
page = StrategyScanPage(
blockcheck_feature=_BlockcheckFeatureStub(),
create_strategy_scan_worker=lambda *_args, **_kwargs: _WorkerStub(),
)
self.addCleanup(page.deleteLater)
page._strategy_scan_run_runtime = _RunRuntimeStub()
set_state_text(page._table, "Старая строка подбора стратегии")
set_state_text(page._log_edit, "Старый лог подбора стратегии")
page._on_start()
self.assertEqual(page._table.rowCount(), 0)
self.assertEqual(page._table.accessibleName(), "Результаты подбора стратегии: пока нет результатов")
self.assertEqual(
page._table.property("screenReaderStateText"),
"Результаты подбора стратегии: пока нет результатов",
)
self.assertEqual(page._log_edit.accessibleName(), "Подробный лог подбора стратегии: пока нет записей")
self.assertEqual(
page._log_edit.property("screenReaderStateText"),
"Подробный лог подбора стратегии: пока нет записей",
)
def test_language_refresh_updates_action_section_screen_reader_state(self) -> None:
action_label = CaptionLabel("Old")
apply_language_plan_ui(
blockcheck_feature=blockcheck_public,
language="ru",
log_expanded=False,
control_card=_TitleCardStub(),
results_card=_TitleCardStub(),
log_card=_TitleCardStub(),
expand_log_btn=PushButton(),
warning_card=_TitleCardStub(),
start_btn=PushButton(),
stop_btn=PushButton(),
actions_title_label=action_label,
prepare_support_btn=PushButton(),
protocol_combo=_ComboStub(3),
games_scope_label=CaptionLabel("Old UDP"),
games_scope_combo=_ComboStub(2),
quick_domain_btn=PushButton(),
)
self.assertEqual(action_label.text(), "Действия")
self.assertEqual(
action_label.property("screenReaderStateText"),
"Раздел подбора стратегии: Действия",
)
class _ProgressFeatureStub:
def build_progress_plan(self, **_kwargs):
return SimpleNamespace(total=3, status_text="Проверяется стратегия TLS fake")
class _SignalStub:
def connect(self, _callback) -> None:
pass
class _WorkerStub:
def __init__(self) -> None:
self.run_log_started = _SignalStub()
self.strategy_started = _SignalStub()
self.strategy_result = _SignalStub()
self.scan_log = _SignalStub()
self.phase_changed = _SignalStub()
self.scan_finished = _SignalStub()
class _RunRuntimeStub:
worker = None
def is_running(self) -> bool:
return False
def start_qobject_worker(self, *, parent, worker_factory) -> None:
self.worker = worker_factory(1)
class _TitleCardStub:
def __init__(self) -> None:
self.title = ""
def set_title(self, title: str) -> None:
self.title = str(title)
class _ComboStub:
def __init__(self, count: int) -> None:
self.items = [""] * int(count)
def setItemText(self, index: int, text: str) -> None: # noqa: N802
self.items[int(index)] = str(text)
class _FakeProgressBar:
def __init__(self) -> None:
self.properties = {}
self.accessible_name = ""
self.accessible_description = ""
self._value = 0
self._maximum = 100
def setRange(self, _minimum: int, maximum: int) -> None: # noqa: N802
self._maximum = int(maximum)
def value(self) -> int:
return self._value
def setValue(self, value: int) -> None: # noqa: N802
self._value = int(value)
def maximum(self) -> int:
return self._maximum
def accessibleName(self) -> str: # noqa: N802
return self.accessible_name
def setAccessibleName(self, text: str) -> None: # noqa: N802
self.accessible_name = str(text)
def accessibleDescription(self) -> str: # noqa: N802
return self.accessible_description
def setAccessibleDescription(self, text: str) -> None: # noqa: N802
self.accessible_description = str(text)
def property(self, name: str) -> object:
return self.properties.get(name)
def setProperty(self, name: str, value: object) -> None: # noqa: N802
self.properties[name] = value
if __name__ == "__main__":
unittest.main()