From 6692443b188c2b4ece02ce92b10a081e19ec3889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Sat, 7 Jan 2023 15:44:15 +0100 Subject: [PATCH] TestComponent: implement word-diff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxime “pep” Buquet --- Cargo.toml | 1 + src/component/test.rs | 99 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6366d2c..848c54c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,4 @@ xmpp-parsers = { version = "^0.19", features = ["component"] } [dev-dependencies] syntect = "5.0" +diff = "0.1" diff --git a/src/component/test.rs b/src/component/test.rs index b368742..ff9afb3 100644 --- a/src/component/test.rs +++ b/src/component/test.rs @@ -25,6 +25,7 @@ use std::task::Context; use std::thread; use async_trait::async_trait; +use diff; use futures::{task::Poll, Stream}; use log::debug; use syntect::{ @@ -203,6 +204,92 @@ impl Component { buf } + fn hl_bg(color: String) -> String { + format!("{}{}", color, "\x1b[48;5;8m") + } + + fn compare_hl(expected: &str, actual: &str) -> String { + let hl_expected = Component::hl(expected.clone()); + let hl_actual = Component::hl(actual.clone()); + + if expected == actual { + return format!( + "\nexpected: `{}`\n \x1b[31mactual\x1b[0m: `{}`\n", + hl_expected, hl_actual + ); + } + + let mut buf_expected = String::new(); + let mut buf_actual = String::new(); + let mut last_color: Option = None; + let mut color_start = false; + let mut color_added = false; + let mut clear_bg = false; + for diff in diff::chars(&hl_expected, &hl_actual) { + match diff { + diff::Result::Both(l, r) => { + if clear_bg { + buf_expected.push_str("\x1b[49m"); + buf_actual.push_str("\x1b[49m"); + clear_bg = false; + } + + if l == '\x1b' { + last_color = Some(String::from(l)); + color_start = true; + } else if color_start { + if l == 'm' { + color_start = false; + } + + last_color = last_color.clone().map(|mut c| { + c.push(l); + c + }); + } + + buf_expected.push(l); + buf_actual.push(r); + } + ref result @ diff::Result::Left(ref c) + | ref result @ diff::Result::Right(ref c) => { + clear_bg = true; + + if *c == '\x1b' { + last_color = Some(String::from(*c)); + color_start = true; + color_added = false; + } else if color_start { + last_color = last_color.clone().map(|mut color| { + color.push(*c); + color + }); + } + + if ! color_added && ! color_start && let Some(ref color) = last_color { + buf_expected.push_str(format!("{}", Component::hl_bg(color.clone())).as_str()); + color_added = true; + } + + if color_start && *c == 'm' { + color_start = false; + } + + match result { + diff::Result::Left(_) => buf_expected.push(*c), + diff::Result::Right(_) => buf_actual.push(*c), + _ => unreachable!(), + } + } + } + } + + format!( + "\nexpected: `{}`\n \x1b[31mactual\x1b[0m: `{}`\n", + buf_expected, buf_actual + ) + } + fn send_stanza_inner + Send>(&mut self, el: E) -> Result<(), Error> { let out: TestElement = el.into(); let dest: Jid = match out.attr("to") { @@ -218,19 +305,9 @@ impl Component { Some(expected) => match expected { Expect::Element(el) => { let (expected, actual) = (String::from(&el), String::from(&out)); - let hl_expected = Component::hl(expected.clone()); - let hl_actual = Component::hl(actual.clone()); + debug!("{}", Component::compare_hl(&expected, &actual)); if expected != actual { - debug!( - "\nexpected: `{}`\n \x1b[31mactual\x1b[0m: `{}`\n", - hl_expected, hl_actual - ); panic!("assertion failed: `(actual == expected)`") - } else { - debug!( - "\nexpected: `{}`\n \x1b[32mactual\x1b[0m: `{}`\n", - hl_expected, hl_actual - ); } } Expect::Iq(cb, _) => match Iq::try_from(out.0.clone()) {