From a32af2fff1cb48317408cab94f5fc3e9bff4038b Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 1 Mar 2023 13:38:20 -0600 Subject: [PATCH] fix(toml): Provide a way to show unused manifest keys for workspace inheritance --- src/cargo/core/dependency.rs | 10 + src/cargo/util/toml/mod.rs | 371 +++++++++++++++--- src/cargo/util/toml_mut/manifest.rs | 14 +- tests/testsuite/check.rs | 60 +++ .../testsuite/inheritable_workspace_fields.rs | 122 +++++- tests/testsuite/metadata.rs | 4 +- 6 files changed, 513 insertions(+), 68 deletions(-) diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index db4fdd07393..0b3aba8ada5 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -106,6 +106,16 @@ pub enum DepKind { Build, } +impl DepKind { + pub fn kind_table(&self) -> &'static str { + match self { + DepKind::Normal => "dependencies", + DepKind::Development => "dev-dependencies", + DepKind::Build => "build-dependencies", + } + } +} + impl ser::Serialize for DepKind { fn serialize(&self, s: S) -> Result where diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 6b429d6a151..9e7c6f63e20 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -239,6 +239,15 @@ impl<'de, P: Deserialize<'de> + Clone> de::Deserialize<'de> for TomlDependency

Vec { + match self { + TomlDependency::Simple(_) => vec![], + TomlDependency::Detailed(detailed) => detailed.other.keys().cloned().collect(), + } + } +} + pub trait ResolveToPath { fn resolve(&self, config: &Config) -> PathBuf; } @@ -288,6 +297,10 @@ pub struct DetailedTomlDependency { lib: Option, /// A platform name, like `x86_64-apple-darwin` target: Option, + /// This is here to provide a way to see the "unused manifest keys" when deserializing + #[serde(skip_serializing)] + #[serde(flatten)] + other: BTreeMap, } // Explicit implementation so we avoid pulling in P: Default @@ -311,6 +324,7 @@ impl Default for DetailedTomlDependency

{ artifact: Default::default(), lib: Default::default(), target: Default::default(), + other: Default::default(), } } } @@ -340,7 +354,7 @@ pub struct TomlManifest { replace: Option>, patch: Option>>, workspace: Option, - badges: Option>>>, + badges: Option, } #[derive(Deserialize, Serialize, Clone, Debug, Default)] @@ -901,16 +915,14 @@ impl<'de> de::Deserialize<'de> for VecStringOrBool { } } -fn version_trim_whitespace<'de, D>( - deserializer: D, -) -> Result, D::Error> +fn version_trim_whitespace<'de, D>(deserializer: D) -> Result where D: de::Deserializer<'de>, { struct Visitor; impl<'de> de::Visitor<'de> for Visitor { - type Value = MaybeWorkspaceField; + type Value = MaybeWorkspaceSemverVersion; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("SemVer version") @@ -963,29 +975,6 @@ pub enum MaybeWorkspace { Workspace(W), } -impl<'de, T: Deserialize<'de>, W: WorkspaceInherit + de::Deserialize<'de>> de::Deserialize<'de> - for MaybeWorkspace -{ - fn deserialize(deserializer: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, - { - let value = serde_value::Value::deserialize(deserializer)?; - - if let Ok(w) = W::deserialize(serde_value::ValueDeserializer::::new( - value.clone(), - )) { - return if w.workspace() { - Ok(MaybeWorkspace::Workspace(w)) - } else { - Err(de::Error::custom("`workspace` cannot be false")) - }; - } - T::deserialize(serde_value::ValueDeserializer::::new(value)) - .map(MaybeWorkspace::Defined) - } -} - impl MaybeWorkspace { fn resolve<'a>( self, @@ -1029,6 +1018,37 @@ impl MaybeWorkspace { type MaybeWorkspaceDependency = MaybeWorkspace; +impl<'de> de::Deserialize<'de> for MaybeWorkspaceDependency { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let value = serde_value::Value::deserialize(deserializer)?; + + if let Ok(w) = TomlWorkspaceDependency::deserialize(serde_value::ValueDeserializer::< + D::Error, + >::new(value.clone())) + { + return if w.workspace() { + Ok(MaybeWorkspace::Workspace(w)) + } else { + Err(de::Error::custom("`workspace` cannot be false")) + }; + } + TomlDependency::deserialize(serde_value::ValueDeserializer::::new(value)) + .map(MaybeWorkspace::Defined) + } +} + +impl MaybeWorkspaceDependency { + fn unused_keys(&self) -> Vec { + match self { + MaybeWorkspaceDependency::Defined(d) => d.unused_keys(), + MaybeWorkspaceDependency::Workspace(w) => w.other.keys().cloned().collect(), + } + } +} + #[derive(Deserialize, Serialize, Clone, Debug)] #[serde(rename_all = "kebab-case")] pub struct TomlWorkspaceDependency { @@ -1038,6 +1058,10 @@ pub struct TomlWorkspaceDependency { #[serde(rename = "default_features")] default_features2: Option, optional: Option, + /// This is here to provide a way to see the "unused manifest keys" when deserializing + #[serde(skip_serializing)] + #[serde(flatten)] + other: BTreeMap, } impl WorkspaceInherit for TomlWorkspaceDependency { @@ -1123,13 +1147,206 @@ impl TomlWorkspaceDependency { } } -type MaybeWorkspaceField = MaybeWorkspace; +//. This already has a `Deserialize` impl from version_trim_whitespace +type MaybeWorkspaceSemverVersion = MaybeWorkspace; + +type MaybeWorkspaceString = MaybeWorkspace; +impl<'de> de::Deserialize<'de> for MaybeWorkspaceString { + fn deserialize(d: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = MaybeWorkspaceString; + + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_str("a string or workspace") + } + + fn visit_string(self, value: String) -> Result + where + E: de::Error, + { + Ok(MaybeWorkspaceString::Defined(value)) + } + + fn visit_map(self, map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mvd = de::value::MapAccessDeserializer::new(map); + TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace) + } + } + + d.deserialize_any(Visitor) + } +} + +type MaybeWorkspaceVecString = MaybeWorkspace, TomlWorkspaceField>; +impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecString { + fn deserialize(d: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = MaybeWorkspaceVecString; + + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("a vector of strings or workspace") + } + fn visit_seq(self, v: A) -> Result + where + A: de::SeqAccess<'de>, + { + let seq = de::value::SeqAccessDeserializer::new(v); + Vec::deserialize(seq).map(MaybeWorkspace::Defined) + } + + fn visit_map(self, map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mvd = de::value::MapAccessDeserializer::new(map); + TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace) + } + } + + d.deserialize_any(Visitor) + } +} + +type MaybeWorkspaceStringOrBool = MaybeWorkspace; +impl<'de> de::Deserialize<'de> for MaybeWorkspaceStringOrBool { + fn deserialize(d: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = MaybeWorkspaceStringOrBool; + + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("a string, a bool, or workspace") + } + + fn visit_bool(self, v: bool) -> Result + where + E: de::Error, + { + let b = de::value::BoolDeserializer::new(v); + StringOrBool::deserialize(b).map(MaybeWorkspace::Defined) + } + + fn visit_string(self, v: String) -> Result + where + E: de::Error, + { + let string = de::value::StringDeserializer::new(v); + StringOrBool::deserialize(string).map(MaybeWorkspace::Defined) + } + + fn visit_map(self, map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mvd = de::value::MapAccessDeserializer::new(map); + TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace) + } + } + + d.deserialize_any(Visitor) + } +} + +type MaybeWorkspaceVecStringOrBool = MaybeWorkspace; +impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecStringOrBool { + fn deserialize(d: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = MaybeWorkspaceVecStringOrBool; + + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("a boolean, a vector of strings, or workspace") + } + + fn visit_bool(self, v: bool) -> Result + where + E: de::Error, + { + let b = de::value::BoolDeserializer::new(v); + VecStringOrBool::deserialize(b).map(MaybeWorkspace::Defined) + } + + fn visit_seq(self, v: A) -> Result + where + A: de::SeqAccess<'de>, + { + let seq = de::value::SeqAccessDeserializer::new(v); + VecStringOrBool::deserialize(seq).map(MaybeWorkspace::Defined) + } + + fn visit_map(self, map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mvd = de::value::MapAccessDeserializer::new(map); + TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace) + } + } + + d.deserialize_any(Visitor) + } +} + +type MaybeWorkspaceBtreeMap = + MaybeWorkspace>, TomlWorkspaceField>; + +impl<'de> de::Deserialize<'de> for MaybeWorkspaceBtreeMap { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let value = serde_value::Value::deserialize(deserializer)?; + + if let Ok(w) = TomlWorkspaceField::deserialize( + serde_value::ValueDeserializer::::new(value.clone()), + ) { + return if w.workspace() { + Ok(MaybeWorkspace::Workspace(w)) + } else { + Err(de::Error::custom("`workspace` cannot be false")) + }; + } + BTreeMap::deserialize(serde_value::ValueDeserializer::::new(value)) + .map(MaybeWorkspace::Defined) + } +} #[derive(Deserialize, Serialize, Clone, Debug)] pub struct TomlWorkspaceField { + #[serde(deserialize_with = "bool_no_false")] workspace: bool, } +fn bool_no_false<'de, D: de::Deserializer<'de>>(deserializer: D) -> Result { + let b: bool = Deserialize::deserialize(deserializer)?; + if b { + Ok(b) + } else { + Err(de::Error::custom("`workspace` cannot be false")) + } +} + impl WorkspaceInherit for TomlWorkspaceField { fn inherit_toml_table(&self) -> &str { "package" @@ -1149,12 +1366,12 @@ impl WorkspaceInherit for TomlWorkspaceField { #[derive(Deserialize, Serialize, Clone, Debug)] #[serde(rename_all = "kebab-case")] pub struct TomlPackage { - edition: Option>, - rust_version: Option>, + edition: Option, + rust_version: Option, name: InternedString, #[serde(deserialize_with = "version_trim_whitespace")] - version: MaybeWorkspaceField, - authors: Option>>, + version: MaybeWorkspaceSemverVersion, + authors: Option, build: Option, metabuild: Option, #[serde(rename = "default-target")] @@ -1162,9 +1379,9 @@ pub struct TomlPackage { #[serde(rename = "forced-target")] forced_target: Option, links: Option, - exclude: Option>>, - include: Option>>, - publish: Option>, + exclude: Option, + include: Option, + publish: Option, workspace: Option, im_a_teapot: Option, autobins: Option, @@ -1174,15 +1391,15 @@ pub struct TomlPackage { default_run: Option, // Package metadata. - description: Option>, - homepage: Option>, - documentation: Option>, - readme: Option>, - keywords: Option>>, - categories: Option>>, - license: Option>, - license_file: Option>, - repository: Option>, + description: Option, + homepage: Option, + documentation: Option, + readme: Option, + keywords: Option, + categories: Option, + license: Option, + license_file: Option, + repository: Option, resolver: Option, // Note that this field must come last due to the way toml serialization @@ -1700,6 +1917,16 @@ impl TomlManifest { let mut inheritable = toml_config.package.clone().unwrap_or_default(); inheritable.update_ws_path(package_root.to_path_buf()); inheritable.update_deps(toml_config.dependencies.clone()); + if let Some(ws_deps) = &inheritable.dependencies { + for (name, dep) in ws_deps { + unused_dep_keys( + name, + "workspace.dependencies", + dep.unused_keys(), + &mut warnings, + ); + } + } let ws_root_config = WorkspaceRootConfig::new( package_root, &toml_config.members, @@ -1898,7 +2125,18 @@ impl TomlManifest { .clone() .resolve_with_self(n, |dep| dep.resolve(n, inheritable, cx))?; let dep = resolved.to_dependency(n, cx, kind)?; - validate_package_name(dep.name_in_toml().as_str(), "dependency name", "")?; + let name_in_toml = dep.name_in_toml().as_str(); + validate_package_name(name_in_toml, "dependency name", "")?; + let kind_name = match kind { + Some(k) => k.kind_table(), + None => "dependencies", + }; + let table_in_toml = if let Some(platform) = &cx.platform { + format!("target.{}.{kind_name}", platform.to_string()) + } else { + kind_name.to_string() + }; + unused_dep_keys(name_in_toml, &table_in_toml, v.unused_keys(), cx.warnings); cx.deps.push(dep); deps.insert(n.to_string(), MaybeWorkspace::Defined(resolved.clone())); } @@ -2426,6 +2664,12 @@ impl TomlManifest { spec ) })?; + unused_dep_keys( + dep.name_in_toml().as_str(), + "replace", + replacement.unused_keys(), + &mut cx.warnings, + ); dep.set_version_req(VersionReq::exact(version)) .lock_version(version); replace.push((spec, dep)); @@ -2435,21 +2679,32 @@ impl TomlManifest { fn patch(&self, cx: &mut Context<'_, '_>) -> CargoResult>> { let mut patch = HashMap::new(); - for (url, deps) in self.patch.iter().flatten() { - let url = match &url[..] { + for (toml_url, deps) in self.patch.iter().flatten() { + let url = match &toml_url[..] { CRATES_IO_REGISTRY => CRATES_IO_INDEX.parse().unwrap(), _ => cx .config - .get_registry_index(url) - .or_else(|_| url.into_url()) + .get_registry_index(toml_url) + .or_else(|_| toml_url.into_url()) .with_context(|| { - format!("[patch] entry `{}` should be a URL or registry name", url) + format!( + "[patch] entry `{}` should be a URL or registry name", + toml_url + ) })?, }; patch.insert( url, deps.iter() - .map(|(name, dep)| dep.to_dependency(name, cx, None)) + .map(|(name, dep)| { + unused_dep_keys( + name, + &format!("patch.{toml_url}",), + dep.unused_keys(), + &mut cx.warnings, + ); + dep.to_dependency(name, cx, None) + }) .collect::>>()?, ); } @@ -2489,6 +2744,18 @@ impl TomlManifest { } } +fn unused_dep_keys( + dep_name: &str, + kind: &str, + unused_keys: Vec, + warnings: &mut Vec, +) { + for unused in unused_keys { + let key = format!("unused manifest key: {kind}.{dep_name}.{unused}"); + warnings.push(key); + } +} + fn inheritable_from_path( config: &Config, workspace_path: PathBuf, diff --git a/src/cargo/util/toml_mut/manifest.rs b/src/cargo/util/toml_mut/manifest.rs index 8c88333608a..f3fc150e12a 100644 --- a/src/cargo/util/toml_mut/manifest.rs +++ b/src/cargo/util/toml_mut/manifest.rs @@ -59,17 +59,9 @@ impl DepTable { /// Keys to the table. pub fn to_table(&self) -> Vec<&str> { if let Some(target) = &self.target { - vec!["target", target, self.kind_table()] + vec!["target", target, self.kind.kind_table()] } else { - vec![self.kind_table()] - } - } - - fn kind_table(&self) -> &str { - match self.kind { - DepKind::Normal => "dependencies", - DepKind::Development => "dev-dependencies", - DepKind::Build => "build-dependencies", + vec![self.kind.kind_table()] } } } @@ -164,7 +156,7 @@ impl Manifest { let mut sections = Vec::new(); for table in DepTable::KINDS { - let dependency_type = table.kind_table(); + let dependency_type = table.kind.kind_table(); // Dependencies can be in the three standard sections... if self .data diff --git a/tests/testsuite/check.rs b/tests/testsuite/check.rs index 7f2c8bc1b90..9582480865a 100644 --- a/tests/testsuite/check.rs +++ b/tests/testsuite/check.rs @@ -1459,3 +1459,63 @@ fn check_fixable_warning_for_clippy() { .with_stderr_contains("[..] (run `cargo clippy --fix --lib -p foo` to apply 1 suggestion)") .run(); } + +#[cargo_test] +fn check_unused_manifest_keys() { + Package::new("dep", "0.1.0").publish(); + Package::new("foo", "0.1.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "bar" + version = "0.2.0" + authors = [] + + [dependencies] + dep = { version = "0.1.0", wxz = "wxz" } + foo = { version = "0.1.0", abc = "abc" } + + [dev-dependencies] + foo = { version = "0.1.0", wxz = "wxz" } + + [build-dependencies] + foo = { version = "0.1.0", wxz = "wxz" } + + [target.'cfg(windows)'.dependencies] + foo = { version = "0.1.0", wxz = "wxz" } + + [target.x86_64-pc-windows-gnu.dev-dependencies] + foo = { version = "0.1.0", wxz = "wxz" } + + [target.bar.build-dependencies] + foo = { version = "0.1.0", wxz = "wxz" } + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .with_stderr( + "\ +[WARNING] unused manifest key: dependencies.dep.wxz +[WARNING] unused manifest key: dependencies.foo.abc +[WARNING] unused manifest key: dev-dependencies.foo.wxz +[WARNING] unused manifest key: build-dependencies.foo.wxz +[WARNING] unused manifest key: target.bar.build-dependencies.foo.wxz +[WARNING] unused manifest key: target.cfg(windows).dependencies.foo.wxz +[WARNING] unused manifest key: target.x86_64-pc-windows-gnu.dev-dependencies.foo.wxz +[UPDATING] `[..]` index +[DOWNLOADING] crates ... +[DOWNLOADED] foo v0.1.0 ([..]) +[DOWNLOADED] dep v0.1.0 ([..]) +[CHECKING] [..] +[CHECKING] [..] +[CHECKING] bar v0.2.0 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} diff --git a/tests/testsuite/inheritable_workspace_fields.rs b/tests/testsuite/inheritable_workspace_fields.rs index d32419d7e69..1fc4873df6b 100644 --- a/tests/testsuite/inheritable_workspace_fields.rs +++ b/tests/testsuite/inheritable_workspace_fields.rs @@ -1215,7 +1215,7 @@ fn error_workspace_false() { Caused by: `workspace` cannot be false - in `package.description` + in `package.description.workspace` ", ) .run(); @@ -1253,8 +1253,8 @@ fn error_workspace_dependency_looked_for_workspace_itself() { .with_status(101) .with_stderr( "\ -[WARNING] [CWD]/Cargo.toml: dependency (dep) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions [WARNING] [CWD]/Cargo.toml: unused manifest key: workspace.dependencies.dep.workspace +[WARNING] [CWD]/Cargo.toml: dependency (dep) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions [UPDATING] `dummy-registry` index [ERROR] no matching package named `dep` found location searched: registry `crates-io` @@ -1573,8 +1573,8 @@ fn cannot_inherit_in_patch() { .with_status(101) .with_stderr( "\ -[WARNING] [CWD]/Cargo.toml: dependency (bar) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions [WARNING] [CWD]/Cargo.toml: unused manifest key: patch.crates-io.bar.workspace +[WARNING] [CWD]/Cargo.toml: dependency (bar) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions [UPDATING] `dummy-registry` index [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` @@ -1584,3 +1584,119 @@ Caused by: ) .run(); } + +#[cargo_test] +fn warn_inherit_unused_manifest_key_dep() { + Package::new("dep", "0.1.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = [] + [workspace.dependencies] + dep = { version = "0.1", wxz = "wxz" } + + [package] + name = "bar" + version = "0.2.0" + authors = [] + + [dependencies] + dep = { workspace = true, wxz = "wxz" } + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .with_stderr( + "\ +[WARNING] [CWD]/Cargo.toml: unused manifest key: workspace.dependencies.dep.wxz +[WARNING] [CWD]/Cargo.toml: unused manifest key: dependencies.dep.wxz +[UPDATING] `[..]` index +[DOWNLOADING] crates ... +[DOWNLOADED] dep v0.1.0 ([..]) +[CHECKING] [..] +[CHECKING] bar v0.2.0 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cargo_test] +fn warn_inherit_unused_manifest_key_package() { + Package::new("dep", "0.1.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + badges = { workspace = true, xyz = "abc"} + + [workspace] + members = [] + [workspace.package] + version = "1.2.3" + authors = ["Rustaceans"] + description = "This is a crate" + documentation = "https://www.rust-lang.org/learn" + homepage = "https://www.rust-lang.org" + repository = "https://github.com/example/example" + license = "MIT" + keywords = ["cli"] + categories = ["development-tools"] + publish = true + edition = "2018" + rust-version = "1.60" + exclude = ["foo.txt"] + include = ["bar.txt", "**/*.rs", "Cargo.toml"] + [workspace.package.badges] + gitlab = { repository = "https://gitlab.com/rust-lang/rust", branch = "master" } + + [package] + name = "bar" + version = { workspace = true, xyz = "abc"} + authors = { workspace = true, xyz = "abc"} + description = { workspace = true, xyz = "abc"} + documentation = { workspace = true, xyz = "abc"} + homepage = { workspace = true, xyz = "abc"} + repository = { workspace = true, xyz = "abc"} + license = { workspace = true, xyz = "abc"} + keywords = { workspace = true, xyz = "abc"} + categories = { workspace = true, xyz = "abc"} + publish = { workspace = true, xyz = "abc"} + edition = { workspace = true, xyz = "abc"} + rust-version = { workspace = true, xyz = "abc"} + exclude = { workspace = true, xyz = "abc"} + include = { workspace = true, xyz = "abc"} + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .with_stderr( + "\ +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.authors.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.categories.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.description.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.documentation.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.edition.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.exclude.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.homepage.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.include.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.keywords.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.license.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.publish.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.repository.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.rust-version.xyz +[WARNING] [CWD]/Cargo.toml: unused manifest key: package.version.xyz +[CHECKING] bar v1.2.3 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index 888f4737217..547916e7a77 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -1797,7 +1797,7 @@ fn cargo_metadata_with_invalid_authors_field() { r#"[ERROR] failed to parse manifest at `[..]` Caused by: - invalid type: string "", expected a sequence + invalid type: string "", expected a vector of strings or workspace in `package.authors`"#, ) .run(); @@ -1847,7 +1847,7 @@ fn cargo_metadata_with_invalid_publish_field() { r#"[ERROR] failed to parse manifest at `[..]` Caused by: - invalid type: string "foo", expected a boolean or vector of strings + invalid type: string "foo", expected a boolean, a vector of strings, or workspace in `package.publish`"#, ) .run();