Skip to main content

dotm/
diff.rs

1use similar::TextDiff;
2
3pub fn format_unified_diff(original: &str, modified: &str, label_a: &str, label_b: &str) -> String {
4    let diff = TextDiff::from_lines(original, modified);
5    let mut output = String::new();
6
7    output.push_str(&format!("--- {}\n", label_a));
8    output.push_str(&format!("+++ {}\n", label_b));
9
10    for hunk in diff.unified_diff().context_radius(3).iter_hunks() {
11        output.push_str(&format!("{}", hunk));
12    }
13
14    output
15}
16
17#[cfg(test)]
18mod tests {
19    use super::*;
20
21    #[test]
22    fn format_diff_shows_unified_output() {
23        let original = "line1\nline2\nline3\n";
24        let modified = "line1\nmodified_line2\nline3\nnew_line4\n";
25        let output = format_unified_diff(
26            original,
27            modified,
28            "deployed: .config/app.conf",
29            "current: .config/app.conf",
30        );
31        assert!(output.contains("--- deployed:"));
32        assert!(output.contains("+++ current:"));
33        assert!(output.contains("-line2"));
34        assert!(output.contains("+modified_line2"));
35        assert!(output.contains("+new_line4"));
36    }
37
38    #[test]
39    fn no_diff_produces_empty_output() {
40        let content = "same\ncontent\n";
41        let output = format_unified_diff(content, content, "a", "b");
42        // Headers are still present but no hunks
43        assert!(output.starts_with("--- a\n+++ b\n"));
44        // No @@ hunk headers
45        assert!(!output.contains("@@"));
46    }
47}