diff --git a/tests/test_file_manager.py b/tests/test_file_manager.py index 985b240..f1e4184 100644 --- a/tests/test_file_manager.py +++ b/tests/test_file_manager.py @@ -105,13 +105,9 @@ class TestReadFile: assert fm.read_file(sub) == "" def test_file_outside_workspace_returns_empty_string(self, fm, tmp_path): - # tmp_path.parent is a shared pytest temp dir, so we clean up to avoid - # leaving stray files that could affect other tests. outside = tmp_path.parent / "outside.py" outside.write_text("secret") - result = fm.read_file(outside) - assert result == "" - outside.unlink() + assert fm.read_file(outside) == "" # ── save_file ───────────────────────────────────────────────────────────────── diff --git a/tests/test_state.py b/tests/test_state.py deleted file mode 100644 index f1a6e0e..0000000 --- a/tests/test_state.py +++ /dev/null @@ -1,242 +0,0 @@ -"""Tests for frontend/state.py — init_state() session initialisation.""" - -import sys -from pathlib import Path -import pytest -from unittest.mock import patch - -sys.path.insert(0, str(Path(__file__).parent.parent)) - -from backend.managers.chat_manager import ChatManager - - -# ── Fake session_state ──────────────────────────────────────────────────────── - -class FakeSessionState: - """Minimal stand-in for st.session_state that supports attribute and 'in' access.""" - - def __init__(self): - self._data = {} - - def __contains__(self, key): - return key in self._data - - def __setattr__(self, name, value): - if name == "_data": - super().__setattr__(name, value) - else: - self._data[name] = value - - def __getattr__(self, name): - try: - return self._data[name] - except KeyError: - raise AttributeError(name) - - def get(self, key, default=None): - return self._data.get(key, default) - - -@pytest.fixture -def fake_state(): - """Inject a FakeSessionState in place of st.session_state for the duration of a test.""" - state = FakeSessionState() - with patch("frontend.state.st.session_state", state): - yield state - - -# ── Key initialisation ──────────────────────────────────────────────────────── - -class TestInitStateKeys: - """Tests that init_state() creates all required session keys with the correct default values.""" - - EXPECTED_KEYS = [ - "last_selected", - "selected_folder", - "selected_folder_rel", - "chat_manager", - "open_files", - "files_content", - "active_file", - "active_tab", - "is_editing", - "code_suggestions", - "code_execution_output", - "chat_history", - "agent_mode", - "coding_agent", - "agent_status", - "agent_log", - "agent_pending_action", - ] - - def test_all_expected_keys_are_set(self, fake_state): - from frontend.state import init_state - init_state() - for key in self.EXPECTED_KEYS: - assert key in fake_state, f"Missing key: {key}" - - def test_open_files_initialised_as_empty_list(self, fake_state): - from frontend.state import init_state - init_state() - assert fake_state.open_files == [] - - def test_files_content_initialised_as_empty_dict(self, fake_state): - from frontend.state import init_state - init_state() - assert fake_state.files_content == {} - - def test_active_file_initialised_as_none(self, fake_state): - from frontend.state import init_state - init_state() - assert fake_state.active_file is None - - def test_chat_history_initialised_as_empty_list(self, fake_state): - from frontend.state import init_state - init_state() - assert fake_state.chat_history == [] - - def test_agent_mode_initialised_as_false(self, fake_state): - from frontend.state import init_state - init_state() - assert fake_state.agent_mode is False - - def test_agent_status_initialised_as_idle(self, fake_state): - from frontend.state import init_state - init_state() - assert fake_state.agent_status == "idle" - - def test_chat_manager_is_chat_manager_instance(self, fake_state): - from frontend.state import init_state - init_state() - assert isinstance(fake_state.chat_manager, ChatManager) - - -# ── Idempotency ─────────────────────────────────────────────────────────────── - -class TestInitStateIdempotency: - """Tests that calling init_state() a second time never resets keys that were already set. - This mirrors Streamlit's own pattern: initialise only when the key is absent.""" - - def test_second_call_does_not_overwrite_open_files(self, fake_state): - """init_state() must not reset state that was set by the user.""" - from frontend.state import init_state - init_state() - fake_state.open_files = ["/workspace/file.py"] - init_state() - assert fake_state.open_files == ["/workspace/file.py"] - - def test_second_call_does_not_overwrite_chat_history(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.chat_history = [{"role": "user", "content": "Hi"}] - init_state() - assert len(fake_state.chat_history) == 1 - - def test_second_call_does_not_replace_chat_manager(self, fake_state): - from frontend.state import init_state - init_state() - original = fake_state.chat_manager - init_state() - assert fake_state.chat_manager is original - - def test_second_call_does_not_overwrite_active_file(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.active_file = "/workspace/main.py" - init_state() - assert fake_state.active_file == "/workspace/main.py" - - def test_second_call_does_not_overwrite_last_selected(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.last_selected = "src/app.py" - init_state() - assert fake_state.last_selected == "src/app.py" - - def test_second_call_does_not_overwrite_selected_folder(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.selected_folder = "/workspace/src" - init_state() - assert fake_state.selected_folder == "/workspace/src" - - def test_second_call_does_not_overwrite_selected_folder_rel(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.selected_folder_rel = "src" - init_state() - assert fake_state.selected_folder_rel == "src" - - def test_second_call_does_not_overwrite_files_content(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.files_content = {"/workspace/main.py": "x = 1"} - init_state() - assert fake_state.files_content == {"/workspace/main.py": "x = 1"} - - def test_second_call_does_not_overwrite_active_tab(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.active_tab = 2 - init_state() - assert fake_state.active_tab == 2 - - def test_second_call_does_not_overwrite_is_editing(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.is_editing = True - init_state() - assert fake_state.is_editing is True - - def test_second_call_does_not_overwrite_code_suggestions(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.code_suggestions = ["use f-strings"] - init_state() - assert fake_state.code_suggestions == ["use f-strings"] - - def test_second_call_does_not_overwrite_code_execution_output(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.code_execution_output = "previous output" - init_state() - assert fake_state.code_execution_output == "previous output" - - def test_second_call_does_not_overwrite_agent_mode(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.agent_mode = True - init_state() - assert fake_state.agent_mode is True - - def test_second_call_does_not_overwrite_coding_agent(self, fake_state): - # object() is used as a sentinel: a unique instance that cannot accidentally - # equal any value init_state() might write, so identity check is unambiguous. - from frontend.state import init_state - init_state() - sentinel = object() - fake_state.coding_agent = sentinel - init_state() - assert fake_state.coding_agent is sentinel - - def test_second_call_does_not_overwrite_agent_status(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.agent_status = "waiting_approval" - init_state() - assert fake_state.agent_status == "waiting_approval" - - def test_second_call_does_not_overwrite_agent_log(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.agent_log = [{"step": 1, "tool": "write_file"}] - init_state() - assert len(fake_state.agent_log) == 1 - - def test_second_call_does_not_overwrite_agent_pending_action(self, fake_state): - from frontend.state import init_state - init_state() - fake_state.agent_pending_action = {"tool": "write_file", "arguments": {}} - init_state() - assert fake_state.agent_pending_action is not None diff --git a/tests/test_system_prompter.py b/tests/test_system_prompter.py index 214f3ba..e256d87 100644 --- a/tests/test_system_prompter.py +++ b/tests/test_system_prompter.py @@ -53,11 +53,6 @@ class TestSystemPrompterWithFileContext: prompt = SystemPrompter.generate_prompt(file_context={"name": "f.py", "content": "pass"}) assert "" in prompt - def test_with_context_is_longer_than_base(self): - base = SystemPrompter.generate_prompt() - with_ctx = SystemPrompter.generate_prompt(file_context={"name": "f.py", "content": "x=1"}) - assert len(with_ctx) > len(base) - def test_missing_name_key_uses_unknown(self): prompt = SystemPrompter.generate_prompt(file_context={"content": "some code"}) assert "unknown" in prompt