pub(in crate::frontend) fn suffix_delta(
current: Option<&str>,
emitted: &mut String,
) -> Option<String> {
let current = current?;
let delta = current.strip_prefix(emitted.as_str())?;
if delta.is_empty() {
return None;
}
emitted.push_str(delta);
Some(delta.to_string())
}
#[cfg(test)]
pub(in crate::frontend) struct RecordedFixture {
pub(in crate::frontend) snapshots: Vec<Vec<serde_json::Value>>,
pub(in crate::frontend) final_call: Vec<serde_json::Value>,
}
#[cfg(test)]
pub(in crate::frontend) fn recorded_fixture(recorded: &str, fixture: &str) -> RecordedFixture {
let mut snapshots = Vec::new();
let mut final_call = None;
for line in recorded.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let mut parts = line.splitn(3, ' ');
let (name, marker, payload) = (
parts.next().expect("fixture name"),
parts.next().expect("prefix marker"),
parts.next().expect("tool_calls json"),
);
if name != fixture {
continue;
}
let calls = serde_json::from_str::<Vec<serde_json::Value>>(payload).expect("fixture json");
if marker == "final" {
final_call = Some(calls);
} else {
snapshots.push(calls);
}
}
assert!(!snapshots.is_empty(), "no snapshots for fixture {fixture}");
RecordedFixture {
snapshots,
final_call: final_call.expect("fixture final parse"),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn suffix_delta_reports_only_the_new_suffix() {
let mut emitted = String::from("abc");
assert_eq!(
suffix_delta(Some("abcdef"), &mut emitted).as_deref(),
Some("def")
);
assert_eq!(emitted, "abcdef");
assert!(suffix_delta(Some("abcdef"), &mut emitted).is_none());
assert!(suffix_delta(Some("xyz"), &mut emitted).is_none());
assert!(suffix_delta(None, &mut emitted).is_none());
}
}