diff --git a/Cargo.lock b/Cargo.lock index 95fae292ede..8660353e652 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -472,7 +472,7 @@ version = "0.4.7" [[package]] name = "cargo-test-support" -version = "0.8.2" +version = "0.9.0" dependencies = [ "anstream", "anstyle", diff --git a/Cargo.toml b/Cargo.toml index 132360db883..1b5bbb1f93d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ cargo-credential-macos-keychain = { version = "0.4.18", path = "credential/cargo cargo-credential-wincred = { version = "0.4.18", path = "credential/cargo-credential-wincred" } cargo-platform = { path = "crates/cargo-platform", version = "0.3.0" } cargo-test-macro = { version = "0.4.7", path = "crates/cargo-test-macro" } -cargo-test-support = { version = "0.8.2", path = "crates/cargo-test-support" } +cargo-test-support = { version = "0.9.0", path = "crates/cargo-test-support" } cargo-util = { version = "0.2.25", path = "crates/cargo-util" } cargo-util-schemas = { version = "0.10.1", path = "crates/cargo-util-schemas" } cargo_metadata = "0.21.0" diff --git a/crates/cargo-test-support/Cargo.toml b/crates/cargo-test-support/Cargo.toml index 13d086b0809..e9e6406eece 100644 --- a/crates/cargo-test-support/Cargo.toml +++ b/crates/cargo-test-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-test-support" -version = "0.8.2" +version = "0.9.0" edition.workspace = true rust-version = "1.90" # MSRV:1 license.workspace = true diff --git a/crates/cargo-test-support/src/compare.rs b/crates/cargo-test-support/src/compare.rs index f1f3e4c2a66..2338d81ce7d 100644 --- a/crates/cargo-test-support/src/compare.rs +++ b/crates/cargo-test-support/src/compare.rs @@ -229,6 +229,12 @@ fn add_regex_redactions(subs: &mut snapbox::Redactions) { .unwrap(); subs.insert("[HASH]", regex!(r"/[a-z0-9\-_]+-(?[0-9a-f]{16})")) .unwrap(); + // Match multi-part hashes like `06/b451d0d6f88b1d` used in directory paths + subs.insert("[HASH]", regex!(r"/(?[a-f0-9]{2}\/[0-9a-f]{14})")) + .unwrap(); + // Match file name hashes like `foo-06b451d0d6f88b1d` + subs.insert("[HASH]", regex!(r"[a-z0-9]+-(?[a-f0-9]{16})")) + .unwrap(); subs.insert( "[AVG_ELAPSED]", regex!(r"(?[0-9]+(\.[0-9]+)?) ns/iter"), diff --git a/crates/cargo-test-support/src/paths.rs b/crates/cargo-test-support/src/paths.rs index cc6119bcc9f..10a0283a6d8 100644 --- a/crates/cargo-test-support/src/paths.rs +++ b/crates/cargo-test-support/src/paths.rs @@ -1,6 +1,8 @@ //! Access common paths and manipulate the filesystem use filetime::FileTime; +use itertools::Itertools; +use walkdir::WalkDir; use std::cell::RefCell; use std::env; @@ -12,6 +14,9 @@ use std::sync::Mutex; use std::sync::OnceLock; use std::sync::atomic::{AtomicUsize, Ordering}; +use crate::compare::assert_e2e; +use crate::compare::match_contains; + static CARGO_INTEGRATION_TEST_DIR: &str = "cit"; static GLOBAL_ROOT: OnceLock>> = OnceLock::new(); @@ -152,6 +157,10 @@ pub trait CargoPathExt { fn move_in_time(&self, travel_amount: F) where F: Fn(i64, u32) -> (i64, u32); + + fn assert_build_dir_layout(&self, expected: impl snapbox::IntoData); + + fn assert_dir_layout(&self, expected: impl snapbox::IntoData, ignored_path_patterns: &[String]); } impl CargoPathExt for Path { @@ -236,6 +245,43 @@ impl CargoPathExt for Path { }); } } + + #[track_caller] + fn assert_build_dir_layout(&self, expected: impl snapbox::IntoData) { + // We call `unordered()` here to because the build-dir has some scenarios that make + // consistent ordering not possible. + // Notably: + // 1. Binaries with `.exe` on Windows causing the ordering to change with the dep-info `.d` + // file. + // 2. Directories with hashes are often reordered differently by platform. + self.assert_dir_layout(expected.unordered(), &build_dir_ignored_path_patterns()); + } + + #[track_caller] + fn assert_dir_layout( + &self, + expected: impl snapbox::IntoData, + ignored_path_patterns: &[String], + ) { + let assert = assert_e2e(); + let actual = WalkDir::new(self) + .sort_by_file_name() + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_file()) + .map(|e| e.path().to_string_lossy().into_owned()) + .filter(|file| { + for ignored in ignored_path_patterns { + if match_contains(&ignored, file, &assert.redactions()).is_ok() { + return false; + } + } + return true; + }) + .join("\n"); + + assert.eq(format!("{actual}\n"), expected); + } } impl CargoPathExt for PathBuf { @@ -260,6 +306,21 @@ impl CargoPathExt for PathBuf { { self.as_path().move_in_time(travel_amount) } + + #[track_caller] + fn assert_build_dir_layout(&self, expected: impl snapbox::IntoData) { + self.as_path().assert_build_dir_layout(expected); + } + + #[track_caller] + fn assert_dir_layout( + &self, + expected: impl snapbox::IntoData, + ignored_path_patterns: &[String], + ) { + self.as_path() + .assert_dir_layout(expected, ignored_path_patterns); + } } fn do_op(path: &Path, desc: &str, mut f: F) @@ -290,6 +351,20 @@ where } } +/// The paths to ignore when [`CargoPathExt::assert_build_dir_layout`] is called +fn build_dir_ignored_path_patterns() -> Vec { + vec![ + // Ignore MacOS debug symbols as there are many files/directories that would clutter up + // tests few not a lot of benefit. + "[..].dSYM/[..]", + // Ignore Windows debub symbols files (.pdb) + "[..].pdb", + ] + .into_iter() + .map(ToString::to_string) + .collect() +} + /// Get the filename for a library. /// /// `kind` should be one of: diff --git a/src/doc/contrib/src/tests/writing.md b/src/doc/contrib/src/tests/writing.md index 34058506700..99eef916d3f 100644 --- a/src/doc/contrib/src/tests/writing.md +++ b/src/doc/contrib/src/tests/writing.md @@ -64,6 +64,16 @@ test. - See [`support::compare`] for an explanation of the string pattern matching. Patterns are used to make it easier to match against the expected output. +#### Filesystem layout testing + +Tests often to need to verify Cargo created/removed files. +The `CargoPathExt` trait (implemented by `Path` and `PathBuf`) provides a `assert_dir_layout()` to verify the files in a directory (including nested directories). +This takes a snapshot of file paths for the given directory and asserts that all files are present and no new files have been created. +This function also takes a list of patterns to ignore from the snapshot to make working with platform specific files easier. + +Note: You will commonly need to call `unordered()` before passing your snapshot to deal with platform differences like binaries having `.exe` on Windows. +`assert_build_dir_layout` is a more specialized version of `assert_dir_layout()` that is automatically unordered and ignores common platform specific files designed for the Cargo build cache. + #### Testing Nightly Features If you are testing a Cargo feature that only works on "nightly" Cargo, then diff --git a/tests/testsuite/build_dir.rs b/tests/testsuite/build_dir.rs index d3b8941a268..6af2799037f 100644 --- a/tests/testsuite/build_dir.rs +++ b/tests/testsuite/build_dir.rs @@ -6,15 +6,13 @@ //! file verify the files saved to disk are in the correct locations according to the `build-dir` //! configuration. //! -//! Tests check if directories match some "layout" by using [`assert_build_dir_layout`] and -//! [`assert_artifact_dir_layout`]. +//! Tests check if directories match some "layout" by using [`CargoPathExt::assert_file_layout`] use std::path::PathBuf; use crate::prelude::*; use cargo_test_support::registry::RegistryBuilder; -use cargo_test_support::{Project, prelude::*}; -use cargo_test_support::{paths, project, str}; +use cargo_test_support::{paths, prelude::*, project, str}; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX, EXE_SUFFIX}; #[cargo_test] @@ -33,20 +31,30 @@ fn binary_with_debug() { p.cargo("build").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - assert_artifact_dir_layout(p.root().join("target-dir"), "debug"); - assert_exists_patterns_with_base_dir( - &p.root(), - &[ - // Check the pre-uplifted binary in the build-dir - &format!("build-dir/debug/deps/foo*{EXE_SUFFIX}"), - "build-dir/debug/deps/foo*.d", - // Verify the binary was copied to the target-dir - &format!("target-dir/debug/foo{EXE_SUFFIX}"), - "target-dir/debug/foo.d", - ], - ); assert_not_exists(&p.root().join("target")); + + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/deps/foo[..].d + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/foo[EXE] +[ROOT]/foo/target-dir/debug/foo.d + +"#]]); } #[cargo_test] @@ -65,8 +73,6 @@ fn binary_with_release() { p.cargo("build --release").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "release"); - assert_exists(&p.root().join(format!("target-dir/release/foo{EXE_SUFFIX}"))); assert_exists_patterns_with_base_dir( &p.root(), &[ @@ -78,6 +84,28 @@ fn binary_with_release() { "target-dir/release/foo.d", ], ); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/release/.cargo-lock +[ROOT]/foo/build-dir/release/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/release/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/release/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/release/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/release/deps/foo[..][EXE] +[ROOT]/foo/build-dir/release/deps/foo[..].d + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/release/.cargo-lock +[ROOT]/foo/target-dir/release/foo[EXE] +[ROOT]/foo/target-dir/release/foo.d + +"#]]); } #[cargo_test] @@ -146,8 +174,6 @@ fn libs() { p.cargo("build").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - // Verify lib artifacts were copied into the artifact dir assert_exists_patterns_with_base_dir(&p.root().join("target-dir/debug"), &expected_files); } @@ -161,8 +187,20 @@ fn should_default_to_target() { p.cargo("build").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("target"), "debug"); - assert_exists(&p.root().join(format!("target/debug/foo{EXE_SUFFIX}"))); + p.root().join("target").assert_build_dir_layout(str![[r#" +[ROOT]/foo/target/.rustc_info.json +[ROOT]/foo/target/CACHEDIR.TAG +[ROOT]/foo/target/debug/.cargo-lock +[ROOT]/foo/target/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/target/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/target/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/target/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/target/debug/deps/foo[..][EXE] +[ROOT]/foo/target/debug/deps/foo[..].d +[ROOT]/foo/target/debug/foo[EXE] +[ROOT]/foo/target/debug/foo.d + +"#]]); } #[cargo_test] @@ -176,8 +214,18 @@ fn should_respect_env_var() { .enable_mac_dsym() .run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - assert_exists(&p.root().join(format!("target/debug/foo{EXE_SUFFIX}"))); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/deps/foo[..].d + +"#]]); } #[cargo_test] @@ -208,14 +256,32 @@ fn build_script_should_output_to_build_dir() { p.cargo("build").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - assert_exists_patterns_with_base_dir( - &p.root(), - &[ - &format!("build-dir/debug/build/foo-*/build-script-build{EXE_SUFFIX}"), - "build-dir/debug/build/foo-*/out/foo.txt", // Verify OUT_DIR - ], - ); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/deps/foo[..].d +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/run-build-script-build-script-build +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/run-build-script-build-script-build.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-build-script-build-script-build +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/build-script-build-script-build +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/build-script-build-script-build.json +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/build_script_build[..].d +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/build_script_build[..][EXE] +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/build-script-build[EXE] +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/out/foo.txt +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/output +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/stderr +[ROOT]/foo/build-dir/debug/build/foo-[HASH]/root-output + +"#]]); } #[cargo_test] @@ -247,8 +313,40 @@ fn cargo_tmpdir_should_output_to_build_dir() { p.cargo("test").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - assert_exists(&p.root().join(format!("build-dir/tmp/foo.txt"))); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/deps/foo-[HASH].d +[ROOT]/foo/build-dir/debug/deps/foo-[HASH].d +[ROOT]/foo/build-dir/debug/deps/foo[..].d +[ROOT]/foo/build-dir/debug/deps/foo-[HASH][EXE] +[ROOT]/foo/build-dir/debug/deps/foo-[HASH][EXE] +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-test-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/test-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/test-bin-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-test-integration-test-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/test-integration-test-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/test-integration-test-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/tmp/foo.txt +[ROOT]/foo/build-dir/.rustc_info.json + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/foo[EXE] + +"#]]); } #[cargo_test] @@ -268,18 +366,28 @@ fn examples_should_output_to_build_dir_and_uplift_to_target_dir() { p.cargo("build --examples").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - assert_exists_patterns_with_base_dir( - &p.root(), - &[ - // uplifted (target-dir) - &format!("target-dir/debug/examples/foo{EXE_SUFFIX}"), - "target-dir/debug/examples/foo.d", - // pre-uplifted (build-dir) - &format!("build-dir/debug/examples/foo*{EXE_SUFFIX}"), - "build-dir/debug/examples/foo*.d", - ], - ); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-example-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/example-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/example-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/examples/foo[..][EXE] +[ROOT]/foo/build-dir/debug/examples/foo[..].d + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/examples/foo[EXE] +[ROOT]/foo/target-dir/debug/examples/foo.d + +"#]]); } #[cargo_test] @@ -299,14 +407,33 @@ fn benches_should_output_to_build_dir() { p.cargo("build --bench=foo").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - assert_exists_patterns_with_base_dir( - &p.root(), - &[ - &format!("build-dir/debug/deps/foo*{EXE_SUFFIX}"), - "build-dir/debug/deps/foo*.d", - ], - ); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/deps/foo-[HASH].d +[ROOT]/foo/build-dir/debug/deps/foo[..].d +[ROOT]/foo/build-dir/debug/deps/foo-[HASH][EXE] +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-test-bench-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/test-bench-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/test-bench-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/.rustc_info.json + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/foo[EXE] + +"#]]); } #[cargo_test] @@ -347,17 +474,35 @@ fn cargo_package_should_build_in_build_dir_and_output_to_target_dir() { p.cargo("package").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - let package_artifact_dir = p.root().join("target-dir/package"); assert_exists(&package_artifact_dir); assert_exists(&package_artifact_dir.join("foo-0.0.1.crate")); assert!(package_artifact_dir.join("foo-0.0.1.crate").is_file()); - - let package_build_dir = p.root().join("build-dir/package"); - assert_exists(&package_build_dir); - assert_exists(&package_build_dir.join("foo-0.0.1")); - assert!(package_build_dir.join("foo-0.0.1").is_dir()); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/deps/foo[..].d +[ROOT]/foo/build-dir/debug/foo[EXE] +[ROOT]/foo/build-dir/debug/foo.d +[ROOT]/foo/build-dir/package/foo-0.0.1/Cargo.lock +[ROOT]/foo/build-dir/package/foo-0.0.1/Cargo.toml +[ROOT]/foo/build-dir/package/foo-0.0.1/Cargo.toml.orig +[ROOT]/foo/build-dir/package/foo-0.0.1/src/main.rs +[ROOT]/foo/build-dir/package/foo-0.0.1.crate + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/package/foo-0.0.1.crate + +"#]]); } #[cargo_test] @@ -381,8 +526,6 @@ fn cargo_publish_should_only_touch_build_dir() { .enable_mac_dsym() .run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - let package_artifact_dir = p.root().join("target-dir/package"); assert!(!package_artifact_dir.exists()); @@ -408,7 +551,28 @@ fn cargo_clean_should_clean_the_target_dir_and_build_dir() { p.cargo("build").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/deps/foo[..].d + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/foo[EXE] +[ROOT]/foo/target-dir/debug/foo.d + +"#]]); p.cargo("clean").enable_mac_dsym().run(); @@ -526,11 +690,30 @@ fn template_workspace_root() { p.cargo("build").enable_mac_dsym().run(); - assert_build_dir_layout(p.root().join("build-dir"), "debug"); - assert_artifact_dir_layout(p.root().join("target-dir"), "debug"); - // Verify the binary was uplifted to the target-dir assert_exists(&p.root().join(&format!("target-dir/debug/foo{EXE_SUFFIX}"))); + p.root().join("build-dir").assert_build_dir_layout(str![[r#" +[ROOT]/foo/build-dir/.rustc_info.json +[ROOT]/foo/build-dir/CACHEDIR.TAG +[ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/build-dir/debug/deps/foo[..].d + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/foo[EXE] +[ROOT]/foo/target-dir/debug/foo.d + +"#]]); } #[cargo_test] @@ -549,11 +732,32 @@ fn template_cargo_cache_home() { p.cargo("build").enable_mac_dsym().run(); - assert_build_dir_layout(paths::home().join(".cargo/build-dir"), "debug"); - assert_artifact_dir_layout(p.root().join("target-dir"), "debug"); - // Verify the binary was uplifted to the target-dir assert_exists(&p.root().join(&format!("target-dir/debug/foo{EXE_SUFFIX}"))); + paths::cargo_home() + .join("build-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/home/.cargo/build-dir/.rustc_info.json +[ROOT]/home/.cargo/build-dir/CACHEDIR.TAG +[ROOT]/home/.cargo/build-dir/debug/.cargo-lock +[ROOT]/home/.cargo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/home/.cargo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/home/.cargo/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/home/.cargo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/home/.cargo/build-dir/debug/deps/foo[..][EXE] +[ROOT]/home/.cargo/build-dir/debug/deps/foo[..].d + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/foo[EXE] +[ROOT]/foo/target-dir/debug/foo.d + +"#]]); } #[cargo_test] @@ -587,11 +791,31 @@ fn template_workspace_path_hash() { let hash_dir = parse_workspace_manifest_path_hash(&foo_dir); let build_dir = hash_dir.as_path().join("build-dir"); - assert_build_dir_layout(build_dir, "debug"); - assert_artifact_dir_layout(p.root().join("target-dir"), "debug"); // Verify the binary was uplifted to the target-dir assert_exists(&p.root().join(&format!("target-dir/debug/foo{EXE_SUFFIX}"))); + build_dir.assert_build_dir_layout(str![[r#" +[ROOT]/foo/foo/[HASH]/build-dir/.rustc_info.json +[ROOT]/foo/foo/[HASH]/build-dir/CACHEDIR.TAG +[ROOT]/foo/foo/[HASH]/build-dir/debug/.cargo-lock +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/dep-bin-foo +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/foo/[HASH]/build-dir/debug/deps/foo[..][EXE] +[ROOT]/foo/foo/[HASH]/build-dir/debug/deps/foo[..].d + +"#]]); + + p.root() + .join("target-dir") + .assert_build_dir_layout(str![[r#" +[ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/foo[EXE] +[ROOT]/foo/target-dir/debug/foo.d + +"#]]); } /// Verify that the {workspace-path-hash} does not changes if cargo is run from inside of @@ -633,7 +857,25 @@ fn template_workspace_path_hash_should_handle_symlink() { let foo_dir = p.root().join("foo"); assert_exists(&foo_dir); let original_hash_dir = parse_workspace_manifest_path_hash(&foo_dir); - verify_layouts(&p, &original_hash_dir); + + original_hash_dir.assert_build_dir_layout(str![[r#" +[ROOT]/foo/foo/[HASH]/build-dir/.rustc_info.json +[ROOT]/foo/foo/[HASH]/build-dir/CACHEDIR.TAG +[ROOT]/foo/foo/[HASH]/build-dir/debug/.cargo-lock +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/dep-lib-foo +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/lib-foo +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/lib-foo.json +[ROOT]/foo/foo/[HASH]/build-dir/debug/deps/foo-[HASH].d +[ROOT]/foo/foo/[HASH]/build-dir/debug/deps/libfoo-[HASH].rmeta + +"#]]); + + p.root().join("target").assert_build_dir_layout(str![[r#" +[ROOT]/foo/target/CACHEDIR.TAG +[ROOT]/foo/target/debug/.cargo-lock + +"#]]); // Create a symlink of the project root. let mut symlinked_dir = p.root().clone(); @@ -650,16 +892,28 @@ fn template_workspace_path_hash_should_handle_symlink() { // Parse and verify the hash created from the symlinked dir assert_exists(&foo_dir); let symlink_hash_dir = parse_workspace_manifest_path_hash(&foo_dir); - verify_layouts(&p, &symlink_hash_dir); + + symlink_hash_dir.assert_build_dir_layout(str![[r#" +[ROOT]/foo/foo/[HASH]/build-dir/.rustc_info.json +[ROOT]/foo/foo/[HASH]/build-dir/CACHEDIR.TAG +[ROOT]/foo/foo/[HASH]/build-dir/debug/.cargo-lock +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/dep-lib-foo +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/lib-foo +[ROOT]/foo/foo/[HASH]/build-dir/debug/.fingerprint/foo-[HASH]/lib-foo.json +[ROOT]/foo/foo/[HASH]/build-dir/debug/deps/foo-[HASH].d +[ROOT]/foo/foo/[HASH]/build-dir/debug/deps/libfoo-[HASH].rmeta + +"#]]); + + p.root().join("target").assert_build_dir_layout(str![[r#" +[ROOT]/foo/target/CACHEDIR.TAG +[ROOT]/foo/target/debug/.cargo-lock + +"#]]); // Verify the hash dir created from the symlinked and non-symlinked dirs are the same. assert_eq!(original_hash_dir, symlink_hash_dir); - - fn verify_layouts(p: &Project, build_dir_parent: &PathBuf) { - let build_dir = build_dir_parent.as_path().join("build-dir"); - assert_build_dir_layout(build_dir, "debug"); - assert_artifact_dir_layout(p.root().join("target"), "debug"); - } } #[cargo_test] @@ -749,71 +1003,6 @@ fn parse_workspace_manifest_path_hash(hash_dir: &PathBuf) -> PathBuf { return inner_hash_dir.path(); } -#[track_caller] -fn assert_build_dir_layout(path: PathBuf, profile: &str) { - assert_dir_layout(path, profile, true); -} - -#[allow(dead_code)] -#[track_caller] -fn assert_artifact_dir_layout(path: PathBuf, profile: &str) { - assert_dir_layout(path, profile, false); -} - -#[track_caller] -fn assert_dir_layout(path: PathBuf, profile: &str, is_build_dir: bool) { - println!("checking if {path:?} is a build directory ({is_build_dir})"); - // For things that are in both `target` and the build directory we only check if they are - // present if `is_build_dir` is true. - if is_build_dir { - assert_eq!( - is_build_dir, - path.join(profile).is_dir(), - "Expected {:?} to exist and be a directory", - path.join(profile) - ); - } - - let error_message = |dir: &str| { - if is_build_dir { - format!("`{dir}` dir was expected but not found") - } else { - format!("`{dir}` dir was not expected but was found") - } - }; - - if is_build_dir { - assert_exists(&path.join(".rustc_info.json")); - } else { - assert_not_exists(&path.join(".rustc_info.json")); - } - - assert_eq!( - is_build_dir, - path.join(profile).join("deps").is_dir(), - "{}", - error_message("deps") - ); - assert_eq!( - is_build_dir, - path.join(profile).join("build").is_dir(), - "{}", - error_message("build") - ); - assert_eq!( - is_build_dir, - path.join(profile).join("incremental").is_dir(), - "{}", - error_message("incremental") - ); - assert_eq!( - is_build_dir, - path.join(profile).join(".fingerprint").is_dir(), - "{}", - error_message(".fingerprint") - ); -} - #[track_caller] fn assert_exists(path: &PathBuf) { assert!(