From 972cc2b7a40d4beb366ea8706518750ac09fecd4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 13:20:36 +0000 Subject: [PATCH] Fix generic warning headlines Agent-Logs-Url: https://github.com/3rdIteration/seedsigner/sessions/727019d5-0a61-41de-b780-5ecd7305c121 Co-authored-by: 3rdIteration <2230318+3rdIteration@users.noreply.github.com> --- src/seedsigner/gui/screens/screen.py | 1 + src/seedsigner/views/seed_views.py | 4 + src/seedsigner/views/tools_views.py | 1 + tests/test_status_headlines.py | 105 +++++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 tests/test_status_headlines.py diff --git a/src/seedsigner/gui/screens/screen.py b/src/seedsigner/gui/screens/screen.py index 949b72301..cec43fbda 100644 --- a/src/seedsigner/gui/screens/screen.py +++ b/src/seedsigner/gui/screens/screen.py @@ -1100,6 +1100,7 @@ class ErrorScreen(WarningScreen): title: str = _mft("Error") status_icon_name: str = SeedSignerIconConstants.ERROR status_color: str = GUIConstants.ERROR_COLOR + status_headline: str = None diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index b4aa3e34e..fbbaa4663 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -451,6 +451,7 @@ def run(self): self.run_screen( WarningScreen, title="No Secrets to Load", + status_headline=None, text="No BIP39 Secrets to Load from Seedkeeper", show_back_button=False, ) @@ -550,6 +551,7 @@ def run(self): self.run_screen( WarningScreen, title="Error", + status_headline=None, text=str(e), show_back_button=True, ) @@ -1875,6 +1877,7 @@ def run(self): self.run_screen( WarningScreen, title="No Secrets to Load", + status_headline=None, text="No SLIP39 Shares on SeedKeeper", show_back_button=False, ) @@ -1914,6 +1917,7 @@ def run(self): self.run_screen( WarningScreen, title="Error", + status_headline=None, text=str(e), show_back_button=True, ) diff --git a/src/seedsigner/views/tools_views.py b/src/seedsigner/views/tools_views.py index 10ddc099e..bca56cac4 100644 --- a/src/seedsigner/views/tools_views.py +++ b/src/seedsigner/views/tools_views.py @@ -466,6 +466,7 @@ def run(self): self.run_screen( WarningScreen, title=_("microSD card not detected"), + status_headline=None, text=_("Insert a microSD card to save the discharge log."), button_data=[ButtonOption(_("Back"))], ) diff --git a/tests/test_status_headlines.py b/tests/test_status_headlines.py new file mode 100644 index 000000000..332f14d21 --- /dev/null +++ b/tests/test_status_headlines.py @@ -0,0 +1,105 @@ +import base # noqa: F401 -- ensure hardware mocks +from unittest.mock import Mock + +from base import BaseTest +from seedsigner.gui.screens.screen import DireWarningScreen, ErrorScreen, WarningScreen +from seedsigner.hardware.battery_hat import BatteryHat +from seedsigner.views import seed_views, tools_views + + +class TestStatusHeadlines(BaseTest): + def test_error_screen_default_headline_is_none(self): + assert ErrorScreen.__dataclass_fields__["status_headline"].default is None + assert WarningScreen.__dataclass_fields__["status_headline"].default == "Privacy Leak!" + assert DireWarningScreen.__dataclass_fields__["status_headline"].default == "Classified Info!" + + def test_seedkeeper_no_secrets_warning_omits_privacy_headline(self, monkeypatch): + class MockConnector: + def seedkeeper_list_secret_headers(self): + return [] + + monkeypatch.setattr( + seed_views.seedkeeper_utils, + "init_satochip", + lambda *args, **kwargs: MockConnector(), + ) + + view = seed_views.SeedKeeperSelectView() + view.run_screen = Mock(return_value=0) + + view.run() + + assert view.run_screen.call_args.args[0] is WarningScreen + assert view.run_screen.call_args.kwargs["status_headline"] is None + + def test_seedkeeper_error_warning_omits_privacy_headline(self, monkeypatch): + class MockConnector: + def seedkeeper_list_secret_headers(self): + raise RuntimeError("Interrupted") + + monkeypatch.setattr( + seed_views.seedkeeper_utils, + "init_satochip", + lambda *args, **kwargs: MockConnector(), + ) + + view = seed_views.SeedKeeperSelectView() + view.run_screen = Mock(return_value=0) + + view.run() + + assert view.run_screen.call_args.args[0] is WarningScreen + assert view.run_screen.call_args.kwargs["status_headline"] is None + + def test_slip39_seedkeeper_no_secrets_warning_omits_privacy_headline(self, monkeypatch): + class MockConnector: + def seedkeeper_list_secret_headers(self): + return [] + + monkeypatch.setattr( + seed_views.seedkeeper_utils, + "init_satochip", + lambda *args, **kwargs: MockConnector(), + ) + + view = seed_views.SeedSlip39LoadFromSeedkeeperView() + view.run_screen = Mock(return_value=0) + + view.run() + + assert view.run_screen.call_args.args[0] is WarningScreen + assert view.run_screen.call_args.kwargs["status_headline"] is None + + def test_slip39_seedkeeper_error_warning_omits_privacy_headline(self, monkeypatch): + class MockConnector: + def seedkeeper_list_secret_headers(self): + raise RuntimeError("Interrupted") + + monkeypatch.setattr( + seed_views.seedkeeper_utils, + "init_satochip", + lambda *args, **kwargs: MockConnector(), + ) + + view = seed_views.SeedSlip39LoadFromSeedkeeperView() + view.run_screen = Mock(return_value=0) + + view.run() + + assert view.run_screen.call_args.args[0] is WarningScreen + assert view.run_screen.call_args.kwargs["status_headline"] is None + + def test_battery_calibration_missing_sd_warning_omits_privacy_headline(self, monkeypatch): + battery_hat = Mock() + battery_hat.is_enabled.return_value = True + battery_hat.process_discharge_log.return_value = None + monkeypatch.setattr(BatteryHat, "get_instance", classmethod(lambda cls: battery_hat)) + self.mock_microsd.is_inserted = False + + view = tools_views.ToolsBatteryCalibrationView() + view.run_screen = Mock(return_value=0) + + view.run() + + assert view.run_screen.call_args.args[0] is WarningScreen + assert view.run_screen.call_args.kwargs["status_headline"] is None