1use similar::TextDiff;
5
6pub fn unified_diff(old: &str, new: &str, context: usize) -> String {
9 if old == new {
10 return String::new();
11 }
12 TextDiff::from_lines(old, new)
13 .unified_diff()
14 .context_radius(context)
15 .header("a", "b")
16 .to_string()
17}
18
19pub fn changed_lines(old: &str, new: &str) -> usize {
22 TextDiff::from_lines(old, new)
23 .iter_all_changes()
24 .filter(|c| c.tag() != similar::ChangeTag::Equal)
25 .count()
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31
32 #[test]
33 fn identical_inputs_produce_no_diff() {
34 assert_eq!(unified_diff("a\nb\n", "a\nb\n", 1), "");
35 assert_eq!(changed_lines("a\nb\n", "a\nb\n"), 0);
36 }
37
38 #[test]
39 fn diff_shows_only_changed_hunk_with_context() {
40 let old = "one\ntwo\nthree\nfour\nfive\n";
41 let new = "one\ntwo\nTHREE\nfour\nfive\n";
42 let d = unified_diff(old, new, 1);
43 assert!(d.contains("-three"));
44 assert!(d.contains("+THREE"));
45 assert!(!d.contains("one"));
47 assert!(!d.contains("five"));
48 }
49
50 #[test]
51 fn changed_lines_counts_inserts_and_deletes() {
52 assert_eq!(changed_lines("a\nb\nc\n", "a\nB\nc\n"), 2);
54 }
55}