Repository: mitsuhiko/insta
Pull request #540 (2024-07-28 22:55:29)

Allow snapshotting values which contain `###`


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bea8c63..4462392 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ All notable changes to insta and cargo-insta are documented here.
 
 ## 1.40.0
 
+- Inline snapshots now use the required number of `#`s to escape the snapshot
+  value, rather than always using `###`. This allows snapshotting values which
+  themselves contain `###`. If there are no existing `#` characters in the
+  snapshot value, a single `#` will be used.
+
 - Print a warning when encountering old snapshot formats.  #503
 
 - No longer suggest running `cargo insta` message when running `cargo insta test --check`.  #515
diff --git a/insta/src/snapshot.rs b/insta/src/snapshot.rs
index 7b9e6d6..a11585b 100644
--- a/insta/src/snapshot.rs
+++ b/insta/src/snapshot.rs
@@ -528,9 +528,25 @@ impl SnapshotContents {
     pub fn to_inline(&self, indentation: usize) -> String {
         let contents = &self.0;
         let mut out = String::new();
+
+        // Escape the string if needed, with `r#`, using with 1 more `#` than
+        // the maximum number of existing contiguous `#`.
         let is_escape = contents.contains(&['\n', '\\', '"'][..]);
+        let delimiter = if is_escape {
+            let max_contiguous_hash = contents
+                .split(|c| c != '#')
+                .map(|group| group.len())
+                .max()
+                .unwrap_or(0);
+            out.push('r');
+            "#".repeat(max_contiguous_hash + 1)
+        } else {
+            "".to_string()
+        };
+
+        out.push_str(&delimiter);
+        out.push('"');
 
-        out.push_str(if is_escape { "r###\"" } else { "\"" });
         // if we have more than one line we want to change into the block
         // representation mode
         if contents.contains('\n') {
@@ -554,7 +570,8 @@ impl SnapshotContents {
             out.push_str(contents);
         }
 
-        out.push_str(if is_escape { "\"###" } else { "\"" });
+        out.push('"');
+        out.push_str(&delimiter);
 
         out
     }
@@ -739,10 +756,10 @@ a
 b"[1..];
     assert_eq!(
         SnapshotContents(t.to_string()).to_inline(0),
-        "r###\"
+        "r#\"
 a
 b
-\"###"
+\"#"
     );
 
     let t = &"
@@ -750,10 +767,10 @@ a
 b"[1..];
     assert_eq!(
         SnapshotContents(t.to_string()).to_inline(4),
-        "r###\"
+        "r#\"
     a
     b
-    \"###"
+    \"#"
     );
 
     let t = &"
@@ -761,10 +778,10 @@ b"[1..];
     b"[1..];
     assert_eq!(
         SnapshotContents(t.to_string()).to_inline(0),
-        "r###\"
+        "r#\"
     a
     b
-\"###"
+\"#"
     );
 
     let t = &"
@@ -773,11 +790,11 @@ b"[1..];
     b"[1..];
     assert_eq!(
         SnapshotContents(t.to_string()).to_inline(0),
-        "r###\"
+        "r#\"
     a
 
     b
-\"###"
+\"#"
     );
 
     let t = &"
@@ -785,15 +802,30 @@ b"[1..];
 "[1..];
     assert_eq!(
         SnapshotContents(t.to_string()).to_inline(0),
-        "r###\"
+        "r#\"
     ab
-\"###"
+\"#"
     );
 
     let t = "ab";
     assert_eq!(SnapshotContents(t.to_string()).to_inline(0), r#""ab""#);
 }
 
+#[test]
+fn test_snapshot_contents_hashes() {
+    let t = "a###b";
+    assert_eq!(SnapshotContents(t.to_string()).to_inline(0), r#""a###b""#);
+
+    let t = "a\n###b";
+    assert_eq!(
+        SnapshotContents(t.to_string()).to_inline(0),
+        r#####"r####"
+a
+###b
+"####"#####
+    );
+}
+
 #[test]
 fn test_normalize_inline_snapshot() {
     use similar_asserts::assert_eq;


Test patch:
diff --git a/cargo-insta/tests/snapshots/main__test_json_inline.snap b/cargo-insta/tests/snapshots/main__test_json_inline.snap
index cefac29..ca186b3 100644
--- a/cargo-insta/tests/snapshots/main__test_json_inline.snap
+++ b/cargo-insta/tests/snapshots/main__test_json_inline.snap
@@ -18,12 +18,12 @@ fn test_json_snapshot() {
     };
     insta::assert_json_snapshot!(&user, {
         ".id" => "[user_id]",
-    }, @r###"
+    }, @r#"
     {
       "id": "[user_id]",
       "email": "john.doe@example.com"
     }
-    "###);
+    "#);
 }
 
 #[test]
@@ -34,7 +34,7 @@ fn test_json_snapshot_trailing_comma() {
     };
     insta::assert_compact_json_snapshot!(
         &user,
-        @r###"{"id": 42, "email": "john.doe@example.com"}"###,
+        @r#"{"id": 42, "email": "john.doe@example.com"}"#,
     );
 }
 
@@ -49,11 +49,11 @@ fn test_json_snapshot_trailing_comma_redaction() {
         {
             ".id" => "[user_id]",
         },
-        @r###"
+        @r#"
     {
       "id": "[user_id]",
       "email": "john.doe@example.com"
     }
-    "###,
+    "#,
     );
 }
diff --git a/cargo-insta/tests/snapshots/main__test_yaml_inline.snap b/cargo-insta/tests/snapshots/main__test_yaml_inline.snap
index 2f59598..3d739b7 100644
--- a/cargo-insta/tests/snapshots/main__test_yaml_inline.snap
+++ b/cargo-insta/tests/snapshots/main__test_yaml_inline.snap
@@ -18,11 +18,11 @@ fn test_yaml_snapshot() {
     };
     insta::assert_yaml_snapshot!(&user, {
         ".id" => "[user_id]",
-    }, @r###"
+    }, @r#"
     ---
     id: "[user_id]"
     email: john.doe@example.com
-    "###);
+    "#);
 }
 
 #[test]
@@ -36,10 +36,10 @@ fn test_yaml_snapshot_trailing_comma() {
         {
             ".id" => "[user_id]",
         },
-        @r###"
+        @r#"
     ---
     id: "[user_id]"
     email: john.doe@example.com
-    "###,
+    "#,
     );
 }