summaryrefslogtreecommitdiffstats
path: root/vendor/snapbox/src/report
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/snapbox/src/report')
-rw-r--r--vendor/snapbox/src/report/color.rs127
-rw-r--r--vendor/snapbox/src/report/diff.rs384
-rw-r--r--vendor/snapbox/src/report/mod.rs9
3 files changed, 520 insertions, 0 deletions
diff --git a/vendor/snapbox/src/report/color.rs b/vendor/snapbox/src/report/color.rs
new file mode 100644
index 000000000..f1cd363b4
--- /dev/null
+++ b/vendor/snapbox/src/report/color.rs
@@ -0,0 +1,127 @@
+#[derive(Copy, Clone, Debug)]
+#[allow(dead_code)]
+pub struct Palette {
+ pub(crate) info: styled::Style,
+ pub(crate) warn: styled::Style,
+ pub(crate) error: styled::Style,
+ pub(crate) hint: styled::Style,
+ pub(crate) expected: styled::Style,
+ pub(crate) actual: styled::Style,
+}
+
+impl Palette {
+ #[cfg(feature = "color")]
+ pub fn always() -> Self {
+ Self {
+ info: styled::Style(yansi::Style::new(yansi::Color::Green)),
+ warn: styled::Style(yansi::Style::new(yansi::Color::Yellow)),
+ error: styled::Style(yansi::Style::new(yansi::Color::Red)),
+ hint: styled::Style(yansi::Style::new(yansi::Color::Unset).dimmed()),
+ expected: styled::Style(yansi::Style::new(yansi::Color::Green).underline()),
+ actual: styled::Style(yansi::Style::new(yansi::Color::Red).underline()),
+ }
+ }
+
+ #[cfg(not(feature = "color"))]
+ pub fn always() -> Self {
+ Self::never()
+ }
+
+ pub fn never() -> Self {
+ Self {
+ info: Default::default(),
+ warn: Default::default(),
+ error: Default::default(),
+ hint: Default::default(),
+ expected: Default::default(),
+ actual: Default::default(),
+ }
+ }
+
+ pub fn auto() -> Self {
+ if is_colored() {
+ Self::always()
+ } else {
+ Self::never()
+ }
+ }
+
+ pub fn info<D: std::fmt::Display>(self, item: D) -> Styled<D> {
+ self.info.paint(item)
+ }
+
+ pub fn warn<D: std::fmt::Display>(self, item: D) -> Styled<D> {
+ self.warn.paint(item)
+ }
+
+ pub fn error<D: std::fmt::Display>(self, item: D) -> Styled<D> {
+ self.error.paint(item)
+ }
+
+ pub fn hint<D: std::fmt::Display>(self, item: D) -> Styled<D> {
+ self.hint.paint(item)
+ }
+
+ pub fn expected<D: std::fmt::Display>(self, item: D) -> Styled<D> {
+ self.expected.paint(item)
+ }
+
+ pub fn actual<D: std::fmt::Display>(self, item: D) -> Styled<D> {
+ self.actual.paint(item)
+ }
+}
+
+fn is_colored() -> bool {
+ #[cfg(feature = "color")]
+ {
+ concolor::get(concolor::Stream::Either).ansi_color()
+ }
+
+ #[cfg(not(feature = "color"))]
+ {
+ false
+ }
+}
+
+pub(crate) use styled::Style;
+pub use styled::Styled;
+
+#[cfg(feature = "color")]
+mod styled {
+ #[derive(Copy, Clone, Debug, Default)]
+ pub(crate) struct Style(pub(crate) yansi::Style);
+
+ impl Style {
+ pub(crate) fn paint<T: std::fmt::Display>(self, item: T) -> Styled<T> {
+ Styled(self.0.paint(item))
+ }
+ }
+
+ pub struct Styled<D: std::fmt::Display>(yansi::Paint<D>);
+
+ impl<D: std::fmt::Display> std::fmt::Display for Styled<D> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+}
+
+#[cfg(not(feature = "color"))]
+mod styled {
+ #[derive(Copy, Clone, Debug, Default)]
+ pub(crate) struct Style;
+
+ impl Style {
+ pub(crate) fn paint<T: std::fmt::Display>(self, item: T) -> Styled<T> {
+ Styled(item)
+ }
+ }
+
+ pub struct Styled<D: std::fmt::Display>(D);
+
+ impl<D: std::fmt::Display> std::fmt::Display for Styled<D> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+}
diff --git a/vendor/snapbox/src/report/diff.rs b/vendor/snapbox/src/report/diff.rs
new file mode 100644
index 000000000..adc9f7935
--- /dev/null
+++ b/vendor/snapbox/src/report/diff.rs
@@ -0,0 +1,384 @@
+pub fn write_diff(
+ writer: &mut dyn std::fmt::Write,
+ expected: &crate::Data,
+ actual: &crate::Data,
+ expected_name: Option<&dyn std::fmt::Display>,
+ actual_name: Option<&dyn std::fmt::Display>,
+ palette: crate::report::Palette,
+) -> Result<(), std::fmt::Error> {
+ #[allow(unused_mut)]
+ let mut rendered = false;
+ #[cfg(feature = "diff")]
+ if let (Some(expected), Some(actual)) = (expected.render(), actual.render()) {
+ write_diff_inner(
+ writer,
+ &expected,
+ &actual,
+ expected_name,
+ actual_name,
+ palette,
+ )?;
+ rendered = true;
+ }
+
+ if !rendered {
+ if let Some(expected_name) = expected_name {
+ writeln!(writer, "{} {}:", expected_name, palette.info("(expected)"))?;
+ } else {
+ writeln!(writer, "{}:", palette.info("Expected"))?;
+ }
+ writeln!(writer, "{}", palette.info(&expected))?;
+ if let Some(actual_name) = actual_name {
+ writeln!(writer, "{} {}:", actual_name, palette.error("(actual)"))?;
+ } else {
+ writeln!(writer, "{}:", palette.error("Actual"))?;
+ }
+ writeln!(writer, "{}", palette.error(&actual))?;
+ }
+ Ok(())
+}
+
+#[cfg(feature = "diff")]
+fn write_diff_inner(
+ writer: &mut dyn std::fmt::Write,
+ expected: &str,
+ actual: &str,
+ expected_name: Option<&dyn std::fmt::Display>,
+ actual_name: Option<&dyn std::fmt::Display>,
+ palette: crate::report::Palette,
+) -> Result<(), std::fmt::Error> {
+ let timeout = std::time::Duration::from_millis(500);
+ let min_elide = 20;
+ let context = 5;
+
+ let changes = similar::TextDiff::configure()
+ .algorithm(similar::Algorithm::Patience)
+ .timeout(timeout)
+ .newline_terminated(false)
+ .diff_lines(expected, actual);
+
+ writeln!(writer)?;
+ if let Some(expected_name) = expected_name {
+ writeln!(
+ writer,
+ "{}",
+ palette.info(format_args!("{:->4} expected: {}", "", expected_name))
+ )?;
+ } else {
+ writeln!(writer, "{}", palette.info(format_args!("--- Expected")))?;
+ }
+ if let Some(actual_name) = actual_name {
+ writeln!(
+ writer,
+ "{}",
+ palette.error(format_args!("{:+>4} actual: {}", "", actual_name))
+ )?;
+ } else {
+ writeln!(writer, "{}", palette.error(format_args!("+++ Actual")))?;
+ }
+ let changes = changes
+ .ops()
+ .iter()
+ .flat_map(|op| changes.iter_inline_changes(op))
+ .collect::<Vec<_>>();
+ let tombstones = if min_elide < changes.len() {
+ let mut tombstones = vec![true; changes.len()];
+
+ let mut counter = context;
+ for (i, change) in changes.iter().enumerate() {
+ match change.tag() {
+ similar::ChangeTag::Insert | similar::ChangeTag::Delete => {
+ counter = context;
+ tombstones[i] = false;
+ }
+ similar::ChangeTag::Equal => {
+ if counter != 0 {
+ tombstones[i] = false;
+ counter -= 1;
+ }
+ }
+ }
+ }
+
+ let mut counter = context;
+ for (i, change) in changes.iter().enumerate().rev() {
+ match change.tag() {
+ similar::ChangeTag::Insert | similar::ChangeTag::Delete => {
+ counter = context;
+ tombstones[i] = false;
+ }
+ similar::ChangeTag::Equal => {
+ if counter != 0 {
+ tombstones[i] = false;
+ counter -= 1;
+ }
+ }
+ }
+ }
+ tombstones
+ } else {
+ Vec::new()
+ };
+
+ let mut elided = false;
+ for (i, change) in changes.into_iter().enumerate() {
+ if tombstones.get(i).copied().unwrap_or(false) {
+ if !elided {
+ let sign = "⋮";
+
+ write!(writer, "{:>4} ", " ",)?;
+ write!(writer, "{:>4} ", " ",)?;
+ writeln!(writer, "{}", palette.hint(sign))?;
+ }
+ elided = true;
+ } else {
+ elided = false;
+ match change.tag() {
+ similar::ChangeTag::Insert => {
+ write_change(writer, change, "+", palette.actual, palette.error, palette)?;
+ }
+ similar::ChangeTag::Delete => {
+ write_change(writer, change, "-", palette.expected, palette.info, palette)?;
+ }
+ similar::ChangeTag::Equal => {
+ write_change(writer, change, "|", palette.hint, palette.hint, palette)?;
+ }
+ }
+ }
+ }
+
+ Ok(())
+}
+
+#[cfg(feature = "diff")]
+fn write_change(
+ writer: &mut dyn std::fmt::Write,
+ change: similar::InlineChange<str>,
+ sign: &str,
+ em_style: crate::report::Style,
+ style: crate::report::Style,
+ palette: crate::report::Palette,
+) -> Result<(), std::fmt::Error> {
+ if let Some(index) = change.old_index() {
+ write!(writer, "{:>4} ", palette.hint(index + 1),)?;
+ } else {
+ write!(writer, "{:>4} ", " ",)?;
+ }
+ if let Some(index) = change.new_index() {
+ write!(writer, "{:>4} ", palette.hint(index + 1),)?;
+ } else {
+ write!(writer, "{:>4} ", " ",)?;
+ }
+ write!(writer, "{} ", style.paint(sign))?;
+ for &(emphasized, change) in change.values() {
+ let cur_style = if emphasized { em_style } else { style };
+ write!(writer, "{}", cur_style.paint(change))?;
+ }
+ if change.missing_newline() {
+ writeln!(writer, "{}", em_style.paint("∅"))?;
+ }
+
+ Ok(())
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[cfg(feature = "diff")]
+ #[test]
+ fn diff_eq() {
+ let expected = "Hello\nWorld\n";
+ let expected_name = "A";
+ let actual = "Hello\nWorld\n";
+ let actual_name = "B";
+ let palette = crate::report::Palette::never();
+
+ let mut actual_diff = String::new();
+ write_diff_inner(
+ &mut actual_diff,
+ expected,
+ actual,
+ Some(&expected_name),
+ Some(&actual_name),
+ palette,
+ )
+ .unwrap();
+ let expected_diff = "
+---- expected: A
+++++ actual: B
+ 1 1 | Hello
+ 2 2 | World
+";
+
+ assert_eq!(expected_diff, actual_diff);
+ }
+
+ #[cfg(feature = "diff")]
+ #[test]
+ fn diff_ne_line_missing() {
+ let expected = "Hello\nWorld\n";
+ let expected_name = "A";
+ let actual = "Hello\n";
+ let actual_name = "B";
+ let palette = crate::report::Palette::never();
+
+ let mut actual_diff = String::new();
+ write_diff_inner(
+ &mut actual_diff,
+ expected,
+ actual,
+ Some(&expected_name),
+ Some(&actual_name),
+ palette,
+ )
+ .unwrap();
+ let expected_diff = "
+---- expected: A
+++++ actual: B
+ 1 1 | Hello
+ 2 - World
+";
+
+ assert_eq!(expected_diff, actual_diff);
+ }
+
+ #[cfg(feature = "diff")]
+ #[test]
+ fn diff_eq_trailing_extra_newline() {
+ let expected = "Hello\nWorld";
+ let expected_name = "A";
+ let actual = "Hello\nWorld\n";
+ let actual_name = "B";
+ let palette = crate::report::Palette::never();
+
+ let mut actual_diff = String::new();
+ write_diff_inner(
+ &mut actual_diff,
+ expected,
+ actual,
+ Some(&expected_name),
+ Some(&actual_name),
+ palette,
+ )
+ .unwrap();
+ let expected_diff = "
+---- expected: A
+++++ actual: B
+ 1 1 | Hello
+ 2 - World∅
+ 2 + World
+";
+
+ assert_eq!(expected_diff, actual_diff);
+ }
+
+ #[cfg(feature = "diff")]
+ #[test]
+ fn diff_eq_trailing_newline_missing() {
+ let expected = "Hello\nWorld\n";
+ let expected_name = "A";
+ let actual = "Hello\nWorld";
+ let actual_name = "B";
+ let palette = crate::report::Palette::never();
+
+ let mut actual_diff = String::new();
+ write_diff_inner(
+ &mut actual_diff,
+ expected,
+ actual,
+ Some(&expected_name),
+ Some(&actual_name),
+ palette,
+ )
+ .unwrap();
+ let expected_diff = "
+---- expected: A
+++++ actual: B
+ 1 1 | Hello
+ 2 - World
+ 2 + World∅
+";
+
+ assert_eq!(expected_diff, actual_diff);
+ }
+
+ #[cfg(feature = "diff")]
+ #[test]
+ fn diff_eq_elided() {
+ let mut expected = String::new();
+ expected.push_str("Hello\n");
+ for i in 0..20 {
+ expected.push_str(&i.to_string());
+ expected.push('\n');
+ }
+ expected.push_str("World\n");
+ for i in 0..20 {
+ expected.push_str(&i.to_string());
+ expected.push('\n');
+ }
+ expected.push_str("!\n");
+ let expected_name = "A";
+
+ let mut actual = String::new();
+ actual.push_str("Goodbye\n");
+ for i in 0..20 {
+ actual.push_str(&i.to_string());
+ actual.push('\n');
+ }
+ actual.push_str("Moon\n");
+ for i in 0..20 {
+ actual.push_str(&i.to_string());
+ actual.push('\n');
+ }
+ actual.push_str("?\n");
+ let actual_name = "B";
+
+ let palette = crate::report::Palette::never();
+
+ let mut actual_diff = String::new();
+ write_diff_inner(
+ &mut actual_diff,
+ &expected,
+ &actual,
+ Some(&expected_name),
+ Some(&actual_name),
+ palette,
+ )
+ .unwrap();
+ let expected_diff = "
+---- expected: A
+++++ actual: B
+ 1 - Hello
+ 1 + Goodbye
+ 2 2 | 0
+ 3 3 | 1
+ 4 4 | 2
+ 5 5 | 3
+ 6 6 | 4
+ ⋮
+ 17 17 | 15
+ 18 18 | 16
+ 19 19 | 17
+ 20 20 | 18
+ 21 21 | 19
+ 22 - World
+ 22 + Moon
+ 23 23 | 0
+ 24 24 | 1
+ 25 25 | 2
+ 26 26 | 3
+ 27 27 | 4
+ ⋮
+ 38 38 | 15
+ 39 39 | 16
+ 40 40 | 17
+ 41 41 | 18
+ 42 42 | 19
+ 43 - !
+ 43 + ?
+";
+
+ assert_eq!(expected_diff, actual_diff);
+ }
+}
diff --git a/vendor/snapbox/src/report/mod.rs b/vendor/snapbox/src/report/mod.rs
new file mode 100644
index 000000000..6c9a238b8
--- /dev/null
+++ b/vendor/snapbox/src/report/mod.rs
@@ -0,0 +1,9 @@
+//! Utilities to report test results to users
+
+mod color;
+mod diff;
+
+pub use color::Palette;
+pub(crate) use color::Style;
+pub use color::Styled;
+pub use diff::write_diff;