"""Unit tests for event dataclass wire serialization."""
from navi.core.events import (
AIHelperTokensUsed,
CompressionStarted,
ContextCompressed,
PlanReady,
PlanningDebugData,
PlanningStatus,
ProfileSwitched,
StreamEnd,
StreamStopped,
SubagentComplete,
TextDelta,
ThinkingDelta,
ThinkingEnd,
TodoUpdated,
ToolEvent,
ToolStarted,
TurnThinking,
)
class TestToolStarted:
def test_to_wire(self):
ev = ToolStarted(tool_name="fs", arguments={"action": "read"})
assert ev.to_wire() == {
"type": "tool_started",
"tool": "fs",
"args": {"action": "read"},
"is_subagent": False,
"metadata": {},
"tool_call_id": "",
}
def test_to_wire_carries_metadata(self):
ev = ToolStarted(tool_name="todo", arguments={"op": "update"}, metadata={"step_text": "run tests"})
assert ev.to_wire()["metadata"] == {"step_text": "run tests"}
def test_to_wire_subagent(self):
ev = ToolStarted(tool_name="spawn_agent", arguments={}, is_subagent=True)
assert ev.to_wire()["is_subagent"] is True
class TestToolEvent:
def test_to_wire(self):
ev = ToolEvent(
tool_name="fs",
arguments={"path": "/tmp"},
result="file contents",
success=True,
metadata={"size": 42},
)
assert ev.to_wire() == {
"type": "tool_call",
"tool": "fs",
"args": {"path": "/tmp"},
"result": "file contents",
"success": True,
"is_subagent": False,
"metadata": {"size": 42},
"tool_call_id": "",
}
class TestTextDelta:
def test_to_wire(self):
assert TextDelta(delta="hello").to_wire() == {"type": "stream_delta", "delta": "hello"}
class TestThinkingDelta:
def test_to_wire(self):
assert ThinkingDelta(delta="hmm").to_wire() == {"type": "thinking_delta", "delta": "hmm"}
class TestThinkingEnd:
def test_to_wire(self):
assert ThinkingEnd().to_wire() == {"type": "thinking_end"}
class TestStreamEnd:
def test_to_wire(self):
ev = StreamEnd(
full_content="done",
context_tokens=150,
max_context_tokens=8192,
elapsed_seconds=1.5,
tool_call_count=2,
token_count=150,
)
wire = ev.to_wire()
assert wire["type"] == "stream_end"
assert wire["content"] == "done"
assert wire["context_tokens"] == 150
assert wire["tool_call_count"] == 2
class TestStreamStopped:
def test_to_wire(self):
assert StreamStopped().to_wire() == {"type": "stream_stopped"}
class TestContextCompressed:
def test_to_wire(self):
ev = ContextCompressed(messages_before=10, messages_after=3, summary="summary text")
wire = ev.to_wire()
assert wire["type"] == "context_compressed"
assert wire["messages_before"] == 10
assert wire["messages_after"] == 3
assert wire["summary"] == "summary text"
assert wire["context_tokens"] is None
class TestProfileSwitched:
def test_to_wire(self):
ev = ProfileSwitched(profile_id="dev", profile_name="Developer")
assert ev.to_wire() == {
"type": "profile_switched",
"profile_id": "dev",
"profile_name": "Developer",
}
class TestPlanningStatus:
def test_to_wire(self):
ev = PlanningStatus(phase=1, label="Working on it...")
assert ev.to_wire() == {
"type": "planning_status",
"phase": 1,
"label": "Working on it...",
"is_subagent": False,
}
class TestPlanReady:
def test_to_wire(self):
ev = PlanReady(plan="1. Do thing")
wire = ev.to_wire()
assert wire["type"] == "plan_ready"
assert wire["plan"] == "1. Do thing"
assert wire["is_subagent"] is False
class TestTurnThinking:
def test_to_wire(self):
ev = TurnThinking(thinking="reasoning...", is_subagent=True)
wire = ev.to_wire()
assert wire["type"] == "turn_thinking"
assert wire["thinking"] == "reasoning..."
assert wire["is_subagent"] is True
class TestCompressionStarted:
def test_to_wire(self):
ev = CompressionStarted(context_tokens=5000, max_context_tokens=8192)
wire = ev.to_wire()
assert wire["type"] == "compression_started"
assert wire["context_tokens"] == 5000
assert wire["max_context_tokens"] == 8192
class TestInternalEvents:
"""Internal events must NOT serialize to the wire."""
def test_subagent_complete(self):
assert SubagentComplete(token_count=42).to_wire() is None
def test_planning_debug_data(self):
assert PlanningDebugData(log={"phases": {}}).to_wire() is None
def test_ai_helper_tokens_used(self):
ev = AIHelperTokensUsed(prompt_tokens=10, completion_tokens=20)
assert ev.to_wire() is None
assert ev.total == 30
class TestTodoUpdated:
def test_to_wire_empty(self):
ev = TodoUpdated(session_id="sess1")
assert ev.to_wire() == {"type": "todo_updated", "session_id": "sess1", "tasks": []}
def test_to_wire_with_tasks(self):
tasks = [
{"index": 1, "text": "step one", "status": "done", "validation": "ran tests"},
{"index": 2, "text": "step two", "status": "in_progress", "validation": ""},
]
ev = TodoUpdated(session_id="sess1", tasks=tasks)
wire = ev.to_wire()
assert wire["type"] == "todo_updated"
assert wire["session_id"] == "sess1"
assert wire["tasks"] == tasks
assert len(wire["tasks"]) == 2