From 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:41:41 +0200 Subject: Merging upstream version 1.70.0+dfsg2. Signed-off-by: Daniel Baumann --- src/tools/cargo/tests/testsuite/dep_info.rs | 600 ++++++++++++++++++++++++++++ 1 file changed, 600 insertions(+) create mode 100644 src/tools/cargo/tests/testsuite/dep_info.rs (limited to 'src/tools/cargo/tests/testsuite/dep_info.rs') diff --git a/src/tools/cargo/tests/testsuite/dep_info.rs b/src/tools/cargo/tests/testsuite/dep_info.rs new file mode 100644 index 000000000..e9ea47792 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/dep_info.rs @@ -0,0 +1,600 @@ +//! Tests for dep-info files. This includes the dep-info file Cargo creates in +//! the output directory, and the ones stored in the fingerprint. + +use cargo_test_support::compare::assert_match_exact; +use cargo_test_support::paths::{self, CargoPathExt}; +use cargo_test_support::registry::Package; +use cargo_test_support::{ + basic_bin_manifest, basic_manifest, main_file, project, rustc_host, Project, +}; +use filetime::FileTime; +use std::fs; +use std::path::Path; +use std::str; + +// Helper for testing dep-info files in the fingerprint dir. +#[track_caller] +fn assert_deps(project: &Project, fingerprint: &str, test_cb: impl Fn(&Path, &[(u8, &str)])) { + let mut files = project + .glob(fingerprint) + .map(|f| f.expect("unwrap glob result")) + // Filter out `.json` entries. + .filter(|f| f.extension().is_none()); + let info_path = files + .next() + .unwrap_or_else(|| panic!("expected 1 dep-info file at {}, found 0", fingerprint)); + assert!(files.next().is_none(), "expected only 1 dep-info file"); + let dep_info = fs::read(&info_path).unwrap(); + let dep_info = &mut &dep_info[..]; + let deps = (0..read_usize(dep_info)) + .map(|_| { + ( + read_u8(dep_info), + str::from_utf8(read_bytes(dep_info)).unwrap(), + ) + }) + .collect::>(); + test_cb(&info_path, &deps); + + fn read_usize(bytes: &mut &[u8]) -> usize { + let ret = &bytes[..4]; + *bytes = &bytes[4..]; + + u32::from_le_bytes(ret.try_into().unwrap()) as usize + } + + fn read_u8(bytes: &mut &[u8]) -> u8 { + let ret = bytes[0]; + *bytes = &bytes[1..]; + ret + } + + fn read_bytes<'a>(bytes: &mut &'a [u8]) -> &'a [u8] { + let n = read_usize(bytes); + let ret = &bytes[..n]; + *bytes = &bytes[n..]; + ret + } +} + +fn assert_deps_contains(project: &Project, fingerprint: &str, expected: &[(u8, &str)]) { + assert_deps(project, fingerprint, |info_path, entries| { + for (e_kind, e_path) in expected { + let pattern = glob::Pattern::new(e_path).unwrap(); + let count = entries + .iter() + .filter(|(kind, path)| kind == e_kind && pattern.matches(path)) + .count(); + if count != 1 { + panic!( + "Expected 1 match of {} {} in {:?}, got {}:\n{:#?}", + e_kind, e_path, info_path, count, entries + ); + } + } + }) +} + +#[cargo_test] +fn build_dep_info() { + let p = project() + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .build(); + + p.cargo("build").run(); + + let depinfo_bin_path = &p.bin("foo").with_extension("d"); + + assert!(depinfo_bin_path.is_file()); + + let depinfo = p.read_file(depinfo_bin_path.to_str().unwrap()); + + let bin_path = p.bin("foo"); + let src_path = p.root().join("src").join("foo.rs"); + if !depinfo.lines().any(|line| { + line.starts_with(&format!("{}:", bin_path.display())) + && line.contains(src_path.to_str().unwrap()) + }) { + panic!( + "Could not find {:?}: {:?} in {:?}", + bin_path, src_path, depinfo_bin_path + ); + } +} + +#[cargo_test] +fn build_dep_info_lib() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["lib"] + "#, + ) + .file("build.rs", "fn main() {}") + .file("src/lib.rs", "") + .file("examples/ex.rs", "") + .build(); + + p.cargo("build --example=ex").run(); + assert!(p.example_lib("ex", "lib").with_extension("d").is_file()); +} + +#[cargo_test] +fn build_dep_info_rlib() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["rlib"] + "#, + ) + .file("src/lib.rs", "") + .file("examples/ex.rs", "") + .build(); + + p.cargo("build --example=ex").run(); + assert!(p.example_lib("ex", "rlib").with_extension("d").is_file()); +} + +#[cargo_test] +fn build_dep_info_dylib() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["dylib"] + "#, + ) + .file("src/lib.rs", "") + .file("examples/ex.rs", "") + .build(); + + p.cargo("build --example=ex").run(); + assert!(p.example_lib("ex", "dylib").with_extension("d").is_file()); +} + +#[cargo_test] +fn dep_path_inside_target_has_correct_path() { + let p = project() + .file("Cargo.toml", &basic_bin_manifest("a")) + .file("target/debug/blah", "") + .file( + "src/main.rs", + r#" + fn main() { + let x = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/target/debug/blah")); + } + "#, + ) + .build(); + + p.cargo("build").run(); + + let depinfo_path = &p.bin("a").with_extension("d"); + + assert!(depinfo_path.is_file(), "{:?}", depinfo_path); + + let depinfo = p.read_file(depinfo_path.to_str().unwrap()); + + let bin_path = p.bin("a"); + let target_debug_blah = Path::new("target").join("debug").join("blah"); + if !depinfo.lines().any(|line| { + line.starts_with(&format!("{}:", bin_path.display())) + && line.contains(target_debug_blah.to_str().unwrap()) + }) { + panic!( + "Could not find {:?}: {:?} in {:?}", + bin_path, target_debug_blah, depinfo_path + ); + } +} + +#[cargo_test] +fn no_rewrite_if_no_change() { + let p = project().file("src/lib.rs", "").build(); + + p.cargo("build").run(); + let dep_info = p.root().join("target/debug/libfoo.d"); + let metadata1 = dep_info.metadata().unwrap(); + p.cargo("build").run(); + let metadata2 = dep_info.metadata().unwrap(); + + assert_eq!( + FileTime::from_last_modification_time(&metadata1), + FileTime::from_last_modification_time(&metadata2), + ); +} + +#[cargo_test(nightly, reason = "-Z binary-dep-depinfo is unstable")] +fn relative_depinfo_paths_ws() { + // Test relative dep-info paths in a workspace with --target with + // proc-macros and other dependency kinds. + Package::new("regdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + Package::new("pmdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + Package::new("bdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + + let p = project() + /*********** Workspace ***********/ + .file( + "Cargo.toml", + r#" + [workspace] + members = ["foo"] + "#, + ) + /*********** Main Project ***********/ + .file( + "foo/Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2018" + + [dependencies] + pm = {path = "../pm"} + bar = {path = "../bar"} + regdep = "0.1" + + [build-dependencies] + bdep = "0.1" + bar = {path = "../bar"} + "#, + ) + .file( + "foo/src/main.rs", + r#" + pm::noop!{} + + fn main() { + bar::f(); + regdep::f(); + } + "#, + ) + .file("foo/build.rs", "fn main() { bdep::f(); }") + /*********** Proc Macro ***********/ + .file( + "pm/Cargo.toml", + r#" + [package] + name = "pm" + version = "0.1.0" + edition = "2018" + + [lib] + proc-macro = true + + [dependencies] + pmdep = "0.1" + "#, + ) + .file( + "pm/src/lib.rs", + r#" + extern crate proc_macro; + use proc_macro::TokenStream; + + #[proc_macro] + pub fn noop(_item: TokenStream) -> TokenStream { + pmdep::f(); + "".parse().unwrap() + } + "#, + ) + /*********** Path Dependency `bar` ***********/ + .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) + .file("bar/src/lib.rs", "pub fn f() {}") + .build(); + + let host = rustc_host(); + p.cargo("build -Z binary-dep-depinfo --target") + .arg(&host) + .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) + .with_stderr_contains("[COMPILING] foo [..]") + .run(); + + assert_deps_contains( + &p, + "target/debug/.fingerprint/pm-*/dep-lib-pm", + &[(0, "src/lib.rs"), (1, "debug/deps/libpmdep-*.rlib")], + ); + + assert_deps_contains( + &p, + &format!("target/{}/debug/.fingerprint/foo-*/dep-bin-foo", host), + &[ + (0, "src/main.rs"), + ( + 1, + &format!( + "debug/deps/{}pm-*.{}", + paths::get_lib_prefix("proc-macro"), + paths::get_lib_extension("proc-macro") + ), + ), + (1, &format!("{}/debug/deps/libbar-*.rlib", host)), + (1, &format!("{}/debug/deps/libregdep-*.rlib", host)), + ], + ); + + assert_deps_contains( + &p, + "target/debug/.fingerprint/foo-*/dep-build-script-build-script-build", + &[(0, "build.rs"), (1, "debug/deps/libbdep-*.rlib")], + ); + + // Make sure it stays fresh. + p.cargo("build -Z binary-dep-depinfo --target") + .arg(&host) + .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) + .with_stderr("[FINISHED] dev [..]") + .run(); +} + +#[cargo_test(nightly, reason = "-Z binary-dep-depinfo is unstable")] +fn relative_depinfo_paths_no_ws() { + // Test relative dep-info paths without a workspace with proc-macros and + // other dependency kinds. + Package::new("regdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + Package::new("pmdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + Package::new("bdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + + let p = project() + /*********** Main Project ***********/ + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2018" + + [dependencies] + pm = {path = "pm"} + bar = {path = "bar"} + regdep = "0.1" + + [build-dependencies] + bdep = "0.1" + bar = {path = "bar"} + "#, + ) + .file( + "src/main.rs", + r#" + pm::noop!{} + + fn main() { + bar::f(); + regdep::f(); + } + "#, + ) + .file("build.rs", "fn main() { bdep::f(); }") + /*********** Proc Macro ***********/ + .file( + "pm/Cargo.toml", + r#" + [package] + name = "pm" + version = "0.1.0" + edition = "2018" + + [lib] + proc-macro = true + + [dependencies] + pmdep = "0.1" + "#, + ) + .file( + "pm/src/lib.rs", + r#" + extern crate proc_macro; + use proc_macro::TokenStream; + + #[proc_macro] + pub fn noop(_item: TokenStream) -> TokenStream { + pmdep::f(); + "".parse().unwrap() + } + "#, + ) + /*********** Path Dependency `bar` ***********/ + .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) + .file("bar/src/lib.rs", "pub fn f() {}") + .build(); + + p.cargo("build -Z binary-dep-depinfo") + .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) + .with_stderr_contains("[COMPILING] foo [..]") + .run(); + + assert_deps_contains( + &p, + "target/debug/.fingerprint/pm-*/dep-lib-pm", + &[(0, "src/lib.rs"), (1, "debug/deps/libpmdep-*.rlib")], + ); + + assert_deps_contains( + &p, + "target/debug/.fingerprint/foo-*/dep-bin-foo", + &[ + (0, "src/main.rs"), + ( + 1, + &format!( + "debug/deps/{}pm-*.{}", + paths::get_lib_prefix("proc-macro"), + paths::get_lib_extension("proc-macro") + ), + ), + (1, "debug/deps/libbar-*.rlib"), + (1, "debug/deps/libregdep-*.rlib"), + ], + ); + + assert_deps_contains( + &p, + "target/debug/.fingerprint/foo-*/dep-build-script-build-script-build", + &[(0, "build.rs"), (1, "debug/deps/libbdep-*.rlib")], + ); + + // Make sure it stays fresh. + p.cargo("build -Z binary-dep-depinfo") + .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) + .with_stderr("[FINISHED] dev [..]") + .run(); +} + +#[cargo_test] +fn reg_dep_source_not_tracked() { + // Make sure source files in dep-info file are not tracked for registry dependencies. + Package::new("regdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + regdep = "0.1" + "#, + ) + .file("src/lib.rs", "pub fn f() { regdep::f(); }") + .build(); + + p.cargo("check").run(); + + assert_deps( + &p, + "target/debug/.fingerprint/regdep-*/dep-lib-regdep", + |info_path, entries| { + for (kind, path) in entries { + if *kind == 1 { + panic!( + "Did not expect package root relative path type: {:?} in {:?}", + path, info_path + ); + } + } + }, + ); +} + +#[cargo_test(nightly, reason = "-Z binary-dep-depinfo is unstable")] +fn canonical_path() { + if !cargo_test_support::symlink_supported() { + return; + } + Package::new("regdep", "0.1.0") + .file("src/lib.rs", "pub fn f() {}") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + regdep = "0.1" + "#, + ) + .file("src/lib.rs", "pub fn f() { regdep::f(); }") + .build(); + + let real = p.root().join("real_target"); + real.mkdir_p(); + p.symlink(real, "target"); + + p.cargo("check -Z binary-dep-depinfo") + .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) + .run(); + + assert_deps_contains( + &p, + "target/debug/.fingerprint/foo-*/dep-lib-foo", + &[(0, "src/lib.rs"), (1, "debug/deps/libregdep-*.rmeta")], + ); +} + +#[cargo_test] +fn non_local_build_script() { + // Non-local build script information is not included. + Package::new("bar", "1.0.0") + .file( + "build.rs", + r#" + fn main() { + println!("cargo:rerun-if-changed=build.rs"); + } + "#, + ) + .file("src/lib.rs", "") + .publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build").run(); + let contents = p.read_file("target/debug/foo.d"); + assert_match_exact( + "[ROOT]/foo/target/debug/foo[EXE]: [ROOT]/foo/src/main.rs", + &contents, + ); +} -- cgit v1.2.3