diff --git a/tests/copilot_usage/test_parser.py b/tests/copilot_usage/test_parser.py index fdc9682..86d6606 100644 --- a/tests/copilot_usage/test_parser.py +++ b/tests/copilot_usage/test_parser.py @@ -55,6 +55,7 @@ _extract_session_name, _first_pass, _FirstPassResult, + _full_scandir_discovery, _infer_model_from_metrics, _insert_session_entry, _read_config_model, @@ -522,6 +523,33 @@ def test_two_level_deep_events_not_discovered(self, tmp_path: Path) -> None: assert paths == [valid] +# --------------------------------------------------------------------------- +# _full_scandir_discovery — OSError on DirEntry.is_dir (issue #896) +# --------------------------------------------------------------------------- + + +class TestFullScanDirDiscovery: + """Cover error-handling paths in _full_scandir_discovery.""" + + def test_is_dir_oserror_entry_is_skipped(self, tmp_path: Path) -> None: + """An entry whose is_dir() raises OSError must be silently skipped.""" + from unittest.mock import MagicMock + + bad_entry = MagicMock(spec=os.DirEntry) + bad_entry.name = "broken-session" + bad_entry.is_dir.side_effect = OSError("permission denied") + + ctx = MagicMock() + ctx.__enter__ = MagicMock(return_value=iter([bad_entry])) + ctx.__exit__ = MagicMock(return_value=False) + + with patch("os.scandir", return_value=ctx): + result = _full_scandir_discovery(tmp_path, include_plan=False) + + assert result == [] + bad_entry.is_dir.assert_called_once_with(follow_symlinks=False) + + # --------------------------------------------------------------------------- # _discover_with_identity — no stat for absent plan.md (issue #763) # ---------------------------------------------------------------------------