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        // Write the current public API to the snapshot path
29        std::fs::write(snapshot_path, actual).unwrap_or_else(|err| {
30            panic!("Failed to write snapshot to `{:?}`: {err}", snapshot_path,)
31        });
32    } else {
33        // Assert that the current public API matches the snapshot
34        let expected = std::fs::read_to_string(snapshot_path).unwrap_or_else(|err| {
35            panic!("Failed to read snapshot from `{:?}`: {err}", snapshot_path,)
36        });
37        similar_asserts::assert_eq!(actual, expected);
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    fn test_assert_eq(first: &str, second: &str) {
46        let test_dir = std::env::temp_dir()
47            .join(format!("assert-or-bless"))
48            .join(format!("test-{}", fastrand::u32(0..1_000_000_000)));
49
50        std::fs::create_dir_all(&test_dir).unwrap();
51
52        let snapshot_path = test_dir.join("test-snapshot.txt");
53        assert_eq_or_bless_if(first, &snapshot_path, true);
54        assert_eq_or_bless(second, &snapshot_path);
55
56        let _ = std::fs::remove_dir_all(&test_dir);
57    }
58
59    #[test]
60    fn assert_eq_succeeds() {
61        test_assert_eq(
62            "this is the\ncorrect snapshot contents",
63            "this is the\ncorrect snapshot contents",
64        );
65    }
66
67    #[test]
68    #[should_panic]
69    fn assert_eq_panics() {
70        test_assert_eq(
71            "this is the\ncorrect snapshot contents",
72            "this is the\nWRONG snapshot contents",
73        );
74    }
75}