use super::*;
use crate::output::OutputEvent;
use crate::tui::transcript_cards::visual_lines::{
take_body_lines_formatted_for_test, visual_lines,
};
#[test]
fn streaming_plain_prefixes_match_whole_input_sanitization() {
for input in [
"first\n\n界 cafe\u{301} 👩\u{200d}💻\nlast\n\n",
"first\n\x1b[31mred\x1b[0m\nend",
"first\n\x1b]8;;https://example.com\nsecret\x1b\\link\x1b]8;;\x1b\\\nend",
"first\nAuthorization: Bearer abcdefghijklmnopqrstuvwxyz\nend",
"first\napi_key=sk-test-only-not-a-real-key-1234567890\nend",
"first\n{\"password\":\n\"test-only-secret\"}\nend",
"first\ncontrol\r\t\x08\x07\u{009b}31mend\nlast",
"# Heading\n**bold**\n```rust\nlet x = 1;\n```",
] {
let state = MissionControlState::default();
for end in input
.char_indices()
.map(|(index, _)| index)
.chain([input.len()])
{
let body = &input[..end];
let incremental = assistant_card(
TranscriptCardId { entry_index: 0 },
body,
true,
false,
Some(&state),
);
let cold = assistant_card(TranscriptCardId { entry_index: 0 }, body, true, false, None);
assert_eq!(incremental.body, cold.body);
assert_eq!(incremental.body_lines, cold.body_lines, "prefix {body:?}");
}
let replaced = assistant_card(
TranscriptCardId { entry_index: 0 },
"replacement\ntail",
true,
false,
Some(&state),
);
assert_eq!(
replaced.body_lines,
render("replacement\ntail", RenderInputKind::Plain)
);
let final_card = assistant_card(
TranscriptCardId { entry_index: 0 },
input,
false,
false,
Some(&state),
);
assert_eq!(
final_card.body_lines,
render(&final_card.body, RenderInputKind::Markdown)
);
assert!(state.transcript_cache.borrow().streaming.is_none());
}
}
fn assert_cold_visual_equivalence(state: &MissionControlState, width: u16) {
let warm = visual_lines(state, width);
let retained = std::mem::take(&mut *state.transcript_cache.borrow_mut());
let cold = visual_lines(state, width);
*state.transcript_cache.borrow_mut() = retained;
assert_eq!(warm, cold, "width {width}");
}
#[test]
fn streaming_visual_appends_preserve_styles_copy_coordinates_and_final_markdown() {
let mut state = MissionControlState::default();
let mut full = String::new();
for text in [
"first\n",
"\n界 cafe",
"\u{301} 👩",
"\u{200d}💻\n",
"\x1b[",
"31mred",
"\x1b[0m\n",
"Authorization: Bear",
"er test-only-secret\n",
"# Heading\n**bold**\n",
"```rust\nlet x = 1;\n```\n",
] {
full.push_str(text);
state.apply_output_event(&OutputEvent::AssistantDelta { text: text.into() });
for width in [1, 8, 24, 80] {
assert_cold_visual_equivalence(&state, width);
}
}
state.apply_output_event(&OutputEvent::AssistantComplete { text: full });
state.begin_final_assistant_plain_first_paint();
assert_cold_visual_equivalence(&state, 24);
assert!(state.transcript_cache.borrow().streaming.is_none());
state.finish_final_assistant_plain_first_paint();
assert_cold_visual_equivalence(&state, 24);
}
#[test]
fn streaming_append_only_formats_unfinished_tail_and_bounds_width_caches() {
let mut state = MissionControlState::default();
state.apply_output_event(&OutputEvent::AssistantDelta {
text: format!("{}tail", "completed long line 界\n".repeat(100)),
});
visual_lines(&state, 24);
take_body_lines_formatted_for_test();
state.apply_output_event(&OutputEvent::AssistantDelta {
text: " grows".into(),
});
visual_lines(&state, 24);
assert_eq!(take_body_lines_formatted_for_test(), 1);
assert_cold_visual_equivalence(&state, 24);
for width in 1..8 {
assert_cold_visual_equivalence(&state, width);
}
assert!(
state
.transcript_cache
.borrow()
.streaming
.as_ref()
.unwrap()
.visual_lines
.len()
<= 4
);
state.focus_transcript();
assert_cold_visual_equivalence(&state, 24);
state.focus_prompt();
assert_cold_visual_equivalence(&state, 24);
let theme = crate::tui::theme::MissionControlTheme::from_runtime_appearance(
&crate::appearance::RuntimeAppearance::default(),
1,
);
assert!(state.set_theme(theme, false));
assert_cold_visual_equivalence(&state, 24);
assert_cold_visual_equivalence(&state, 3000);
assert!(
!state
.transcript_cache
.borrow()
.streaming
.as_ref()
.unwrap()
.visual_lines
.contains_key(&3000)
);
state
.transcript_cache
.borrow_mut()
.clear_visual_projection();
assert!(
state
.transcript_cache
.borrow()
.streaming
.as_ref()
.unwrap()
.visual_lines
.is_empty()
);
assert_cold_visual_equivalence(&state, 24);
let index = state
.transcript_cache
.borrow()
.streaming
.as_ref()
.unwrap()
.entry_index;
state.transcript_cache.borrow_mut().evict_front(index, 1);
assert!(state.transcript_cache.borrow().streaming.is_none());
}
#[test]
fn oversized_streams_do_not_retain_incremental_caches() {
let state = MissionControlState::default();
let body = "x".repeat(transcript::MAX_STREAMING_CACHE_BYTES + 1);
let card = assistant_card(
TranscriptCardId { entry_index: 0 },
&body,
true,
false,
Some(&state),
);
assert_eq!(card.body_lines, render(&body, RenderInputKind::Plain));
assert!(state.transcript_cache.borrow().streaming.is_none());
}