109 lines
4.1 KiB
Python
109 lines
4.1 KiB
Python
"""Tests for the /new command."""
|
|
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
|
|
class TestNewCommand:
|
|
async def test_execute_calls_start_new_session(self):
|
|
from EvoScientist.commands.base import CommandContext
|
|
from EvoScientist.commands.implementation.session import NewCommand
|
|
|
|
ui = MagicMock()
|
|
ui.start_new_session = AsyncMock()
|
|
ctx = CommandContext(
|
|
agent=None,
|
|
thread_id="old-tid",
|
|
ui=ui,
|
|
workspace_dir="/old/ws",
|
|
)
|
|
await NewCommand().execute(ctx, [])
|
|
ui.start_new_session.assert_awaited_once()
|
|
|
|
def test_requires_agent_false(self):
|
|
from EvoScientist.commands.implementation.session import NewCommand
|
|
|
|
assert NewCommand().requires_agent is False
|
|
|
|
async def test_no_agent_access(self):
|
|
"""Command body must not touch ctx.agent (it's still loading)."""
|
|
from EvoScientist.commands.base import CommandContext
|
|
from EvoScientist.commands.implementation.session import NewCommand
|
|
|
|
ui = MagicMock()
|
|
ui.start_new_session = AsyncMock()
|
|
ctx = CommandContext(agent=None, thread_id="tid", ui=ui)
|
|
# No AttributeError even though ctx.agent is None
|
|
await NewCommand().execute(ctx, [])
|
|
|
|
async def test_clears_invited_experts_and_announces(self):
|
|
"""/new dismisses invited experts uniformly with channel-shutdown clear."""
|
|
from EvoScientist.commands.base import ChannelRuntime, CommandContext
|
|
from EvoScientist.commands.implementation.session import NewCommand
|
|
|
|
ui = MagicMock()
|
|
ui.start_new_session = AsyncMock()
|
|
runtime = ChannelRuntime()
|
|
runtime.active_teams = ["idea-brainstorm"]
|
|
ctx = CommandContext(
|
|
agent=None,
|
|
thread_id="tid",
|
|
ui=ui,
|
|
channel_runtime=runtime,
|
|
)
|
|
await NewCommand().execute(ctx, [])
|
|
assert runtime.active_teams == []
|
|
messages = [call.args[0] for call in ui.append_system.call_args_list]
|
|
assert any(
|
|
"Dismissed experts on new session: idea-brainstorm" in msg
|
|
for msg in messages
|
|
)
|
|
|
|
async def test_no_announcement_when_no_experts_invited(self):
|
|
"""No noise on ``/new`` when the invite list is already empty."""
|
|
from EvoScientist.commands.base import ChannelRuntime, CommandContext
|
|
from EvoScientist.commands.implementation.session import NewCommand
|
|
|
|
ui = MagicMock()
|
|
ui.start_new_session = AsyncMock()
|
|
runtime = ChannelRuntime()
|
|
ctx = CommandContext(
|
|
agent=None,
|
|
thread_id="tid",
|
|
ui=ui,
|
|
channel_runtime=runtime,
|
|
)
|
|
await NewCommand().execute(ctx, [])
|
|
ui.append_system.assert_not_called()
|
|
|
|
async def test_no_announcement_without_channel_runtime(self):
|
|
"""Runs cleanly when no ChannelRuntime is attached."""
|
|
from EvoScientist.commands.base import CommandContext
|
|
from EvoScientist.commands.implementation.session import NewCommand
|
|
|
|
ui = MagicMock()
|
|
ui.start_new_session = AsyncMock()
|
|
ctx = CommandContext(agent=None, thread_id="tid", ui=ui, channel_runtime=None)
|
|
await NewCommand().execute(ctx, [])
|
|
ui.append_system.assert_not_called()
|
|
|
|
async def test_failed_session_start_keeps_invitations(self):
|
|
"""A raising start_new_session leaves the current session's invites."""
|
|
import pytest
|
|
|
|
from EvoScientist.commands.base import ChannelRuntime, CommandContext
|
|
from EvoScientist.commands.implementation.session import NewCommand
|
|
|
|
ui = MagicMock()
|
|
ui.start_new_session = AsyncMock(side_effect=RuntimeError("gateway down"))
|
|
runtime = ChannelRuntime()
|
|
runtime.active_teams = ["idea-brainstorm"]
|
|
ctx = CommandContext(
|
|
agent=None,
|
|
thread_id="tid",
|
|
ui=ui,
|
|
channel_runtime=runtime,
|
|
)
|
|
with pytest.raises(RuntimeError):
|
|
await NewCommand().execute(ctx, [])
|
|
assert runtime.active_teams == ["idea-brainstorm"]
|