assert_or_bless/
lib.rs

1/// Asserts that `actual` matches the text-file snapshot at `snapshot_path`. If
2/// there is a diff the function will panic with a helpful diff that shows what
3/// changed.
4///
5/// If the env var `ASSERT_OR_BLESS` is set to `bless` then `actual` will be
6/// written to the snapshot file at `snapshot_path` instead of asserting that it
7/// matches.
8pub fn assert_eq_or_bless(actual: impl AsRef<str>, snapshot_path: impl AsRef<std::path::Path>) {
9    assert_eq_or_bless_if(
10        actual,
11        snapshot_path,
12        std::env::var("ASSERT_OR_BLESS") == Ok("bless".to_string()),
13    );
14}
15
16/// Same as [`assert_eq_or_bless`] but allows you to use custom logic to
17/// determine when to bless. Maybe you want to use a different environment
18/// variable, for example.
19pub fn assert_eq_or_bless_if(
20    actual: impl AsRef<str>,
21    snapshot_path: impl AsRef<std::path::Path>,
22    bless: bool,
23) {
24    let snapshot_path = snapshot_path.as_ref();
25    let actual = actual.as_ref();
26
27    if bless {
28        std::fs::write(snapshot_path, actual)
29            .unwrap_or_else(|err| panic!("Writing `{snapshot_path:?}`: {err}"));
30    } else {
31        let expected = std::fs::read_to_string(snapshot_path)
32            .unwrap_or_else(|err| panic!("Reading `{snapshot_path:?}`: {err}"));
33        similar_asserts::assert_eq!(actual, expected);
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    struct DirGuard(std::path::PathBuf);
42    impl DirGuard {
43        fn new(path: std::path::PathBuf) -> Self {
44            std::fs::create_dir_all(&path).unwrap();
45            Self(path)
46        }
47    }
48    impl Drop for DirGuard {
49        fn drop(&mut self) {
50            let _ = std::fs::remove_dir_all(&self.0);
51        }
52    }
53
54    fn test_assert_eq(first: &str, second: &str) {
55        let dir = DirGuard::new(
56            std::env::temp_dir().join(format!("assert-or-bless-{}", fastrand::u32(0..1_000_000))),
57        );
58        let snapshot_path = dir.0.join("test-snapshot.txt");
59        assert_eq_or_bless_if(first, &snapshot_path, true);
60        assert_eq_or_bless(second, &snapshot_path);
61    }
62
63    #[test]
64    fn assert_eq_succeeds() {
65        test_assert_eq(
66            "this is the\ncorrect snapshot contents",
67            "this is the\ncorrect snapshot contents",
68        );
69    }
70
71    #[test]
72    #[should_panic]
73    fn assert_eq_panics() {
74        test_assert_eq(
75            "this is the\ncorrect snapshot contents",
76            "this is the\nWRONG snapshot contents",
77        );
78    }
79}