diff --git a/tests/tools/.gitignore b/tests/tools/.gitignore new file mode 100644 index 000000000..67fc140b9 --- /dev/null +++ b/tests/tools/.gitignore @@ -0,0 +1 @@ +fixtures/ diff --git a/tests/tools/src/lib.rs b/tests/tools/src/lib.rs index 087bc8e7b..af13d4e8e 100644 --- a/tests/tools/src/lib.rs +++ b/tests/tools/src/lib.rs @@ -492,11 +492,7 @@ pub fn scripted_fixture_read_only_with_args_standalone_single_archive( /// Ok(()) /// } /// ``` -pub fn rust_fixture_read_only( - name: &str, - version: u32, - make_fixture: impl FnOnce(&Path) -> Result, -) -> Result { +pub fn rust_fixture_read_only(name: &str, version: u32, make_fixture: impl FnOnce(&Path) -> Result) -> Result { rust_fixture_read_only_inner(name, version, make_fixture, None, DirectoryRoot::IntegrationTest) } @@ -593,18 +589,17 @@ fn rust_fixture_read_only_inner( let archive_name = format!("rust-{name}"); let archive_file_path = fixture_path_inner( - Path::new("generated-archives").join(format!( - "{archive_name}.tar{}", - if cfg!(feature = "xz") { ".xz" } else { "" } - )), + Path::new("generated-archives").join(format!("{archive_name}.{}", tar_extension())), root, ); let (force_run, script_result_directory) = destination_dir.map_or_else( || { let dir = fixture_path_inner( - Path::new("generated-do-not-edit") - .join(&archive_name) - .join(format!("{}-{}", script_identity, family_name())), + Path::new("generated-do-not-edit").join(&archive_name).join(format!( + "{}-{}", + script_identity, + family_name() + )), root, ); (false, dir) @@ -727,9 +722,9 @@ fn scripted_fixture_read_only_with_args_inner( ArgsInHash::No => "".into(), }; Path::new("generated-archives").join(format!( - "{}{suffix}.tar{}", + "{}{suffix}.{}", script_basename.to_str().expect("valid UTF-8"), - if cfg!(feature = "xz") { ".xz" } else { "" } + tar_extension() )) }, root, @@ -1220,133 +1215,13 @@ pub fn umask() -> u32 { u32::from_str_radix(text, 8).expect("parses as octal number") } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn parse_version() { - assert_eq!(git_version_from_bytes(b"git version 2.37.2").unwrap(), (2, 37, 2)); - assert_eq!( - git_version_from_bytes(b"git version 2.32.1 (Apple Git-133)").unwrap(), - (2, 32, 1) - ); - } - - #[test] - fn parse_version_with_trailing_newline() { - assert_eq!(git_version_from_bytes(b"git version 2.37.2\n").unwrap(), (2, 37, 2)); - } - - const SCOPE_ENV_VALUE: &str = "gitconfig"; - - fn populate_ad_hoc_config_files(dir: &Path) { - const CONFIG_DATA: &[u8] = b"[foo]\n\tbar = baz\n"; - - let paths: &[PathBuf] = if cfg!(windows) { - let unc_literal_nul = dir.canonicalize().expect("directory exists").join("nul"); - &[dir.join(SCOPE_ENV_VALUE), dir.join("-"), unc_literal_nul] - } else { - &[dir.join(SCOPE_ENV_VALUE), dir.join("-"), dir.join(":")] - }; - // Create the files. - for path in paths { - std::fs::write(path, CONFIG_DATA).expect("can write contents"); - } - // Verify the files. This is mostly to show we really made a `\\?\...\nul` on Windows. - for path in paths { - let buf = std::fs::read(path).expect("the file really exists"); - assert_eq!(buf, CONFIG_DATA, "{path:?} should be a config file"); - } - } - - #[test] - fn configure_command_clears_external_config() { - let temp = tempfile::TempDir::new().expect("can create temp dir"); - populate_ad_hoc_config_files(temp.path()); - - let mut cmd = std::process::Command::new(GIT_PROGRAM); - cmd.env("GIT_CONFIG_SYSTEM", SCOPE_ENV_VALUE); - cmd.env("GIT_CONFIG_GLOBAL", SCOPE_ENV_VALUE); - configure_command(&mut cmd, ["config", "-l", "--show-origin"], temp.path()); - - let output = cmd.output().expect("can run git"); - let lines: Vec<_> = output - .stdout - .to_str() - .expect("valid UTF-8") - .lines() - .filter(|line| !line.starts_with("command line:\t")) - .collect(); - let status = output.status.code().expect("terminated normally"); - assert_eq!(lines, Vec::<&str>::new(), "should be no config variables from files"); - assert_eq!(status, 0, "reading the config should succeed"); - } - - #[test] - #[cfg(windows)] - fn bash_program_ok_for_platform() { - let path = bash_program(); - assert!(path.is_absolute()); - - let for_version = std::process::Command::new(path) - .arg("--version") - .output() - .expect("can pass it `--version`"); - assert!(for_version.status.success(), "passing `--version` succeeds"); - let version_line = for_version - .stdout - .lines() - .nth(0) - .expect("`--version` output has first line"); - assert!( - version_line.ends_with(b"-pc-msys)"), // On Windows, "-pc-linux-gnu)" would be WSL. - "it is an MSYS bash (such as Git Bash)" - ); - - let for_uname_os = std::process::Command::new(path) - .args(["-c", "uname -o"]) - .output() - .expect("can tell it to run `uname -o`"); - assert!(for_uname_os.status.success(), "telling it to run `uname -o` succeeds"); - assert_eq!( - for_uname_os.stdout.trim_end(), - b"Msys", - "it runs commands in an MSYS environment" - ); - } - - #[test] - #[cfg(not(windows))] - fn bash_program_ok_for_platform() { - assert_eq!(bash_program(), Path::new("bash")); - } - - #[test] - fn bash_program_unix_path() { - let path = bash_program() - .to_str() - .expect("This test depends on the bash path being valid Unicode"); - assert!( - !path.contains('\\'), - "The path to bash should have no backslashes, barring very unusual environments" - ); - } - - fn is_rooted_relative(path: impl AsRef) -> bool { - let p = path.as_ref(); - p.is_relative() && p.has_root() - } - - #[test] - #[cfg(windows)] - fn unix_style_absolute_is_rooted_relative() { - assert!(is_rooted_relative("/bin/bash"), "can detect paths like /bin/bash"); - } - - #[test] - fn bash_program_absolute_or_unrooted() { - let bash = bash_program(); - assert!(!is_rooted_relative(bash), "{bash:?}"); +fn tar_extension() -> &'static str { + if cfg!(feature = "xz") { + ".tar.xz" + } else { + ".tar" } } + +#[cfg(test)] +mod tests; diff --git a/tests/tools/src/tests.rs b/tests/tools/src/tests.rs new file mode 100644 index 000000000..049a379e1 --- /dev/null +++ b/tests/tools/src/tests.rs @@ -0,0 +1,127 @@ +use super::*; + +#[test] +fn parse_version() { + assert_eq!(git_version_from_bytes(b"git version 2.37.2").unwrap(), (2, 37, 2)); + assert_eq!( + git_version_from_bytes(b"git version 2.32.1 (Apple Git-133)").unwrap(), + (2, 32, 1) + ); +} + +#[test] +fn parse_version_with_trailing_newline() { + assert_eq!(git_version_from_bytes(b"git version 2.37.2\n").unwrap(), (2, 37, 2)); +} + +const SCOPE_ENV_VALUE: &str = "gitconfig"; + +fn populate_ad_hoc_config_files(dir: &Path) { + const CONFIG_DATA: &[u8] = b"[foo]\n\tbar = baz\n"; + + let paths: &[PathBuf] = if cfg!(windows) { + let unc_literal_nul = dir.canonicalize().expect("directory exists").join("nul"); + &[dir.join(SCOPE_ENV_VALUE), dir.join("-"), unc_literal_nul] + } else { + &[dir.join(SCOPE_ENV_VALUE), dir.join("-"), dir.join(":")] + }; + // Create the files. + for path in paths { + std::fs::write(path, CONFIG_DATA).expect("can write contents"); + } + // Verify the files. This is mostly to show we really made a `\\?\...\nul` on Windows. + for path in paths { + let buf = std::fs::read(path).expect("the file really exists"); + assert_eq!(buf, CONFIG_DATA, "{path:?} should be a config file"); + } +} + +#[test] +fn configure_command_clears_external_config() { + let temp = tempfile::TempDir::new().expect("can create temp dir"); + populate_ad_hoc_config_files(temp.path()); + + let mut cmd = std::process::Command::new(GIT_PROGRAM); + cmd.env("GIT_CONFIG_SYSTEM", SCOPE_ENV_VALUE); + cmd.env("GIT_CONFIG_GLOBAL", SCOPE_ENV_VALUE); + configure_command(&mut cmd, ["config", "-l", "--show-origin"], temp.path()); + + let output = cmd.output().expect("can run git"); + let lines: Vec<_> = output + .stdout + .to_str() + .expect("valid UTF-8") + .lines() + .filter(|line| !line.starts_with("command line:\t")) + .collect(); + let status = output.status.code().expect("terminated normally"); + assert_eq!(lines, Vec::<&str>::new(), "should be no config variables from files"); + assert_eq!(status, 0, "reading the config should succeed"); +} + +#[test] +#[cfg(windows)] +fn bash_program_ok_for_platform() { + let path = bash_program(); + assert!(path.is_absolute()); + + let for_version = std::process::Command::new(path) + .arg("--version") + .output() + .expect("can pass it `--version`"); + assert!(for_version.status.success(), "passing `--version` succeeds"); + let version_line = for_version + .stdout + .lines() + .nth(0) + .expect("`--version` output has first line"); + assert!( + version_line.ends_with(b"-pc-msys)"), // On Windows, "-pc-linux-gnu)" would be WSL. + "it is an MSYS bash (such as Git Bash)" + ); + + let for_uname_os = std::process::Command::new(path) + .args(["-c", "uname -o"]) + .output() + .expect("can tell it to run `uname -o`"); + assert!(for_uname_os.status.success(), "telling it to run `uname -o` succeeds"); + assert_eq!( + for_uname_os.stdout.trim_end(), + b"Msys", + "it runs commands in an MSYS environment" + ); +} + +#[test] +#[cfg(not(windows))] +fn bash_program_ok_for_platform() { + assert_eq!(bash_program(), Path::new("bash")); +} + +#[test] +fn bash_program_unix_path() { + let path = bash_program() + .to_str() + .expect("This test depends on the bash path being valid Unicode"); + assert!( + !path.contains('\\'), + "The path to bash should have no backslashes, barring very unusual environments" + ); +} + +fn is_rooted_relative(path: impl AsRef) -> bool { + let p = path.as_ref(); + p.is_relative() && p.has_root() +} + +#[test] +#[cfg(windows)] +fn unix_style_absolute_is_rooted_relative() { + assert!(is_rooted_relative("/bin/bash"), "can detect paths like /bin/bash"); +} + +#[test] +fn bash_program_absolute_or_unrooted() { + let bash = bash_program(); + assert!(!is_rooted_relative(bash), "{bash:?}"); +} diff --git a/tests/tools/tests/rust_fixture.rs b/tests/tools/tests/rust_fixture.rs index f6e099496..ecc581946 100644 --- a/tests/tools/tests/rust_fixture.rs +++ b/tests/tools/tests/rust_fixture.rs @@ -1,12 +1,6 @@ -use std::path::Path; - use gix_testtools::{Creation, Result}; -use serial_test::serial; - -// Tests for Rust closure fixtures #[test] -#[serial] fn rust_fixture_read_only_creates_and_caches_fixture() -> Result { // First call should create the fixture let dir = gix_testtools::rust_fixture_read_only("test_fixture_read_only", 1, |dir| { @@ -40,7 +34,6 @@ fn rust_fixture_read_only_creates_and_caches_fixture() -> Result { } #[test] -#[serial] fn rust_fixture_read_only_version_change_invalidates_cache() -> Result { // Create fixture with version 1 let dir1 = gix_testtools::rust_fixture_read_only("test_fixture_version", 1, |dir| { @@ -65,69 +58,32 @@ fn rust_fixture_read_only_version_change_invalidates_cache() -> Result { } #[test] -#[serial] -fn rust_fixture_writable_copy_from_read_only() -> Result { - // Create a writable fixture by copying from read-only - let temp_dir = gix_testtools::rust_fixture_writable( - "test_fixture_writable_copy", - 1, - Creation::CopyFromReadOnly, - |dir| { +fn rust_fixture_writable() -> Result { + for creation in [Creation::CopyFromReadOnly, Creation::ExecuteScript] { + let tmp = gix_testtools::rust_fixture_writable("test_fixture_writable_copy", 1, creation, |dir| { std::fs::write(dir.join("original.txt"), "original content")?; Ok(()) - }, - )?; - - // Verify the fixture was created - let original_path = temp_dir.path().join("original.txt"); - assert!(original_path.exists()); - assert_eq!(std::fs::read_to_string(&original_path)?, "original content"); - - // Verify we can write to the directory (it's writable) - let new_file = temp_dir.path().join("new_file.txt"); - std::fs::write(&new_file, "new content")?; - assert!(new_file.exists()); - assert_eq!(std::fs::read_to_string(&new_file)?, "new content"); - - Ok(()) -} - -#[test] -#[serial] -fn rust_fixture_writable_execute_closure() -> Result { - // Create a writable fixture by executing the closure directly in temp dir - let temp_dir = gix_testtools::rust_fixture_writable( - "test_fixture_writable_exec", - 1, - Creation::ExecuteScript, - |dir| { - std::fs::write(dir.join("executed.txt"), "executed content")?; - Ok(()) - }, - )?; - - // Verify the fixture was created - let executed_path = temp_dir.path().join("executed.txt"); - assert!(executed_path.exists()); - assert_eq!(std::fs::read_to_string(&executed_path)?, "executed content"); - - // Verify we can write to the directory - let new_file = temp_dir.path().join("modified.txt"); - std::fs::write(&new_file, "modified")?; - assert!(new_file.exists()); - + })?; + + // Verify the fixture was created + let original_path = tmp.path().join("original.txt"); + assert!(original_path.exists()); + assert_eq!(std::fs::read_to_string(&original_path)?, "original content"); + + // Verify we can write to the directory (it's writable) + let new_file = tmp.path().join("new_file.txt"); + std::fs::write(&new_file, "new content")?; + assert!(new_file.exists()); + assert_eq!(std::fs::read_to_string(&new_file)?, "new content"); + } Ok(()) } #[test] -#[serial] fn rust_fixture_closure_error_propagates() { // Test that errors from the closure are properly propagated - let result = gix_testtools::rust_fixture_read_only("test_fixture_error", 1, |_dir| { - Err("intentional error".into()) - }); + let result = gix_testtools::rust_fixture_read_only("test_fixture_error", 1, |_dir| Err("intentional error".into())); - assert!(result.is_err()); let err_msg = result.unwrap_err().to_string(); assert!( err_msg.contains("Rust fixture closure"), @@ -140,7 +96,6 @@ fn rust_fixture_closure_error_propagates() { } #[test] -#[serial] fn rust_fixture_standalone_uses_fixtures_directory() -> Result { let dir = gix_testtools::rust_fixture_read_only_standalone("test_fixture_standalone", 1, |dir| { std::fs::write(dir.join("standalone.txt"), "standalone")?; @@ -161,33 +116,3 @@ fn rust_fixture_standalone_uses_fixtures_directory() -> Result { assert!(dir.join("standalone.txt").exists()); Ok(()) } - -#[test] -#[serial] -fn rust_fixture_directory_passed_to_closure_exists() -> Result { - let dir = gix_testtools::rust_fixture_read_only("test_fixture_dir_exists", 1, |dir| { - // The directory should exist when the closure is called - assert!(dir.is_dir(), "Directory should exist when closure is called"); - std::fs::write(dir.join("marker.txt"), "created")?; - Ok(()) - })?; - - assert!(dir.join("marker.txt").exists()); - Ok(()) -} - -fn helper_create_fixture(dir: &Path) -> Result { - std::fs::write(dir.join("helper_file.txt"), "from helper")?; - Ok(()) -} - -#[test] -#[serial] -fn rust_fixture_with_function_reference() -> Result { - // Test that we can pass a function reference instead of a closure - let dir = gix_testtools::rust_fixture_read_only("test_fixture_fn_ref", 1, helper_create_fixture)?; - - assert!(dir.join("helper_file.txt").exists()); - assert_eq!(std::fs::read_to_string(dir.join("helper_file.txt"))?, "from helper"); - Ok(()) -}