my fork of dmp
Updated benchmarks and added some compatibility tests
Anubhab Bandyopadhyay 2024-08-28
parent 1ee0c37 · commit 369bf55
-rw-r--r--src/dmp.rs182
-rw-r--r--src/html.rs28
-rw-r--r--tests/compat.rs92
3 files changed, 205 insertions, 97 deletions
diff --git a/src/dmp.rs b/src/dmp.rs
index 8be5a4e..c677a36 100644
--- a/src/dmp.rs
+++ b/src/dmp.rs
@@ -2615,31 +2615,31 @@ impl DiffMatchPatch {
}
/// Takes a diff array and returns a pretty HTML sequence. This function is mainly intended as an example from which to write ones own display functions.
- ///
+ ///
/// # Example
/// ```
/// # use diff_match_patch_rs::{DiffMatchPatch, Error, Efficient, HtmlConfig};
/// # fn main() -> Result<(), Error> {
/// let dmp = DiffMatchPatch::new();
- ///
+ ///
/// let diffs = dmp.diff_main::<Efficient>("The old man and the new house?", "The old man and the old dog!")?;
/// let htmlcfg = HtmlConfig::new();
- ///
+ ///
/// let pretty = dmp.diff_pretty_html(&diffs, &htmlcfg)?;
/// // Should print: "<span>The old man and the </span><del>new house?</del><ins>old dog!</ins>"
/// println!("{pretty}");
- ///
+ ///
/// # Ok(())
/// # }
/// ```
- ///
+ ///
/// Check out [`HtmlConfig`] options for ways to control the generated html.
- ///
+ ///
/// [`HtmlConfig`]: html/struct.HtmlConfig.html
pub fn diff_pretty_html<T: DType>(
&self,
diffs: &[Diff<T>],
- html_cfg: &HtmlConfig
+ html_cfg: &HtmlConfig,
) -> Result<String, crate::errors::Error> {
let mut diffs = diffs.to_vec();
DiffMatchPatch::cleanup_semantic(&mut diffs);
@@ -2653,14 +2653,14 @@ impl DiffMatchPatch {
let txt = match T::to_string(diff.data()) {
Ok(txt) => {
let mut txt = txt
- .replace("&", "&amp;")
- .replace("<", "&lt;")
- .replace(">", "&gt;");
+ .replace("&", "&amp;")
+ .replace("<", "&lt;")
+ .replace(">", "&gt;");
if html_cfg.nltobr() {
txt = txt.replace('\n', "<br>")
}
-
+
txt
}
Err(e) => {
@@ -2675,33 +2675,51 @@ impl DiffMatchPatch {
}
match diff.op() {
- Ops::Insert => Some(
- format!(
- "<{}{}{}>{txt}</{}>",
- html_cfg.insert_tag(),
- if let Some(cl) = html_cfg.insert_class() { format!(" class=\"{cl}\"") } else { String::new() },
- if let Some(st) = html_cfg.insert_style() { format!(" style=\"{st}\"") } else { String::new() },
- html_cfg.insert_tag()
- )
- ),
- Ops::Delete => Some(
- format!(
- "<{}{}{}>{txt}</{}>",
- html_cfg.delete_tag(),
- if let Some(cl) = html_cfg.delete_class() { format!(" class=\"{cl}\"") } else { String::new() },
- if let Some(st) = html_cfg.delete_style() { format!(" style=\"{st}\"") } else { String::new() },
- html_cfg.delete_tag()
- )
- ),
- Ops::Equal => Some(
- format!(
- "<{}{}{}>{txt}</{}>",
- html_cfg.equality_tag(),
- if let Some(cl) = html_cfg.equality_class() { format!(" class=\"{cl}\"") } else { String::new() },
- if let Some(st) = html_cfg.equality_style() { format!(" style=\"{st}\"") } else { String::new() },
- html_cfg.equality_tag()
- )
- ),
+ Ops::Insert => Some(format!(
+ "<{}{}{}>{txt}</{}>",
+ html_cfg.insert_tag(),
+ if let Some(cl) = html_cfg.insert_class() {
+ format!(" class=\"{cl}\"")
+ } else {
+ String::new()
+ },
+ if let Some(st) = html_cfg.insert_style() {
+ format!(" style=\"{st}\"")
+ } else {
+ String::new()
+ },
+ html_cfg.insert_tag()
+ )),
+ Ops::Delete => Some(format!(
+ "<{}{}{}>{txt}</{}>",
+ html_cfg.delete_tag(),
+ if let Some(cl) = html_cfg.delete_class() {
+ format!(" class=\"{cl}\"")
+ } else {
+ String::new()
+ },
+ if let Some(st) = html_cfg.delete_style() {
+ format!(" style=\"{st}\"")
+ } else {
+ String::new()
+ },
+ html_cfg.delete_tag()
+ )),
+ Ops::Equal => Some(format!(
+ "<{}{}{}>{txt}</{}>",
+ html_cfg.equality_tag(),
+ if let Some(cl) = html_cfg.equality_class() {
+ format!(" class=\"{cl}\"")
+ } else {
+ String::new()
+ },
+ if let Some(st) = html_cfg.equality_style() {
+ format!(" style=\"{st}\"")
+ } else {
+ String::new()
+ },
+ html_cfg.equality_tag()
+ )),
}
})
.collect::<Vec<_>>()
@@ -2738,26 +2756,26 @@ impl DiffMatchPatch {
}
/// Given two texts, or an already computed list of differences (`diffs`), return an array of patch objects.
- ///
+ ///
/// # Example
/// ```
/// # use diff_match_patch_rs::{DiffMatchPatch, Error, Efficient, PatchInput};
- ///
+ ///
/// # fn main() -> Result<(), Error> {
/// let dmp = DiffMatchPatch::new();
- ///
+ ///
/// // You can also make patches from the old and new string directly
/// let patches = dmp.patch_make::<Efficient>(PatchInput::new_text_text("Apples are a fruit.", "Bananas are also fruit"))?;
/// let (new_from_old, _) = dmp.patch_apply(&patches, "Apples are a fruit.")?;
/// assert_eq!("Bananas are also fruit", new_from_old);
- ///
+ ///
/// // Or, create some diffs in `Efficient` or `Compact` mode
/// let diffs = dmp.diff_main::<Efficient>("Apples are a fruit.", "Bananas are also fruit")?;
/// // Now, lets convert the diffs to a bunch of patches - you can use an existing set of diffs to create patches
/// let patches = dmp.patch_make(PatchInput::new_diffs(&diffs))?;
/// let (new_from_old, _) = dmp.patch_apply(&patches, "Apples are a fruit.")?;
/// assert_eq!("Bananas are also fruit", new_from_old);
- ///
+ ///
/// // Or, from the source texts and diffs
/// let patches = dmp.patch_make(PatchInput::new_text_diffs("Apples are a fruit.", &diffs))?;
/// let (new_from_old, _) = dmp.patch_apply(&patches, "Apples are a fruit.")?;
@@ -2765,10 +2783,10 @@ impl DiffMatchPatch {
/// # Ok(())
/// # }
/// ```
- ///
+ ///
/// The [`PatchInput::new_text_diffs`] method is preferred, use it if you happen to have that data available, otherwise this function will compute the missing pieces.
- ///
- ///
+ ///
+ ///
pub fn patch_make<T: DType>(
&self,
input: PatchInput<T>,
@@ -2801,32 +2819,32 @@ impl DiffMatchPatch {
}
/// Reduces an array of patch objects to a block of text which looks extremely similar to the standard GNU diff/patch format. This text may be stored or transmitted.
- ///
+ ///
/// # Example
- ///
+ ///
/// ```
/// # use diff_match_patch_rs::{DiffMatchPatch, Error, Compat, PatchInput};
- ///
+ ///
/// # fn main() -> Result<(), Error> {
/// let dmp = DiffMatchPatch::new();
- ///
+ ///
/// // Making patches from source and edited text - both in `Efficient` and `Compat` mode
/// let patches = dmp.patch_make::<Compat>(PatchInput::new_text_text("Apples are fruit!", "Bananas are also fruit!"))?;
/// let patch_to_text = dmp.patch_to_text(&patches);
- ///
+ ///
/// // Prints patches in GNU diff/ patch format
/// // You can use this format for transmission and/ or storage.
/// println!("{patch_to_text}");
- ///
+ ///
/// # Ok(())
/// # }
/// ```
- ///
+ ///
/// Check out the [`diff_to_delta`] and [`diff_from_delta`] methods for a more compact way of representing diffs.
- ///
+ ///
/// [`diff_to_delta`]: ./method.diff_to_delta
/// [`diff_from_delta`]: ./method.diff_from_delta
- ///
+ ///
pub fn patch_to_text<T: DType>(&self, patches: &Patches<T>) -> String {
patches.iter().map(|p| p.to_string()).collect::<String>()
}
@@ -2834,26 +2852,26 @@ impl DiffMatchPatch {
/// Parses a block of text (which was presumably created by the [`patch_to_text`] method) and returns an array of patch objects.
///
/// # Example
- ///
+ ///
/// ```
/// # use diff_match_patch_rs::{DiffMatchPatch, Error, Compat, PatchInput};
- ///
+ ///
/// # fn main() -> Result<(), Error> {
/// let dmp = DiffMatchPatch::new();
- ///
+ ///
/// // Making patches from source and edited text - both in `Efficient` and `Compat` mode
/// let patches = dmp.patch_make::<Compat>(PatchInput::new_text_text("Apples are fruit!", "Bananas are also fruit!"))?;
/// let patch_to_text = dmp.patch_to_text(&patches);
- ///
+ ///
/// // let's create patches back from text
/// let patches_recreated = dmp.patch_from_text::<Compat>(&patch_to_text)?;
- ///
+ ///
/// // Now you can `patch_apply` the `patches_recreated` to your source text
- ///
+ ///
/// # Ok(())
/// # }
/// ```
- ///
+ ///
/// [`patch_to_text`]: ./method.patch_to_text
pub fn patch_from_text<T: DType>(&self, text: &str) -> Result<Patches<T>, Error> {
if text.is_empty() {
@@ -2943,19 +2961,18 @@ impl DiffMatchPatch {
Ok(patches)
}
-
/// Crush the diff into an encoded string which describes the operations required to transform text_old into text_new.
/// E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'.
/// Operations are tab-separated. Inserted text is escaped using %xx notation.
- ///
+ ///
/// # Example
- ///
+ ///
/// ```
/// # use diff_match_patch_rs::{DiffMatchPatch, Error, Compat, PatchInput};
/// # fn main() -> Result<(), Error> {
- ///
+ ///
/// let dmp = DiffMatchPatch::new();
- ///
+ ///
/// // let's create some diffs
/// let diffs = dmp.diff_main::<Compat>("The old house and the new dog!", "The old man and the new dog!")?;
/// // now, you can create a `delta` string which can be used to re-create the diffs
@@ -2963,10 +2980,10 @@ impl DiffMatchPatch {
/// println!("{delta:?}");
/// // You should see something like the following
/// // "=8\t-5\t+man\t=17"
- ///
+ ///
/// // now you can use the `diff_from_delta()` to recover the diffs
/// let diffs_later = dmp.diff_from_delta::<Compat>("The old house and the new dog!", &delta);
- ///
+ ///
/// # Ok(())
/// # }
/// ```
@@ -2999,18 +3016,17 @@ impl DiffMatchPatch {
T::to_string(&data)
}
-
/// Given the original text `old`, and an encoded string which describes the
/// operations required to transform text1 into text2, compute the full diff.
- ///
+ ///
/// # Example
- ///
+ ///
/// ```
/// # use diff_match_patch_rs::{DiffMatchPatch, Error, Compat, PatchInput};
/// # fn main() -> Result<(), Error> {
- ///
+ ///
/// let dmp = DiffMatchPatch::new();
- ///
+ ///
/// // let's create some diffs
/// let diffs = dmp.diff_main::<Compat>("The old house and the new dog!", "The old man and the new dog!")?;
/// // now, you can create a `delta` string which can be used to re-create the diffs
@@ -3018,16 +3034,16 @@ impl DiffMatchPatch {
/// println!("{delta:?}");
/// // You should see something like the following
/// // "=8\t-5\t+man\t=17"
- ///
+ ///
/// // now you can use the `diff_from_delta()` to recover the diffs
/// let diffs_later = dmp.diff_from_delta::<Compat>("The old house and the new dog!", &delta);
/// // Now, you can use these diffs to apply patches to the source text
/// let patches = dmp.patch_make(PatchInput::new_text_diffs("The old house and the new dog!", &diffs))?;
/// let (new_from_old, _) = dmp.patch_apply(&patches, "The old house and the new dog!")?;
- ///
- ///
+ ///
+ ///
/// assert_eq!("The old man and the new dog!", &new_from_old);
- ///
+ ///
/// # Ok(())
/// # }
/// ```
@@ -3099,27 +3115,27 @@ impl DiffMatchPatch {
/// If `delete_threshold` is closer to 0, then the deleted text must match the expected text more closely.
/// If `delete_threshold` is closer to 1, then the deleted text may contain anything.
/// In most use cases `delete_threshold` should just be set to the same value as `match_threshold`. Both values default to `0.5`
- ///
+ ///
/// # Example
/// # Example
/// ```
/// # use diff_match_patch_rs::{DiffMatchPatch, Error, Efficient, PatchInput};
- ///
+ ///
/// # fn main() -> Result<(), Error> {
/// let dmp = DiffMatchPatch::new();
- ///
+ ///
/// // You can also make patches from the old and new string directly
/// let patches = dmp.patch_make::<Efficient>(PatchInput::new_text_text("Apples are a fruit.", "Bananas are also fruit"))?;
/// let (new_from_old, _) = dmp.patch_apply(&patches, "Apples are a fruit.")?;
/// assert_eq!("Bananas are also fruit", new_from_old);
- ///
+ ///
/// // Or, create some diffs in `Efficient` or `Compact` mode
/// let diffs = dmp.diff_main::<Efficient>("Apples are a fruit.", "Bananas are also fruit")?;
/// // Now, lets convert the diffs to a bunch of patches - you can use an existing set of diffs to create patches
/// let patches = dmp.patch_make(PatchInput::new_diffs(&diffs))?;
/// let (new_from_old, _) = dmp.patch_apply(&patches, "Apples are a fruit.")?;
/// assert_eq!("Bananas are also fruit", new_from_old);
- ///
+ ///
/// // Or, from the source texts and diffs
/// let patches = dmp.patch_make(PatchInput::new_text_diffs("Apples are a fruit.", &diffs))?;
/// let (new_from_old, _) = dmp.patch_apply(&patches, "Apples are a fruit.")?;
diff --git a/src/html.rs b/src/html.rs
index b312991..0d9052d 100644
--- a/src/html.rs
+++ b/src/html.rs
@@ -1,13 +1,13 @@
/// A struct representing some properties to control the [`pretty_html`] generation.
/// The `insert_tag`, `delete_tag` and `equality_tag` represents the `html` tag to wrap the part of the text being inserted, deleted or equality.
-///
+///
/// E.g. if `insert_tag` is set to `span`, the text to be inserted will be wrapped around with `<span>some text to insert</span>`.
/// `insert_tag` defaults to the `ins` tag, `delete_tag` defaults to the `del` tag and `equality_tag` defaults to `span`.
-///
+///
/// `nltobr` switch enables or disables replacing of `\n` in the text with a `<br>` element. Defaults to `true`
-///
+///
/// `insert_class`, `delete_class` or `equality_class` if set will be added as a `class="your css class"`. Defaults to `None`
-///
+///
/// `insert_style`, `delete_style` and `equality_style` would add css style property to the output.
/// E.g. if `insert_style: Some("background: yellow; color: purple")` is set the
/// `insert` part of the pretty html would look like `<ins style="background: yellow; color: purple">insert text</ins>`
@@ -21,10 +21,10 @@ pub struct HtmlConfig<'a> {
equality_class: Option<&'a str>,
insert_style: Option<&'a str>,
delete_style: Option<&'a str>,
- equality_style: Option<&'a str>
+ equality_style: Option<&'a str>,
}
-impl <'a>Default for HtmlConfig<'a> {
+impl<'a> Default for HtmlConfig<'a> {
fn default() -> Self {
Self {
insert_tag: "ins",
@@ -36,22 +36,22 @@ impl <'a>Default for HtmlConfig<'a> {
equality_class: None,
insert_style: None,
delete_style: None,
- equality_style: None
+ equality_style: None,
}
}
}
-impl <'a>HtmlConfig<'a> {
+impl<'a> HtmlConfig<'a> {
/// Creates a new instance of the struct with some defaults.
- ///
+ ///
/// `insert_tag` defaults to "ins".
- ///
+ ///
/// `delete_tag` defaults to "del"
- ///
+ ///
/// `equality_tag` defaults to "span"
- ///
+ ///
/// `nltobr` defaults to `true`
- ///
+ ///
/// Other fields defaults to `None`
pub fn new() -> Self {
Self::default()
@@ -146,4 +146,4 @@ impl <'a>HtmlConfig<'a> {
pub fn set_equality_style(&mut self, style: Option<&'a str>) {
self.equality_style = style;
}
-} \ No newline at end of file
+}
diff --git a/tests/compat.rs b/tests/compat.rs
new file mode 100644
index 0000000..4324bae
--- /dev/null
+++ b/tests/compat.rs
@@ -0,0 +1,92 @@
+use diff_match_patch_rs::{Compat, DiffMatchPatch, Error, PatchInput};
+
+// Compatibility with other libraries
+
+// Python Compat
+// Check https://github.com/AnubhabB/diff-match-patch-rs-bench/python/compat.py
+#[test]
+fn test_compat_python_patch_text() -> Result<(), Error> {
+ const TXT_OLD: &str = "** Paragraph 2
+Let's start with some basics 😊. We've got your standard smiley face 🙂, your sad face â˜šī¸, and your angry face 😠. But wait, there's more! 🤩 We've also got some more complex emotions like 😍, 🤤, and 🚀. And let's not forget about the classics: 😉, 👍, and 👏.";
+
+ const TXT_NEW: &str = "** Paragraph 2
+Now, let's explore some emotional extremes 🌊. We've got your ecstatic face 🤩, your devastated face 😭, and your utterly confused face đŸ¤¯. But that's not all! 🤔 We've also got some subtle emotions like 😐, 🙃, and 👀.";
+
+ // Patch generated from python library [diff-match-patch](https://pypi.org/project/diff-match-patch/) for the above text
+ const PATCH_TXT: &str = "@@ -12,38 +12,52 @@\n h 2%0A\n-Let's start with some basics %F0%9F%98%8A\n+Now, let's explore some emotional extremes %F0%9F%8C%8A\n . We\n@@ -73,48 +73,47 @@\n our \n+ec\n sta\n-ndard smiley\n+tic\n face \n-%F0%9F%99%82\n+%F0%9F%A4%A9\n , your \n-sa\n+devastate\n d face \n-%E2%98%B9%EF%B8%8F\n+%F0%9F%98%AD\n , an\n@@ -123,47 +123,54 @@\n our \n-angry\n+utterly confused\n face \n-%F0%9F%98%A0\n+%F0%9F%A4%AF\n . But \n-wait, there's more! %F0%9F%A4%A9\n+that's not all! %F0%9F%A4%94\n We'\n@@ -190,20 +190,14 @@\n ome \n-more comp\n+subt\n le\n-x\n emo\n@@ -211,70 +211,16 @@\n ike \n-%F0%9F%98%8D, %F0%9F%A4%A4\n+%F0%9F%98%90, %F0%9F%99%83\n , and \n-%F0%9F%9A%80. And let's not forget about the classics: %F0%9F%98%89, %F0%9F%91%8D, and %F0%9F%91%8F\n+%F0%9F%91%80\n .\n";
+
+ let dmp = DiffMatchPatch::default();
+ let patches = dmp.patch_from_text::<Compat>(PATCH_TXT)?;
+ let (txt_new, _) = dmp.patch_apply(&patches, TXT_OLD)?;
+
+ // Check if Python patch can be converted to new text
+ assert_eq!(TXT_NEW, &txt_new);
+
+ Ok(())
+}
+
+#[test]
+fn test_compat_python_patch_delta() -> Result<(), Error> {
+ const TXT_OLD: &str = "** Paragraph 2
+Let's start with some basics 😊. We've got your standard smiley face 🙂, your sad face â˜šī¸, and your angry face 😠. But wait, there's more! 🤩 We've also got some more complex emotions like 😍, 🤤, and 🚀. And let's not forget about the classics: 😉, 👍, and 👏.";
+
+ const TXT_NEW: &str = "** Paragraph 2
+Now, let's explore some emotional extremes 🌊. We've got your ecstatic face 🤩, your devastated face 😭, and your utterly confused face đŸ¤¯. But that's not all! 🤔 We've also got some subtle emotions like 😐, 🙃, and 👀.";
+
+ // Delta generated from python library [diff-match-patch](https://pypi.org/project/diff-match-patch/) for the above text
+ const DELTA: &str = "=15\t-1\t+Now, l\t=5\t-3\t+explo\t=1\t-6\t+e\t=6\t-1\t+emotion\t=1\t-3\t+l extreme\t=2\t-1\t+%F0%9F%8C%8A\t=17\t+ec\t=3\t-8\t+t\t=1\t-3\t+c\t=6\t-1\t+%F0%9F%A4%A9\t=7\t+deva\t=1\t+t\t=1\t+te\t=7\t-2\t+%F0%9F%98%AD\t=11\t-3\t+utte\t=1\t+l\t=2\t+confused \t=5\t-1\t+%F0%9F%A4%AF\t=6\t-6\t=2\t-3\t+at\t=3\t-1\t+n\t=1\t-2\t+t all\t=2\t-1\t+%F0%9F%A4%94\t=21\t-9\t+subt\t=2\t-1\t=15\t-1\t+%F0%9F%98%90\t=2\t-1\t+%F0%9F%99%83\t=6\t-55\t+%F0%9F%91%80\t=1";
+
+ let dmp = DiffMatchPatch::default();
+ let diffs = dmp.diff_from_delta::<Compat>(TXT_OLD, DELTA)?;
+ let patches = dmp.patch_make(PatchInput::new_text_diffs(TXT_OLD, &diffs))?;
+ let (txt_new, _) = dmp.patch_apply(&patches, TXT_OLD)?;
+
+ assert_eq!(TXT_NEW, &txt_new);
+
+ Ok(())
+}
+
+// JavaScript Compat
+// Check https://github.com/AnubhabB/diff-match-patch-rs-bench/node/compat.js
+// TODO: we'll have to do this in browser because `encodeURI` wont work
+// #[test]
+// fn test_compat_js_patch_text() -> Result<(), Error> {
+// const TXT_OLD: &str = "** Paragraph 2
+// Let's start with some basics 😊. We've got your standard smiley face 🙂, your sad face â˜šī¸, and your angry face 😠. But wait, there's more! 🤩 We've also got some more complex emotions like 😍, 🤤, and 🚀. And let's not forget about the classics: 😉, 👍, and 👏.";
+
+// const TXT_NEW: &str = "** Paragraph 2
+// Now, let's explore some emotional extremes 🌊. We've got your ecstatic face 🤩, your devastated face 😭, and your utterly confused face đŸ¤¯. But that's not all! 🤔 We've also got some subtle emotions like 😐, 🙃, and 👀.";
+
+// // Patch generated from python library [diff-match-patch](https://www.npmjs.com/package/diff-match-patch) for the above text
+// const PATCH_TXT: &str = "@@ -12,38 +12,52 @@\n h 2%0A\n-Let's start with some basics %F0%9F%98%8A\n+Now, let's explore some emotional extremes %F0%9F%8C%8A\n . We\n@@ -73,48 +73,47 @@\n our \n+ec\n sta\n-ndard smiley\n+tic\n face \n-%F0%9F%99%82\n+%F0%9F%A4%A9\n , your \n-sa\n+devastate\n d face \n-%E2%98%B9%EF%B8%8F\n+%F0%9F%98%AD\n , an\n@@ -123,47 +123,54 @@\n our \n-angry\n+utterly confused\n face \n-%F0%9F%98%A0\n+%F0%9F%A4%AF\n . But \n-wait, there's more! %F0%9F%A4%A9\n+that's not all! %F0%9F%A4%94\n We'\n@@ -190,20 +190,14 @@\n ome \n-more comp\n+subt\n le\n-x\n emo\n@@ -211,70 +211,16 @@\n ike \n-%F0%9F%98%8D, %F0%9F%A4%A4\n+%F0%9F%98%90, %F0%9F%99%83\n , and \n-%F0%9F%9A%80. And let's not forget about the classics: %F0%9F%98%89, %F0%9F%91%8D, and %F0%9F%91%8F\n+%F0%9F%91%80\n .\n";
+
+// let dmp = DiffMatchPatch::default();
+// let patches = dmp.patch_from_text::<Compat>(PATCH_TXT)?;
+// let (txt_new, _) = dmp.patch_apply(&patches, TXT_OLD)?;
+
+// // Check if Python patch can be converted to new text
+// assert_eq!(TXT_NEW, &txt_new);
+
+// Ok(())
+// }
+
+// #[test]
+// fn test_compat_js_patch_delta() -> Result<(), Error> {
+// const TXT_OLD: &str = "** Paragraph 2
+// Let's start with some basics 😊. We've got your standard smiley face 🙂, your sad face â˜šī¸, and your angry face 😠. But wait, there's more! 🤩 We've also got some more complex emotions like 😍, 🤤, and 🚀. And let's not forget about the classics: 😉, 👍, and 👏.";
+
+// const TXT_NEW: &str = "** Paragraph 2
+// Now, let's explore some emotional extremes 🌊. We've got your ecstatic face 🤩, your devastated face 😭, and your utterly confused face đŸ¤¯. But that's not all! 🤔 We've also got some subtle emotions like 😐, 🙃, and 👀.";
+
+// // Delta generated from python library [diff-match-patch](https://www.npmjs.com/package/diff-match-patch) for the above text
+// const DELTA: &str = "=15\t-1\t+Now, l\t=5\t-3\t+explo\t=1\t-6\t+e\t=6\t-1\t+emotion\t=1\t-3\t+l extreme\t=2\t-1\t+%F0%9F%8C%8A\t=17\t+ec\t=3\t-8\t+t\t=1\t-3\t+c\t=6\t-1\t+%F0%9F%A4%A9\t=7\t+deva\t=1\t+t\t=1\t+te\t=7\t-2\t+%F0%9F%98%AD\t=11\t-3\t+utte\t=1\t+l\t=2\t+confused \t=5\t-1\t+%F0%9F%A4%AF\t=6\t-6\t=2\t-3\t+at\t=3\t-1\t+n\t=1\t-2\t+t all\t=2\t-1\t+%F0%9F%A4%94\t=21\t-9\t+subt\t=2\t-1\t=15\t-1\t+%F0%9F%98%90\t=2\t-1\t+%F0%9F%99%83\t=6\t-55\t+%F0%9F%91%80\t=1";
+
+// let dmp = DiffMatchPatch::default();
+// let diffs = dmp.diff_from_delta::<Compat>(TXT_OLD, DELTA)?;
+// let patches = dmp.patch_make(PatchInput::new_text_diffs(TXT_OLD, &diffs))?;
+// let (txt_new, _) = dmp.patch_apply(&patches, TXT_OLD)?;
+
+// assert_eq!(TXT_NEW, &txt_new);
+
+// Ok(())
+// }