blob: 2e151f903170ff9f6bbf202e5442af01c7727fb0 [file] [log] [blame]
use std::{path::Path, time::Duration};
use similar::{Algorithm, ChangeTag, TextDiff};
use crate::snapshot::{MetaData, Snapshot};
use crate::utils::{format_rust_expression, style, term_width};
/// Prints the summary of a snapshot
pub fn print_snapshot_summary(
workspace_root: &Path,
snapshot: &Snapshot,
snapshot_file: Option<&Path>,
mut line: Option<u32>,
) {
// default to old assertion line from snapshot.
if line.is_none() {
line = snapshot.metadata().assertion_line();
}
if let Some(snapshot_file) = snapshot_file {
let snapshot_file = workspace_root
.join(snapshot_file)
.strip_prefix(workspace_root)
.ok()
.map(|x| x.to_path_buf())
.unwrap_or_else(|| snapshot_file.to_path_buf());
println!(
"Snapshot file: {}",
style(snapshot_file.display()).cyan().underlined()
);
}
if let Some(name) = snapshot.snapshot_name() {
println!("Snapshot: {}", style(name).yellow());
} else {
println!("Snapshot: {}", style("<inline>").dim());
}
if let Some(ref value) = snapshot.metadata().get_relative_source(workspace_root) {
println!(
"Source: {}{}",
style(value.display()).cyan(),
if let Some(line) = line {
format!(":{}", style(line).bold())
} else {
"".to_string()
}
);
}
if let Some(ref value) = snapshot.metadata().input_file() {
println!("Input file: {}", style(value).cyan());
}
}
/// Prints a diff against an old snapshot.
pub fn print_snapshot_diff(
workspace_root: &Path,
new: &Snapshot,
old_snapshot: Option<&Snapshot>,
snapshot_file: Option<&Path>,
mut line: Option<u32>,
show_info: bool,
) {
// default to old assertion line from snapshot.
if line.is_none() {
line = new.metadata().assertion_line();
}
print_snapshot_summary(workspace_root, new, snapshot_file, line);
let old_contents = old_snapshot.as_ref().map_or("", |x| x.contents_str());
let new_contents = new.contents_str();
print_changeset(old_contents, new_contents, new.metadata(), show_info);
}
pub fn print_snapshot_diff_with_title(
workspace_root: &Path,
new_snapshot: &Snapshot,
old_snapshot: Option<&Snapshot>,
line: u32,
snapshot_file: Option<&Path>,
) {
let width = term_width();
println!(
"{title:━^width$}",
title = style(" Snapshot Differences ").bold(),
width = width
);
print_snapshot_diff(
workspace_root,
new_snapshot,
old_snapshot,
snapshot_file,
Some(line),
true,
);
}
pub fn print_snapshot_summary_with_title(
workspace_root: &Path,
new_snapshot: &Snapshot,
old_snapshot: Option<&Snapshot>,
line: u32,
snapshot_file: Option<&Path>,
) {
let _old_snapshot = old_snapshot;
let width = term_width();
println!(
"{title:━^width$}",
title = style(" Snapshot Summary ").bold(),
width = width
);
print_snapshot_summary(workspace_root, new_snapshot, snapshot_file, Some(line));
println!("{title:━^width$}", title = "", width = width);
}
pub fn print_changeset(old: &str, new: &str, metadata: &MetaData, show_info: bool) {
let width = term_width();
let diff = TextDiff::configure()
.algorithm(Algorithm::Patience)
.timeout(Duration::from_millis(500))
.diff_lines(old, new);
println!("{:─^1$}", "", width);
if show_info {
if let Some(expr) = metadata.expression() {
println!("Expression: {}", style(format_rust_expression(expr)));
println!("{:─^1$}", "", width);
}
if let Some(descr) = metadata.description() {
println!("{}", descr);
println!("{:─^1$}", "", width);
}
if let Some(info) = metadata.private_info() {
let out = serde_yaml::to_string(&info).unwrap();
println!("{}", out.trim().strip_prefix("---").unwrap().trim_start());
println!("{:─^1$}", "", width);
}
}
if !old.is_empty() {
println!("{}", style("-old snapshot").red());
println!("{}", style("+new results").green());
} else {
println!("{}", style("+new results").green());
}
println!("────────────┬{:─^1$}", "", width.saturating_sub(13));
let mut has_changes = false;
for (idx, group) in diff.grouped_ops(4).iter().enumerate() {
if idx > 0 {
println!("┈┈┈┈┈┈┈┈┈┈┈┈┼{:┈^1$}", "", width.saturating_sub(13));
}
for op in group {
for change in diff.iter_inline_changes(op) {
match change.tag() {
ChangeTag::Insert => {
has_changes = true;
print!(
"{:>5} {:>5} │{}",
"",
style(change.new_index().unwrap()).cyan().dim().bold(),
style("+").green(),
);
for &(emphasized, change) in change.values() {
if emphasized {
print!("{}", style(change).green().underlined());
} else {
print!("{}", style(change).green());
}
}
}
ChangeTag::Delete => {
has_changes = true;
print!(
"{:>5} {:>5} │{}",
style(change.old_index().unwrap()).cyan().dim(),
"",
style("-").red(),
);
for &(emphasized, change) in change.values() {
if emphasized {
print!("{}", style(change).red().underlined());
} else {
print!("{}", style(change).red());
}
}
}
ChangeTag::Equal => {
print!(
"{:>5} {:>5} │ ",
style(change.old_index().unwrap()).cyan().dim(),
style(change.new_index().unwrap()).cyan().dim().bold(),
);
for &(_, change) in change.values() {
print!("{}", style(change).dim());
}
}
}
if change.missing_newline() {
println!();
}
}
}
}
if !has_changes {
println!(
"{:>5} {:>5} │{}",
"",
style("-").dim(),
style(" snapshots are matching").cyan(),
);
}
println!("────────────┴{:─^1$}", "", width.saturating_sub(13),);
}