use crate::cleanup::{apply_backtrack, apply_spoken_commands, deterministic_light, guard_accepts, Level};
pub trait Formatter {
fn format(&self, level: Level, text: &str) -> String;
}
pub struct DeterministicFormatter;
impl Formatter for DeterministicFormatter {
fn format(&self, _level: Level, text: &str) -> String {
deterministic_light(text)
}
}
pub fn guarded_format(f: &dyn Formatter, level: Level, raw: &str) -> String {
let pre = apply_backtrack(&apply_spoken_commands(raw));
if level == Level::None {
return pre;
}
let candidate = f.format(level, &pre);
if guard_accepts(&pre, &candidate) {
candidate
} else {
deterministic_light(&pre)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::{Faithful, OverEditing};
#[test]
fn none_level_returns_pre_layer_unchanged() {
assert_eq!(guarded_format(&Faithful, Level::None, "i am not done"), "i am not done");
}
#[test]
fn pre_layer_runs_before_formatting() {
let out = guarded_format(&Faithful, Level::Light, "the answer is yes scratch that the answer is no");
assert!(!out.contains("yes"));
assert!(out.contains("answer is no"));
}
#[test]
fn guard_rejects_a_meaning_substitution_and_falls_back() {
let out = guarded_format(&OverEditing, Level::Light, "i love her");
assert!(!out.contains("hate"));
assert!(out.to_lowercase().contains("love"));
}
#[test]
fn guard_rejects_a_dropped_negation_and_falls_back() {
let out = guarded_format(&OverEditing, Level::Light, "i am not angry");
assert!(out.to_lowercase().contains("not"));
}
#[test]
fn faithful_output_passes_the_guard_unchanged() {
assert_eq!(guarded_format(&Faithful, Level::Light, "um so i keep avoiding it"), "So I keep avoiding it.");
}
#[test]
fn guard_fires_at_medium_too() {
let out = guarded_format(&OverEditing, Level::Medium, "i love her");
assert!(!out.contains("hate"));
assert!(out.to_lowercase().contains("love"));
}
}