use diff_match_patch; use std::collections::HashMap; use core::char; pub fn diff_rebuildtexts( diffs: Vec) -> Vec { let mut text1: String = "".to_string(); let mut text2: String = "".to_string(); for x in 0..diffs.len() { if diffs[x].operation != 1 { text1 += diffs[x].text.as_str(); } if diffs[x].operation != -1 { text2 += diffs[x].text.as_str(); } } vec![text1, text2] } #[test] pub fn test_diff_common_prefix() { let mut dmp = diff_match_patch::Dmp::new(); assert_eq!(0, dmp.diff_common_prefix(&("abc".to_string().chars().collect()), &("xyz".to_string().chars().collect()))); assert_eq!(4, dmp.diff_common_prefix(&("1234abcdef".to_string().chars().collect()), &("1234xyz".to_string().chars().collect()))); assert_eq!(4, dmp.diff_common_prefix(&("1234".to_string().chars().collect()), &("1234xyz".to_string().chars().collect()))); } #[test] pub fn test_diff_common_suffix() { let mut dmp = diff_match_patch::Dmp::new(); assert_eq!(0, dmp.diff_common_suffix(&("abc".to_string().chars().collect()), &("xyz".to_string().chars().collect()))); assert_eq!(4, dmp.diff_common_suffix(&("abcdef1234".to_string().chars().collect()), &("xyz1234".to_string().chars().collect()))); assert_eq!(4, dmp.diff_common_suffix(&("1234".to_string().chars().collect()), &("xyz1234".to_string().chars().collect()))); } #[test] pub fn test_diff_common_overlap() { let mut dmp = diff_match_patch::Dmp::new(); assert_eq!(0, dmp.diff_common_overlap(&("".to_string().chars().collect()), &("abcd".to_string().chars().collect()))); assert_eq!(3, dmp.diff_common_overlap(&("abc".to_string().chars().collect()), &("abcd".to_string().chars().collect()))); assert_eq!(0, dmp.diff_common_overlap(&("123456".to_string().chars().collect()), &("abcd".to_string().chars().collect()))); assert_eq!(3, dmp.diff_common_overlap(&("123456xxx".to_string().chars().collect()), &("xxxabcd".to_string().chars().collect()))); } #[test] pub fn test_diff_half_match() { let mut dmp = diff_match_patch::Dmp::new(); let temp: Vec = vec![]; assert_eq!(temp, dmp.diff_half_match(&("1234567890".to_string().chars().collect()), &("abcdef".to_string().chars().collect()))); assert_eq!(temp, dmp.diff_half_match(&("12345".to_string().chars().collect()), &("23".to_string().chars().collect()))); assert_eq!(dmp.split_by_char("12,90,a,z,345678", ','), dmp.diff_half_match(&("1234567890".to_string().chars().collect()), &("a345678z".to_string().chars().collect()))); assert_eq!(dmp.split_by_char("a,z,12,90,345678", ','), dmp.diff_half_match(&("a345678z".to_string().chars().collect()), &("1234567890".to_string().chars().collect()))); assert_eq!(dmp.split_by_char("abc,z,1234,0,56789", ','), dmp.diff_half_match(&("abc56789z".to_string().chars().collect()), &("1234567890".to_string().chars().collect()))); assert_eq!(dmp.split_by_char("a,xyz,1,7890,23456", ','), dmp.diff_half_match(&("a23456xyz".to_string().chars().collect()), &("1234567890".to_string().chars().collect()))); assert_eq!(dmp.split_by_char("12123,123121,a,z,1234123451234", ','), dmp.diff_half_match(&("121231234123451234123121".to_string().chars().collect()), &("a1234123451234z".to_string().chars().collect()))); assert_eq!(dmp.split_by_char(",-=-=-=-=-=,x,,x-=-=-=-=-=-=-=", ','), dmp.diff_half_match(&("x-=-=-=-=-=-=-=-=-=-=-=-=".to_string().chars().collect()), &("xx-=-=-=-=-=-=-=".to_string().chars().collect()))); assert_eq!(dmp.split_by_char("-=-=-=-=-=,,,y,-=-=-=-=-=-=-=y", ','), dmp.diff_half_match(&("-=-=-=-=-=-=-=-=-=-=-=-=y".to_string().chars().collect()), &("-=-=-=-=-=-=-=yy".to_string().chars().collect()))); assert_eq!(dmp.split_by_char("qHillo,w,x,Hulloy,HelloHe", ','), dmp.diff_half_match(&("qHilloHelloHew".to_string().chars().collect()), &("xHelloHeHulloy".to_string().chars().collect()))); } #[test] pub fn test_diff_lines_tochars() { let mut dmp = diff_match_patch::Dmp::new(); assert_eq!(("\x01\x02\x01".to_string(), "\x02\x01\x02".to_string(), vec!["".to_string(), "alpha\n".to_string(), "beta\n".to_string()]), dmp.diff_lines_tochars(&("alpha\nbeta\nalpha\n".to_string().chars().collect()), &("beta\nalpha\nbeta\n".to_string().chars().collect()))); assert_eq!(("".to_string(), "\x01\x02\x03\x03".to_string(), vec!["".to_string(), "alpha\r\n".to_string(), "beta\r\n".to_string(), "\r\n".to_string()]), dmp.diff_lines_tochars(&("".to_string().chars().collect()), &("alpha\r\nbeta\r\n\r\n\r\n".to_string().chars().collect()))); assert_eq!(("\x01".to_string(), "\x02".to_string(), vec!["".to_string(), "a".to_string(), "b".to_string()]), dmp.diff_lines_tochars(&("a".to_string().chars().collect()), &("b".to_string().chars().collect()))); let n: u32 = 300; let mut line_list: Vec = vec![]; let mut char_list: Vec = vec![]; for i in 1..n+1{ line_list.push(i.to_string() + "\n"); match char::from_u32(i) { Some(ch) => { char_list.push(ch); }, None => {} } } let chars: String = char_list.into_iter().collect(); assert_eq!(n as usize, line_list.len()); let lines = line_list.join(""); let lines_vec: Vec = lines.chars().collect(); assert_eq!(n as usize, chars.chars().count()); line_list.insert(0, "".to_string()); assert_eq!((chars, "".to_string(), line_list), dmp.diff_lines_tochars(&lines_vec, &vec![])) } #[test] pub fn test_diff_words_tochars() { let mut dmp = diff_match_patch::Dmp::new(); assert_eq!(("\x01\x02\x03\x02\x01".to_string(), "\x03\x02\x01\x02\x03".to_string(), vec!["".to_string(), "alpha".to_string(), " ".to_string(), "beta".to_string()]), dmp.diff_words_tochars(&"alpha beta alpha".to_string(), &"beta alpha beta".to_string()) ); assert_eq!(("\x01\x02".to_string(), "\x03\x02\x01".to_string(), vec!["".to_string(), "alpha".to_string(), "\n".to_string(), "beta".to_string()]), dmp.diff_words_tochars(&"alpha\n".to_string(), &"beta\nalpha".to_string()) ); let old_string = "betty bought some butter ".to_string(); let new_string = "betty sought some butter".to_string(); let mut diff_arr = vec![ diff_match_patch::Diff::new(0, "betty ".to_string()), diff_match_patch::Diff::new(-1, "b".to_string()), diff_match_patch::Diff::new(1, "s".to_string()), diff_match_patch::Diff::new(0, "ought some butter".to_string()), diff_match_patch::Diff::new(-1, " ".to_string()) ]; println!("{:?}", diff_arr); assert_eq!(diff_arr, dmp.diff_main(&old_string, &new_string, true)); diff_arr = vec![ diff_match_patch::Diff::new(0, "betty ".to_string()), diff_match_patch::Diff::new(-1, "bought".to_string()), diff_match_patch::Diff::new(1, "sought".to_string()), diff_match_patch::Diff::new(0, " some butter".to_string()), diff_match_patch::Diff::new(-1, " ".to_string()) ]; let (chars1, chars2, hash_arr) = dmp.diff_words_tochars(&old_string, &new_string); let mut res_diffs = dmp.diff_main(&chars1, &chars2, true); dmp.diff_chars_tolines(&mut res_diffs, &hash_arr); println!("{:?}",&res_diffs); assert_eq!(diff_arr, res_diffs); } #[test] pub fn test_diff_chars_tolines() { let mut dmp = diff_match_patch::Dmp::new(); let mut diffs = vec![diff_match_patch::Diff::new(0, "\x01\x02\x01".to_string()), diff_match_patch::Diff::new(1, "\x02\x01\x02".to_string())]; dmp.diff_chars_tolines(&mut diffs, &vec!["".to_string(), "alpha\n".to_string(), "beta\n".to_string()]); assert_eq!(vec![diff_match_patch::Diff::new(0, "alpha\nbeta\nalpha\n".to_string()), diff_match_patch::Diff::new(1, "beta\nalpha\nbeta\n".to_string())], diffs); let n: u32 = 30; let mut line_list: Vec = vec![]; let mut char_list: Vec = vec![]; for i in 1..n + 1 { line_list.push(i.to_string() + "\n"); match char::from_u32(i) { Some(ch) => { char_list.push(ch); } None => { } } } let chars: String = char_list.into_iter().collect(); assert_eq!(n as usize, line_list.len()); let lines = line_list.join(""); assert_eq!(n as usize, chars.chars().count()); line_list.insert(0, "".to_string()); let mut diffs = vec![diff_match_patch::Diff::new(-1, chars)]; dmp.diff_chars_tolines(&mut diffs, &line_list); assert_eq!(diffs, vec![diff_match_patch::Diff::new(-1, lines)]); // line_list = vec![]; // for i in 1..1115000 + 1 { // line_list.push(i.to_string() + "\n"); // } // chars = line_list.join(""); // let mut temp: Vec = chars.chars().collect(); // let (temp1, temp2, results) = dmp.diff_lines_tochars(&temp, &vec![]); // diffs = vec![diff_match_patch::Diff::new(1, results[0].clone())]; // dmp.diff_chars_tolines(&mut diffs, results[2].clone().chars().collect())); // assert_eq!(chars, diffs[0].text); } #[test] pub fn test_diff_cleanup_merge() { let mut dmp = diff_match_patch::Dmp::new(); let mut diffs: Vec = vec![]; let temp: Vec = vec![]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(temp, diffs); // No change case. diffs = vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "b".to_string()), diff_match_patch::Diff::new(1, "c".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "b".to_string()), diff_match_patch::Diff::new(1, "c".to_string())], diffs); // Merge equalities. diffs = vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(0, "b".to_string()), diff_match_patch::Diff::new(0, "c".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "abc".to_string())], diffs); // Merge deletions. diffs = vec![diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(-1, "b".to_string()), diff_match_patch::Diff::new(-1, "c".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abc".to_string())], diffs); // Merge insertions. diffs = vec![diff_match_patch::Diff::new(1, "a".to_string()), diff_match_patch::Diff::new(1, "b".to_string()), diff_match_patch::Diff::new(1, "c".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(1, "abc".to_string())], diffs); // Merge interweave. diffs = vec![diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(1, "b".to_string()), diff_match_patch::Diff::new(-1, "c".to_string()), diff_match_patch::Diff::new(1, "d".to_string()), diff_match_patch::Diff::new(0, "e".to_string()), diff_match_patch::Diff::new(0, "f".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "ac".to_string()), diff_match_patch::Diff::new(1, "bd".to_string()), diff_match_patch::Diff::new(0, "ef".to_string())], diffs); // Prefix and suffix detection. diffs = vec![diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(1, "abc".to_string()), diff_match_patch::Diff::new(-1, "dc".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "d".to_string()), diff_match_patch::Diff::new(1, "b".to_string()), diff_match_patch::Diff::new(0, "c".to_string())], diffs); // Prefix and suffix detection with equalities. diffs = vec![diff_match_patch::Diff::new(0, "x".to_string()), diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(1, "abc".to_string()), diff_match_patch::Diff::new(-1, "dc".to_string()), diff_match_patch::Diff::new(0, "y".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "xa".to_string()), diff_match_patch::Diff::new(-1, "d".to_string()), diff_match_patch::Diff::new(1, "b".to_string()), diff_match_patch::Diff::new(0, "cy".to_string())], diffs); // Slide edit left. diffs = vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(1, "ba".to_string()), diff_match_patch::Diff::new(0, "c".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(1, "ab".to_string()), diff_match_patch::Diff::new(0, "ac".to_string())], diffs); // Slide edit right. diffs = vec![diff_match_patch::Diff::new(0, "c".to_string()), diff_match_patch::Diff::new(1, "ab".to_string()), diff_match_patch::Diff::new(0, "a".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "ca".to_string()), diff_match_patch::Diff::new(1, "ba".to_string())], diffs); // # Slide edit left recursive. diffs = vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "b".to_string()), diff_match_patch::Diff::new(0, "c".to_string()), diff_match_patch::Diff::new(-1, "ac".to_string()), diff_match_patch::Diff::new(0, "x".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(0, "acx".to_string())], diffs); // # Slide edit right recursive. diffs = vec![diff_match_patch::Diff::new(0, "x".to_string()), diff_match_patch::Diff::new(-1, "ca".to_string()), diff_match_patch::Diff::new(0, "c".to_string()), diff_match_patch::Diff::new(-1, "b".to_string()), diff_match_patch::Diff::new(0, "a".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "xca".to_string()), diff_match_patch::Diff::new(-1, "cba".to_string())], diffs); // # Empty merge. diffs = vec![diff_match_patch::Diff::new(-1, "b".to_string()), diff_match_patch::Diff::new(1, "ab".to_string()), diff_match_patch::Diff::new(0, "c".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(1, "a".to_string()), diff_match_patch::Diff::new(0, "bc".to_string())], diffs); // # Empty equality. diffs = vec![diff_match_patch::Diff::new(0, "".to_string()), diff_match_patch::Diff::new(1, "a".to_string()), diff_match_patch::Diff::new(0, "b".to_string())]; dmp.diff_cleanup_merge(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(1, "a".to_string()), diff_match_patch::Diff::new(0, "b".to_string())], diffs); } #[test] pub fn test_diff_cleanup_semantic_lossless() { // Slide diffs to match logical boundaries. // Null case. let mut dmp = diff_match_patch::Dmp::new(); let mut diffs: Vec = vec![]; let temp: Vec = vec![]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(temp, diffs); // Blank lines. diffs = vec![diff_match_patch::Diff::new(0, "AAA\r\n\r\nBBB".to_string()), diff_match_patch::Diff::new(1, "\r\nDDD\r\n\r\nBBB".to_string()), diff_match_patch::Diff::new(0, "\r\nEEE".to_string())]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "AAA\r\n\r\n".to_string()), diff_match_patch::Diff::new(1, "BBB\r\nDDD\r\n\r\n".to_string()), diff_match_patch::Diff::new(0, "BBB\r\nEEE".to_string())], diffs); // # Line boundaries. diffs = vec![diff_match_patch::Diff::new(0, "AAA\r\nBBB".to_string()), diff_match_patch::Diff::new(1, " DDD\r\nBBB".to_string()), diff_match_patch::Diff::new(0, " EEE".to_string())]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "AAA\r\n".to_string()), diff_match_patch::Diff::new(1, "BBB DDD\r\n".to_string()), diff_match_patch::Diff::new(0, "BBB EEE".to_string())], diffs); // # Word boundaries. diffs = vec![diff_match_patch::Diff::new(0, "The c".to_string()), diff_match_patch::Diff::new(1, "ow and the c".to_string()), diff_match_patch::Diff::new(0, "at.".to_string())]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "The ".to_string()), diff_match_patch::Diff::new(1, "cow and the ".to_string()), diff_match_patch::Diff::new(0, "cat.".to_string())], diffs); // # Alphanumeric boundaries. diffs = vec![diff_match_patch::Diff::new(0, "The-c".to_string()), diff_match_patch::Diff::new(1, "ow-and-the-c".to_string()), diff_match_patch::Diff::new(0, "at.".to_string())]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "The-".to_string()), diff_match_patch::Diff::new(1, "cow-and-the-".to_string()), diff_match_patch::Diff::new(0, "cat.".to_string())], diffs); // # Hitting the start. diffs = vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(0, "ax".to_string())]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(0, "aax".to_string())], diffs); // # Hitting the end. diffs = vec![diff_match_patch::Diff::new(0, "xa".to_string()), diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(0, "a".to_string())]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "xaa".to_string()), diff_match_patch::Diff::new(-1, "a".to_string())], diffs); // # Sentence boundaries. diffs = vec![diff_match_patch::Diff::new(0, "The xxx. The ".to_string()), diff_match_patch::Diff::new(1, "zzz. The ".to_string()), diff_match_patch::Diff::new(0, "yyy.".to_string())]; dmp.diff_cleanup_semantic_lossless(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "The xxx.".to_string()), diff_match_patch::Diff::new(1, " The zzz.".to_string()), diff_match_patch::Diff::new(0, " The yyy.".to_string())], diffs); } #[test] pub fn test_diff_cleanup_semantic() { let mut dmp = diff_match_patch::Dmp::new(); // Null case. let mut diffs: Vec = vec![]; let temp: Vec = vec![]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(diffs, temp); // No elimination #1. diffs = vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(1, "cd".to_string()), diff_match_patch::Diff::new(0, "c12".to_string()), diff_match_patch::Diff::new(-1, "e".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(1, "cd".to_string()), diff_match_patch::Diff::new(0, "c12".to_string()), diff_match_patch::Diff::new(-1, "e".to_string())], diffs); // No elimination #2. diffs = vec![diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(1, "ABC".to_string()), diff_match_patch::Diff::new(0, "1234".to_string()), diff_match_patch::Diff::new(-1, "wxyz".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(1, "ABC".to_string()), diff_match_patch::Diff::new(0, "1234".to_string()), diff_match_patch::Diff::new(-1, "wxyz".to_string())], diffs); // Simple elimination. diffs = vec![diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(0, "b".to_string()), diff_match_patch::Diff::new(-1, "c".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(1, "b".to_string())], diffs); // Backpass elimination. diffs = vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(0, "cd".to_string()), diff_match_patch::Diff::new(-1, "e".to_string()), diff_match_patch::Diff::new(0, "f".to_string()), diff_match_patch::Diff::new(1, "g".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abcdef".to_string()), diff_match_patch::Diff::new(1, "cdfg".to_string())], diffs); // Multiple eliminations. diffs = vec![diff_match_patch::Diff::new(1, "1".to_string()), diff_match_patch::Diff::new(0, "A".to_string()), diff_match_patch::Diff::new(-1, "B".to_string()), diff_match_patch::Diff::new(1, "2".to_string()), diff_match_patch::Diff::new(0, "_".to_string()), diff_match_patch::Diff::new(1, "1".to_string()), diff_match_patch::Diff::new(0, "A".to_string()), diff_match_patch::Diff::new(-1, "B".to_string()), diff_match_patch::Diff::new(1, "2".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "AB_AB".to_string()), diff_match_patch::Diff::new(1, "1A2_1A2".to_string())], diffs); // Word boundaries. diffs = vec![diff_match_patch::Diff::new(0, "The c".to_string()), diff_match_patch::Diff::new(-1, "ow and the c".to_string()), diff_match_patch::Diff::new(0, "at.".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(0, "The ".to_string()), diff_match_patch::Diff::new(-1, "cow and the ".to_string()), diff_match_patch::Diff::new(0, "cat.".to_string())], diffs); // No overlap elimination. diffs = vec![diff_match_patch::Diff::new(-1, "abcxx".to_string()), diff_match_patch::Diff::new(1, "xxdef".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abcxx".to_string()), diff_match_patch::Diff::new(1, "xxdef".to_string())], diffs); // Overlap elimination. diffs = vec![diff_match_patch::Diff::new(-1, "abcxxx".to_string()), diff_match_patch::Diff::new(1, "xxxdef".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(0, "xxx".to_string()), diff_match_patch::Diff::new(1, "def".to_string())], diffs); // Reverse overlap elimination. diffs = vec![diff_match_patch::Diff::new(-1, "xxxabc".to_string()), diff_match_patch::Diff::new(1, "defxxx".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(1, "def".to_string()), diff_match_patch::Diff::new(0, "xxx".to_string()), diff_match_patch::Diff::new(-1, "abc".to_string())], diffs); // Two overlap eliminations. diffs = vec![diff_match_patch::Diff::new(-1, "abcd1212".to_string()), diff_match_patch::Diff::new(1, "1212efghi".to_string()), diff_match_patch::Diff::new(0, "----".to_string()), diff_match_patch::Diff::new(-1, "A3".to_string()), diff_match_patch::Diff::new(1, "3BC".to_string())]; dmp.diff_cleanup_semantic(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abcd".to_string()), diff_match_patch::Diff::new(0, "1212".to_string()), diff_match_patch::Diff::new(1, "efghi".to_string()), diff_match_patch::Diff::new(0, "----".to_string()), diff_match_patch::Diff::new(-1, "A".to_string()), diff_match_patch::Diff::new(0, "3".to_string()), diff_match_patch::Diff::new(1, "BC".to_string())], diffs); } #[test] pub fn test_diff_cleanup_efficiency() { let mut dmp = diff_match_patch::Dmp::new(); dmp.edit_cost = 4; // Null case. let mut diffs: Vec = vec![]; let temp: Vec = vec![]; dmp.diff_cleanup_efficiency(&mut diffs); assert_eq!(temp, diffs); // No elimination. diffs = vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(1, "12".to_string()), diff_match_patch::Diff::new(0, "wxyz".to_string()), diff_match_patch::Diff::new(-1, "cd".to_string()), diff_match_patch::Diff::new(1, "34".to_string())]; dmp.diff_cleanup_efficiency(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(1, "12".to_string()), diff_match_patch::Diff::new(0, "wxyz".to_string()), diff_match_patch::Diff::new(-1, "cd".to_string()), diff_match_patch::Diff::new(1, "34".to_string())], diffs); // Four-edit elimination. diffs = vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(1, "12".to_string()), diff_match_patch::Diff::new(0, "xyz".to_string()), diff_match_patch::Diff::new(-1, "cd".to_string()), diff_match_patch::Diff::new(1, "34".to_string())]; dmp.diff_cleanup_efficiency(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abxyzcd".to_string()), diff_match_patch::Diff::new(1, "12xyz34".to_string())], diffs); // Three-edit elimination. diffs = vec![diff_match_patch::Diff::new(1, "12".to_string()), diff_match_patch::Diff::new(0, "x".to_string()), diff_match_patch::Diff::new(-1, "cd".to_string()), diff_match_patch::Diff::new(1, "34".to_string())]; dmp.diff_cleanup_efficiency(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "xcd".to_string()), diff_match_patch::Diff::new(1, "12x34".to_string())], diffs); // Backpass elimination. diffs = vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(1, "12".to_string()), diff_match_patch::Diff::new(0, "xy".to_string()), diff_match_patch::Diff::new(1, "34".to_string()), diff_match_patch::Diff::new(0, "z".to_string()), diff_match_patch::Diff::new(-1, "cd".to_string()), diff_match_patch::Diff::new(1, "56".to_string())]; dmp.diff_cleanup_efficiency(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abxyzcd".to_string()), diff_match_patch::Diff::new(1, "12xy34z56".to_string())], diffs); // High cost elimination. dmp.edit_cost = 5; diffs = vec![diff_match_patch::Diff::new(-1, "ab".to_string()), diff_match_patch::Diff::new(1, "12".to_string()), diff_match_patch::Diff::new(0, "wxyz".to_string()), diff_match_patch::Diff::new(-1, "cd".to_string()), diff_match_patch::Diff::new(1, "34".to_string())]; dmp.diff_cleanup_efficiency(&mut diffs); assert_eq!(vec![diff_match_patch::Diff::new(-1, "abwxyzcd".to_string()), diff_match_patch::Diff::new(1, "12wxyz34".to_string())], diffs); } #[test] pub fn test_diff_text() { let mut dmp = diff_match_patch::Dmp::new(); let mut diffs: Vec = vec![diff_match_patch::Diff::new(0, "jump".to_string()), diff_match_patch::Diff::new(-1, "s".to_string()), diff_match_patch::Diff::new(1, "ed".to_string()), diff_match_patch::Diff::new(0, " over ".to_string()), diff_match_patch::Diff::new(-1, "the".to_string()), diff_match_patch::Diff::new(1, "a".to_string()), diff_match_patch::Diff::new(0, " lazy".to_string())]; assert_eq!("jumps over the lazy".to_string(), dmp.diff_text1(&mut diffs)); assert_eq!("jumped over a lazy".to_string(), dmp.diff_text2(&mut diffs)); } #[test] pub fn test_diff_delta() { let mut dmp = diff_match_patch::Dmp::new(); let mut diffs = vec![diff_match_patch::Diff::new(0, "jump".to_string()), diff_match_patch::Diff::new(-1, "s".to_string()), diff_match_patch::Diff::new(1, "ed".to_string()), diff_match_patch::Diff::new(0, " over ".to_string()), diff_match_patch::Diff::new(-1, "the".to_string()), diff_match_patch::Diff::new(1, "a".to_string()), diff_match_patch::Diff::new(0, " lazy".to_string()), diff_match_patch::Diff::new(1, "old dog".to_string())]; let mut text1 = dmp.diff_text1(&mut diffs); assert_eq!("jumps over the lazy".to_string(), text1); let mut delta = dmp.diff_todelta(&mut diffs); assert_eq!("=4\t-1\t+ed\t=6\t-3\t+a\t=5\t+old dog".to_string(), delta); // Convert delta string into a diff. assert_eq!(diffs, dmp.diff_from_delta(&text1, &delta)); // # Generates error (19 != 20). // try: // self.dmp.diff_fromDelta(text1 + "x", delta) // self.assertFalse(True) // except ValueError: // # Exception expected. // pass // # Generates error (19 != 18). // try: // self.dmp.diff_fromDelta(text1[1:], delta) // self.assertFalse(True) // except ValueError: // # Exception expected. // pass // # Generates error (%c3%xy invalid Unicode). // # Note: Python 3 can decode this. // #try: // # self.dmp.diff_fromDelta("", "+%c3xy") // # self.assertFalse(True) // #except ValueError: // # # Exception expected. // # pass // Test deltas with special characters. diffs = vec![diff_match_patch::Diff::new(0, "\u{0680} \x00 \t %".to_string()), diff_match_patch::Diff::new(-1, "\u{0681} \x01 \n ^".to_string()), diff_match_patch::Diff::new(1, "\u{0682} \x02 \\ |".to_string())]; text1 = dmp.diff_text1(&mut diffs); assert_eq!("\u{0680} \x00 \t %\u{0681} \x01 \n ^".to_string(), text1); delta = dmp.diff_todelta(&mut diffs); assert_eq!("=7\t-7\t+%DA%82 %02 %5C %7C".to_string(), delta); // Convert delta string into a diff. assert_eq!(diffs, dmp.diff_from_delta(&text1, &delta)); // Verify pool of unchanged characters. diffs = vec![diff_match_patch::Diff::new(1, "A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , # ".to_string())]; let text2 = dmp.diff_text2(&mut diffs); assert_eq!("A-Z a-z 0-9 - _ . ! ~ * \' ( ) ; / ? : @ & = + $ , # ".to_string(), text2); delta = dmp.diff_todelta(&mut diffs); assert_eq!("+A-Z a-z 0-9 - _ . ! ~ * \' ( ) ; / ? : @ & = + $ , # ".to_string(), delta); // Convert delta string into a diff. assert_eq!(diffs, dmp.diff_from_delta(&("".to_string()), &delta)); // 160 kb string. let mut a = "abcdefghij".to_string(); for _i in 0..14 { a += a.clone().as_str(); } diffs = vec![diff_match_patch::Diff::new(1, a.clone())]; delta = dmp.diff_todelta(&mut diffs); assert_eq!('+'.to_string() + a.as_str(), delta); // Convert delta string into a diff. assert_eq!(diffs, dmp.diff_from_delta(&"".to_string(), &delta)); } #[test] pub fn test_diff_xindex() { } #[test] pub fn test_diff_levenshtein() { let mut dmp = diff_match_patch::Dmp::new(); assert_eq!(4, dmp.diff_levenshtein(&mut vec![diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(1, "1234".to_string()), diff_match_patch::Diff::new(0, "xyz".to_string())])); // Levenshtein with leading equality. assert_eq!(4, dmp.diff_levenshtein(&mut vec![diff_match_patch::Diff::new(0, "xyz".to_string()), diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(1, "1234".to_string())])); // # Levenshtein with middle equality. assert_eq!(7, dmp.diff_levenshtein(&mut vec![diff_match_patch::Diff::new(-1, "abc".to_string()), diff_match_patch::Diff::new(0, "xyz".to_string()), diff_match_patch::Diff::new(1, "1234".to_string())])); } #[test] pub fn test_diff_bisect() { let mut dmp = diff_match_patch::Dmp::new(); let a = "cat".to_string(); let b = "map".to_string(); assert_eq!(vec![diff_match_patch::Diff::new(-1, "c".to_string()), diff_match_patch::Diff::new(1, "m".to_string()), diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "t".to_string()), diff_match_patch::Diff::new(1, "p".to_string())] , dmp.diff_bisect(&a.chars().collect(), &b.chars().collect())); } #[test] pub fn test_diff_main() { let mut new_dmp = diff_match_patch::Dmp::new(); let temp: Vec = Vec::new(); assert_eq!(temp, new_dmp.diff_main("", "", true)); assert_eq!(vec![diff_match_patch::Diff::new(0, "abc".to_string())], new_dmp.diff_main("abc", "abc", true)); assert_eq!(vec![diff_match_patch::Diff::new(0, "ab".to_string()), diff_match_patch::Diff::new(1, "123".to_string()), diff_match_patch::Diff::new(0, "c".to_string())], new_dmp.diff_main("abc", "ab123c", true)); assert_eq!(vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "123".to_string()), diff_match_patch::Diff::new(0, "bc".to_string())], new_dmp.diff_main("a123bc", "abc", true)); assert_eq!(vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(1, "123".to_string()), diff_match_patch::Diff::new(0, "b".to_string()), diff_match_patch::Diff::new(1, "456".to_string()), diff_match_patch::Diff::new(0, "c".to_string())], new_dmp.diff_main("abc", "a123b456c", true)); assert_eq!(vec![diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "123".to_string()), diff_match_patch::Diff::new(0, "b".to_string()), diff_match_patch::Diff::new(-1, "456".to_string()), diff_match_patch::Diff::new(0, "c".to_string())], new_dmp.diff_main("a123b456c", "abc", true)); assert_eq!(vec![diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(1, "b".to_string())], new_dmp.diff_main("a", "b", true)); assert_eq!(vec![diff_match_patch::Diff::new(-1, "Apple".to_string()), diff_match_patch::Diff::new(1, "Banana".to_string()), diff_match_patch::Diff::new(0, "s are a".to_string()), diff_match_patch::Diff::new(1, "lso".to_string()), diff_match_patch::Diff::new(0, " fruit.".to_string())], new_dmp.diff_main("Apples are a fruit.", "Bananas are also fruit.", true)); assert_eq!(vec![diff_match_patch::Diff::new(-1, "a".to_string()), diff_match_patch::Diff::new(1, "\u{0680}".to_string()), diff_match_patch::Diff::new(0, "x".to_string()), diff_match_patch::Diff::new(-1, "\t".to_string()), diff_match_patch::Diff::new(1, "\n".to_string())], new_dmp.diff_main("ax\t", "\u{0680}x\n", false)); assert_eq!(vec![diff_match_patch::Diff::new(-1, "1".to_string()), diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "y".to_string()), diff_match_patch::Diff::new(0, "b".to_string()), diff_match_patch::Diff::new(-1, "2".to_string()), diff_match_patch::Diff::new(1, "xab".to_string())], new_dmp.diff_main("1ayb2", "abxab", false)); assert_eq!(vec![diff_match_patch::Diff::new(1, "xaxcx".to_string()), diff_match_patch::Diff::new(0, "abc".to_string()), diff_match_patch::Diff::new(-1, "y".to_string())], new_dmp.diff_main("abcy", "xaxcxabc", false)); assert_eq!(vec![diff_match_patch::Diff::new(-1, "ABCD".to_string()), diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(-1, "=".to_string()), diff_match_patch::Diff::new(1, "-".to_string()), diff_match_patch::Diff::new(0, "bcd".to_string()), diff_match_patch::Diff::new(-1, "=".to_string()), diff_match_patch::Diff::new(1, "-".to_string()), diff_match_patch::Diff::new(0, "efghijklmnopqrs".to_string()), diff_match_patch::Diff::new(-1, "EFGHIJKLMNOefg".to_string())], new_dmp.diff_main("ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg", "a-bcd-efghijklmnopqrs", false)); assert_eq!(vec![diff_match_patch::Diff::new(1, " ".to_string()), diff_match_patch::Diff::new(0, "a".to_string()), diff_match_patch::Diff::new(1, "nd".to_string()), diff_match_patch::Diff::new(0, " [[Pennsylvania]]".to_string()), diff_match_patch::Diff::new(-1, " and [[New".to_string())], new_dmp.diff_main("a [[Pennsylvania]] and [[New", " and [[Pennsylvania]]", false)); // let mut a: String = "`Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.\n".to_string(); // let mut b: String = "I am the very model of a modern major general,\nI've information vegetable, animal, and mineral,\nI know the kings of England, and I quote the fights historical,\nFrom Marathon to Waterloo, in order categorical.\n".to_string(); // for x in 0..10 { // a += a.clone().as_str(); // b += b.clone().as_str(); // } let mut a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n"; let mut b = "abcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\n"; assert_eq!(new_dmp.diff_main(a, b, true), new_dmp.diff_main(a, b, false)); a = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; b = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"; assert_eq!(new_dmp.diff_main(a, b, true), new_dmp.diff_main(a, b, false)); a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n"; b = "abcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n"; let texts_linemode = diff_rebuildtexts(new_dmp.diff_main(a, b, true)); let texts_textmode = diff_rebuildtexts(new_dmp.diff_main(a, b, false)); assert_eq!(texts_linemode, texts_textmode); } #[test] pub fn test_match_apphabet() { let mut dmp = diff_match_patch::Dmp::new(); let mut s: HashMap = HashMap::new(); s.insert('a', 4); s.insert('b', 2); s.insert('c', 1); assert_eq!(s, dmp.match_alphabet(&("abc".chars().collect()))); s.insert('a', 37); s.insert('b', 18); s.insert('c', 8); assert_eq!(s, dmp.match_alphabet(&("abcaba".chars().collect()))); } #[test] pub fn test_match_bitap() { let mut dmp = diff_match_patch::Dmp::new(); dmp.match_distance = 100; dmp.match_threshold = 0.5; assert_eq!(5, dmp.match_bitap(&("abcdefghijk".chars().collect()), &("fgh".chars().collect()), 5)); assert_eq!(5, dmp.match_bitap(&("abcdefghijk".chars().collect()), &("fgh".chars().collect()), 0)); // Fuzzy matches. assert_eq!(4, dmp.match_bitap(&("abcdefghijk".chars().collect()), &("efxhi".chars().collect()), 0)); assert_eq!(2, dmp.match_bitap(&("abcdefghijk".chars().collect()), &("cdefxyhijk".chars().collect()), 5)); assert_eq!(-1, dmp.match_bitap(&("abcdefghijk".chars().collect()), &("bxy".chars().collect()), 1)); // Overflow. assert_eq!(2, dmp.match_bitap(&("123456789xx0".chars().collect()), &("3456789x0".chars().collect()), 2)); assert_eq!(0, dmp.match_bitap(&("abcdef".chars().collect()), &("xxabc".chars().collect()), 4)); assert_eq!(3, dmp.match_bitap(&("abcdef".chars().collect()), &("defyy".chars().collect()), 4)); assert_eq!(0, dmp.match_bitap(&("abcdef".chars().collect()), &("xabcdefy".chars().collect()), 0)); // Threshold test. dmp.match_threshold = 0.3; assert_eq!(-1, dmp.match_bitap(&("abcdefghijk".chars().collect()), &("efxyhi".chars().collect()), 1)); dmp.match_threshold = 0.0; assert_eq!(1, dmp.match_bitap(&("abcdefghijk".chars().collect()), &("bcdef".chars().collect()), 1)); dmp.match_threshold = 0.5; // Multiple select. assert_eq!(0, dmp.match_bitap(&("abcdexyzabcde".chars().collect()), &("abccde".chars().collect()), 3)); assert_eq!(8, dmp.match_bitap(&("abcdexyzabcde".chars().collect()), &("abccde".chars().collect()), 5)); // Distance test. dmp.match_distance = 10; assert_eq!(-1, dmp.match_bitap(&("abcdefghijklmnopqrstuvwxyz".chars().collect()), &("abcdefg".chars().collect()), 24)); assert_eq!(0, dmp.match_bitap(&("abcdefghijklmnopqrstuvwxyz".chars().collect()), &("abcdxxefg".chars().collect()), 1)); dmp.match_distance = 1000; assert_eq!(0, dmp.match_bitap(&("abcdefghijklmnopqrstuvwxyz".chars().collect()), &("abcdefg".chars().collect()), 24)); } #[test] pub fn test_match_main() { let mut dmp = diff_match_patch::Dmp::new(); assert_eq!(0, dmp.match_main("abcdef", "abcdef", 1000)); assert_eq!(-1, dmp.match_main("", "abcdef", 1)); assert_eq!(3, dmp.match_main("abcdef", "", 3)); assert_eq!(3, dmp.match_main("abcdef", "de", 3)); assert_eq!(3, dmp.match_main("abcdef", "defy", 4)); assert_eq!(0, dmp.match_main("abcdef", "abcdefy", 0)); dmp.match_threshold = 0.7; assert_eq!(4, dmp.match_main("I am the very model of a modern major general.", " that berry ", 5)); dmp.match_threshold = 0.5; } #[test] pub fn test_patch_obj() { let mut patch = diff_match_patch::Patch::new(vec![], 0, 0, 0, 0); patch.start1 = 20; patch.start2 = 21; patch.length1 = 18; patch.length2 = 17; patch.diffs = vec![diff_match_patch::Diff::new(0, "jump".to_string()), diff_match_patch::Diff::new(-1, "s".to_string()), diff_match_patch::Diff::new(1, "ed".to_string()), diff_match_patch::Diff::new(0, " over ".to_string()), diff_match_patch::Diff::new(-1, "the".to_string()), diff_match_patch::Diff::new(1, "a".to_string()), diff_match_patch::Diff::new(0, "\nlaz".to_string())]; assert_eq!("@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n %0Alaz\n".to_string(), patch.to_string()); } #[test] pub fn test_patch_from_text() { let mut dmp = diff_match_patch::Dmp::new(); let diffs: Vec = vec![]; assert_eq!(diffs, dmp.patch_from_text("".to_string())); let strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n %0Alaz\n".to_string(); assert_eq!(strp, dmp.patch_from_text(strp.clone())[0].to_string()); assert_eq!("@@ -1,1 +1,1 @@\n-a\n+b\n".to_string(), dmp.patch_from_text("@@ -1 +1 @@\n-a\n+b\n".to_string())[0].to_string()); assert_eq!("@@ -1,3 +0,0 @@\n-abc\n".to_string(), dmp.patch_from_text("@@ -1,3 +0,0 @@\n-abc\n".to_string())[0].to_string()); assert_eq!("@@ -0,0 +1,3 @@\n+abc\n".to_string(), dmp.patch_from_text("@@ -0,0 +1,3 @@\n+abc\n".to_string())[0].to_string()); } #[test] pub fn test_patch_to_text() { let mut dmp = diff_match_patch::Dmp::new(); let mut strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n laz\n".to_string(); let mut p = dmp.patch_from_text(strp.clone()); assert_eq!(strp, dmp.patch_to_text(&mut p)); strp = "@@ -1,9 +1,9 @@\n-f\n+F\n oo+fooba\n@@ -7,8 +7,8 @@\n obar\n-,\n+.\n tes\n".to_string(); p = dmp.patch_from_text(strp.clone()); assert_eq!(strp, dmp.patch_to_text(&mut p)); } #[test] pub fn test_patch_add_context() { let mut dmp = diff_match_patch::Dmp::new(); dmp.patch_margin = 4; let mut p = dmp.patch_from_text("@@ -21,4 +21,10 @@\n-jump\n+somersault\n".to_string())[0].clone(); dmp.patch_add_context(&mut p, &mut ("The quick brown fox jumps over the lazy dog.".chars().collect())); assert_eq!(p.to_string(), "@@ -17,12 +17,18 @@\n fox \n-jump\n+somersault\n s ov\n".to_string()); // Same, but not enough trailing context. p = dmp.patch_from_text("@@ -21,4 +21,10 @@\n-jump\n+somersault\n".to_string())[0].clone(); dmp.patch_add_context(&mut p, &mut ("The quick brown fox jumps.".chars().collect())); assert_eq!(p.to_string(), "@@ -17,10 +17,16 @@\n fox \n-jump\n+somersault\n s.\n".to_string()); // Same, but not enough leading context. let mut p = dmp.patch_from_text("@@ -3 +3,2 @@\n-e\n+at\n".to_string())[0].clone(); dmp.patch_add_context(&mut p, &mut ("The quick brown fox jumps.".chars().collect())); assert_eq!(p.to_string(), "@@ -1,7 +1,8 @@\n Th\n-e\n+at\n qui\n".to_string()); // # Same, but with ambiguity. p = dmp.patch_from_text("@@ -3 +3,2 @@\n-e\n+at\n".to_string())[0].clone(); dmp.patch_add_context(&mut p, &mut ("The quick brown fox jumps. The quick brown fox crashes.".chars().collect())); assert_eq!(p.to_string(), "@@ -1,27 +1,28 @@\n Th\n-e\n+at\n quick brown fox jumps. \n".to_string()); } #[test] pub fn test_patch_make() { let mut dmp = diff_match_patch::Dmp::new(); // Null case. let mut patches = dmp.patch_make1("", ""); assert_eq!("".to_string(), dmp.patch_to_text(&mut patches)); let text1 = "The quick brown fox jumps over the lazy dog."; let text2 = "That quick brown fox jumped over a lazy dog."; // Text2+Text1 inputs. let mut expected_patch = "@@ -1,8 +1,7 @@\n Th\n-at\n+e\n qui\n@@ -21,17 +21,18 @@\n jump\n-ed\n+s\n over \n-a\n+the\n laz\n".to_string(); // The second patch must be "-21,17 +21,18", not "-22,17 +21,18" due to rolling context. patches = dmp.patch_make1(text2, text1); assert_eq!(expected_patch, dmp.patch_to_text(&mut patches)); // Text1+Text2 inputs. expected_patch = "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n quick b\n@@ -22,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n laz\n".to_string(); patches = dmp.patch_make1(text1, text2); assert_eq!(expected_patch, dmp.patch_to_text(&mut patches)); // Diff input. let mut diffs = dmp.diff_main(text1, text2, false); patches = dmp.patch_make2(&mut diffs); assert_eq!(expected_patch, dmp.patch_to_text(&mut patches)); // Text1+Diff inputs. patches = dmp.patch_make4(text1, &mut diffs); assert_eq!(expected_patch, dmp.patch_to_text(&mut patches)); // Text1+Text2+Diff inputs (deprecated). patches = dmp.patch_make3(text1, text2, &mut diffs); assert_eq!(expected_patch, dmp.patch_to_text(&mut patches)); // Character encoding. patches = dmp.patch_make1("`1234567890-=[]\\;',./", "~!@#$%^&*()_+{}|:\"<>?"); assert_eq!("@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n".to_string(), dmp.patch_to_text(&mut patches)); // Character decoding. diffs = vec![diff_match_patch::Diff::new(-1, "`1234567890-=[]\\;',./".to_string()), diff_match_patch::Diff::new(1, "~!@#$%^&*()_+{}|:\"<>?".to_string())]; assert_eq!(diffs, dmp.patch_from_text("@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n".to_string())[0].diffs); // Long string with repeats. let mut text1 = "".to_string(); for _x in 0..100 { text1 += "abcdef"; } let text2 = text1.clone() + "123"; expected_patch = "@@ -573,28 +573,31 @@\n cdefabcdefabcdefabcdefabcdef\n+123\n".to_string(); patches = dmp.patch_make1(text1.as_str(), text2.as_str()); assert_eq!(expected_patch, dmp.patch_to_text(&mut patches)); } #[test] pub fn test_patch_splitmax() { let mut dmp = diff_match_patch::Dmp::new(); // Assumes that Match_MaxBits is 31. dmp.match_maxbits = 32; let mut patches = dmp.patch_make1("abcdefghijklmnopqrstuvwxyz01234567890", "XabXcdXefXghXijXklXmnXopXqrXstXuvXwxXyzX01X23X45X67X89X0"); dmp.patch_splitmax(&mut patches); assert_eq!("@@ -1,32 +1,46 @@\n+X\n ab\n+X\n cd\n+X\n ef\n+X\n gh\n+X\n ij\n+X\n kl\n+X\n mn\n+X\n op\n+X\n qr\n+X\n st\n+X\n uv\n+X\n wx\n+X\n yz\n+X\n 012345\n@@ -25,13 +39,18 @@\n zX01\n+X\n 23\n+X\n 45\n+X\n 67\n+X\n 89\n+X\n 0\n".to_string(), dmp.patch_to_text(&mut patches)); patches = dmp.patch_make1("abcdef1234567890123456789012345678901234567890123456789012345678901234567890uvwxyz", "abcdefuvwxyz"); let old_totext = dmp.patch_to_text(&mut patches); dmp.patch_splitmax(&mut patches); assert_eq!(old_totext, dmp.patch_to_text(&mut patches)); patches = dmp.patch_make1("1234567890123456789012345678901234567890123456789012345678901234567890", "abc"); dmp.patch_splitmax(&mut patches); assert_eq!("@@ -1,32 +1,4 @@\n-1234567890123456789012345678\n 9012\n@@ -29,32 +1,4 @@\n-9012345678901234567890123456\n 7890\n@@ -57,14 +1,3 @@\n-78901234567890\n+abc\n", dmp.patch_to_text(&mut patches)); patches = dmp.patch_make1("abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1", "abcdefghij , h : 1 , t : 1 abcdefghij , h : 1 , t : 1 abcdefghij , h : 0 , t : 1"); dmp.patch_splitmax(&mut patches); assert_eq!("@@ -2,32 +2,32 @@\n bcdefghij , h : \n-0\n+1\n , t : 1 abcdef\n@@ -29,32 +29,32 @@\n bcdefghij , h : \n-0\n+1\n , t : 1 abcdef\n".to_string(), dmp.patch_to_text(&mut patches)); } #[test] pub fn test_patch_add_padding() { // Both edges full. let mut dmp = diff_match_patch::Dmp::new(); let mut patches = dmp.patch_make1("", "test"); assert_eq!("@@ -0,0 +1,4 @@\n+test\n".to_string(), dmp.patch_to_text(&mut patches)); dmp.patch_add_padding(&mut patches); assert_eq!("@@ -1,8 +1,12 @@\n %01%02%03%04\n+test\n %01%02%03%04\n".to_string(), dmp.patch_to_text(&mut patches)); // Both edges partial. patches = dmp.patch_make1("XY", "XtestY"); assert_eq!("@@ -1,2 +1,6 @@\n X\n+test\n Y\n".to_string(), dmp.patch_to_text(&mut patches)); dmp.patch_add_padding(&mut patches); assert_eq!("@@ -2,8 +2,12 @@\n %02%03%04X\n+test\n Y%01%02%03\n".to_string(), dmp.patch_to_text(&mut patches)); // Both edges none. patches = dmp.patch_make1("XXXXYYYY", "XXXXtestYYYY"); assert_eq!("@@ -1,8 +1,12 @@\n XXXX\n+test\n YYYY\n".to_string(), dmp.patch_to_text(&mut patches)); dmp.patch_add_padding(&mut patches); assert_eq!("@@ -5,8 +5,12 @@\n XXXX\n+test\n YYYY\n".to_string(), dmp.patch_to_text(&mut patches)); } #[test] pub fn test_patch_apply() { let mut dmp = diff_match_patch::Dmp::new(); dmp.match_distance = 1000; dmp.match_threshold = 0.5; dmp.patch_delete_threshold = 0.5; // Null case. let mut patches = dmp.patch_make1("", ""); let mut results = dmp.patch_apply(&mut patches, "Hello world."); assert_eq!(("Hello world.".chars().collect(), vec![]), results); // Exact match. patches = dmp.patch_make1("The quick brown fox jumps over the lazy dog.", "That quick brown fox jumped over a lazy dog."); results = dmp.patch_apply(&mut patches, "The quick brown fox jumps over the lazy dog."); assert_eq!(("That quick brown fox jumped over a lazy dog.".chars().collect(), vec![true, true]), results); // Partial match. results = dmp.patch_apply(&mut patches, "The quick red rabbit jumps over the tired tiger."); assert_eq!(("That quick red rabbit jumped over a tired tiger.".chars().collect(), vec![true, true]), results); // Failed match. results = dmp.patch_apply(&mut patches, "I am the very model of a modern major general."); assert_eq!(("I am the very model of a modern major general.".chars().collect(), vec![false, false]), results); // Big delete, small change. patches = dmp.patch_make1("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy"); results = dmp.patch_apply(&mut patches, "x123456789012345678901234567890-----++++++++++-----123456789012345678901234567890y"); assert_eq!(("xabcy".chars().collect(), vec![true, true]), results); // Big delete, big change 1. patches = dmp.patch_make1("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy"); results = dmp.patch_apply(&mut patches, "x12345678901234567890---------------++++++++++---------------12345678901234567890y"); assert_eq!(("xabc12345678901234567890---------------++++++++++---------------12345678901234567890y".chars().collect(), vec![false, true]), results); // Big delete, big change 2. dmp.patch_delete_threshold = 0.6; patches = dmp.patch_make1("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy"); results = dmp.patch_apply(&mut patches, "x12345678901234567890---------------++++++++++---------------12345678901234567890y"); assert_eq!(("xabcy".chars().collect(), vec![true, true]), results); dmp.patch_delete_threshold = 0.5; // Compensate for failed patch. dmp.match_threshold = 0.0; dmp.match_distance = 0; patches = dmp.patch_make1("abcdefghijklmnopqrstuvwxyz--------------------1234567890", "abcXXXXXXXXXXdefghijklmnopqrstuvwxyz--------------------1234567YYYYYYYYYY890"); results = dmp.patch_apply(&mut patches, "ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567890"); assert_eq!(("ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567YYYYYYYYYY890".chars().collect(), vec![false, true]), results); dmp.match_threshold = 0.5; dmp.match_distance = 1000; // No side effects. patches = dmp.patch_make1("", "test"); let mut patchstr = dmp.patch_to_text(&mut patches); results = dmp.patch_apply(&mut patches, ""); assert_eq!(patchstr, dmp.patch_to_text(&mut patches)); // No side effects with major delete. patches = dmp.patch_make1("The quick brown fox jumps over the lazy dog.", "Woof"); patchstr = dmp.patch_to_text(&mut patches); dmp.patch_apply(&mut patches, "The quick brown fox jumps over the lazy dog."); assert_eq!(patchstr, dmp.patch_to_text(&mut patches)); // Edge exact match. patches = dmp.patch_make1("", "test"); dmp.patch_apply(&mut patches, ""); assert_eq!(("test".chars().collect(), vec![true]), results); // Near edge exact match. patches = dmp.patch_make1("XY", "XtestY"); results = dmp.patch_apply(&mut patches, "XY"); assert_eq!(("XtestY".chars().collect(), vec![true]), results); // Edge partial match. patches = dmp.patch_make1("y", "y123"); results = dmp.patch_apply(&mut patches, "x"); assert_eq!(("x123".chars().collect(), vec![true]), results); }