diff --git a/src/main.py b/src/main.py index 99b2dac..c1b378f 100644 --- a/src/main.py +++ b/src/main.py @@ -13,6 +13,7 @@ import signal import time import argparse import tomli +from tomli import TOMLDecodeError from colorama import init as colorama_init from termcolor import colored from utils.color_scheme import color_text @@ -46,7 +47,7 @@ def load_global_config() -> dict: try: with open(config_path, "rb") as f: return tomli.load(f) - except Exception as exc: + except (OSError, TOMLDecodeError) as exc: logging.warning(f"Failed to read {config_path}: {exc}") return {} diff --git a/src/tests/test_load_global_config.py b/src/tests/test_load_global_config.py new file mode 100644 index 0000000..1ff9373 --- /dev/null +++ b/src/tests/test_load_global_config.py @@ -0,0 +1,24 @@ +"""Tests for load_global_config failure scenarios.""" + +import logging +from pathlib import Path + +import pytest + +from main import load_global_config + + +def test_load_global_config_invalid_toml(monkeypatch, tmp_path, caplog): + """Invalid TOML should log a warning and return an empty dict.""" + config_dir = tmp_path / ".seedpass" + config_dir.mkdir() + config_file = config_dir / "config.toml" + config_file.write_text("invalid = [") + + monkeypatch.setattr(Path, "home", lambda: tmp_path) + + with caplog.at_level(logging.WARNING): + result = load_global_config() + + assert result == {} + assert "Failed to read" in caplog.text diff --git a/src/tests/test_terminal_utils_failure_handling.py b/src/tests/test_terminal_utils_failure_handling.py new file mode 100644 index 0000000..6dbfce2 --- /dev/null +++ b/src/tests/test_terminal_utils_failure_handling.py @@ -0,0 +1,37 @@ +"""Tests for terminal utility failure handling.""" + +import logging +import pytest + +from utils.terminal_utils import ( + clear_header_with_notification, + format_profile, +) + + +class ErrorFingerprintManager: + def get_name(self, _fingerprint): # pragma: no cover - helper + raise ValueError("boom") + + +class ErrorPM: + fingerprint_manager = ErrorFingerprintManager() + + def get_current_notification(self): # pragma: no cover - helper + raise RuntimeError("bad") + + +def test_format_profile_reraises(monkeypatch, caplog): + pm = ErrorPM() + with caplog.at_level(logging.ERROR): + with pytest.raises(ValueError): + format_profile("abc", pm) + assert "Error retrieving name for fingerprint" in caplog.text + + +def test_clear_header_with_notification_reraises(caplog): + pm = ErrorPM() + with caplog.at_level(logging.ERROR): + with pytest.raises(RuntimeError): + clear_header_with_notification(pm) + assert "Error getting current notification" in caplog.text diff --git a/src/utils/terminal_utils.py b/src/utils/terminal_utils.py index 3b1e853..80d772e 100644 --- a/src/utils/terminal_utils.py +++ b/src/utils/terminal_utils.py @@ -1,7 +1,8 @@ """Utility functions for terminal output.""" +import logging import sys - +import queue from termcolor import colored @@ -17,8 +18,11 @@ def format_profile(fingerprint: str | None, pm=None) -> str | None: name = pm.fingerprint_manager.get_name(fingerprint) if name: return f"{name} ({fingerprint})" - except Exception: - pass + except Exception as exc: # pragma: no cover - unexpected errors + logging.error( + "Error retrieving name for fingerprint %s: %s", fingerprint, exc + ) + raise return fingerprint @@ -93,8 +97,11 @@ def clear_header_with_notification( if hasattr(pm, "get_current_notification"): try: note = pm.get_current_notification() - except Exception: + except (queue.Empty, AttributeError): note = None + except Exception as exc: # pragma: no cover - unexpected errors + logging.error("Error getting current notification: %s", exc) + raise line = "" if note: