diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..125217d --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,22 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + run-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Set up Python + run: uv python install 3.12 + + - name: Run tests + run: uv run --extra dev pytest tests/ -v diff --git a/tests/test_channel_theme.py b/tests/test_channel_theme.py index 3d22a39..7ccfd7b 100644 --- a/tests/test_channel_theme.py +++ b/tests/test_channel_theme.py @@ -41,22 +41,19 @@ def test_colorfgbg_light(self): def test_default_is_dark(self): with patch.dict("os.environ", {"ANTON_THEME": "", "COLORFGBG": ""}, clear=False): - with patch("anton.channel.theme.os.uname") as mock_uname: - mock_uname.return_value.sysname = "Linux" + with patch("anton.channel.theme.sys.platform", "linux"): assert detect_color_mode() == "dark" def test_macos_dark_mode(self): with patch.dict("os.environ", {"ANTON_THEME": "", "COLORFGBG": ""}, clear=False): - with patch("anton.channel.theme.os.uname") as mock_uname: - mock_uname.return_value.sysname = "Darwin" + with patch("anton.channel.theme.sys.platform", "darwin"): with patch("anton.channel.theme.subprocess.run") as mock_run: mock_run.return_value.returncode = 0 assert detect_color_mode() == "dark" def test_macos_light_mode(self): with patch.dict("os.environ", {"ANTON_THEME": "", "COLORFGBG": ""}, clear=False): - with patch("anton.channel.theme.os.uname") as mock_uname: - mock_uname.return_value.sysname = "Darwin" + with patch("anton.channel.theme.sys.platform", "darwin"): with patch("anton.channel.theme.subprocess.run") as mock_run: mock_run.return_value.returncode = 1 assert detect_color_mode() == "light" diff --git a/tests/test_chat_scratchpad.py b/tests/test_chat_scratchpad.py index 94d0d0a..645addf 100644 --- a/tests/test_chat_scratchpad.py +++ b/tests/test_chat_scratchpad.py @@ -205,6 +205,7 @@ async def test_scratchpad_dump_streams_tool_result(self): """dump action yields a StreamToolResult for display, but sends a short summary back to the LLM to avoid it parroting the full notebook.""" mock_llm = AsyncMock() + mock_llm.plan = AsyncMock(return_value=_text_response("STATUS: COMPLETE — task done")) call_count = 0 @@ -259,6 +260,7 @@ async def test_scratchpad_in_streaming_path(self): final_response = _text_response("Got 99.") mock_llm = AsyncMock() + mock_llm.plan = AsyncMock(return_value=_text_response("STATUS: COMPLETE — task done")) call_count = 0 diff --git a/tests/test_chat_ui.py b/tests/test_chat_ui.py index 471f9bf..68045bd 100644 --- a/tests/test_chat_ui.py +++ b/tests/test_chat_ui.py @@ -226,4 +226,3 @@ def test_text_routes_to_buffer_after_tools(self, MockLive): assert display._initial_text == "Initial text" assert display._buffer == "Answer text" assert display._in_tool_phase - assert display._answer_started diff --git a/tests/test_datasource.py b/tests/test_datasource.py index 3989cdf..dc7a13a 100644 --- a/tests/test_datasource.py +++ b/tests/test_datasource.py @@ -583,7 +583,7 @@ async def test_partial_save_on_n_answer(self, registry, vault_dir, make_session) conns = vault.list_connections() assert len(conns) == 1 assert conns[0]["engine"] == "postgresql" - assert conns[0]["name"].isdigit() + assert conns[0]["name"].isalnum() session._scratchpads.get_or_create.assert_not_called() @pytest.mark.asyncio diff --git a/tests/test_settings.py b/tests/test_settings.py index 5833fe8..ebc318a 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -8,21 +8,37 @@ from anton.config.settings import AntonSettings +_ANTON_MODEL_KEYS = [ + "ANTON_PLANNING_PROVIDER", + "ANTON_PLANNING_MODEL", + "ANTON_CODING_PROVIDER", + "ANTON_CODING_MODEL", +] + + class TestAntonSettingsDefaults: - def test_default_planning_provider(self): - s = AntonSettings(anthropic_api_key="test") + def test_default_planning_provider(self, monkeypatch): + for k in _ANTON_MODEL_KEYS: + monkeypatch.delenv(k, raising=False) + s = AntonSettings(anthropic_api_key="test", _env_file=None) assert s.planning_provider == "anthropic" - def test_default_planning_model(self): - s = AntonSettings(anthropic_api_key="test") + def test_default_planning_model(self, monkeypatch): + for k in _ANTON_MODEL_KEYS: + monkeypatch.delenv(k, raising=False) + s = AntonSettings(anthropic_api_key="test", _env_file=None) assert s.planning_model == "claude-sonnet-4-6" - def test_default_coding_provider(self): - s = AntonSettings(anthropic_api_key="test") + def test_default_coding_provider(self, monkeypatch): + for k in _ANTON_MODEL_KEYS: + monkeypatch.delenv(k, raising=False) + s = AntonSettings(anthropic_api_key="test", _env_file=None) assert s.coding_provider == "anthropic" - def test_default_coding_model(self): - s = AntonSettings(anthropic_api_key="test") + def test_default_coding_model(self, monkeypatch): + for k in _ANTON_MODEL_KEYS: + monkeypatch.delenv(k, raising=False) + s = AntonSettings(anthropic_api_key="test", _env_file=None) assert s.coding_model == "claude-haiku-4-5-20251001" def test_default_memory_dir(self):