diff --git a/tests/dsv_cli_tests.rs b/tests/dsv_cli_tests.rs index c9c6ab65c..9f702e2ca 100644 --- a/tests/dsv_cli_tests.rs +++ b/tests/dsv_cli_tests.rs @@ -36,11 +36,7 @@ fn succinctly_bin() -> &'static Path { String::from_utf8_lossy(&output.stderr) ); - let mut path = std::env::current_exe().expect("resolve current_exe"); - path.pop(); // drop the test executable's file name -> `.../deps` - if path.file_name().and_then(|s| s.to_str()) == Some("deps") { - path.pop(); // drop `deps` -> `.../` - } + let mut path = target_profile_dir_from_test_exe(); path.push(format!("succinctly{}", std::env::consts::EXE_SUFFIX)); assert!( path.is_file(), @@ -51,6 +47,24 @@ fn succinctly_bin() -> &'static Path { }) } +/// Derive `//` from this test executable's own path. +/// +/// The classic flat layout places the test exe at +/// `//deps/-`, but nightly's build-dir-layout-v2 +/// (rust-lang/cargo#17258, defaulted on nightly toolchains from ~2026-07) +/// instead nests it at `//build///out/-`. +/// Both layouts keep `` as the path component immediately after +/// `target`, so locate it that way instead of assuming a fixed depth. +fn target_profile_dir_from_test_exe() -> PathBuf { + let current_exe = std::env::current_exe().expect("resolve current_exe"); + let components: Vec<_> = current_exe.components().collect(); + let target_idx = components + .iter() + .rposition(|c| c.as_os_str() == "target") + .expect("test executable path has no `target` component"); + components[..=target_idx + 1].iter().collect() +} + /// Run `dsv generate` and capture stdout, stderr, and exit code. fn run_generate(size: &str, extra_args: &[&str]) -> Result<(String, String, i32)> { let output = Command::new(succinctly_bin()) diff --git a/tests/json_validate_tests.rs b/tests/json_validate_tests.rs index 6aabab04d..c58dcd474 100644 --- a/tests/json_validate_tests.rs +++ b/tests/json_validate_tests.rs @@ -38,13 +38,9 @@ fn succinctly_bin() -> &'static Path { String::from_utf8_lossy(&output.stderr) ); - // The test executable lives at `//deps/-`; - // the CLI binary is its sibling at `//succinctly`. - let mut path = std::env::current_exe().expect("resolve current_exe"); - path.pop(); // drop the test executable's file name -> `.../deps` - if path.file_name().and_then(|s| s.to_str()) == Some("deps") { - path.pop(); // drop `deps` -> `.../` - } + // The CLI binary is `//succinctly`, a sibling of the + // test executable's own `//` ancestor. + let mut path = target_profile_dir_from_test_exe(); path.push(format!("succinctly{}", std::env::consts::EXE_SUFFIX)); assert!( path.is_file(), @@ -55,6 +51,24 @@ fn succinctly_bin() -> &'static Path { }) } +/// Derive `//` from this test executable's own path. +/// +/// The classic flat layout places the test exe at +/// `//deps/-`, but nightly's build-dir-layout-v2 +/// (rust-lang/cargo#17258, defaulted on nightly toolchains from ~2026-07) +/// instead nests it at `//build///out/-`. +/// Both layouts keep `` as the path component immediately after +/// `target`, so locate it that way instead of assuming a fixed depth. +fn target_profile_dir_from_test_exe() -> PathBuf { + let current_exe = std::env::current_exe().expect("resolve current_exe"); + let components: Vec<_> = current_exe.components().collect(); + let target_idx = components + .iter() + .rposition(|c| c.as_os_str() == "target") + .expect("test executable path has no `target` component"); + components[..=target_idx + 1].iter().collect() +} + /// Helper to run `json validate` with input from stdin. fn run_validate_stdin(input: &str, extra_args: &[&str]) -> Result<(String, String, i32)> { let mut cmd = Command::new(succinctly_bin()) diff --git a/tests/text_cli_tests.rs b/tests/text_cli_tests.rs index 20bd55272..7c3da359e 100644 --- a/tests/text_cli_tests.rs +++ b/tests/text_cli_tests.rs @@ -38,11 +38,7 @@ fn succinctly_bin() -> &'static Path { String::from_utf8_lossy(&output.stderr) ); - let mut path = std::env::current_exe().expect("resolve current_exe"); - path.pop(); // drop the test executable's file name -> `.../deps` - if path.file_name().and_then(|s| s.to_str()) == Some("deps") { - path.pop(); // drop `deps` -> `.../` - } + let mut path = target_profile_dir_from_test_exe(); path.push(format!("succinctly{}", std::env::consts::EXE_SUFFIX)); assert!( path.is_file(), @@ -53,6 +49,24 @@ fn succinctly_bin() -> &'static Path { }) } +/// Derive `//` from this test executable's own path. +/// +/// The classic flat layout places the test exe at +/// `//deps/-`, but nightly's build-dir-layout-v2 +/// (rust-lang/cargo#17258, defaulted on nightly toolchains from ~2026-07) +/// instead nests it at `//build///out/-`. +/// Both layouts keep `` as the path component immediately after +/// `target`, so locate it that way instead of assuming a fixed depth. +fn target_profile_dir_from_test_exe() -> PathBuf { + let current_exe = std::env::current_exe().expect("resolve current_exe"); + let components: Vec<_> = current_exe.components().collect(); + let target_idx = components + .iter() + .rposition(|c| c.as_os_str() == "target") + .expect("test executable path has no `target` component"); + components[..=target_idx + 1].iter().collect() +} + /// Run `text validate utf8` with raw bytes piped on stdin. fn run_validate_stdin(input: &[u8], extra_args: &[&str]) -> Result<(Vec, String, i32)> { let mut cmd = Command::new(succinctly_bin()) diff --git a/tests/yaml_validate_tests.rs b/tests/yaml_validate_tests.rs index 52d79c1d4..7cf52f6bb 100644 --- a/tests/yaml_validate_tests.rs +++ b/tests/yaml_validate_tests.rs @@ -28,11 +28,7 @@ fn succinctly_bin() -> &'static Path { String::from_utf8_lossy(&output.stderr) ); - let mut path = std::env::current_exe().expect("resolve current_exe"); - path.pop(); - if path.file_name().and_then(|s| s.to_str()) == Some("deps") { - path.pop(); - } + let mut path = target_profile_dir_from_test_exe(); path.push(format!("succinctly{}", std::env::consts::EXE_SUFFIX)); assert!( path.is_file(), @@ -43,6 +39,24 @@ fn succinctly_bin() -> &'static Path { }) } +/// Derive `//` from this test executable's own path. +/// +/// The classic flat layout places the test exe at +/// `//deps/-`, but nightly's build-dir-layout-v2 +/// (rust-lang/cargo#17258, defaulted on nightly toolchains from ~2026-07) +/// instead nests it at `//build///out/-`. +/// Both layouts keep `` as the path component immediately after +/// `target`, so locate it that way instead of assuming a fixed depth. +fn target_profile_dir_from_test_exe() -> PathBuf { + let current_exe = std::env::current_exe().expect("resolve current_exe"); + let components: Vec<_> = current_exe.components().collect(); + let target_idx = components + .iter() + .rposition(|c| c.as_os_str() == "target") + .expect("test executable path has no `target` component"); + components[..=target_idx + 1].iter().collect() +} + fn run_validate_stdin(input: &str, extra_args: &[&str]) -> Result<(String, String, i32)> { let mut cmd = Command::new(succinctly_bin()) .args(["yaml", "validate"])