diff --git a/cargo-insta/tests/functional/binary.rs b/cargo-insta/tests/functional/binary.rs new file mode 100644 index 00000000..1f17ad33 --- /dev/null +++ b/cargo-insta/tests/functional/binary.rs @@ -0,0 +1,500 @@ +use insta::assert_snapshot; + +use crate::TestFiles; + +/// A pending binary snapshot should have a binary file with the passed extension alongside it. +#[test] +fn test_binary_pending() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_binary_pending" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +#[test] +fn test_binary_snapshot() { + insta::assert_binary_snapshot!(".txt", b"test".to_vec()); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project.insta_cmd().args(["test"]).output().unwrap(); + + assert!(!&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,8 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_binary_pending__binary_snapshot.snap.new + + src/snapshots/test_binary_pending__binary_snapshot.snap.new.txt + "); +} + +/// An accepted binary snapshot should have a binary file with the passed extension alongside it. +#[test] +fn test_binary_accept() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_binary_accept" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +#[test] +fn test_binary_snapshot() { + insta::assert_binary_snapshot!(".txt", b"test".to_vec()); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,8 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_binary_accept__binary_snapshot.snap + + src/snapshots/test_binary_accept__binary_snapshot.snap.txt + "); +} + +/// Changing the extension passed to the `assert_binary_snapshot` macro should create a new pending +/// snapshot with a binary file with the new extension alongside it and once approved the old binary +/// file with the old extension should be deleted. +#[test] +fn test_binary_change_extension() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_binary_change_extension" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +#[test] +fn test_binary_snapshot() { + insta::assert_binary_snapshot!(".txt", b"test".to_vec()); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + test_project.update_file( + "src/main.rs", + r#" +#[test] +fn test_binary_snapshot() { + insta::assert_binary_snapshot!(".json", b"test".to_vec()); +} +"# + .to_string(), + ); + + let output = test_project.insta_cmd().args(["test"]).output().unwrap(); + + assert!(!&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,10 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_binary_change_extension__binary_snapshot.snap + + src/snapshots/test_binary_change_extension__binary_snapshot.snap.new + + src/snapshots/test_binary_change_extension__binary_snapshot.snap.new.json + + src/snapshots/test_binary_change_extension__binary_snapshot.snap.txt + "); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,8 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_binary_change_extension__binary_snapshot.snap + + src/snapshots/test_binary_change_extension__binary_snapshot.snap.json + "); +} + +/// An assert with a pending binary snapshot should have both the metadata file and the binary file +/// deleted when the assert is removed and the tests are re-run. +#[test] +fn test_binary_pending_snapshot_removal() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_binary_pending_snapshot_removal" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +#[test] +fn test_binary_snapshot() { + insta::assert_binary_snapshot!(".txt", b"test".to_vec()); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project.insta_cmd().args(["test"]).output().unwrap(); + + assert!(!&output.status.success()); + + test_project.update_file("src/main.rs", "".to_string()); + + let output = test_project.insta_cmd().args(["test"]).output().unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,6 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + "); +} + +/// Replacing a text snapshot with binary one should work and simply replace the text snapshot file +/// with the new metadata file and a new binary snapshot file alongside it. +#[test] +fn test_change_text_to_binary() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_change_text_to_binary" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +#[test] +fn test() { + insta::assert_snapshot!("test"); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,7 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_change_text_to_binary__test.snap + "); + + test_project.update_file( + "src/main.rs", + r#" +#[test] +fn test() { + insta::assert_binary_snapshot!(".txt", b"test".to_vec()); +} +"# + .to_string(), + ); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,8 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_change_text_to_binary__test.snap + + src/snapshots/test_change_text_to_binary__test.snap.txt + "); +} + +/// When changing a snapshot from a binary to a text snapshot the previous binary file should be +/// gone after having approved the the binary snapshot. +#[test] +fn test_change_binary_to_text() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_change_binary_to_text" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +#[test] +fn test() { + insta::assert_binary_snapshot!("some_name.json", b"{}".to_vec()); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,8 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_change_binary_to_text__some_name.snap + + src/snapshots/test_change_binary_to_text__some_name.snap.json + "); + + test_project.update_file( + "src/main.rs", + r#" +#[test] +fn test() { + insta::assert_snapshot!("some_name", "test"); +} +"# + .to_string(), + ); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,7 @@ + + + Cargo.lock + Cargo.toml + src + src/main.rs + + src/snapshots + + src/snapshots/test_change_binary_to_text__some_name.snap + "); +} + +#[test] +fn test_binary_unreferenced_delete() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_binary_unreferenced_delete" +version = "0.1.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/lib.rs", + r#" +#[test] +fn test_snapshot() { + insta::assert_binary_snapshot!(".txt", b"abcd".to_vec()); +} +"# + .to_string(), + ) + .create_project(); + + // Run tests to create snapshots + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + test_project.update_file("src/lib.rs", "".to_string()); + + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,8 @@ + + + Cargo.lock + Cargo.toml + src + src/lib.rs + + src/snapshots + + src/snapshots/test_binary_unreferenced_delete__snapshot.snap + + src/snapshots/test_binary_unreferenced_delete__snapshot.snap.txt + "); + + // Run cargo insta test with --unreferenced=delete + let output = test_project + .insta_cmd() + .args([ + "test", + "--unreferenced=delete", + "--accept", + "--", + "--nocapture", + ]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + // We should now see the unreferenced snapshot deleted + assert_snapshot!(test_project.file_tree_diff(), @r" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,6 @@ + + + Cargo.lock + Cargo.toml + src + src/lib.rs + + src/snapshots + "); +} diff --git a/cargo-insta/tests/functional/inline.rs b/cargo-insta/tests/functional/inline.rs new file mode 100644 index 00000000..4d5aaaad --- /dev/null +++ b/cargo-insta/tests/functional/inline.rs @@ -0,0 +1,361 @@ +use insta::assert_snapshot; + +use crate::TestFiles; + +#[test] +fn test_json_inline() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_json_inline" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH', features=["json", "redactions"] } +serde = { version = "1.0", features = ["derive"] } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +use serde::Serialize; + +#[derive(Serialize)] +struct User { + id: u64, + email: String, +} + +#[test] +fn test_json_snapshot() { + let user = User { + id: 42, + email: "john.doe@example.com".into(), + }; + insta::assert_json_snapshot!(&user, { + ".id" => "[user_id]", + }, @""); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept", "--", "--nocapture"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.diff("src/main.rs"), @r##" + --- Original: src/main.rs + +++ Updated: src/main.rs + @@ -15,5 +15,10 @@ + }; + insta::assert_json_snapshot!(&user, { + ".id" => "[user_id]", + - }, @""); + + }, @r#" + + { + + "id": "[user_id]", + + "email": "john.doe@example.com" + + } + + "#); + } + "##); +} + +#[test] +fn test_yaml_inline() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_yaml_inline" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH', features=["yaml", "redactions"] } +serde = { version = "1.0", features = ["derive"] } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +use serde::Serialize; + +#[derive(Serialize)] +struct User { + id: u64, + email: String, +} + +#[test] +fn test_yaml_snapshot() { + let user = User { + id: 42, + email: "john.doe@example.com".into(), + }; + insta::assert_yaml_snapshot!(&user, { + ".id" => "[user_id]", + }, @""); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.diff("src/main.rs"), @r###" + --- Original: src/main.rs + +++ Updated: src/main.rs + @@ -15,5 +15,8 @@ + }; + insta::assert_yaml_snapshot!(&user, { + ".id" => "[user_id]", + - }, @""); + + }, @r#" + + id: "[user_id]" + + email: john.doe@example.com + + "#); + } + "###); +} + +#[test] +fn test_utf8_inline() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_utf8_inline" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +#[test] +fn test_non_basic_plane() { + /* an offset here ❄️ */ insta::assert_snapshot!("a 😀oeu", @""); +} + +#[test] +fn test_remove_existing_value() { + insta::assert_snapshot!("this is the new value", @"this is the old value"); +} + +#[test] +fn test_remove_existing_value_multiline() { + insta::assert_snapshot!( + "this is the new value", + @"this is\ + this is the old value\ + it really is" + ); +} + +#[test] +fn test_trailing_comma_in_inline_snapshot() { + insta::assert_snapshot!( + "new value", + @"old value", // comma here + ); +} +"# + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.diff("src/main.rs"), @r##" + --- Original: src/main.rs + +++ Updated: src/main.rs + @@ -1,21 +1,19 @@ + + #[test] + fn test_non_basic_plane() { + - /* an offset here ❄️ */ insta::assert_snapshot!("a 😀oeu", @""); + + /* an offset here ❄️ */ insta::assert_snapshot!("a 😀oeu", @"a 😀oeu"); + } + + #[test] + fn test_remove_existing_value() { + - insta::assert_snapshot!("this is the new value", @"this is the old value"); + + insta::assert_snapshot!("this is the new value", @"this is the new value"); + } + + #[test] + fn test_remove_existing_value_multiline() { + insta::assert_snapshot!( + "this is the new value", + - @"this is\ + - this is the old value\ + - it really is" + + @"this is the new value" + ); + } + + @@ -23,6 +21,6 @@ + fn test_trailing_comma_in_inline_snapshot() { + insta::assert_snapshot!( + "new value", + - @"old value", // comma here + + @"new value", // comma here + ); + } + "##); +} + +/// Test the old format of inline YAML snapshots with a leading `---` still passes +#[test] +fn test_old_yaml_format() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "old-yaml-format" +version = "0.1.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +insta = { path = '$PROJECT_PATH', features = ["yaml"] } +"# + .to_string(), + ) + .add_file( + "src/lib.rs", + r#####" +#[test] +fn test_old_yaml_format() { + insta::assert_yaml_snapshot!("foo", @r####" + --- + foo +"####); +} +"##### + .to_string(), + ) + .create_project(); + + // Check it passes + assert!(test_project + .insta_cmd() + .args(["test", "--", "--nocapture"]) + .output() + .unwrap() + .status + .success()); + // shouldn't be any changes + assert_snapshot!(test_project.diff("src/lib.rs"), @""); + + // Also check that running with `--force-update-snapshots` updates the snapshot + assert!(test_project + .insta_cmd() + .args(["test", "--force-update-snapshots", "--", "--nocapture"]) + .output() + .unwrap() + .status + .success()); + + assert_snapshot!(test_project.diff("src/lib.rs"), @r#####" + --- Original: src/lib.rs + +++ Updated: src/lib.rs + @@ -1,8 +1,5 @@ + + #[test] + fn test_old_yaml_format() { + - insta::assert_yaml_snapshot!("foo", @r####" + - --- + - foo + -"####); + + insta::assert_yaml_snapshot!("foo", @"foo"); + } + "#####); +} + +#[test] +fn test_hashtag_escape_in_inline_snapshot() { + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[package] +name = "test_hashtag_escape" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#####" +#[test] +fn test_hashtag_escape() { + insta::assert_snapshot!(r###"Value with + "## hashtags\n"###, @""); +} +"##### + .to_string(), + ) + .create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.diff("src/main.rs"), @r####" + --- Original: src/main.rs + +++ Updated: src/main.rs + @@ -2,5 +2,8 @@ + #[test] + fn test_hashtag_escape() { + insta::assert_snapshot!(r###"Value with + - "## hashtags\n"###, @""); + + "## hashtags\n"###, @r###" + + Value with + + "## hashtags\n + + "###); + } + "####); +} diff --git a/cargo-insta/tests/functional/main.rs b/cargo-insta/tests/functional/main.rs index 013069bd..d92cd865 100644 --- a/cargo-insta/tests/functional/main.rs +++ b/cargo-insta/tests/functional/main.rs @@ -44,13 +44,13 @@ /// > crates the same... This also causes issues when running the same tests /// > concurrently. use std::collections::HashMap; +use std::env; use std::fs; use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use std::process::Command; use std::process::Stdio; use std::thread; -use std::{env, fs::remove_dir_all}; use console::style; use ignore::WalkBuilder; @@ -59,6 +59,10 @@ use itertools::Itertools; use similar::udiff::unified_diff; use tempfile::TempDir; +mod binary; +mod inline; +mod workspace; + /// Wraps a formatting function to be used as a `Stdio` struct OutputFormatter(F) where @@ -257,149 +261,118 @@ impl TestProject { } #[test] -fn test_json_inline() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" +fn test_force_update_snapshots() { + fn create_test_force_update_project(name: &str, insta_dependency: &str) -> TestProject { + TestFiles::new() + .add_file( + "Cargo.toml", + format!( + r#" [package] -name = "test_json_inline" +name = "test_force_update_{}" version = "0.1.0" edition = "2021" [dependencies] -insta = { path = '$PROJECT_PATH', features=["json", "redactions"] } -serde = { version = "1.0", features = ["derive"] } +insta = {} +"#, + name, insta_dependency + ) + .to_string(), + ) + .add_file( + "src/lib.rs", + r#" +#[test] +fn test_snapshot_with_newline() { + insta::assert_snapshot!("force_update", "Hello, world!"); +} "# - .to_string(), - ) - .add_file( - "src/main.rs", - r#" -use serde::Serialize; + .to_string(), + ) + .add_file( + format!( + "src/snapshots/test_force_update_{}__force_update.snap", + name + ), + r#" +--- +source: src/lib.rs +expression: +--- +Hello, world! -#[derive(Serialize)] -struct User { - id: u64, - email: String, -} -#[test] -fn test_json_snapshot() { - let user = User { - id: 42, - email: "john.doe@example.com".into(), - }; - insta::assert_json_snapshot!(&user, { - ".id" => "[user_id]", - }, @""); -} "# - .to_string(), - ) - .create_project(); + .to_string(), + ) + .create_project() + } - let output = test_project + let test_current_insta = + create_test_force_update_project("current", "{ path = '$PROJECT_PATH' }"); + let test_insta_1_40_0 = create_test_force_update_project("1_40_0", "\"1.40.0\""); + + // Test with current insta version + let output_current = test_current_insta .insta_cmd() - .args(["test", "--accept", "--", "--nocapture"]) + .args(["test", "--accept", "--force-update-snapshots"]) .output() .unwrap(); - assert!(&output.status.success()); - - assert_snapshot!(test_project.diff("src/main.rs"), @r##" - --- Original: src/main.rs - +++ Updated: src/main.rs - @@ -15,5 +15,10 @@ - }; - insta::assert_json_snapshot!(&user, { - ".id" => "[user_id]", - - }, @""); - + }, @r#" - + { - + "id": "[user_id]", - + "email": "john.doe@example.com" - + } - + "#); - } - "##); -} - -#[test] -fn test_yaml_inline() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_yaml_inline" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH', features=["yaml", "redactions"] } -serde = { version = "1.0", features = ["derive"] } -"# - .to_string(), - ) - .add_file( - "src/main.rs", - r#" -use serde::Serialize; - -#[derive(Serialize)] -struct User { - id: u64, - email: String, -} - -#[test] -fn test_yaml_snapshot() { - let user = User { - id: 42, - email: "john.doe@example.com".into(), - }; - insta::assert_yaml_snapshot!(&user, { - ".id" => "[user_id]", - }, @""); -} -"# - .to_string(), - ) - .create_project(); + assert!(&output_current.status.success()); - let output = test_project + // Test with insta 1.40.0 + let output_1_40_0 = test_insta_1_40_0 .insta_cmd() - .args(["test", "--accept"]) + .args(["test", "--accept", "--force-update-snapshots"]) .output() .unwrap(); - assert!(&output.status.success()); + assert!(&output_1_40_0.status.success()); - assert_snapshot!(test_project.diff("src/main.rs"), @r###" - --- Original: src/main.rs - +++ Updated: src/main.rs - @@ -15,5 +15,8 @@ - }; - insta::assert_yaml_snapshot!(&user, { - ".id" => "[user_id]", - - }, @""); - + }, @r#" - + id: "[user_id]" - + email: john.doe@example.com - + "#); - } - "###); + // Check that both versions updated the snapshot correctly + assert_snapshot!(test_current_insta.diff("src/snapshots/test_force_update_current__force_update.snap"), @r#" + --- Original: src/snapshots/test_force_update_current__force_update.snap + +++ Updated: src/snapshots/test_force_update_current__force_update.snap + @@ -1,8 +1,6 @@ + - + --- + source: src/lib.rs + -expression: + +expression: "\"Hello, world!\"" + +snapshot_kind: text + --- + Hello, world! + - + - + "#); + + assert_snapshot!(test_insta_1_40_0.diff("src/snapshots/test_force_update_1_40_0__force_update.snap"), @r#" + --- Original: src/snapshots/test_force_update_1_40_0__force_update.snap + +++ Updated: src/snapshots/test_force_update_1_40_0__force_update.snap + @@ -1,8 +1,6 @@ + - + --- + source: src/lib.rs + -expression: + +expression: "\"Hello, world!\"" + +snapshot_kind: text + --- + Hello, world! + - + - + "#); } #[test] -fn test_utf8_inline() { +fn test_force_update_inline_snapshot_linebreaks() { let test_project = TestFiles::new() .add_file( "Cargo.toml", r#" [package] -name = "test_utf8_inline" +name = "force-update-inline-linebreaks" version = "0.1.0" edition = "2021" @@ -409,1266 +382,105 @@ insta = { path = '$PROJECT_PATH' } .to_string(), ) .add_file( - "src/main.rs", - r#" -#[test] -fn test_non_basic_plane() { - /* an offset here ❄️ */ insta::assert_snapshot!("a 😀oeu", @""); -} - -#[test] -fn test_remove_existing_value() { - insta::assert_snapshot!("this is the new value", @"this is the old value"); -} - -#[test] -fn test_remove_existing_value_multiline() { - insta::assert_snapshot!( - "this is the new value", - @"this is\ - this is the old value\ - it really is" - ); -} - + "src/lib.rs", + r#####" #[test] -fn test_trailing_comma_in_inline_snapshot() { - insta::assert_snapshot!( - "new value", - @"old value", // comma here - ); +fn test_linebreaks() { + insta::assert_snapshot!("foo", @r####" + foo + + "####); } -"# - .to_string(), +"##### + .to_string(), ) .create_project(); + // Run the test with --force-update-snapshots and --accept let output = test_project .insta_cmd() - .args(["test", "--accept"]) + .args(["test", "--force-update-snapshots", "--", "--nocapture"]) .output() .unwrap(); assert!(&output.status.success()); - assert_snapshot!(test_project.diff("src/main.rs"), @r##" - --- Original: src/main.rs - +++ Updated: src/main.rs - @@ -1,21 +1,19 @@ - - #[test] - fn test_non_basic_plane() { - - /* an offset here ❄️ */ insta::assert_snapshot!("a 😀oeu", @""); - + /* an offset here ❄️ */ insta::assert_snapshot!("a 😀oeu", @"a 😀oeu"); - } - - #[test] - fn test_remove_existing_value() { - - insta::assert_snapshot!("this is the new value", @"this is the old value"); - + insta::assert_snapshot!("this is the new value", @"this is the new value"); - } + // Linebreaks should be reset + assert_snapshot!(test_project.diff("src/lib.rs"), @r#####" + --- Original: src/lib.rs + +++ Updated: src/lib.rs + @@ -1,8 +1,5 @@ #[test] - fn test_remove_existing_value_multiline() { - insta::assert_snapshot!( - "this is the new value", - - @"this is\ - - this is the old value\ - - it really is" - + @"this is the new value" - ); - } - - @@ -23,6 +21,6 @@ - fn test_trailing_comma_in_inline_snapshot() { - insta::assert_snapshot!( - "new value", - - @"old value", // comma here - + @"new value", // comma here - ); + fn test_linebreaks() { + - insta::assert_snapshot!("foo", @r####" + - foo + - + - "####); + + insta::assert_snapshot!("foo", @"foo"); } - "##); + "#####); } -// Note that names need to be different to prevent the cache confusing them. -fn workspace_with_root_crate(name: String) -> TestFiles { - TestFiles::new() +#[test] +fn test_force_update_inline_snapshot_hashes() { + let test_project = TestFiles::new() .add_file( "Cargo.toml", - format!( - r#" + r#" [package] -name = "{name}" +name = "force-update-inline-hashes" version = "0.1.0" edition = "2021" -[workspace] -members = [ - "member", -] - -[workspace.dependencies] -insta = {{path = '$PROJECT_PATH'}} - -[dependencies] -insta = {{ workspace = true }} - -"# - ) - .to_string(), - ) - .add_file( - "member/Cargo.toml", - format!( - r#" -[package] -name = "{name}-member" -version = "0.0.0" -edition = "2021" - [dependencies] -insta = {{ workspace = true }} -"# - ) - .to_string(), - ) - .add_file( - "member/src/lib.rs", - r#" -#[test] -fn test_member() { - insta::assert_debug_snapshot!(vec![1, 2, 3]); -} +insta = { path = '$PROJECT_PATH' } "# .to_string(), ) .add_file( - "src/main.rs", - r#" -fn main() { - println!("Hello, world!"); -} - + "src/lib.rs", + r#####" #[test] -fn test_root() { - insta::assert_debug_snapshot!(vec![1, 2, 3]); +fn test_excessive_hashes() { + insta::assert_snapshot!("foo", @r####"foo"####); } -"# - .to_string(), +"##### + .to_string(), ) -} - -/// Check that in a workspace with a default root crate, running `cargo insta -/// test --workspace --accept` will update snapshots in both the root crate and the -/// member crate. -#[test] -fn test_root_crate_workspace_accept() { - let test_project = - workspace_with_root_crate("root-crate-workspace-accept".to_string()).create_project(); + .create_project(); + // Run the test with --force-update-snapshots and --accept let output = test_project .insta_cmd() - .args(["test", "--accept", "--workspace"]) + .args(["test", "--force-update-snapshots", "--", "--nocapture"]) .output() .unwrap(); assert!(&output.status.success()); - assert_snapshot!(test_project.file_tree_diff(), @r###" - --- Original file tree - +++ Updated file tree - @@ -1,8 +1,13 @@ - - + Cargo.lock - Cargo.toml - member - member/Cargo.toml - member/src - member/src/lib.rs - + member/src/snapshots - + member/src/snapshots/root_crate_workspace_accept_member__member.snap - src - src/main.rs - + src/snapshots - + src/snapshots/root_crate_workspace_accept__root.snap - "### ); -} - -/// Check that in a workspace with a default root crate, running `cargo insta -/// test --workspace` will correctly report the number of pending snapshots -#[test] -fn test_root_crate_workspace() { - let test_project = - workspace_with_root_crate("root-crate-workspace".to_string()).create_project(); - - let output = test_project - .insta_cmd() - // Need to disable colors to assert the output below - .args(["test", "--workspace", "--color=never"]) - .stderr(Stdio::piped()) - .output() - .unwrap(); - - // 1.39 had a bug where it would claim there were 3 snapshots here - assert!( - String::from_utf8_lossy(&output.stderr).contains("info: 2 snapshots to review"), - "{}", - String::from_utf8_lossy(&output.stderr) - ); -} - -/// Check that in a workspace with a default root crate, running `cargo insta -/// test --accept` will only update snapshots in the root crate -#[test] -fn test_root_crate_no_all() { - let test_project = workspace_with_root_crate("root-crate-no-all".to_string()).create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r###" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,5 @@ - - + Cargo.lock - Cargo.toml - member - member/Cargo.toml - @@ -6,3 +7,5 @@ - member/src/lib.rs - src - src/main.rs - + src/snapshots - + src/snapshots/root_crate_no_all__root.snap - "### ); -} - -fn workspace_with_virtual_manifest(name: String) -> TestFiles { - TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[workspace] -members = [ - "member-1", - "member-2", -] - -[workspace.dependencies] -insta = {path = '$PROJECT_PATH'} -"# - .to_string() - .to_string(), - ) - .add_file( - "member-1/Cargo.toml", - format!( - r#" -[package] -name = "{name}-member-1" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = {{ workspace = true }} -"# - ) - .to_string(), - ) - .add_file( - "member-1/src/lib.rs", - r#" -#[test] -fn test_member_1() { - insta::assert_debug_snapshot!(vec![1, 2, 3]); -} -"# - .to_string(), - ) - .add_file( - "member-2/Cargo.toml", - format!( - r#" -[package] -name = "{name}-member-2" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = {{ workspace = true }} -"# - ) - .to_string(), - ) - .add_file( - "member-2/src/lib.rs", - r#" -#[test] -fn test_member_2() { - insta::assert_debug_snapshot!(vec![4, 5, 6]); -} -"# - .to_string(), - ) -} - -/// Check that in a workspace with a virtual manifest, running `cargo insta test -/// --workspace --accept` updates snapshots in all member crates. -#[test] -fn test_virtual_manifest_all() { - let test_project = - workspace_with_virtual_manifest("virtual-manifest-all".to_string()).create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept", "--workspace"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r###" - --- Original file tree - +++ Updated file tree - @@ -1,10 +1,15 @@ - - + Cargo.lock - Cargo.toml - member-1 - member-1/Cargo.toml - member-1/src - member-1/src/lib.rs - + member-1/src/snapshots - + member-1/src/snapshots/virtual_manifest_all_member_1__member_1.snap - member-2 - member-2/Cargo.toml - member-2/src - member-2/src/lib.rs - + member-2/src/snapshots - + member-2/src/snapshots/virtual_manifest_all_member_2__member_2.snap - "### ); -} - -/// Check that in a workspace with a virtual manifest, running `cargo insta test -/// --accept` updates snapshots in all member crates. -#[test] -fn test_virtual_manifest_default() { - let test_project = - workspace_with_virtual_manifest("virtual-manifest-default".to_string()).create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r###" - --- Original file tree - +++ Updated file tree - @@ -1,10 +1,15 @@ - - + Cargo.lock - Cargo.toml - member-1 - member-1/Cargo.toml - member-1/src - member-1/src/lib.rs - + member-1/src/snapshots - + member-1/src/snapshots/virtual_manifest_default_member_1__member_1.snap - member-2 - member-2/Cargo.toml - member-2/src - member-2/src/lib.rs - + member-2/src/snapshots - + member-2/src/snapshots/virtual_manifest_default_member_2__member_2.snap - "### ); -} - -/// Check that in a workspace with a virtual manifest, running `cargo insta test -/// -p ` will only update snapshots in that crate. -#[test] -fn test_virtual_manifest_single_crate() { - let test_project = - workspace_with_virtual_manifest("virtual-manifest-single".to_string()).create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept", "-p", "virtual-manifest-single-member-1"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r###" - --- Original file tree - +++ Updated file tree - @@ -1,9 +1,12 @@ - - + Cargo.lock - Cargo.toml - member-1 - member-1/Cargo.toml - member-1/src - member-1/src/lib.rs - + member-1/src/snapshots - + member-1/src/snapshots/virtual_manifest_single_member_1__member_1.snap - member-2 - member-2/Cargo.toml - member-2/src - "### ); -} - -/// Test the old format of inline YAML snapshots with a leading `---` still passes -#[test] -fn test_old_yaml_format() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "old-yaml-format" -version = "0.1.0" -edition = "2021" - -[lib] -doctest = false - -[dependencies] -insta = { path = '$PROJECT_PATH', features = ["yaml"] } -"# - .to_string(), - ) - .add_file( - "src/lib.rs", - r#####" -#[test] -fn test_old_yaml_format() { - insta::assert_yaml_snapshot!("foo", @r####" - --- - foo -"####); -} -"##### - .to_string(), - ) - .create_project(); - - // Check it passes - assert!(test_project - .insta_cmd() - .args(["test", "--", "--nocapture"]) - .output() - .unwrap() - .status - .success()); - // shouldn't be any changes - assert_snapshot!(test_project.diff("src/lib.rs"), @""); - - // Also check that running with `--force-update-snapshots` updates the snapshot - assert!(test_project - .insta_cmd() - .args(["test", "--force-update-snapshots", "--", "--nocapture"]) - .output() - .unwrap() - .status - .success()); - - assert_snapshot!(test_project.diff("src/lib.rs"), @r#####" - --- Original: src/lib.rs - +++ Updated: src/lib.rs - @@ -1,8 +1,5 @@ - - #[test] - fn test_old_yaml_format() { - - insta::assert_yaml_snapshot!("foo", @r####" - - --- - - foo - -"####); - + insta::assert_yaml_snapshot!("foo", @"foo"); - } - "#####); -} - -#[test] -fn test_force_update_snapshots() { - fn create_test_force_update_project(name: &str, insta_dependency: &str) -> TestProject { - TestFiles::new() - .add_file( - "Cargo.toml", - format!( - r#" -[package] -name = "test_force_update_{}" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = {} -"#, - name, insta_dependency - ) - .to_string(), - ) - .add_file( - "src/lib.rs", - r#" -#[test] -fn test_snapshot_with_newline() { - insta::assert_snapshot!("force_update", "Hello, world!"); -} -"# - .to_string(), - ) - .add_file( - format!( - "src/snapshots/test_force_update_{}__force_update.snap", - name - ), - r#" ---- -source: src/lib.rs -expression: ---- -Hello, world! - - -"# - .to_string(), - ) - .create_project() - } - - let test_current_insta = - create_test_force_update_project("current", "{ path = '$PROJECT_PATH' }"); - let test_insta_1_40_0 = create_test_force_update_project("1_40_0", "\"1.40.0\""); - - // Test with current insta version - let output_current = test_current_insta - .insta_cmd() - .args(["test", "--accept", "--force-update-snapshots"]) - .output() - .unwrap(); - - assert!(&output_current.status.success()); - - // Test with insta 1.40.0 - let output_1_40_0 = test_insta_1_40_0 - .insta_cmd() - .args(["test", "--accept", "--force-update-snapshots"]) - .output() - .unwrap(); - - assert!(&output_1_40_0.status.success()); - - // Check that both versions updated the snapshot correctly - assert_snapshot!(test_current_insta.diff("src/snapshots/test_force_update_current__force_update.snap"), @r#" - --- Original: src/snapshots/test_force_update_current__force_update.snap - +++ Updated: src/snapshots/test_force_update_current__force_update.snap - @@ -1,8 +1,6 @@ - - - --- - source: src/lib.rs - -expression: - +expression: "\"Hello, world!\"" - +snapshot_kind: text - --- - Hello, world! - - - - - "#); - - assert_snapshot!(test_insta_1_40_0.diff("src/snapshots/test_force_update_1_40_0__force_update.snap"), @r#" - --- Original: src/snapshots/test_force_update_1_40_0__force_update.snap - +++ Updated: src/snapshots/test_force_update_1_40_0__force_update.snap - @@ -1,8 +1,6 @@ - - - --- - source: src/lib.rs - -expression: - +expression: "\"Hello, world!\"" - +snapshot_kind: text - --- - Hello, world! - - - - - "#); -} - -#[test] -fn test_force_update_inline_snapshot_linebreaks() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "force-update-inline-linebreaks" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/lib.rs", - r#####" -#[test] -fn test_linebreaks() { - insta::assert_snapshot!("foo", @r####" - foo - - "####); -} -"##### - .to_string(), - ) - .create_project(); - - // Run the test with --force-update-snapshots and --accept - let output = test_project - .insta_cmd() - .args(["test", "--force-update-snapshots", "--", "--nocapture"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - // Linebreaks should be reset - assert_snapshot!(test_project.diff("src/lib.rs"), @r#####" - --- Original: src/lib.rs - +++ Updated: src/lib.rs - @@ -1,8 +1,5 @@ - - #[test] - fn test_linebreaks() { - - insta::assert_snapshot!("foo", @r####" - - foo - - - - "####); - + insta::assert_snapshot!("foo", @"foo"); - } - "#####); -} - -#[test] -fn test_force_update_inline_snapshot_hashes() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "force-update-inline-hashes" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/lib.rs", - r#####" -#[test] -fn test_excessive_hashes() { - insta::assert_snapshot!("foo", @r####"foo"####); -} -"##### - .to_string(), - ) - .create_project(); - - // Run the test with --force-update-snapshots and --accept - let output = test_project - .insta_cmd() - .args(["test", "--force-update-snapshots", "--", "--nocapture"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - // `--force-update-snapshots` should remove the hashes - assert_snapshot!(test_project.diff("src/lib.rs"), @r#####" - --- Original: src/lib.rs - +++ Updated: src/lib.rs - @@ -1,5 +1,5 @@ + // `--force-update-snapshots` should remove the hashes + assert_snapshot!(test_project.diff("src/lib.rs"), @r#####" + --- Original: src/lib.rs + +++ Updated: src/lib.rs + @@ -1,5 +1,5 @@ #[test] fn test_excessive_hashes() { - insta::assert_snapshot!("foo", @r####"foo"####); - + insta::assert_snapshot!("foo", @"foo"); - } - "#####); -} - -#[test] -fn test_inline_snapshot_indent() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "inline-indent" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/lib.rs", - r#####" -#[test] -fn test_wrong_indent_force() { - insta::assert_snapshot!(r#" - foo - foo - "#, @r#" - foo - foo - "#); -} -"##### - .to_string(), - ) - .create_project(); - - // ...and that it passes with `--require-full-match`. Note that ideally this - // would fail, but we can't read the desired indent without serde, which is - // in `cargo-insta` only. So this tests the current state rather than the - // ideal state (and I don't think there's a reasonable way to get the ideal state) - // Now confirm that `--require-full-match` passes - let output = test_project - .insta_cmd() - .args([ - "test", - "--check", - "--require-full-match", - "--", - "--nocapture", - ]) - .output() - .unwrap(); - assert!(&output.status.success()); -} - -#[test] -fn test_matches_fully_linebreaks() { - // Until #563 merges, we should be OK with different leading newlines, even - // in exact / full match mode. - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "exact-match-inline" -version = "0.1.0" -edition = "2021" - -[lib] -doctest = false - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/lib.rs", - r#####" -#[test] -fn test_additional_linebreak() { - // Additional newline here - insta::assert_snapshot!(r#" - - ( - "name_foo", - "insta_tests__tests", - ) - "#, @r#" - ( - "name_foo", - "insta_tests__tests", - ) - "#); -} -"##### - .to_string(), - ) - .create_project(); - - // Confirm the test passes despite the indent - let output = test_project - .insta_cmd() - .args([ - "test", - "--check", - "--require-full-match", - "--", - "--nocapture", - ]) - .output() - .unwrap(); - assert!(&output.status.success()); -} - -#[test] -fn test_hashtag_escape_in_inline_snapshot() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_hashtag_escape" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/main.rs", - r#####" -#[test] -fn test_hashtag_escape() { - insta::assert_snapshot!(r###"Value with - "## hashtags\n"###, @""); -} -"##### - .to_string(), - ) - .create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.diff("src/main.rs"), @r####" - --- Original: src/main.rs - +++ Updated: src/main.rs - @@ -2,5 +2,8 @@ - #[test] - fn test_hashtag_escape() { - insta::assert_snapshot!(r###"Value with - - "## hashtags\n"###, @""); - + "## hashtags\n"###, @r###" - + Value with - + "## hashtags\n - + "###); - } - "####); -} - -#[test] -fn test_snapshot_name_clash() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "snapshot_name_clash_test" -version = "0.1.0" -edition = "2021" - -[lib] -doctest = false - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/lib.rs", - r#" -use insta::assert_debug_snapshot; - -#[test] -fn test_foo_always_missing() { - assert_debug_snapshot!(42); -} - -#[test] -fn foo_always_missing() { - assert_debug_snapshot!(42); -} -"# - .to_string(), - ) - .create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept", "--", "--nocapture"]) - .stderr(Stdio::piped()) - .output() - .unwrap(); - - // The test should fail due to the name clash - assert!(!output.status.success()); - - let error_output = String::from_utf8_lossy(&output.stderr); - - // Check for the name clash error message - assert!(error_output.contains("Insta snapshot name clash detected between 'foo_always_missing' and 'test_foo_always_missing' in 'snapshot_name_clash_test'. Rename one function.")); -} - -/// A pending binary snapshot should have a binary file with the passed extension alongside it. -#[test] -fn test_binary_pending() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_binary_pending" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/main.rs", - r#" -#[test] -fn test_binary_snapshot() { - insta::assert_binary_snapshot!(".txt", b"test".to_vec()); -} -"# - .to_string(), - ) - .create_project(); - - let output = test_project.insta_cmd().args(["test"]).output().unwrap(); - - assert!(!&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,8 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_binary_pending__binary_snapshot.snap.new - + src/snapshots/test_binary_pending__binary_snapshot.snap.new.txt - "); -} - -/// An accepted binary snapshot should have a binary file with the passed extension alongside it. -#[test] -fn test_binary_accept() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_binary_accept" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/main.rs", - r#" -#[test] -fn test_binary_snapshot() { - insta::assert_binary_snapshot!(".txt", b"test".to_vec()); -} -"# - .to_string(), - ) - .create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,8 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_binary_accept__binary_snapshot.snap - + src/snapshots/test_binary_accept__binary_snapshot.snap.txt - "); -} - -/// Changing the extension passed to the `assert_binary_snapshot` macro should create a new pending -/// snapshot with a binary file with the new extension alongside it and once approved the old binary -/// file with the old extension should be deleted. -#[test] -fn test_binary_change_extension() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_binary_change_extension" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/main.rs", - r#" -#[test] -fn test_binary_snapshot() { - insta::assert_binary_snapshot!(".txt", b"test".to_vec()); -} -"# - .to_string(), - ) - .create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - test_project.update_file( - "src/main.rs", - r#" -#[test] -fn test_binary_snapshot() { - insta::assert_binary_snapshot!(".json", b"test".to_vec()); -} -"# - .to_string(), - ); - - let output = test_project.insta_cmd().args(["test"]).output().unwrap(); - - assert!(!&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,10 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_binary_change_extension__binary_snapshot.snap - + src/snapshots/test_binary_change_extension__binary_snapshot.snap.new - + src/snapshots/test_binary_change_extension__binary_snapshot.snap.new.json - + src/snapshots/test_binary_change_extension__binary_snapshot.snap.txt - "); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,8 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_binary_change_extension__binary_snapshot.snap - + src/snapshots/test_binary_change_extension__binary_snapshot.snap.json - "); -} - -/// An assert with a pending binary snapshot should have both the metadata file and the binary file -/// deleted when the assert is removed and the tests are re-run. -#[test] -fn test_binary_pending_snapshot_removal() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_binary_pending_snapshot_removal" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/main.rs", - r#" -#[test] -fn test_binary_snapshot() { - insta::assert_binary_snapshot!(".txt", b"test".to_vec()); -} -"# - .to_string(), - ) - .create_project(); - - let output = test_project.insta_cmd().args(["test"]).output().unwrap(); - - assert!(!&output.status.success()); - - test_project.update_file("src/main.rs", "".to_string()); - - let output = test_project.insta_cmd().args(["test"]).output().unwrap(); - - assert!(&output.status.success()); - - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,6 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - "); -} - -/// Replacing a text snapshot with binary one should work and simply replace the text snapshot file -/// with the new metadata file and a new binary snapshot file alongside it. -#[test] -fn test_change_text_to_binary() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_change_text_to_binary" -version = "0.1.0" -edition = "2021" - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/main.rs", - r#" -#[test] -fn test() { - insta::assert_snapshot!("test"); -} -"# - .to_string(), - ) - .create_project(); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,7 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_change_text_to_binary__test.snap - "); - - test_project.update_file( - "src/main.rs", - r#" -#[test] -fn test() { - insta::assert_binary_snapshot!(".txt", b"test".to_vec()); -} -"# - .to_string(), - ); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,8 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_change_text_to_binary__test.snap - + src/snapshots/test_change_text_to_binary__test.snap.txt - "); + + insta::assert_snapshot!("foo", @"foo"); + } + "#####); } -/// When changing a snapshot from a binary to a text snapshot the previous binary file should be -/// gone after having approved the the binary snapshot. #[test] -fn test_change_binary_to_text() { +fn test_inline_snapshot_indent() { let test_project = TestFiles::new() .add_file( "Cargo.toml", r#" [package] -name = "test_change_binary_to_text" +name = "inline-indent" version = "0.1.0" edition = "2021" @@ -1678,311 +490,154 @@ insta = { path = '$PROJECT_PATH' } .to_string(), ) .add_file( - "src/main.rs", - r#" + "src/lib.rs", + r#####" #[test] -fn test() { - insta::assert_binary_snapshot!("some_name.json", b"{}".to_vec()); +fn test_wrong_indent_force() { + insta::assert_snapshot!(r#" + foo + foo + "#, @r#" + foo + foo + "#); } -"# - .to_string(), +"##### + .to_string(), ) .create_project(); + // ...and that it passes with `--require-full-match`. Note that ideally this + // would fail, but we can't read the desired indent without serde, which is + // in `cargo-insta` only. So this tests the current state rather than the + // ideal state (and I don't think there's a reasonable way to get the ideal state) + // Now confirm that `--require-full-match` passes let output = test_project .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,8 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_change_binary_to_text__some_name.snap - + src/snapshots/test_change_binary_to_text__some_name.snap.json - "); - - test_project.update_file( - "src/main.rs", - r#" -#[test] -fn test() { - insta::assert_snapshot!("some_name", "test"); -} -"# - .to_string(), - ); - - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) + .args([ + "test", + "--check", + "--require-full-match", + "--", + "--nocapture", + ]) .output() .unwrap(); - assert!(&output.status.success()); - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,7 @@ - - + Cargo.lock - Cargo.toml - src - src/main.rs - + src/snapshots - + src/snapshots/test_change_binary_to_text__some_name.snap - "); } -// Can't get the test binary discovery to work, don't have a windows machine to -// hand, others are welcome to fix it. (No specific reason to think that insta -// doesn't work on windows, just that the test doesn't work.) -#[cfg(not(target_os = "windows"))] #[test] -fn test_insta_workspace_root() { - // This function locates the compiled test binary in the target directory. - // It's necessary because the exact filename of the test binary includes a hash - // that we can't predict, so we need to search for it. - fn find_test_binary(dir: &Path) -> PathBuf { - dir.join("target/debug/deps") - .read_dir() - .unwrap() - .filter_map(Result::ok) - .find(|entry| { - let file_name = entry.file_name(); - let file_name_str = file_name.to_str().unwrap_or(""); - // We're looking for a file that: - file_name_str.starts_with("insta_workspace_root_test-") // Matches our test name - && !file_name_str.contains('.') // Doesn't have an extension (it's the executable, not a metadata file) - && entry.metadata().map(|m| m.is_file()).unwrap_or(false) // Is a file, not a directory - }) - .map(|entry| entry.path()) - .expect("Failed to find test binary") - } - - fn run_test_binary( - binary_path: &Path, - current_dir: &Path, - env: Option<(&str, &str)>, - ) -> std::process::Output { - let mut cmd = Command::new(binary_path); - TestProject::clean_env(&mut cmd); - cmd.current_dir(current_dir); - if let Some((key, value)) = env { - cmd.env(key, value); - } - cmd.output().unwrap() - } - +fn test_matches_fully_linebreaks() { + // Until #563 merges, we should be OK with different leading newlines, even + // in exact / full match mode. let test_project = TestFiles::new() .add_file( "Cargo.toml", r#" - [package] - name = "insta_workspace_root_test" - version = "0.1.0" - edition = "2021" - - [dependencies] - insta = { path = '$PROJECT_PATH' } - "# +[package] +name = "exact-match-inline" +version = "0.1.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +insta = { path = '$PROJECT_PATH' } +"# .to_string(), ) .add_file( "src/lib.rs", - r#" -use insta::assert_snapshot; - + r#####" #[test] -fn test_snapshot() { - assert_snapshot!("Hello, world!"); +fn test_additional_linebreak() { + // Additional newline here + insta::assert_snapshot!(r#" + + ( + "name_foo", + "insta_tests__tests", + ) + "#, @r#" + ( + "name_foo", + "insta_tests__tests", + ) + "#); } - "# - .to_string(), +"##### + .to_string(), ) .create_project(); - let mut cargo_cmd = Command::new("cargo"); - TestProject::clean_env(&mut cargo_cmd); - let output = cargo_cmd - .args(["test", "--no-run"]) - .current_dir(&test_project.workspace_dir) + // Confirm the test passes despite the indent + let output = test_project + .insta_cmd() + .args([ + "test", + "--check", + "--require-full-match", + "--", + "--nocapture", + ]) .output() .unwrap(); assert!(&output.status.success()); - - let test_binary_path = find_test_binary(&test_project.workspace_dir); - - // Run the test without snapshot (should fail) - assert!( - !&run_test_binary(&test_binary_path, &test_project.workspace_dir, None,) - .status - .success() - ); - - // Create the snapshot - assert!(&run_test_binary( - &test_binary_path, - &test_project.workspace_dir, - Some(("INSTA_UPDATE", "always")), - ) - .status - .success()); - - // Verify snapshot creation - assert!(test_project.workspace_dir.join("src/snapshots").exists()); - assert!(test_project - .workspace_dir - .join("src/snapshots/insta_workspace_root_test__snapshot.snap") - .exists()); - - // Move the workspace - let moved_workspace = { - let moved_workspace = PathBuf::from("/tmp/cargo-insta-test-moved"); - remove_dir_all(&moved_workspace).ok(); - fs::create_dir(&moved_workspace).unwrap(); - fs::rename(&test_project.workspace_dir, &moved_workspace).unwrap(); - moved_workspace - }; - let moved_binary_path = find_test_binary(&moved_workspace); - - // Run test in moved workspace without INSTA_WORKSPACE_ROOT (should fail) - assert!( - !&run_test_binary(&moved_binary_path, &moved_workspace, None) - .status - .success() - ); - - // Run test in moved workspace with INSTA_WORKSPACE_ROOT (should pass) - assert!(&run_test_binary( - &moved_binary_path, - &moved_workspace, - Some(("INSTA_WORKSPACE_ROOT", moved_workspace.to_str().unwrap())), - ) - .status - .success()); } #[test] -fn test_external_test_path() { +fn test_snapshot_name_clash() { let test_project = TestFiles::new() .add_file( - "proj/Cargo.toml", + "Cargo.toml", r#" [package] -name = "external_test_path" +name = "snapshot_name_clash_test" version = "0.1.0" edition = "2021" +[lib] +doctest = false + [dependencies] insta = { path = '$PROJECT_PATH' } - -[[test]] -name = "tlib" -path = "../tests/lib.rs" "# .to_string(), ) .add_file( - "proj/src/lib.rs", + "src/lib.rs", r#" -pub fn hello() -> String { - "Hello, world!".to_string() +use insta::assert_debug_snapshot; + +#[test] +fn test_foo_always_missing() { + assert_debug_snapshot!(42); } -"# - .to_string(), - ) - .add_file( - "tests/lib.rs", - r#" -use external_test_path::hello; #[test] -fn test_hello() { - insta::assert_snapshot!(hello()); +fn foo_always_missing() { + assert_debug_snapshot!(42); } "# .to_string(), ) .create_project(); - // Change to the proj directory for running cargo commands - let proj_dir = test_project.workspace_dir.join("proj"); - - // Initially, the test should fail - let output = test_project - .insta_cmd() - .current_dir(&proj_dir) - .args(["test", "--"]) - .output() - .unwrap(); - - assert!(!&output.status.success()); - - // Verify that the snapshot was created in the correct location - assert_snapshot!(TestProject::current_file_tree(&test_project.workspace_dir), @r" - proj - proj/Cargo.lock - proj/Cargo.toml - proj/src - proj/src/lib.rs - tests - tests/lib.rs - tests/snapshots - tests/snapshots/tlib__hello.snap.new - "); - - // Run cargo insta accept let output = test_project .insta_cmd() - .current_dir(&proj_dir) - .args(["test", "--accept"]) + .args(["test", "--accept", "--", "--nocapture"]) + .stderr(Stdio::piped()) .output() .unwrap(); - assert!(&output.status.success()); - - // Verify that the snapshot was created in the correct location - assert_snapshot!(TestProject::current_file_tree(&test_project.workspace_dir), @r" - proj - proj/Cargo.lock - proj/Cargo.toml - proj/src - proj/src/lib.rs - tests - tests/lib.rs - tests/snapshots - tests/snapshots/tlib__hello.snap - "); - - // Run the test again, it should pass now - let output = Command::new(env!("CARGO_BIN_EXE_cargo-insta")) - .current_dir(&proj_dir) - .args(["test"]) - .output() - .unwrap(); + // The test should fail due to the name clash + assert!(!output.status.success()); - assert!(&output.status.success()); + let error_output = String::from_utf8_lossy(&output.stderr); - let snapshot_path = test_project - .workspace_dir - .join("tests/snapshots/tlib__hello.snap"); - assert_snapshot!(fs::read_to_string(snapshot_path).unwrap(), @r#" - --- - source: "../tests/lib.rs" - expression: hello() - snapshot_kind: text - --- - Hello, world! - "#); + // Check for the name clash error message + assert!(error_output.contains("Insta snapshot name clash detected between 'foo_always_missing' and 'test_foo_always_missing' in 'snapshot_name_clash_test'. Rename one function.")); } #[test] @@ -2238,88 +893,3 @@ src/ stderr ); } - -#[test] -fn test_binary_unreferenced_delete() { - let test_project = TestFiles::new() - .add_file( - "Cargo.toml", - r#" -[package] -name = "test_binary_unreferenced_delete" -version = "0.1.0" -edition = "2021" - -[lib] -doctest = false - -[dependencies] -insta = { path = '$PROJECT_PATH' } -"# - .to_string(), - ) - .add_file( - "src/lib.rs", - r#" -#[test] -fn test_snapshot() { - insta::assert_binary_snapshot!(".txt", b"abcd".to_vec()); -} -"# - .to_string(), - ) - .create_project(); - - // Run tests to create snapshots - let output = test_project - .insta_cmd() - .args(["test", "--accept"]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - test_project.update_file("src/lib.rs", "".to_string()); - - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,8 @@ - - + Cargo.lock - Cargo.toml - src - src/lib.rs - + src/snapshots - + src/snapshots/test_binary_unreferenced_delete__snapshot.snap - + src/snapshots/test_binary_unreferenced_delete__snapshot.snap.txt - "); - - // Run cargo insta test with --unreferenced=delete - let output = test_project - .insta_cmd() - .args([ - "test", - "--unreferenced=delete", - "--accept", - "--", - "--nocapture", - ]) - .output() - .unwrap(); - - assert!(&output.status.success()); - - // We should now see the unreferenced snapshot deleted - assert_snapshot!(test_project.file_tree_diff(), @r" - --- Original file tree - +++ Updated file tree - @@ -1,4 +1,6 @@ - - + Cargo.lock - Cargo.toml - src - src/lib.rs - + src/snapshots - "); -} diff --git a/cargo-insta/tests/functional/workspace.rs b/cargo-insta/tests/functional/workspace.rs new file mode 100644 index 00000000..d0c842dd --- /dev/null +++ b/cargo-insta/tests/functional/workspace.rs @@ -0,0 +1,595 @@ +use std::{ + fs, + process::{Command, Stdio}, +}; + +use insta::assert_snapshot; + +use crate::{TestFiles, TestProject}; + +// Note that names need to be different to prevent the cache confusing them. +fn workspace_with_root_crate(name: String) -> TestFiles { + TestFiles::new() + .add_file( + "Cargo.toml", + format!( + r#" +[package] +name = "{name}" +version = "0.1.0" +edition = "2021" + +[workspace] +members = [ + "member", +] + +[workspace.dependencies] +insta = {{path = '$PROJECT_PATH'}} + +[dependencies] +insta = {{ workspace = true }} + +"# + ) + .to_string(), + ) + .add_file( + "member/Cargo.toml", + format!( + r#" +[package] +name = "{name}-member" +version = "0.0.0" +edition = "2021" + +[dependencies] +insta = {{ workspace = true }} +"# + ) + .to_string(), + ) + .add_file( + "member/src/lib.rs", + r#" +#[test] +fn test_member() { + insta::assert_debug_snapshot!(vec![1, 2, 3]); +} +"# + .to_string(), + ) + .add_file( + "src/main.rs", + r#" +fn main() { + println!("Hello, world!"); +} + +#[test] +fn test_root() { + insta::assert_debug_snapshot!(vec![1, 2, 3]); +} +"# + .to_string(), + ) +} + +/// Check that in a workspace with a default root crate, running `cargo insta +/// test --workspace --accept` will update snapshots in both the root crate and the +/// member crate. +#[test] +fn test_root_crate_workspace_accept() { + let test_project = + workspace_with_root_crate("root-crate-workspace-accept".to_string()).create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept", "--workspace"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r###" + --- Original file tree + +++ Updated file tree + @@ -1,8 +1,13 @@ + + + Cargo.lock + Cargo.toml + member + member/Cargo.toml + member/src + member/src/lib.rs + + member/src/snapshots + + member/src/snapshots/root_crate_workspace_accept_member__member.snap + src + src/main.rs + + src/snapshots + + src/snapshots/root_crate_workspace_accept__root.snap + "### ); +} + +/// Check that in a workspace with a default root crate, running `cargo insta +/// test --workspace` will correctly report the number of pending snapshots +#[test] +fn test_root_crate_workspace() { + let test_project = + workspace_with_root_crate("root-crate-workspace".to_string()).create_project(); + + let output = test_project + .insta_cmd() + // Need to disable colors to assert the output below + .args(["test", "--workspace", "--color=never"]) + .stderr(Stdio::piped()) + .output() + .unwrap(); + + // 1.39 had a bug where it would claim there were 3 snapshots here + assert!( + String::from_utf8_lossy(&output.stderr).contains("info: 2 snapshots to review"), + "{}", + String::from_utf8_lossy(&output.stderr) + ); +} + +/// Check that in a workspace with a default root crate, running `cargo insta +/// test --accept` will only update snapshots in the root crate +#[test] +fn test_root_crate_no_all() { + let test_project = workspace_with_root_crate("root-crate-no-all".to_string()).create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r###" + --- Original file tree + +++ Updated file tree + @@ -1,4 +1,5 @@ + + + Cargo.lock + Cargo.toml + member + member/Cargo.toml + @@ -6,3 +7,5 @@ + member/src/lib.rs + src + src/main.rs + + src/snapshots + + src/snapshots/root_crate_no_all__root.snap + "### ); +} + +fn workspace_with_virtual_manifest(name: String) -> TestFiles { + TestFiles::new() + .add_file( + "Cargo.toml", + r#" +[workspace] +members = [ + "member-1", + "member-2", +] + +[workspace.dependencies] +insta = {path = '$PROJECT_PATH'} +"# + .to_string() + .to_string(), + ) + .add_file( + "member-1/Cargo.toml", + format!( + r#" +[package] +name = "{name}-member-1" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = {{ workspace = true }} +"# + ) + .to_string(), + ) + .add_file( + "member-1/src/lib.rs", + r#" +#[test] +fn test_member_1() { + insta::assert_debug_snapshot!(vec![1, 2, 3]); +} +"# + .to_string(), + ) + .add_file( + "member-2/Cargo.toml", + format!( + r#" +[package] +name = "{name}-member-2" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = {{ workspace = true }} +"# + ) + .to_string(), + ) + .add_file( + "member-2/src/lib.rs", + r#" +#[test] +fn test_member_2() { + insta::assert_debug_snapshot!(vec![4, 5, 6]); +} +"# + .to_string(), + ) +} + +/// Check that in a workspace with a virtual manifest, running `cargo insta test +/// --workspace --accept` updates snapshots in all member crates. +#[test] +fn test_virtual_manifest_all() { + let test_project = + workspace_with_virtual_manifest("virtual-manifest-all".to_string()).create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept", "--workspace"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r###" + --- Original file tree + +++ Updated file tree + @@ -1,10 +1,15 @@ + + + Cargo.lock + Cargo.toml + member-1 + member-1/Cargo.toml + member-1/src + member-1/src/lib.rs + + member-1/src/snapshots + + member-1/src/snapshots/virtual_manifest_all_member_1__member_1.snap + member-2 + member-2/Cargo.toml + member-2/src + member-2/src/lib.rs + + member-2/src/snapshots + + member-2/src/snapshots/virtual_manifest_all_member_2__member_2.snap + "### ); +} + +/// Check that in a workspace with a virtual manifest, running `cargo insta test +/// --accept` updates snapshots in all member crates. +#[test] +fn test_virtual_manifest_default() { + let test_project = + workspace_with_virtual_manifest("virtual-manifest-default".to_string()).create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r###" + --- Original file tree + +++ Updated file tree + @@ -1,10 +1,15 @@ + + + Cargo.lock + Cargo.toml + member-1 + member-1/Cargo.toml + member-1/src + member-1/src/lib.rs + + member-1/src/snapshots + + member-1/src/snapshots/virtual_manifest_default_member_1__member_1.snap + member-2 + member-2/Cargo.toml + member-2/src + member-2/src/lib.rs + + member-2/src/snapshots + + member-2/src/snapshots/virtual_manifest_default_member_2__member_2.snap + "### ); +} + +/// Check that in a workspace with a virtual manifest, running `cargo insta test +/// -p ` will only update snapshots in that crate. +#[test] +fn test_virtual_manifest_single_crate() { + let test_project = + workspace_with_virtual_manifest("virtual-manifest-single".to_string()).create_project(); + + let output = test_project + .insta_cmd() + .args(["test", "--accept", "-p", "virtual-manifest-single-member-1"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + assert_snapshot!(test_project.file_tree_diff(), @r###" + --- Original file tree + +++ Updated file tree + @@ -1,9 +1,12 @@ + + + Cargo.lock + Cargo.toml + member-1 + member-1/Cargo.toml + member-1/src + member-1/src/lib.rs + + member-1/src/snapshots + + member-1/src/snapshots/virtual_manifest_single_member_1__member_1.snap + member-2 + member-2/Cargo.toml + member-2/src + "### ); +} + +// Can't get the test binary discovery to work on Windows, don't have a windows +// machine to hand, others are welcome to fix it. (No specific reason to think +// that insta doesn't work on windows, just that the test doesn't work.) +#[cfg(not(target_os = "windows"))] +#[test] +fn test_insta_workspace_root() { + use std::{ + fs::{self, remove_dir_all}, + path::{Path, PathBuf}, + process::Command, + }; + + use crate::TestProject; + + // This function locates the compiled test binary in the target directory. + // It's necessary because the exact filename of the test binary includes a hash + // that we can't predict, so we need to search for it. + fn find_test_binary(dir: &Path) -> PathBuf { + dir.join("target/debug/deps") + .read_dir() + .unwrap() + .filter_map(Result::ok) + .find(|entry| { + let file_name = entry.file_name(); + let file_name_str = file_name.to_str().unwrap_or(""); + // We're looking for a file that: + file_name_str.starts_with("insta_workspace_root_test-") // Matches our test name + && !file_name_str.contains('.') // Doesn't have an extension (it's the executable, not a metadata file) + && entry.metadata().map(|m| m.is_file()).unwrap_or(false) // Is a file, not a directory + }) + .map(|entry| entry.path()) + .expect("Failed to find test binary") + } + + fn run_test_binary( + binary_path: &Path, + current_dir: &Path, + env: Option<(&str, &str)>, + ) -> std::process::Output { + let mut cmd = Command::new(binary_path); + TestProject::clean_env(&mut cmd); + cmd.current_dir(current_dir); + if let Some((key, value)) = env { + cmd.env(key, value); + } + cmd.output().unwrap() + } + + let test_project = TestFiles::new() + .add_file( + "Cargo.toml", + r#" + [package] + name = "insta_workspace_root_test" + version = "0.1.0" + edition = "2021" + + [dependencies] + insta = { path = '$PROJECT_PATH' } + "# + .to_string(), + ) + .add_file( + "src/lib.rs", + r#" +use insta::assert_snapshot; + +#[test] +fn test_snapshot() { + assert_snapshot!("Hello, world!"); +} + "# + .to_string(), + ) + .create_project(); + + let mut cargo_cmd = Command::new("cargo"); + TestProject::clean_env(&mut cargo_cmd); + let output = cargo_cmd + .args(["test", "--no-run"]) + .current_dir(&test_project.workspace_dir) + .output() + .unwrap(); + assert!(&output.status.success()); + + let test_binary_path = find_test_binary(&test_project.workspace_dir); + + // Run the test without snapshot (should fail) + assert!( + !&run_test_binary(&test_binary_path, &test_project.workspace_dir, None,) + .status + .success() + ); + + // Create the snapshot + assert!(&run_test_binary( + &test_binary_path, + &test_project.workspace_dir, + Some(("INSTA_UPDATE", "always")), + ) + .status + .success()); + + // Verify snapshot creation + assert!(test_project.workspace_dir.join("src/snapshots").exists()); + assert!(test_project + .workspace_dir + .join("src/snapshots/insta_workspace_root_test__snapshot.snap") + .exists()); + + // Move the workspace + let moved_workspace = { + let moved_workspace = PathBuf::from("/tmp/cargo-insta-test-moved"); + remove_dir_all(&moved_workspace).ok(); + fs::create_dir(&moved_workspace).unwrap(); + fs::rename(&test_project.workspace_dir, &moved_workspace).unwrap(); + moved_workspace + }; + let moved_binary_path = find_test_binary(&moved_workspace); + + // Run test in moved workspace without INSTA_WORKSPACE_ROOT (should fail) + assert!( + !&run_test_binary(&moved_binary_path, &moved_workspace, None) + .status + .success() + ); + + // Run test in moved workspace with INSTA_WORKSPACE_ROOT (should pass) + assert!(&run_test_binary( + &moved_binary_path, + &moved_workspace, + Some(("INSTA_WORKSPACE_ROOT", moved_workspace.to_str().unwrap())), + ) + .status + .success()); +} + +#[test] +fn test_external_test_path() { + let test_project = TestFiles::new() + .add_file( + "proj/Cargo.toml", + r#" +[package] +name = "external_test_path" +version = "0.1.0" +edition = "2021" + +[dependencies] +insta = { path = '$PROJECT_PATH' } + +[[test]] +name = "tlib" +path = "../tests/lib.rs" +"# + .to_string(), + ) + .add_file( + "proj/src/lib.rs", + r#" +pub fn hello() -> String { + "Hello, world!".to_string() +} +"# + .to_string(), + ) + .add_file( + "tests/lib.rs", + r#" +use external_test_path::hello; + +#[test] +fn test_hello() { + insta::assert_snapshot!(hello()); +} +"# + .to_string(), + ) + .create_project(); + + // Change to the proj directory for running cargo commands + let proj_dir = test_project.workspace_dir.join("proj"); + + // Initially, the test should fail + let output = test_project + .insta_cmd() + .current_dir(&proj_dir) + .args(["test", "--"]) + .output() + .unwrap(); + + assert!(!&output.status.success()); + + // Verify that the snapshot was created in the correct location + assert_snapshot!(TestProject::current_file_tree(&test_project.workspace_dir), @r" + proj + proj/Cargo.lock + proj/Cargo.toml + proj/src + proj/src/lib.rs + tests + tests/lib.rs + tests/snapshots + tests/snapshots/tlib__hello.snap.new + "); + + // Run cargo insta accept + let output = test_project + .insta_cmd() + .current_dir(&proj_dir) + .args(["test", "--accept"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + // Verify that the snapshot was created in the correct location + assert_snapshot!(TestProject::current_file_tree(&test_project.workspace_dir), @r" + proj + proj/Cargo.lock + proj/Cargo.toml + proj/src + proj/src/lib.rs + tests + tests/lib.rs + tests/snapshots + tests/snapshots/tlib__hello.snap + "); + + // Run the test again, it should pass now + let output = Command::new(env!("CARGO_BIN_EXE_cargo-insta")) + .current_dir(&proj_dir) + .args(["test"]) + .output() + .unwrap(); + + assert!(&output.status.success()); + + let snapshot_path = test_project + .workspace_dir + .join("tests/snapshots/tlib__hello.snap"); + assert_snapshot!(fs::read_to_string(snapshot_path).unwrap(), @r#" + --- + source: "../tests/lib.rs" + expression: hello() + snapshot_kind: text + --- + Hello, world! + "#); +}