Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add matches_legacy method to encapsulate legacy normalization #599

Merged
merged 3 commits into from
Sep 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 46 additions & 10 deletions insta/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ use std::io::{BufRead, BufReader, Write};
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};

use crate::content::{self, json, yaml, Content};
use crate::{
content::{self, json, yaml, Content},
elog,
utils::style,
};

lazy_static::lazy_static! {
static ref RUN_ID: String = {
Expand Down Expand Up @@ -268,7 +272,7 @@ impl MetaData {
}
}

/// A helper to work with stored snapshots.
/// A helper to work with file snapshots.
#[derive(Debug, Clone)]
pub struct Snapshot {
module_name: String,
Expand Down Expand Up @@ -321,7 +325,7 @@ impl Snapshot {
}
}
}
crate::elog!("A snapshot uses an old snapshot format; please update it to the new format with `cargo insta test --force-update-snapshots --accept`.\n\nSnapshot is at: {}", p.to_string_lossy());
elog!("A snapshot uses an old snapshot format; please update it to the new format with `cargo insta test --force-update-snapshots --accept`.\n\nSnapshot is at: {}", p.to_string_lossy());
rv
};

Expand Down Expand Up @@ -520,7 +524,8 @@ impl SnapshotContents {
SnapshotContents(get_inline_snapshot_value(value))
}

/// Returns the snapshot contents as string with surrounding whitespace removed.
/// Returns the snapshot contents as a normalized string (for example,
/// removing surrounding whitespace)
pub fn as_str(&self) -> &str {
let out = self.0.trim_start_matches(['\r', '\n']).trim_end();
// Old inline snapshots have `---` at the start, so this strips that if
Expand All @@ -532,15 +537,36 @@ impl SnapshotContents {
}
}

/// Returns the snapshot contents as string without any trimming.
/// Returns the snapshot contents as string without any normalization
pub fn as_str_exact(&self) -> &str {
self.0.as_str()
}

/// Matches another snapshot without any normalization
pub fn matches_fully(&self, other: &SnapshotContents) -> bool {
self.as_str_exact() == other.as_str_exact()
}

/// Snapshot matches based on the latest format.
pub fn matches_latest(&self, other: &SnapshotContents) -> bool {
self.as_str() == other.as_str()
}

pub fn matches_legacy(&self, other: &SnapshotContents) -> bool {
fn as_str_legacy(sc: &SnapshotContents) -> &str {
let out = sc.as_str();
// Legacy inline snapshots have `---` at the start, so this strips that if
// it exists.
match out.strip_prefix("---\n") {
Some(old_snapshot) => old_snapshot,
None => out,
}
}
as_str_legacy(self) == as_str_legacy(other)
}

/// Create the literal string to write inline, adding `#` to escape the
/// value, indentation, delimiters
pub fn to_inline(&self, indentation: usize) -> String {
let contents = &self.0;
let mut out = String::new();
Expand Down Expand Up @@ -570,8 +596,9 @@ impl SnapshotContents {
out.extend(
contents
.lines()
// newline needs to be at the start, since we don't want the end
// finishing with a newline - the closing suffix should be on the same line
// Adds an additional newline at the start of multiline
// string (not sure this is the clearest way of representing
// it, but it works...)
.map(|l| {
format!(
"\n{:width$}{l}",
Expand All @@ -580,7 +607,8 @@ impl SnapshotContents {
l = l
)
})
// `lines` removes the final line ending - add back
// `lines` removes the final line ending — add back. Include
// indentation so the closing delimited aligns with the full string.
.chain(Some(format!("\n{:width$}", "", width = indentation))),
);
} else {
Expand Down Expand Up @@ -625,7 +653,15 @@ impl From<SnapshotContents> for String {

impl PartialEq for SnapshotContents {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
// Ideally match on current rules, but otherwise fall back to legacy rules
if self.matches_latest(other) {
true
} else if self.matches_legacy(other) {
elog!("{} {}\n{}",style("Snapshot passes but is a legacy format. Please run `cargo insta test --force-update-snapshots --accept` to update to a newer format.").yellow().bold(),"Snapshot contents:", self.as_str());
true
} else {
false
}
}
}

Expand Down Expand Up @@ -719,7 +755,7 @@ fn get_inline_snapshot_value(frozen_value: &str) -> String {
// (the only call site)

if frozen_value.trim_start().starts_with('⋮') {
crate::elog!("A snapshot uses an old snapshot format; please update it to the new format with `cargo insta test --force-update-snapshots --accept`.\n\nSnapshot is at: {}", frozen_value);
elog!("A snapshot uses an old snapshot format; please update it to the new format with `cargo insta test --force-update-snapshots --accept`.\n\nSnapshot is at: {}", frozen_value);

// legacy format - retain so old snapshots still work
let mut buf = String::new();
Expand Down
Loading