diff --git a/tests/test_ccproxy_manager.py b/tests/test_ccproxy_manager.py index 652abd5..7b0c7f9 100644 --- a/tests/test_ccproxy_manager.py +++ b/tests/test_ccproxy_manager.py @@ -58,7 +58,7 @@ class TestCheckCcproxyAuth: mock_run.return_value = MagicMock( returncode=0, stdout="Authenticated", stderr="" ) - valid, msg = check_ccproxy_auth("codex") + valid, _msg = check_ccproxy_auth("codex") assert valid is True cmd = mock_run.call_args[0][0] assert cmd[1:] == ["auth", "status", "codex"] diff --git a/tests/test_channel_comprehensive.py b/tests/test_channel_comprehensive.py index 705628b..8d1d241 100644 --- a/tests/test_channel_comprehensive.py +++ b/tests/test_channel_comprehensive.py @@ -249,7 +249,7 @@ class TestRetryAsync: ) # With 50% jitter, not all delays should be identical if len(delays) > 1: - assert len(set(f"{d:.4f}" for d in delays)) > 1 + assert len({f"{d:.4f}" for d in delays}) > 1 # ═══════════════════════════════════════════════════════════════════ @@ -1438,10 +1438,10 @@ class TestInboundConsumer: async def _test(): consumer = self._make_consumer() # Start and immediately stop - asyncio.create_task(consumer.run()) + task = asyncio.create_task(consumer.run()) await asyncio.sleep(0.1) await consumer.stop() - await asyncio.sleep(0.1) + await task assert consumer._stopping is True _run(_test()) diff --git a/tests/test_compact_command.py b/tests/test_compact_command.py index 9035ff5..c78d211 100644 --- a/tests/test_compact_command.py +++ b/tests/test_compact_command.py @@ -1,38 +1,29 @@ """Tests for the /compact command (compact_conversation helper).""" -import asyncio from types import SimpleNamespace from unittest.mock import AsyncMock, MagicMock, patch -import pytest - - -@pytest.fixture -def _run(): - """Helper to run async tests.""" - loop = asyncio.new_event_loop() - yield loop.run_until_complete - loop.close() +from tests.conftest import run_async as _run class TestCompactGuards: """Guard conditions that return early without touching the middleware.""" - def test_no_agent(self, _run): + def test_no_agent(self): from EvoScientist.cli.commands import compact_conversation result = _run(compact_conversation(agent=None, thread_id="abc")) assert result.status == "noop" assert "Nothing to compact" in result.message - def test_no_thread_id(self, _run): + def test_no_thread_id(self): from EvoScientist.cli.commands import compact_conversation result = _run(compact_conversation(agent=MagicMock(), thread_id=None)) assert result.status == "noop" assert "Nothing to compact" in result.message - def test_empty_messages(self, _run): + def test_empty_messages(self): from EvoScientist.cli.commands import compact_conversation agent = MagicMock() @@ -43,7 +34,7 @@ class TestCompactGuards: assert result.status == "noop" assert "no messages" in result.message - def test_state_read_failure(self, _run): + def test_state_read_failure(self): from EvoScientist.cli.commands import compact_conversation agent = MagicMock() @@ -57,7 +48,7 @@ class TestCompactGuards: class TestCompactCutoffZero: """When cutoff == 0, conversation is within retention budget.""" - def test_nothing_to_compact_short_conversation(self, _run): + def test_nothing_to_compact_short_conversation(self): from EvoScientist.cli.commands import compact_conversation agent = MagicMock() @@ -102,7 +93,7 @@ class TestCompactCutoffZero: class TestCompactNegligibleSavings: """When cutoff > 0 but savings are too small to be worth it.""" - def test_skip_when_few_messages_and_low_tokens(self, _run): + def test_skip_when_few_messages_and_low_tokens(self): from EvoScientist.cli.commands import compact_conversation agent = MagicMock() @@ -151,7 +142,7 @@ class TestCompactNegligibleSavings: # No LLM call should have been made mock_middleware_inst._acreate_summary.assert_not_called() - def test_still_compacts_when_few_messages_but_high_tokens(self, _run): + def test_still_compacts_when_few_messages_but_high_tokens(self): """2 messages but they account for >2% of tokens — should compact.""" from langchain_core.messages import HumanMessage @@ -211,7 +202,7 @@ class TestCompactNegligibleSavings: class TestCompactSuccess: """Normal compaction flow.""" - def test_successful_compaction(self, _run): + def test_successful_compaction(self): from langchain_core.messages import HumanMessage from EvoScientist.cli.commands import compact_conversation @@ -281,7 +272,7 @@ class TestCompactSuccess: assert "_summarization_event" in event_data assert event_data["_summarization_event"]["cutoff_index"] == 15 - def test_offload_failure_non_fatal(self, _run): + def test_offload_failure_non_fatal(self): """Offload failure should not prevent compaction.""" from langchain_core.messages import HumanMessage diff --git a/tests/test_dingtalk_channel.py b/tests/test_dingtalk_channel.py index 0d76051..f2fd924 100644 --- a/tests/test_dingtalk_channel.py +++ b/tests/test_dingtalk_channel.py @@ -283,11 +283,11 @@ class TestDingTalkProbe: def test_missing_client_id(self): from EvoScientist.channels.dingtalk.probe import validate_dingtalk - ok, msg = _run(validate_dingtalk("", "secret")) + ok, _msg = _run(validate_dingtalk("", "secret")) assert ok is False def test_missing_client_secret(self): from EvoScientist.channels.dingtalk.probe import validate_dingtalk - ok, msg = _run(validate_dingtalk("id", "")) + ok, _msg = _run(validate_dingtalk("id", "")) assert ok is False diff --git a/tests/test_llm.py b/tests/test_llm.py index 1148726..2546c84 100644 --- a/tests/test_llm.py +++ b/tests/test_llm.py @@ -580,7 +580,7 @@ class TestMiniMaxProvider: def test_minimax_model_ids_correct(self): """MiniMax model IDs should match the official API model names.""" minimax_models = get_models_for_provider("minimax") - model_dict = {name: mid for name, mid in minimax_models} + model_dict = dict(minimax_models) assert model_dict["minimax-m2.7"] == "MiniMax-M2.7" assert model_dict["minimax-m2.5"] == "MiniMax-M2.5" assert model_dict["minimax-m2.5-highspeed"] == "MiniMax-M2.5-highspeed" diff --git a/tests/test_mcp_client.py b/tests/test_mcp_client.py index a5447ce..d781e68 100644 --- a/tests/test_mcp_client.py +++ b/tests/test_mcp_client.py @@ -556,7 +556,8 @@ class TestAddMcpServer: add_mcp_server("a", "stdio", command="cmd1") add_mcp_server("b", "http", url="http://x") data = yaml.safe_load(user_mcp_dir.read_text()) - assert "a" in data and "b" in data + assert "a" in data + assert "b" in data class TestRemoveMcpServer: diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 6d17740..26449ad 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -25,7 +25,7 @@ from tests.conftest import run_async as _run class TestGenerateThreadId(unittest.TestCase): def test_length(self): tid = generate_thread_id() - self.assertEqual(len(tid), 8) + assert len(tid) == 8 def test_hex(self): tid = generate_thread_id() @@ -33,58 +33,58 @@ class TestGenerateThreadId(unittest.TestCase): def test_uniqueness(self): ids = {generate_thread_id() for _ in range(100)} - self.assertEqual(len(ids), 100) + assert len(ids) == 100 class TestGetDbPath(unittest.TestCase): def test_uses_config_dir(self): path = get_db_path() - self.assertTrue(str(path).endswith("sessions.db")) - self.assertIn(".config", str(path)) - self.assertIn("evoscientist", str(path)) + assert str(path).endswith("sessions.db") + assert ".config" in str(path) + assert "evoscientist" in str(path) class TestFormatRelativeTime(unittest.TestCase): def test_none(self): - self.assertEqual(_format_relative_time(None), "") + assert _format_relative_time(None) == "" def test_invalid(self): - self.assertEqual(_format_relative_time("not-a-date"), "") + assert _format_relative_time("not-a-date") == "" def test_recent(self): from datetime import datetime now = datetime.now(UTC).isoformat() result = _format_relative_time(now) - self.assertIn("just now", result) + assert "just now" in result def test_minutes(self): from datetime import datetime, timedelta ts = (datetime.now(UTC) - timedelta(minutes=5)).isoformat() result = _format_relative_time(ts) - self.assertIn("min ago", result) + assert "min ago" in result def test_hours(self): from datetime import datetime, timedelta ts = (datetime.now(UTC) - timedelta(hours=2)).isoformat() result = _format_relative_time(ts) - self.assertIn("hour", result) + assert "hour" in result def test_days(self): from datetime import datetime, timedelta ts = (datetime.now(UTC) - timedelta(days=3)).isoformat() result = _format_relative_time(ts) - self.assertIn("day", result) + assert "day" in result def test_months(self): from datetime import datetime, timedelta ts = (datetime.now(UTC) - timedelta(days=65)).isoformat() result = _format_relative_time(ts) - self.assertIn("month", result) + assert "month" in result class TestThreadFunctions(unittest.TestCase): @@ -183,44 +183,44 @@ class TestThreadFunctions(unittest.TestCase): def test_list_threads(self): threads = _run(list_threads(limit=10)) # Should only contain EvoScientist threads - self.assertEqual(len(threads), 3) + assert len(threads) == 3 # Most recent first - self.assertEqual(threads[0]["thread_id"], "def00001") + assert threads[0]["thread_id"] == "def00001" def test_list_threads_with_message_count(self): threads = _run(list_threads(limit=10, include_message_count=True)) - self.assertIn("message_count", threads[0]) + assert "message_count" in threads[0] def test_thread_exists_true(self): - self.assertTrue(_run(thread_exists("abc12345"))) + assert _run(thread_exists("abc12345")) def test_thread_exists_false(self): - self.assertFalse(_run(thread_exists("nonexist"))) + assert not _run(thread_exists("nonexist")) def test_find_similar(self): similar = _run(find_similar_threads("abc1")) - self.assertEqual(len(similar), 2) - self.assertIn("abc12345", similar) - self.assertIn("abc12399", similar) + assert len(similar) == 2 + assert "abc12345" in similar + assert "abc12399" in similar def test_find_similar_no_match(self): similar = _run(find_similar_threads("xyz")) - self.assertEqual(len(similar), 0) + assert len(similar) == 0 def test_get_most_recent(self): recent = _run(get_most_recent()) - self.assertIsNotNone(recent) - self.assertEqual(recent, "def00001") + assert recent is not None + assert recent == "def00001" def test_get_thread_metadata(self): meta = _run(get_thread_metadata("abc12345")) - self.assertIsNotNone(meta) - self.assertEqual(meta["workspace_dir"], "/tmp/ws_abc12345") - self.assertEqual(meta["model"], "claude-sonnet-4-5") + assert meta is not None + assert meta["workspace_dir"] == "/tmp/ws_abc12345" + assert meta["model"] == "claude-sonnet-4-5" def test_get_thread_metadata_missing(self): meta = _run(get_thread_metadata("nonexist")) - self.assertIsNone(meta) + assert meta is None def test_delete_thread(self): # Insert a thread to delete @@ -242,29 +242,29 @@ class TestThreadFunctions(unittest.TestCase): _run(_insert()) - self.assertTrue(_run(thread_exists("todelete"))) - self.assertTrue(_run(delete_thread("todelete"))) - self.assertFalse(_run(thread_exists("todelete"))) + assert _run(thread_exists("todelete")) + assert _run(delete_thread("todelete")) + assert not _run(thread_exists("todelete")) def test_delete_nonexistent(self): - self.assertFalse(_run(delete_thread("nope1234"))) + assert not _run(delete_thread("nope1234")) # -- Agent isolation: OtherAgent data should never be visible -- def test_thread_exists_ignores_other_agent(self): - self.assertFalse(_run(thread_exists("zzz99999"))) + assert not _run(thread_exists("zzz99999")) def test_find_similar_ignores_other_agent(self): similar = _run(find_similar_threads("zzz")) - self.assertEqual(len(similar), 0) + assert len(similar) == 0 def test_get_metadata_ignores_other_agent(self): meta = _run(get_thread_metadata("zzz99999")) - self.assertIsNone(meta) + assert meta is None def test_delete_ignores_other_agent(self): # Should not delete OtherAgent's data - self.assertFalse(_run(delete_thread("zzz99999"))) + assert not _run(delete_thread("zzz99999")) def test_delete_thread_preserves_other_agent_writes(self): """Deleting a shared thread_id must only remove writes linked to @@ -329,8 +329,8 @@ class TestThreadFunctions(unittest.TestCase): return [r[0] for r in rows] remaining = _run(_check()) - self.assertIn("cp_other_shared", remaining) - self.assertNotIn("cp_evo_shared", remaining) + assert "cp_other_shared" in remaining + assert "cp_evo_shared" not in remaining if __name__ == "__main__": diff --git a/tests/test_summarization.py b/tests/test_summarization.py index 4af6844..4fbfa4f 100644 --- a/tests/test_summarization.py +++ b/tests/test_summarization.py @@ -203,10 +203,11 @@ class TestExtractSummarizationText: def test_content_blocks(self): class Msg: - content = [ - {"type": "text", "text": "part1"}, - {"type": "text", "text": "part2"}, - ] + def __init__(self): + self.content = [ + {"type": "text", "text": "part1"}, + {"type": "text", "text": "part2"}, + ] assert _extract_summarization_text(Msg()) == "part1part2" @@ -214,13 +215,15 @@ class TestExtractSummarizationText: """Content blocks may include 'index' field — should still extract text.""" class Msg: - content = [{"type": "text", "text": " vs", "index": 1}] + def __init__(self): + self.content = [{"type": "text", "text": " vs", "index": 1}] assert _extract_summarization_text(Msg()) == " vs" def test_empty_list(self): class Msg: - content = [] + def __init__(self): + self.content = [] assert _extract_summarization_text(Msg()) == "" @@ -232,15 +235,17 @@ class TestExtractSummarizationText: def test_mixed_block_types(self): class Msg: - content = [ - {"type": "text", "text": "hello"}, - {"type": "image", "url": "..."}, - ] + def __init__(self): + self.content = [ + {"type": "text", "text": "hello"}, + {"type": "image", "url": "..."}, + ] assert _extract_summarization_text(Msg()) == "hello" def test_string_blocks_in_list(self): class Msg: - content = ["hello", "world"] + def __init__(self): + self.content = ["hello", "world"] assert _extract_summarization_text(Msg()) == "helloworld" diff --git a/tests/test_wechat_channel.py b/tests/test_wechat_channel.py index 2822328..ce8d7eb 100644 --- a/tests/test_wechat_channel.py +++ b/tests/test_wechat_channel.py @@ -306,7 +306,7 @@ class TestWeChatCrypto: # Parse and verify the encrypted content decrypts back root = ET.fromstring(xml_reply) encrypt = root.find("Encrypt").text - decrypted, app_id = crypto.decrypt(encrypt) + decrypted, _app_id = crypto.decrypt(encrypt) assert decrypted == msg