use std::fmt::Write as _;
use serde_json::Value;
use super::{segment_transcript, SegmentFormat, SegmentKind, SegmentationPolicy};
use crate::error::MemoryError;
use crate::limits::{MAX_FRAGMENTS, MAX_FRAGMENT_BYTES};
fn policy() -> SegmentationPolicy {
SegmentationPolicy::default()
}
#[test]
fn plain_text_without_markers_is_single_body_segment() {
let text = "The deploy pipeline is green.\nNothing else to report.";
let outcome = segment_transcript(text, &policy()).expect("segments");
assert_eq!(outcome.format_detected, SegmentFormat::Plain);
assert_eq!(outcome.segments.len(), 1);
let segment = &outcome.segments[0];
assert_eq!(segment.kind, SegmentKind::Body);
assert_eq!(segment.role, None);
assert_eq!(segment.turn, 0);
assert_eq!(segment.fragment.content, text);
assert_eq!(segment.byte_start, 0);
assert_eq!(segment.byte_end, text.len());
}
#[test]
fn user_assistant_markers_split_turns() {
let text = "User: what is the deploy status?\nAssistant: it is green.\n";
let outcome = segment_transcript(text, &policy()).expect("segments");
assert_eq!(outcome.format_detected, SegmentFormat::Plain);
let roles: Vec<Option<String>> = outcome.segments.iter().map(|s| s.role.clone()).collect();
assert_eq!(
roles,
vec![Some("User".to_owned()), Some("Assistant".to_owned())]
);
assert_eq!(outcome.segments[0].turn, 0);
assert_eq!(outcome.segments[1].turn, 1);
assert!(outcome.segments[0].fragment.content.starts_with("User:"));
assert!(outcome.segments[1]
.fragment
.content
.starts_with("Assistant:"));
}
#[test]
fn jsonl_roles_detected_and_forced_format_errors_on_bad_line() {
let good =
"{\"role\":\"system\",\"content\":\"be terse\"}\n{\"role\":\"user\",\"content\":\"hi\"}\n";
let mut jsonl_policy = policy();
jsonl_policy.format = SegmentFormat::Jsonl;
let outcome = segment_transcript(good, &jsonl_policy).expect("valid jsonl segments");
assert_eq!(outcome.format_detected, SegmentFormat::Jsonl);
assert_eq!(outcome.segments.len(), 2);
assert_eq!(outcome.segments[0].role, Some("system".to_owned()));
assert_eq!(outcome.segments[0].fragment.content, "be terse");
assert_eq!(outcome.segments[1].role, Some("user".to_owned()));
assert_eq!(outcome.segments[1].fragment.content, "hi");
let bad = "{\"role\":\"system\",\"content\":\"be terse\"}\nnot json at all\n";
let err = segment_transcript(bad, &jsonl_policy).expect_err("bad line must error");
match err {
MemoryError::SegmentationError(msg) => {
assert!(msg.contains("line 2"), "{msg}");
}
other => panic!("expected SegmentationError, got {other:?}"),
}
}
#[test]
fn forced_jsonl_no_nonblank_line_is_also_segmentation_error() {
let blank_only = "\n\n";
let mut jsonl_policy = policy();
jsonl_policy.format = SegmentFormat::Jsonl;
let err = segment_transcript(blank_only, &jsonl_policy).expect_err("must error");
match err {
MemoryError::SegmentationError(_) => {}
other => panic!("expected SegmentationError, got {other:?}"),
}
}
#[test]
fn genuine_budget_breaches_still_return_context_over_limit() {
use crate::limits::MAX_TRANSCRIPT_BYTES;
let too_big = "a".repeat(MAX_TRANSCRIPT_BYTES + 1);
let err = segment_transcript(&too_big, &policy()).expect_err("over cap");
assert!(
matches!(err, MemoryError::ContextOverLimit(_)),
"expected ContextOverLimit, got {err:?}"
);
let mut many_turns = String::new();
for i in 0..=MAX_FRAGMENTS {
writeln!(many_turns, "User: turn {i}").expect("write to String never fails");
}
let mut tight_policy = policy();
tight_policy.min_segment_bytes = 0;
let err = segment_transcript(&many_turns, &tight_policy).expect_err("over fragment cap");
assert!(
matches!(err, MemoryError::ContextOverLimit(_)),
"expected ContextOverLimit, got {err:?}"
);
let mut fenced = String::from("```\n");
fenced.push_str(&"a".repeat(MAX_FRAGMENT_BYTES + 1));
fenced.push_str("\n```\n");
let err = segment_transcript(&fenced, &policy()).expect_err("oversized fence");
assert!(
matches!(err, MemoryError::ContextOverLimit(_)),
"expected ContextOverLimit, got {err:?}"
);
}
#[test]
fn resplit_jsonl_content_override_children_get_distinct_nonoverlapping_ranges() {
let big_content = "a".repeat((MAX_FRAGMENT_BYTES * 2) + 100);
let line = serde_json::json!({"role": "user", "content": big_content}).to_string();
let mut text = line;
text.push('\n');
let mut jsonl_policy = policy();
jsonl_policy.format = SegmentFormat::Jsonl;
let outcome = segment_transcript(&text, &jsonl_policy).expect("segments");
assert!(outcome.segments.len() > 1, "{outcome:?}");
for segment in &outcome.segments {
assert!(
segment.fragment.content.len() <= MAX_FRAGMENT_BYTES,
"child of {} bytes exceeds the cap",
segment.fragment.content.len()
);
}
let mut ranges: Vec<(usize, usize)> = outcome
.segments
.iter()
.map(|s| (s.byte_start, s.byte_end))
.collect();
ranges.sort_unstable();
let mut cursor = 0_usize;
for (start, end) in ranges {
assert_eq!(start, cursor, "gap or overlap at byte {cursor}");
assert!(start <= end, "inverted range {start}..{end}");
cursor = end;
}
assert_eq!(cursor, text.len(), "children must partition the whole line");
}
#[test]
fn code_fence_becomes_atomic_code_segment() {
let text = "User: run this\n```rust\nfn main() {}\n```\nUser: thanks\n";
let outcome = segment_transcript(text, &policy()).expect("segments");
let code_segments: Vec<_> = outcome
.segments
.iter()
.filter(|s| s.kind == SegmentKind::Code)
.collect();
assert_eq!(code_segments.len(), 1);
assert_eq!(code_segments[0].fragment.kind.as_deref(), Some("code"));
assert!(code_segments[0].fragment.content.contains("fn main()"));
}
#[test]
fn log_run_with_volatile_prefixes_becomes_log_segment() {
let mut text = String::from("User: what happened?\n");
for i in 0..8 {
writeln!(text, "2026-07-18T10:00:0{i}Z request handled")
.expect("write to String never fails");
}
let outcome = segment_transcript(&text, &policy()).expect("segments");
let log_segments: Vec<_> = outcome
.segments
.iter()
.filter(|s| s.kind == SegmentKind::Log)
.collect();
assert_eq!(log_segments.len(), 1, "{outcome:?}");
assert_eq!(log_segments[0].fragment.kind.as_deref(), Some("log"));
}
#[test]
fn repeated_lines_run_becomes_log_segment() {
let mut text = String::from("User: watch this\n");
for _ in 0..8 {
text.push_str("connection retry failed\n");
}
let outcome = segment_transcript(&text, &policy()).expect("segments");
let log_segments: Vec<_> = outcome
.segments
.iter()
.filter(|s| s.kind == SegmentKind::Log)
.collect();
assert_eq!(log_segments.len(), 1, "{outcome:?}");
}
#[test]
fn system_turn_gets_cache_metadata() {
let text = "System: be terse.\nUser: hello\n";
let outcome = segment_transcript(text, &policy()).expect("segments");
let system_segment = outcome
.segments
.iter()
.find(|s| s.turn == 0)
.expect("first turn segment");
let metadata = system_segment.fragment.metadata.as_ref().expect("metadata");
assert_eq!(metadata.get("cache"), Some(&Value::Bool(true)));
let other_segment = outcome
.segments
.iter()
.find(|s| s.turn == 1)
.expect("second turn segment");
let other_metadata = other_segment.fragment.metadata.as_ref().expect("metadata");
assert_eq!(other_metadata.get("cache"), None);
}
#[test]
fn tiny_segments_merge_within_turn_same_kind() {
let text = "User: two blocks\n```\na\n```\n```\nb\n```\n";
let mut merge_policy = policy();
merge_policy.min_segment_bytes = 4096;
let outcome = segment_transcript(text, &merge_policy).expect("segments");
let code_segments: Vec<_> = outcome
.segments
.iter()
.filter(|s| s.kind == SegmentKind::Code)
.collect();
assert_eq!(code_segments.len(), 1, "{outcome:?}");
assert!(code_segments[0].fragment.content.contains('a'));
assert!(code_segments[0].fragment.content.contains('b'));
assert!(outcome.merged_segments > 0);
}
#[test]
fn segmentation_twice_is_byte_identical() {
let mut text =
String::from("System: be terse\nUser: run it\n```rust\nfn f() {}\n```\nAssistant: watch\n");
for i in 0..8 {
writeln!(text, "2026-07-18T10:00:0{i}Z tick").expect("write to String never fails");
}
let first = segment_transcript(&text, &policy()).expect("first segmentation");
let second = segment_transcript(&text, &policy()).expect("second segmentation");
assert_eq!(first.segments.len(), second.segments.len());
for (a, b) in first.segments.iter().zip(second.segments.iter()) {
assert_eq!(a.turn, b.turn);
assert_eq!(a.role, b.role);
assert_eq!(a.kind, b.kind);
assert_eq!(a.byte_start, b.byte_start);
assert_eq!(a.byte_end, b.byte_end);
assert_eq!(a.fragment.content, b.fragment.content);
}
assert_eq!(first.format_detected, second.format_detected);
assert_eq!(first.merged_segments, second.merged_segments);
}
#[test]
fn segment_ranges_cover_transcript_exactly() {
let mut text =
String::from("System: be terse\nUser: run it\n```rust\nfn f() {}\n```\nAssistant: watch\n");
for i in 0..8 {
writeln!(text, "2026-07-18T10:00:0{i}Z tick").expect("write to String never fails");
}
let outcome = segment_transcript(&text, &policy()).expect("segments");
let mut ranges: Vec<(usize, usize)> = outcome
.segments
.iter()
.map(|s| (s.byte_start, s.byte_end))
.collect();
ranges.sort_unstable();
let mut cursor = 0_usize;
for (start, end) in ranges {
assert_eq!(start, cursor, "gap or overlap at byte {cursor}");
cursor = end;
}
assert_eq!(cursor, text.len());
}
#[test]
fn over_max_fragments_errors_with_actionable_message() {
let mut text = String::new();
for i in 0..=MAX_FRAGMENTS {
writeln!(text, "User: turn {i}").expect("write to String never fails");
}
let mut tight_policy = policy();
tight_policy.min_segment_bytes = 0;
let err = segment_transcript(&text, &tight_policy).expect_err("over the fragment cap");
match err {
MemoryError::ContextOverLimit(msg) => {
assert!(msg.contains("min_segment_bytes"), "{msg}");
}
other => panic!("expected ContextOverLimit, got {other:?}"),
}
}
#[test]
fn oversized_fence_errors() {
let mut text = String::from("```\n");
text.push_str(&"a".repeat(MAX_FRAGMENT_BYTES + 1));
text.push_str("\n```\n");
let err = segment_transcript(&text, &policy()).expect_err("oversized fence");
match err {
MemoryError::ContextOverLimit(msg) => {
assert!(msg.contains("fenced"), "{msg}");
}
other => panic!("expected ContextOverLimit, got {other:?}"),
}
}
#[test]
fn transcript_over_cap_rejected() {
use crate::limits::MAX_TRANSCRIPT_BYTES;
let text = "a".repeat(MAX_TRANSCRIPT_BYTES + 1);
let err = segment_transcript(&text, &policy()).expect_err("over the transcript cap");
match err {
MemoryError::ContextOverLimit(msg) => {
assert!(msg.contains(&MAX_TRANSCRIPT_BYTES.to_string()), "{msg}");
}
other => panic!("expected ContextOverLimit, got {other:?}"),
}
}
#[test]
fn oversized_log_run_is_resplit_not_left_over_the_cap() {
let mut text = String::from("User: watch this\n");
let line_count = (MAX_FRAGMENT_BYTES / 30) + 100;
for i in 0..line_count {
writeln!(text, "2026-07-18T10:00:00Z tick {i}").expect("write to String never fails");
}
assert!(
text.len() > MAX_FRAGMENT_BYTES,
"test setup must exceed the cap"
);
let outcome = segment_transcript(&text, &policy()).expect("must segment, never error");
let log_segments: Vec<_> = outcome
.segments
.iter()
.filter(|s| s.kind == SegmentKind::Log)
.collect();
assert!(log_segments.len() > 1, "{outcome:?}");
for segment in &log_segments {
assert!(
segment.fragment.content.len() <= MAX_FRAGMENT_BYTES,
"log segment of {} bytes exceeds the cap of {MAX_FRAGMENT_BYTES} bytes",
segment.fragment.content.len()
);
}
let mut ranges: Vec<(usize, usize)> = outcome
.segments
.iter()
.map(|s| (s.byte_start, s.byte_end))
.collect();
ranges.sort_unstable();
let mut cursor = 0_usize;
for (start, end) in ranges {
assert_eq!(start, cursor, "gap or overlap at byte {cursor}");
cursor = end;
}
assert_eq!(cursor, text.len());
}
#[test]
fn merge_never_recombines_a_resplit_body_over_the_fragment_cap() {
let big_paragraph = "a".repeat(MAX_FRAGMENT_BYTES - 5);
let text = format!("User: {big_paragraph}\n\ntiny tail\n");
let outcome = segment_transcript(&text, &policy()).expect("segments");
let body_segments: Vec<_> = outcome
.segments
.iter()
.filter(|s| s.kind == SegmentKind::Body)
.collect();
assert!(body_segments.len() >= 2, "{outcome:?}");
for segment in &body_segments {
assert!(
segment.fragment.content.len() <= MAX_FRAGMENT_BYTES,
"body segment of {} bytes exceeds the cap of {MAX_FRAGMENT_BYTES} bytes",
segment.fragment.content.len()
);
}
}
#[test]
fn merge_never_recombines_adjacent_fences_over_the_fragment_cap() {
let near_cap_body = "b".repeat(MAX_FRAGMENT_BYTES - 14);
let text = format!("User: two blocks\n```\na\n```\n```\n{near_cap_body}\n```\n");
let outcome = segment_transcript(&text, &policy()).expect("segments");
let code_segments: Vec<_> = outcome
.segments
.iter()
.filter(|s| s.kind == SegmentKind::Code)
.collect();
assert_eq!(code_segments.len(), 2, "{outcome:?}");
for segment in &code_segments {
assert!(
segment.fragment.content.len() <= MAX_FRAGMENT_BYTES,
"code segment of {} bytes exceeds the cap of {MAX_FRAGMENT_BYTES} bytes",
segment.fragment.content.len()
);
}
}
#[test]
fn jsonl_tolerates_a_blank_line_between_turns() {
let text = "{\"role\":\"system\",\"content\":\"be terse\"}\n\n{\"role\":\"user\",\"content\":\"hi\"}\n";
let outcome = segment_transcript(text, &policy()).expect("segments");
assert_eq!(outcome.format_detected, SegmentFormat::Jsonl, "{outcome:?}");
assert_eq!(outcome.segments.len(), 2, "{outcome:?}");
assert_eq!(outcome.segments[0].turn, 0);
assert_eq!(outcome.segments[0].role, Some("system".to_owned()));
assert_eq!(outcome.segments[1].turn, 1);
assert_eq!(outcome.segments[1].role, Some("user".to_owned()));
let mut ranges: Vec<(usize, usize)> = outcome
.segments
.iter()
.map(|s| (s.byte_start, s.byte_end))
.collect();
ranges.sort_unstable();
let mut cursor = 0_usize;
for (start, end) in ranges {
assert_eq!(start, cursor, "gap or overlap at byte {cursor}");
cursor = end;
}
assert_eq!(cursor, text.len());
}