use std::collections::HashMap;
use super::model::{Directive, MAX_COMBINED_CHARS};
pub fn build_directive_context(all:&HashMap<String, Directive>, active:&[String]) -> String {
if active.is_empty() {
return String::new();
}
let names:Vec<&str> = active.iter().map(|s| s.as_str()).collect();
let mut out = format!("[directives: {}]\n", names.join(", "));
for name in active {
if let Some(d) = all.get(name) {
out.push_str(&format!("{}:\n", d.name));
for line in d.content.lines() {
let line = line.trim_start_matches('#').trim();
if !line.is_empty() {
out.push_str(" ");
out.push_str(line);
out.push('\n');
}
}
}
}
if out.chars().count() > MAX_COMBINED_CHARS {
let trunc:String = out.chars().take(MAX_COMBINED_CHARS).collect();
out = format!("{}…\n", trunc);
}
out
}
#[cfg(test)]
mod tests {
use super::*;
fn active(name:&str, content:&str) -> (HashMap<String, Directive>, Vec<String>) {
let mut all = HashMap::new();
all.insert(
name.to_string(),
Directive { name:name.to_string(), content:content.to_string() },
);
let active = vec![name.to_string()];
(all, active)
}
#[test]
fn test_combined_char_cap_counts_chars_not_bytes() {
let (all, active) = active("focus", &"\u{2014}".repeat(3000));
let out = build_directive_context(&all, &active);
assert!(
out.chars().count() <= MAX_COMBINED_CHARS,
"char-count output must stay within the char cap"
);
assert!(out.len() > MAX_COMBINED_CHARS, "byte length exceeds the cap");
assert!(!out.contains('…'), "within-cap content must not be truncated");
assert!(out.ends_with("\u{2014}\n"));
}
#[test]
fn test_combined_char_cap_truncates_over_cap_content() {
let (all, active) = active("focus", &"-".repeat(4100));
let out = build_directive_context(&all, &active);
assert!(out.ends_with("…\n"), "over-cap content must be truncated");
let content_part = out.trim_end_matches("…\n");
assert_eq!(content_part.chars().count(), MAX_COMBINED_CHARS);
assert_eq!(out.chars().count(), MAX_COMBINED_CHARS + 2);
}
}