use crate::tui::app::reasoning_split::{Segment, split_segments};
fn text(s: &str) -> Segment {
Segment::Text(s.to_string())
}
fn reasoning(s: &str) -> Segment {
Segment::Reasoning(s.to_string())
}
#[test]
fn plain_content_is_one_text_segment() {
assert_eq!(
split_segments("just an answer"),
vec![text("just an answer")]
);
}
#[test]
fn empty_content_yields_nothing() {
assert!(split_segments("").is_empty());
assert!(split_segments(" \n ").is_empty());
}
#[test]
fn iterations_keep_their_chronological_order() {
let persisted = "<!-- reasoning -->\nfirst thought\n<!-- /reasoning -->\n\n\
first answer\n\n\
<!-- reasoning -->\nsecond thought\n<!-- /reasoning -->\n\n\
second answer\n\n";
assert_eq!(
split_segments(persisted),
vec![
reasoning("first thought"),
text("first answer"),
reasoning("second thought"),
text("second answer"),
]
);
}
#[test]
fn only_the_last_text_segment_can_be_the_final_answer() {
let persisted = "<!-- reasoning -->\nthinking\n<!-- /reasoning -->\n\n\
a long intermediate narration\n\n\
<!-- reasoning -->\nmore thinking\n<!-- /reasoning -->\n\n\
the actual answer";
let segments = split_segments(persisted);
let texts: Vec<&Segment> = segments
.iter()
.filter(|s| matches!(s, Segment::Text(_)))
.collect();
assert_eq!(texts.len(), 2, "intermediate text is its own row");
assert_eq!(*texts[1], text("the actual answer"));
}
#[test]
fn reasoning_only_turn_produces_no_visible_text() {
let persisted = "<!-- reasoning -->\nall thought, no answer\n<!-- /reasoning -->\n\n";
assert_eq!(
split_segments(persisted),
vec![reasoning("all thought, no answer")]
);
}
#[test]
fn an_unclosed_block_stays_reasoning() {
let persisted = "answer so far\n\n<!-- reasoning -->\ncut off mid thought";
assert_eq!(
split_segments(persisted),
vec![text("answer so far"), reasoning("cut off mid thought")]
);
}
#[test]
fn text_before_the_first_block_is_kept() {
let persisted = "leading text\n\n<!-- reasoning -->\nthought\n<!-- /reasoning -->\n\n";
assert_eq!(
split_segments(persisted),
vec![text("leading text"), reasoning("thought")]
);
}
#[test]
fn empty_blocks_do_not_create_blank_rows() {
let persisted = "<!-- reasoning -->\n\n<!-- /reasoning -->\n\nreal answer";
assert_eq!(split_segments(persisted), vec![text("real answer")]);
}
#[test]
fn three_blocks_split_into_three_reasoning_rows() {
let persisted = "<!-- reasoning -->\nA\n<!-- /reasoning -->\n\nwall one\n\n\
<!-- reasoning -->\nB\n<!-- /reasoning -->\n\nwall two\n\n\
<!-- reasoning -->\nC\n<!-- /reasoning -->\n\nfinal";
let segments = split_segments(persisted);
assert_eq!(
segments
.iter()
.filter(|s| matches!(s, Segment::Reasoning(_)))
.count(),
3
);
assert_eq!(
segments
.iter()
.filter(|s| matches!(s, Segment::Text(_)))
.count(),
3,
"each unwrapped stretch is its own row, so only the last is the answer"
);
}
use crate::tui::app::reasoning_split::is_intermediate;
#[test]
fn text_followed_by_more_reasoning_is_not_the_answer() {
let segs = vec![
reasoning("thought one"),
text("restated reasoning that looks like an answer"),
reasoning("thought two"),
text("the real answer"),
];
assert!(is_intermediate(&segs, 1), "more reasoning follows it");
assert!(
!is_intermediate(&segs, 3),
"nothing thinks after it, so it is the answer"
);
}
#[test]
fn the_only_text_is_the_answer() {
let segs = vec![reasoning("thinking"), text("answer")];
assert!(!is_intermediate(&segs, 1));
}
#[test]
fn without_any_reasoning_every_text_stays_visible() {
let segs = vec![text("first"), text("second")];
assert!(!is_intermediate(&segs, 0));
assert!(!is_intermediate(&segs, 1));
}
#[test]
fn trailing_reasoning_collapses_all_earlier_text() {
let segs = vec![text("narration"), reasoning("still thinking")];
assert!(is_intermediate(&segs, 0));
}