summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/tests/testsuite/dep_info.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/cargo/tests/testsuite/dep_info.rs')
-rw-r--r--src/tools/cargo/tests/testsuite/dep_info.rs600
1 files changed, 600 insertions, 0 deletions
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::<Vec<_>>();
+ 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,
+ );
+}