diff --git a/tests/conftest.py b/tests/conftest.py index b4ec0f88..b54abec4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,7 @@ +import importlib + +from unittest import mock + import pytest @@ -16,3 +20,24 @@ def isolate_solaar_configuration(tmp_path, monkeypatch): monkeypatch.setattr(configuration, "_yaml_file_path", str(tmp_path / "config.yaml")) monkeypatch.setattr(configuration, "_json_file_path", str(tmp_path / "config.json")) monkeypatch.setattr(configuration, "_config", []) + + +@pytest.fixture(autouse=True) +def mock_desktop_notifications(monkeypatch): + """Swap the libnotify backend for a mock in both desktop_notifications + modules. Tests still exercise the real init/alert/show code paths, but + Notification.show() never reaches the daemon — without this the suite + raises real 'MockDevice' / 'unknown' notifications on every run. + + Returns the Notify mock so notification tests can assert against it.""" + notify = mock.MagicMock(name="Notify") + notify.is_initted.return_value = True + notify.init.return_value = True + for modname in ("solaar.ui.desktop_notifications", "logitech_receiver.desktop_notifications"): + try: + module = importlib.import_module(modname) + except Exception: + continue + monkeypatch.setattr(module, "Notify", notify, raising=False) + monkeypatch.setattr(module, "_notifications", {}, raising=False) + return notify diff --git a/tests/logitech_receiver/test_desktop_notifications.py b/tests/logitech_receiver/test_desktop_notifications.py index 22905862..176cb205 100644 --- a/tests/logitech_receiver/test_desktop_notifications.py +++ b/tests/logitech_receiver/test_desktop_notifications.py @@ -2,7 +2,9 @@ from unittest import mock from logitech_receiver import desktop_notifications -# depends on external environment, so make some tests dependent on availability +# The mock_desktop_notifications autouse fixture (tests/conftest.py) swaps the +# libnotify backend for a mock, so these exercise the real code paths without +# raising real desktop notifications. def test_init(): @@ -22,8 +24,11 @@ class MockDevice(mock.Mock): return True -def test_show(): - dev = MockDevice() - reason = "unknown" - result = desktop_notifications.show(dev, reason) - assert result is not None if desktop_notifications.available else result is None +def test_show(mock_desktop_notifications): + result = desktop_notifications.show(MockDevice(), "unknown") + + if desktop_notifications.available: + assert result is not None + mock_desktop_notifications.Notification.return_value.show.assert_called() + else: + assert result is None diff --git a/tests/solaar/ui/test_desktop_notifications.py b/tests/solaar/ui/test_desktop_notifications.py index c3c16f30..72000ccc 100644 --- a/tests/solaar/ui/test_desktop_notifications.py +++ b/tests/solaar/ui/test_desktop_notifications.py @@ -2,7 +2,9 @@ from unittest import mock from solaar.ui import desktop_notifications -# depends on external environment, so make some tests dependent on availability +# The mock_desktop_notifications autouse fixture (tests/conftest.py) swaps the +# libnotify backend for a mock, so these exercise the real code paths without +# raising real desktop notifications. def test_init(): @@ -15,9 +17,11 @@ def test_uninit(): assert desktop_notifications.uninit() is None -def test_alert(): - reason = "unknown" - assert desktop_notifications.alert(reason) is None +def test_alert(mock_desktop_notifications): + assert desktop_notifications.alert("unknown") is None + + if desktop_notifications.available: + mock_desktop_notifications.Notification.return_value.show.assert_called() class MockDevice(mock.Mock): @@ -27,13 +31,11 @@ class MockDevice(mock.Mock): return True -def test_show(): - dev = MockDevice() - reason = "unknown" - available = desktop_notifications.init() +def test_show(mock_desktop_notifications): + result = desktop_notifications.show(MockDevice(), "unknown") - result = desktop_notifications.show(dev, reason) - if available: + if desktop_notifications.available: assert result is not None + mock_desktop_notifications.Notification.return_value.show.assert_called() else: assert result is None