diff --git a/Cargo.toml b/Cargo.toml index 819e10a..6366d2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,6 @@ log = "^0.4" tokio = "^1.20" tokio-xmpp = { version = "^3.2", default-features = false, features = ["tls-rust"] } xmpp-parsers = { version = "^0.19", features = ["component"] } + +[dev-dependencies] +syntect = "5.0" diff --git a/src/component/test.rs b/src/component/test.rs index 763cedb..c6ebfe2 100644 --- a/src/component/test.rs +++ b/src/component/test.rs @@ -26,6 +26,13 @@ use std::thread; use async_trait::async_trait; use futures::{task::Poll, Stream}; +use log::debug; +use syntect::{ + easy::HighlightLines, + highlighting::{Style, ThemeSet}, + parsing::SyntaxSet, + util::{as_24_bit_terminal_escaped, LinesWithEndings}, +}; use xmpp_parsers::{iq::Iq, message::Message, presence::Presence, Element, Jid}; enum Expect { @@ -118,6 +125,8 @@ pub struct Component { impl Component { pub fn new(in_buffer: Vec) -> Self { + env_logger::builder().is_test(true).init(); + Component { in_buffer: VecDeque::from( in_buffer @@ -178,6 +187,22 @@ impl Component { self.add_expect(stream, Expect::Presence(Box::new(callback), desc.into())) } + fn hl>(element: S) -> String { + let ps = SyntaxSet::load_defaults_newlines(); + let syntax = ps.find_syntax_by_extension("xml").unwrap(); + let ts = ThemeSet::load_defaults(); + + let mut buf = String::new(); + let mut h = HighlightLines::new(syntax, &ts.themes["Solarized (dark)"]); + for line in LinesWithEndings::from(&element.into()) { + let ranges: Vec<(Style, &str)> = h.highlight_line(line, &ps).unwrap(); + let escaped = as_24_bit_terminal_escaped(&ranges[..], false); + buf.push_str(escaped.as_str()); + } + buf.push_str("\x1b[0m"); + buf + } + fn send_stanza_inner + Send>(&mut self, el: E) -> Result<(), Error> { let out: TestElement = el.into(); let dest: Jid = match out.attr("to") { @@ -193,43 +218,55 @@ 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()); if expected != actual { - panic!( - r#"assertion failed: `(actual == expected)` - actual: `{}`, -expected: `{}`"#, - actual, expected - ) + 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()) { Ok(iq) => cb(iq), _ => panic!( "Mismatch stanza type. Expected iq, got: {}", - String::from(&out) + Component::hl(String::from(&out)) ), }, Expect::Message(cb, _) => match Message::try_from(out.0.clone()) { Ok(message) => cb(message), _ => panic!( "Mismatch stanza type. Expected message, got: {}", - String::from(&out) + Component::hl(String::from(&out)) ), }, Expect::Presence(cb, _) => match Presence::try_from(out.0.clone()) { Ok(presence) => cb(presence), _ => panic!( "Mismatch stanza type. Expected presence, got: {}", - String::from(&out) + Component::hl(String::from(&out)) ), }, }, - None => panic!("Missing matching expected element: {:?}", out), + None => panic!( + "Missing matching expected element: {:?}", + Component::hl(&out) + ), }; // Do we need to remove the empty VecDeque from the HashMap? buf.is_empty() } - None => panic!("Missing matching expected element: {:?}", out), + None => panic!( + "Missing matching expected element: {:?}", + Component::hl(&out) + ), }; if empty_buf {