#![crate_name = "difference"]
#![doc(html_root_url = "http://docs.rs/difference")]
#![deny(missing_docs)]
#![deny(warnings)]
mod lcs;
mod merge;
mod display;
use lcs::lcs;
use merge::merge;
#[derive(PartialEq, Debug)]
pub enum Difference {
Same(String),
Add(String),
Rem(String),
}
pub struct Changeset {
pub diffs: Vec<Difference>,
pub split: String,
pub distance: i32,
}
impl Changeset {
pub fn new(orig: &str, edit: &str, split: &str) -> Changeset {
let (dist, common) = lcs(orig, edit, split);
Changeset {
diffs: merge(orig, edit, &common, split),
split: split.to_string(),
distance: dist,
}
}
}
#[deprecated(since = "1.0.0", note = "please use `Changeset::new` instead")]
pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec<Difference>) {
let ch = Changeset::new(orig, edit, split);
(ch.distance, ch.diffs)
}
#[macro_export]
macro_rules! assert_diff {
($orig:expr , $edit:expr, $split: expr, $expected: expr) => ({
let orig = $orig;
let edit = $edit;
let changeset = $crate::Changeset::new(orig, edit, &($split));
if changeset.distance != $expected {
println!("{}", changeset);
panic!("assertion failed: edit distance between {:?} and {:?} is {} and not {}, see \
diffset above",
orig,
edit,
changeset.distance,
&($expected))
}
})
}
#[deprecated(since = "1.0.0", note = "`Changeset` now implements the `Display` trait instead")]
pub fn print_diff(orig: &str, edit: &str, split: &str) {
let ch = Changeset::new(orig, edit, split);
println!("{}", ch);
}
#[test]
fn test_diff() {
let text1 = "Roses are red, violets are blue,\n\
I wrote this library,\n\
just for you.\n\
(It's true).";
let text2 = "Roses are red, violets are blue,\n\
I wrote this documentation,\n\
just for you.\n\
(It's quite true).";
let changeset = Changeset::new(text1, text2, "\n");
assert_eq!(changeset.distance, 4);
assert_eq!(
changeset.diffs,
vec![
Difference::Same("Roses are red, violets are blue,".to_string()),
Difference::Rem("I wrote this library,".to_string()),
Difference::Add("I wrote this documentation,".to_string()),
Difference::Same("just for you.".to_string()),
Difference::Rem("(It's true).".to_string()),
Difference::Add("(It's quite true).".to_string()),
]
);
}
#[test]
fn test_diff_brief() {
let text1 = "Hello\nworld";
let text2 = "Ola\nmundo";
let changeset = Changeset::new(text1, text2, "\n");
assert_eq!(
changeset.diffs,
vec![
Difference::Rem("Hello\nworld".to_string()),
Difference::Add("Ola\nmundo".to_string()),
]
);
}
#[test]
fn test_diff_smaller_line_count_on_left() {
let text1 = "Hello\nworld";
let text2 = "Ola\nworld\nHow is it\ngoing?";
let changeset = Changeset::new(text1, text2, "\n");
assert_eq!(
changeset.diffs,
vec![
Difference::Rem("Hello".to_string()),
Difference::Add("Ola".to_string()),
Difference::Same("world".to_string()),
Difference::Add("How is it\ngoing?".to_string()),
]
);
}
#[test]
fn test_diff_smaller_line_count_on_right() {
let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
let text2 = "Ola\nworld";
let changeset = Changeset::new(text1, text2, "\n");
assert_eq!(
changeset.diffs,
vec![
Difference::Rem("Hello".to_string()),
Difference::Add("Ola".to_string()),
Difference::Same("world".to_string()),
Difference::Rem("What a \nbeautiful\nday!".to_string()),
]
);
}
#[test]
fn test_diff_similar_text_with_smaller_line_count_on_right() {
let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
let text2 = "Hello\nwoRLd";
let changeset = Changeset::new(text1, text2, "\n");
assert_eq!(
changeset.diffs,
vec![
Difference::Same("Hello".to_string()),
Difference::Rem("world\nWhat a \nbeautiful\nday!".to_string()),
Difference::Add("woRLd".to_string()),
]
);
}
#[test]
fn test_diff_similar_text_with_similar_line_count() {
let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
let text2 = "Hello\nwoRLd\nbeautiful";
let changeset = Changeset::new(text1, text2, "\n");
assert_eq!(
changeset.diffs,
vec![
Difference::Same("Hello".to_string()),
Difference::Rem("world\nWhat a ".to_string()),
Difference::Add("woRLd".to_string()),
Difference::Same("beautiful".to_string()),
Difference::Rem("day!".to_string()),
]
);
}
#[test]
#[should_panic]
fn test_assert_diff_panic() {
let text1 = "Roses are red, violets are blue,\n\
I wrote this library,\n\
just for you.\n\
(It's true).";
let text2 = "Roses are red, violets are blue,\n\
I wrote this documentation,\n\
just for you.\n\
(It's quite true).";
assert_diff!(text1, text2, "\n'", 0);
}
#[test]
fn test_assert_diff() {
let text1 = "Roses are red, violets are blue";
let text2 = "Roses are green, violets are blue";
assert_diff!(text1, text2, " ", 2);
}