use smos_domain::{FactId, MemoryKey, SessionId};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MemoryBlockEntry<'a> {
pub id: &'a FactId,
pub document: &'a str,
}
pub fn build<'a>(
facts: impl IntoIterator<Item = MemoryBlockEntry<'a>>,
session_id: &SessionId,
_memory_key: &MemoryKey,
) -> String {
let mut lines: Vec<String> = Vec::new();
lines.push(format!("<smos-memory session=\"{}\">", session_id.as_str()));
for entry in facts {
lines.push(format!("[{}] {}", entry.id.as_str(), entry.document));
}
lines.push("</smos-memory>".to_string());
lines.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
fn sid() -> SessionId {
SessionId::from_raw("sess_abcdef012345").unwrap()
}
fn key() -> MemoryKey {
MemoryKey::from_raw("origa").unwrap()
}
fn fid(content: &str) -> FactId {
FactId::from_content(content)
}
#[test]
fn empty_facts_emits_open_and_close_tags() {
let block = build([], &sid(), &key());
assert_eq!(
block,
"<smos-memory session=\"sess_abcdef012345\">\n</smos-memory>"
);
}
#[test]
fn each_fact_gets_one_line_with_id_and_document() {
let id1 = fid("first fact");
let id2 = fid("second fact");
let facts = vec![
MemoryBlockEntry {
id: &id1,
document: "First fact text",
},
MemoryBlockEntry {
id: &id2,
document: "Second fact text",
},
];
let block = build(facts, &sid(), &key());
let lines: Vec<&str> = block.lines().collect();
assert_eq!(lines.len(), 4);
assert!(lines[1].starts_with(&format!("[{}]", id1.as_str())));
assert!(lines[1].contains("First fact text"));
assert!(lines[2].starts_with(&format!("[{}]", id2.as_str())));
assert!(lines[2].contains("Second fact text"));
assert_eq!(lines[3], "</smos-memory>");
}
#[test]
fn opening_tag_carries_session_id_attribute() {
let block = build([], &sid(), &key());
assert!(block.starts_with("<smos-memory session=\"sess_abcdef012345\">"));
}
#[test]
fn closing_tag_is_emitted_last() {
let id = fid("x");
let facts = vec![MemoryBlockEntry {
id: &id,
document: "y",
}];
let block = build(facts, &sid(), &key());
assert!(block.ends_with("</smos-memory>"));
}
}