let serialized = serde_json::to_value(meta).unwrap();
assert!(!serialized
.as_object()
.unwrap()
.contains_key("workspace_default_members"));
}
macro_rules! sorted {
($e:expr) => {{ letmut v = $e.clone();
v.sort();
v
}};
}
fn cargo_version() -> semver::Version { let output = std::process::Command::new("cargo")
.arg("-V")
.output()
.expect("Failed to exec cargo."); let out = std::str::from_utf8(&output.stdout)
.expect("invalid utf8")
.trim(); let split: Vec<&str> = out.split_whitespace().collect();
assert!(split.len() >= 2, "cargo -V output is unexpected: {}", out); letmut ver = semver::Version::parse(split[1]).expect("cargo -V semver could not be parsed"); // Don't care about metadata, it is awkward to compare.
ver.pre = semver::Prerelease::EMPTY;
ver.build = semver::BuildMetadata::EMPTY;
ver
}
#[test] fn all_the_fields() { // All the fields currently generated as of 1.60. This tries to exercise as // much as possible. let ver = cargo_version(); let minimum = semver::Version::parse("1.56.0").unwrap(); if ver < minimum { // edition added in 1.30 // rename added in 1.31 // links added in 1.33 // doctest added in 1.37 // publish added in 1.39 // dep_kinds added in 1.41 // test added in 1.47 // homepage added in 1.49 // documentation added in 1.49 // doc added in 1.50 // path added in 1.51 // default_run added in 1.55 // rust_version added in 1.58 // workspace_default_members added in 1.71
eprintln!("Skipping all_the_fields test, cargo {} is too old.", ver); return;
} let meta = MetadataCommand::new()
.manifest_path("tests/all/Cargo.toml")
.exec()
.unwrap();
assert_eq!(meta.workspace_root.file_name().unwrap(), "all");
assert_eq!(
serde_json::from_value::<WorkspaceMetadata>(meta.workspace_metadata.clone()).unwrap(),
WorkspaceMetadata {
testobject: TestObject {
myvalue: "abc".to_string()
}
}
);
assert_eq!(meta.workspace_members.len(), 1);
assert!(meta.workspace_members[0].to_string().contains("all")); if ver >= semver::Version::parse("1.71.0").unwrap() {
assert_eq!(&*meta.workspace_default_members, &meta.workspace_members);
}
assert_eq!(meta.packages.len(), 9); let all = meta.packages.iter().find(|p| p.name == "all").unwrap();
assert_eq!(all.version, semver::Version::parse("0.1.0").unwrap());
assert_eq!(all.authors, vec!["Jane Doe <user@example.com>"]);
assert!(all.id.to_string().contains("all"));
assert_eq!(all.description, Some("Package description.".to_string()));
assert_eq!(all.license, Some("MIT/Apache-2.0".to_string()));
assert_eq!(all.license_file, Some(Utf8PathBuf::from("LICENSE")));
assert!(all.license_file().unwrap().ends_with("tests/all/LICENSE"));
assert_eq!(all.publish, Some(vec![]));
assert_eq!(all.links, Some("foo".to_string()));
assert_eq!(all.default_run, Some("otherbin".to_string())); if ver >= semver::Version::parse("1.58.0").unwrap() {
assert_eq!(
all.rust_version,
Some(semver::Version::parse("1.56.0").unwrap())
);
}
assert_eq!(all.dependencies.len(), 8); let bitflags = all
.dependencies
.iter()
.find(|d| d.name == "bitflags")
.unwrap();
assert_eq!(
bitflags.source,
Some("registry+https://github.com/rust-lang/crates.io-index".to_string())
);
assert!(bitflags.optional);
assert_eq!(bitflags.req, semver::VersionReq::parse("^1.0").unwrap());
let all = resolve
.nodes
.iter()
.find(|n| n.id.to_string().contains("all"))
.unwrap();
assert_eq!(all.dependencies.len(), 8);
assert_eq!(all.deps.len(), 8); let newname = all.deps.iter().find(|d| d.name == "newname").unwrap();
assert!(newname.pkg.to_string().contains("oldname")); // Note the underscore here. let path_dep = all.deps.iter().find(|d| d.name == "path_dep").unwrap();
assert!(path_dep.pkg.to_string().contains("path-dep"));
assert_eq!(path_dep.dep_kinds.len(), 1); let kind = &path_dep.dep_kinds[0];
assert_eq!(kind.kind, DependencyKind::Normal);
assert!(kind.target.is_none());
let namedep = all
.deps
.iter()
.find(|d| d.name == "different_name")
.unwrap();
assert!(namedep.pkg.to_string().contains("namedep"));
assert_eq!(sorted!(all.features), vec!["bitflags", "default", "feat1"]);
let bdep = all.deps.iter().find(|d| d.name == "bdep").unwrap();
assert_eq!(bdep.dep_kinds.len(), 1); let kind = &bdep.dep_kinds[0];
assert_eq!(kind.kind, DependencyKind::Build);
assert!(kind.target.is_none());
let devdep = all.deps.iter().find(|d| d.name == "devdep").unwrap();
assert_eq!(devdep.dep_kinds.len(), 1); let kind = &devdep.dep_kinds[0];
assert_eq!(kind.kind, DependencyKind::Development);
assert!(kind.target.is_none());
let windep = all.deps.iter().find(|d| d.name == "windep").unwrap();
assert_eq!(windep.dep_kinds.len(), 1); let kind = &windep.dep_kinds[0];
assert_eq!(kind.kind, DependencyKind::Normal);
assert_eq!(
kind.target.as_ref().map(|x| x.to_string()),
Some("cfg(windows)".to_string())
);
let serialized = serde_json::to_value(meta).unwrap(); if ver >= semver::Version::parse("1.71.0").unwrap() {
assert!(serialized.as_object().unwrap()["workspace_default_members"]
.as_array()
.is_some());
} else {
assert!(!serialized
.as_object()
.unwrap()
.contains_key("workspace_default_members"));
}
}
#[test] fn alt_registry() { // This is difficult to test (would need to set up a custom index). // Just manually check the JSON is handled. let json = r#"
{ "packages": [
{ "name": "alt", "version": "0.1.0", "id": "alt 0.1.0 (path+file:///alt)", "source": null, "dependencies": [
{ "name": "alt2", "source": "registry+https://example.com", "req": "^0.1", "kind": null, "rename": null, "optional": false, "uses_default_features": true, "features": [], "target": null, "registry": "https://example.com"
}
], "targets": [
{ "kind": [ "lib"
], "crate_types": [ "lib"
], "name": "alt", "src_path": "/alt/src/lib.rs", "edition": "2018"
}
], "features": {}, "manifest_path": "/alt/Cargo.toml", "metadata": null, "authors": [], "categories": [], "keywords": [], "readme": null, "repository": null, "edition": "2018", "links": null
}
], "workspace_members": [ "alt 0.1.0 (path+file:///alt)"
], "resolve": null, "target_directory": "/alt/target", "version": 1, "workspace_root": "/alt"
} "#; let meta: Metadata = serde_json::from_str(json).unwrap();
assert_eq!(meta.packages.len(), 1); let alt = &meta.packages[0]; let deps = &alt.dependencies;
assert_eq!(deps.len(), 1); let dep = &deps[0];
assert_eq!(dep.registry, Some("https://example.com".to_string()));
}
#[test] fn current_dir() { let meta = MetadataCommand::new()
.current_dir("tests/all/namedep")
.exec()
.unwrap(); let namedep = meta.packages.iter().find(|p| p.name == "namedep").unwrap();
assert!(namedep.name.starts_with("namedep"));
}
#[test] fn parse_stream_is_robust() { // Proc macros can print stuff to stdout, which naturally breaks JSON messages. // Let's check that we don't die horribly in this case, and report an error. let json_output = r##"{"reason":"compiler-artifact","package_id":"chatty 0.1.0 (path+file:///chatty-macro/chatty)","manifest_path":"chatty-macro/Cargo.toml","target":{"kind":["proc-macro"],"crate_types":["proc-macro"],"name":"chatty","src_path":"/chatty-macro/chatty/src/lib.rs","edition":"2018","doctest":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/chatty-macro/target/debug/deps/libchatty-f2adcff24cdf3bb2.so"],"executable":null,"fresh":false}
Evil proc macro was here!
{"reason":"compiler-artifact","package_id":"chatty-macro 0.1.0 (path+file:///chatty-macro)","manifest_path":"chatty-macro/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"chatty-macro","src_path":"/chatty-macro/src/lib.rs","edition":"2018","doctest":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/chatty-macro/target/debug/libchatty_macro.rlib","/chatty-macro/target/debug/deps/libchatty_macro-cb5956ed52a11fb6.rmeta"],"executable":null,"fresh":false} "##; letmut n_messages = 0; letmut text = String::new(); for message in cargo_metadata::Message::parse_stream(json_output.as_bytes()) { let message = message.unwrap(); match message {
cargo_metadata::Message::TextLine(line) => text = line,
_ => n_messages += 1,
}
}
assert_eq!(n_messages, 2);
assert_eq!(text, "Evil proc macro was here!");
}
#[test] fn advanced_feature_configuration() { fn build_features<F: FnOnce(&mut MetadataCommand) -> &mut MetadataCommand>(
func: F,
) -> Vec<String> { letmut meta = MetadataCommand::new(); let meta = meta.manifest_path("tests/all/Cargo.toml");
let meta = func(meta); let meta = meta.exec().unwrap();
let resolve = meta.resolve.as_ref().unwrap();
let all = resolve
.nodes
.iter()
.find(|n| !n.features.is_empty())
.unwrap();
// Manually specify the same default features let manual_features = build_features(|meta| {
meta.features(CargoOpt::NoDefaultFeatures)
.features(CargoOpt::SomeFeatures(vec![ "feat1".into(), "bitflags".into(),
]))
});
assert_eq!(sorted!(manual_features), vec!["bitflags", "feat1"]);
// Multiple SomeFeatures is same as one longer SomeFeatures let manual_features = build_features(|meta| {
meta.features(CargoOpt::NoDefaultFeatures)
.features(CargoOpt::SomeFeatures(vec!["feat1".into()]))
.features(CargoOpt::SomeFeatures(vec!["feat2".into()]))
});
assert_eq!(sorted!(manual_features), vec!["feat1", "feat2"]);
// No features + All features == All features let all_features = build_features(|meta| {
meta.features(CargoOpt::AllFeatures)
.features(CargoOpt::NoDefaultFeatures)
});
assert_eq!(
sorted!(all_features),
vec!["bitflags", "default", "feat1", "feat2"]
);
// The '--all-features' flag supersedes other feature flags let all_flag_variants = build_features(|meta| {
meta.features(CargoOpt::SomeFeatures(vec!["feat2".into()]))
.features(CargoOpt::NoDefaultFeatures)
.features(CargoOpt::AllFeatures)
});
assert_eq!(sorted!(all_flag_variants), sorted!(all_features));
}
#[test] fn basic_workspace_root_package_exists() { // First try with dependencies let meta = MetadataCommand::new()
.manifest_path("tests/basic_workspace/Cargo.toml")
.exec()
.unwrap();
assert_eq!(meta.root_package().unwrap().name, "ex_bin"); // Now with no_deps, it should still work exactly the same let meta = MetadataCommand::new()
.manifest_path("tests/basic_workspace/Cargo.toml")
.no_deps()
.exec()
.unwrap();
assert_eq!(
meta.root_package()
.expect("workspace root still exists when no_deps used")
.name, "ex_bin"
);
}
#[test] fn debuginfo_variants() { // Checks behavior for the different debuginfo variants. let variants = [
("0", ArtifactDebuginfo::None),
("1", ArtifactDebuginfo::Limited),
("2", ArtifactDebuginfo::Full),
( "\"line-directives-only\"",
ArtifactDebuginfo::LineDirectivesOnly,
),
("\"line-tables-only\"", ArtifactDebuginfo::LineTablesOnly),
("3", ArtifactDebuginfo::UnknownInt(3)),
( "\"abc\"",
ArtifactDebuginfo::UnknownString("abc".to_string()),
),
("null", ArtifactDebuginfo::None),
]; for (value, expected) in variants { let s = r#"{"reason":"compiler-artifact","package_id":"cargo_metadata 0.16.0 (path+file:////cargo_metadata)","manifest_path":"/cargo_metadata/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"cargo_metadata","src_path":"/cargo_metadata/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":DEBUGINFO,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/cargo_metadata/target/debug/deps/libcargo_metadata-27f582f7187b9a2c.rmeta"],"executable":null,"fresh":false}"#; let message: Message = serde_json::from_str(&s.replace("DEBUGINFO", value)).unwrap(); match message {
Message::CompilerArtifact(artifact) => {
assert_eq!(artifact.profile.debuginfo, expected); let de_s = serde_json::to_string(&artifact.profile.debuginfo).unwrap(); // Note: Roundtrip does not retain null value. if value == "null" {
assert_eq!(artifact.profile.debuginfo.to_string(), "0");
assert_eq!(de_s, "0");
} else {
assert_eq!(
artifact.profile.debuginfo.to_string(),
value.trim_matches('"')
);
assert_eq!(de_s, value);
}
}
_ => panic!("unexpected {:?}", message),
}
}
}
#[test] #[should_panic = "WorkspaceDefaultMembers should only be dereferenced on Cargo versions >= 1.71"] fn missing_workspace_default_members() { let meta: Metadata = serde_json::from_str(JSON_OLD_MINIMAL).unwrap(); let _ = &*meta.workspace_default_members;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.