Files
tolaria/src-tauri/src/pi_events_tests.rs
2026-04-29 01:26:33 +02:00

116 lines
3.6 KiB
Rust

use super::*;
#[test]
fn parse_line_reports_read_errors_and_skips_blank_or_invalid_lines() {
let mut events = Vec::new();
let read_error = parse_line(Err(std::io::Error::other("broken pipe")), &mut |event| {
events.push(event)
});
let blank = parse_line(Ok(" ".into()), &mut |event| events.push(event));
let invalid = parse_line(Ok("not json".into()), &mut |event| events.push(event));
assert!(read_error.is_none());
assert!(blank.is_none());
assert!(invalid.is_none());
assert!(matches!(
&events[0],
AiAgentStreamEvent::Error { message } if message.contains("broken pipe")
));
}
#[test]
fn dispatch_maps_session_thinking_and_text() {
let mut events = Vec::new();
let started = serde_json::json!({ "type": "session", "id": "pi-session" });
let thinking = serde_json::json!({
"type": "message_update",
"assistantMessageEvent": { "type": "thinking_delta", "delta": "Checking links" }
});
let text = serde_json::json!({
"type": "message_update",
"assistantMessageEvent": { "type": "text_delta", "delta": "Done" }
});
for event in [started, thinking, text] {
dispatch_event(&event, &mut |event| events.push(event));
}
assert!(matches!(
&events[0],
AiAgentStreamEvent::Init { session_id } if session_id == "pi-session"
));
assert!(matches!(
&events[1],
AiAgentStreamEvent::ThinkingDelta { text } if text == "Checking links"
));
assert!(matches!(
&events[2],
AiAgentStreamEvent::TextDelta { text } if text == "Done"
));
}
#[test]
fn dispatch_maps_tool_events() {
let mut events = Vec::new();
let tool_start = serde_json::json!({
"type": "tool_execution_start",
"toolCallId": "tool_1",
"toolName": "search_notes",
"args": { "query": "today" }
});
let tool_done = serde_json::json!({
"type": "tool_execution_end",
"toolCallId": "tool_1",
"toolName": "search_notes",
"result": { "ok": true }
});
dispatch_event(&tool_start, &mut |event| events.push(event));
dispatch_event(&tool_done, &mut |event| events.push(event));
assert!(matches!(
&events[0],
AiAgentStreamEvent::ToolStart { tool_name, tool_id, input }
if tool_name == "search_notes" && tool_id == "tool_1" && input.as_deref() == Some(r#"{"query":"today"}"#)
));
assert!(matches!(
&events[1],
AiAgentStreamEvent::ToolDone { tool_id, output }
if tool_id == "tool_1" && output.as_deref() == Some(r#"{"ok":true}"#)
));
}
#[test]
fn dispatch_maps_error_events() {
let mut events = Vec::new();
let error = serde_json::json!({ "type": "error", "message": "provider failed" });
dispatch_event(&error, &mut |event| events.push(event));
assert!(matches!(
&events[0],
AiAgentStreamEvent::Error { message } if message == "provider failed"
));
}
#[test]
fn format_error_explains_missing_auth_or_provider_setup() {
let message = format_error(
"provider auth failed: api key required".into(),
"exit status: 1".into(),
);
assert!(message.contains("Pi CLI is not authenticated"));
assert!(message.contains("pi /login"));
}
#[test]
fn format_error_uses_status_or_first_stderr_lines() {
let empty = format_error(String::new(), "exit status: 2".into());
let truncated = format_error("line 1\nline 2\nline 3\nline 4".into(), "ignored".into());
assert_eq!(empty, "pi exited with status exit status: 2");
assert_eq!(truncated, "line 1\nline 2\nline 3");
}