from dataclasses import dataclass from dataclasses import field from typing import Any from typing import List from typing import Optional import gi import pytest from logitech_receiver import receiver from solaar.ui import pair_window gi.require_version("Gtk", "3.0") from gi.repository import Gtk # NOQA: E402 gtk_init = Gtk.init_check()[0] @dataclass class Device: name: str = "test device" kind: str = "test kind" @dataclass class Receiver: name: str receiver_kind: str _set_lock: bool = True pairing: receiver.Pairing = field(default_factory=receiver.Pairing) pairable: bool = True _remaining_pairings: Optional[int] = None def reset_pairing(self): self.receiver = receiver.Pairing() def remaining_pairings(self, cache=True): return self._remaining_pairings def set_lock(self, value=False, timeout=0): self.pairing.lock_open = self._set_lock return self._set_lock def discover(self, cancel=False, timeout=30): self.pairing.discovering = self._set_lock return self._set_lock def pair_device(self, pair=True, slot=0, address=b"\0\0\0\0\0\0", authentication=0x00, entropy=20, force=False): print("PD", self.pairable) return self.pairable @dataclass class Assistant: drawable: bool = True pages: List[Any] = field(default_factory=list) def is_drawable(self): return self.drawable def next_page(self): return True def set_page_complete(self, page, b): return True def commit(self): return True def append_page(self, page): self.pages.append(page) def remove_page(self, page): return True def set_page_type(self, page, type): return True def destroy(self): pass @pytest.mark.skipif(not gtk_init, reason="requires Gtk") @pytest.mark.parametrize( "receiver, lock_open, discovering, page_type", [ (Receiver("unifying", "unifying", True), True, False, Gtk.AssistantPageType.PROGRESS), (Receiver("unifying", "unifying", False), False, False, Gtk.AssistantPageType.SUMMARY), (Receiver("nano", "nano", True, _remaining_pairings=5), True, False, Gtk.AssistantPageType.PROGRESS), (Receiver("nano", "nano", False), False, False, Gtk.AssistantPageType.SUMMARY), (Receiver("bolt", "bolt", True), False, True, Gtk.AssistantPageType.PROGRESS), (Receiver("bolt", "bolt", False), False, False, Gtk.AssistantPageType.SUMMARY), ], ) def test_create(receiver, lock_open, discovering, page_type): assistant = pair_window.create(receiver) assert assistant is not None assert assistant.get_page_type(assistant.get_nth_page(0)) == page_type assert receiver.pairing.lock_open == lock_open assert receiver.pairing.discovering == discovering @pytest.mark.parametrize( "receiver, expected_result, expected_error", [ (Receiver("unifying", "unifying", True), True, False), (Receiver("unifying", "unifying", False), False, True), (Receiver("bolt", "bolt", True), True, False), (Receiver("bolt", "bolt", False), False, True), ], ) def test_prepare(receiver, expected_result, expected_error): result = pair_window.prepare(receiver) assert result == expected_result assert bool(receiver.pairing.error) == expected_error @pytest.mark.parametrize("assistant, expected_result", [(Assistant(True), True), (Assistant(False), False)]) def test_check_lock_state_drawable(assistant, expected_result): r = Receiver("succeed", "unifying", True, receiver.Pairing(lock_open=True)) result = pair_window.check_lock_state(assistant, r, 2) assert result == expected_result @pytest.mark.skipif(not gtk_init, reason="requires Gtk") @pytest.mark.parametrize( "receiver, count, expected_result", [ (Receiver("fail", "unifying", False, receiver.Pairing(lock_open=False)), 2, False), (Receiver("succeed", "unifying", True, receiver.Pairing(lock_open=True)), 1, True), (Receiver("error", "unifying", True, receiver.Pairing(error="error")), 0, False), (Receiver("new device", "unifying", True, receiver.Pairing(new_device=Device())), 2, False), (Receiver("closed", "unifying", True, receiver.Pairing()), 2, False), (Receiver("closed", "unifying", True, receiver.Pairing()), 1, False), (Receiver("closed", "unifying", True, receiver.Pairing()), 0, False), (Receiver("fail bolt", "bolt", False), 1, False), (Receiver("succeed bolt", "bolt", True, receiver.Pairing(lock_open=True)), 0, True), (Receiver("error bolt", "bolt", True, receiver.Pairing(error="error")), 2, False), (Receiver("new device", "bolt", True, receiver.Pairing(lock_open=True, new_device=Device())), 1, False), (Receiver("discovering", "bolt", True, receiver.Pairing(lock_open=True)), 1, True), (Receiver("closed", "bolt", True, receiver.Pairing()), 2, False), (Receiver("closed", "bolt", True, receiver.Pairing()), 1, False), (Receiver("closed", "bolt", True, receiver.Pairing()), 0, False), ( Receiver("pass1", "bolt", True, receiver.Pairing(lock_open=True, device_passkey=50, device_authentication=0x01)), 0, True, ), ( Receiver("pass2", "bolt", True, receiver.Pairing(lock_open=True, device_passkey=50, device_authentication=0x02)), 0, True, ), ( Receiver("adt", "bolt", True, receiver.Pairing(discovering=True, device_address=2, device_name=5), pairable=True), 2, True, ), ( Receiver("adf", "bolt", True, receiver.Pairing(discovering=True, device_address=2, device_name=5), pairable=False), 2, False, ), (Receiver("add fail", "bolt", False, receiver.Pairing(device_address=2, device_passkey=5)), 2, False), ], ) def test_check_lock_state(receiver, count, expected_result): assistant = Assistant(True) check_state = pair_window._check_lock_state(assistant, receiver, count) assert check_state == expected_result @pytest.mark.parametrize( "receiver, pair_device, set_lock, discover, error", [ (Receiver("unifying", "unifying", pairing=receiver.Pairing(lock_open=False, error="error")), 0, 0, 0, None), (Receiver("unifying", "unifying", pairing=receiver.Pairing(lock_open=True, error="error")), 0, 1, 0, "error"), (Receiver("bolt", "bolt", pairing=receiver.Pairing(lock_open=False, error="error")), 0, 0, 0, None), (Receiver("bolt", "bolt", pairing=receiver.Pairing(lock_open=True, error="error")), 1, 0, 0, "error"), (Receiver("bolt", "bolt", pairing=receiver.Pairing(discovering=True, error="error")), 0, 0, 1, "error"), ], ) def test_finish(receiver, pair_device, set_lock, discover, error, mocker): spy_pair_device = mocker.spy(receiver, "pair_device") spy_set_lock = mocker.spy(receiver, "set_lock") spy_discover = mocker.spy(receiver, "discover") assistant = Assistant(True) pair_window._finish(assistant, receiver) assert spy_pair_device.call_count == pair_device assert spy_set_lock.call_count == set_lock assert spy_discover.call_count == discover assert receiver.pairing.error == error @pytest.mark.skipif(not gtk_init, reason="requires Gtk") @pytest.mark.parametrize("error", ["timeout", "device not supported", "too many devices"]) def test_create_failure_page(error, mocker): spy_create = mocker.spy(pair_window, "_create_page") pair_window._pairing_failed(Assistant(True), Receiver("nano", "nano"), error) assert spy_create.call_count == 1