From ee1d688da4142e9f0cc11e2f0b6cf25dd7b21223 Mon Sep 17 00:00:00 2001 From: Ky Phan Date: Sat, 6 Aug 2022 13:52:39 +0700 Subject: [PATCH 1/2] Improve error message for an array --- src/cargo/util/toml/mod.rs | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 58647e03f05..2132bf88c4e 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1041,6 +1041,43 @@ impl MaybeWorkspace { } } +fn workspace_vec_string<'de, D>( + deserializer: D, +) -> Result>>, D::Error> + where + D: de::Deserializer<'de>, +{ + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = Option>>; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("an array") + } + + fn visit_seq(self, v: V) -> Result + where + V: de::SeqAccess<'de>, + { + let seq = de::value::SeqAccessDeserializer::new(v); + let defined = Vec::::deserialize(seq).map(MaybeWorkspace::Defined)?; + Ok(Some(defined)) + } + + fn visit_map(self, map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mvd = de::value::MapAccessDeserializer::new(map); + let workspace = TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)?; + Ok(Some(workspace)) + } + } + + deserializer.deserialize_any(Visitor) +} + #[derive(Deserialize, Serialize, Clone, Debug)] pub struct TomlWorkspaceField { workspace: bool, @@ -1060,6 +1097,8 @@ pub struct TomlProject { name: InternedString, #[serde(deserialize_with = "version_trim_whitespace")] version: MaybeWorkspace, + #[serde(default)] + #[serde(deserialize_with = "workspace_vec_string")] authors: Option>>, build: Option, metabuild: Option, @@ -1068,7 +1107,11 @@ pub struct TomlProject { #[serde(rename = "forced-target")] forced_target: Option, links: Option, + #[serde(default)] + #[serde(deserialize_with = "workspace_vec_string")] exclude: Option>>, + #[serde(default)] + #[serde(deserialize_with = "workspace_vec_string")] include: Option>>, publish: Option>, workspace: Option, @@ -1084,7 +1127,11 @@ pub struct TomlProject { homepage: Option>, documentation: Option>, readme: Option>, + #[serde(default)] + #[serde(deserialize_with = "workspace_vec_string")] keywords: Option>>, + #[serde(default)] + #[serde(deserialize_with = "workspace_vec_string")] categories: Option>>, license: Option>, license_file: Option>, From 8f1a75d584a71c15f5c9d9ef322b3ce54b031274 Mon Sep 17 00:00:00 2001 From: Ky Phan Date: Mon, 8 Aug 2022 22:05:43 +0700 Subject: [PATCH 2/2] Add unit test for invalid authors, refactor name --- src/cargo/util/toml/mod.rs | 26 +++++++++++++------------- tests/testsuite/metadata.rs | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 2132bf88c4e..ced9d5ac0f4 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1041,11 +1041,11 @@ impl MaybeWorkspace { } } -fn workspace_vec_string<'de, D>( +fn maybe_workspace_vec_string<'de, D>( deserializer: D, ) -> Result>>, D::Error> - where - D: de::Deserializer<'de>, +where + D: de::Deserializer<'de>, { struct Visitor; @@ -1053,12 +1053,12 @@ fn workspace_vec_string<'de, D>( type Value = Option>>; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("an array") + formatter.write_str("vector of strings") } fn visit_seq(self, v: V) -> Result - where - V: de::SeqAccess<'de>, + where + V: de::SeqAccess<'de>, { let seq = de::value::SeqAccessDeserializer::new(v); let defined = Vec::::deserialize(seq).map(MaybeWorkspace::Defined)?; @@ -1066,8 +1066,8 @@ fn workspace_vec_string<'de, D>( } fn visit_map(self, map: V) -> Result - where - V: de::MapAccess<'de>, + where + V: de::MapAccess<'de>, { let mvd = de::value::MapAccessDeserializer::new(map); let workspace = TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)?; @@ -1098,7 +1098,7 @@ pub struct TomlProject { #[serde(deserialize_with = "version_trim_whitespace")] version: MaybeWorkspace, #[serde(default)] - #[serde(deserialize_with = "workspace_vec_string")] + #[serde(deserialize_with = "maybe_workspace_vec_string")] authors: Option>>, build: Option, metabuild: Option, @@ -1108,10 +1108,10 @@ pub struct TomlProject { forced_target: Option, links: Option, #[serde(default)] - #[serde(deserialize_with = "workspace_vec_string")] + #[serde(deserialize_with = "maybe_workspace_vec_string")] exclude: Option>>, #[serde(default)] - #[serde(deserialize_with = "workspace_vec_string")] + #[serde(deserialize_with = "maybe_workspace_vec_string")] include: Option>>, publish: Option>, workspace: Option, @@ -1128,10 +1128,10 @@ pub struct TomlProject { documentation: Option>, readme: Option>, #[serde(default)] - #[serde(deserialize_with = "workspace_vec_string")] + #[serde(deserialize_with = "maybe_workspace_vec_string")] keywords: Option>>, #[serde(default)] - #[serde(deserialize_with = "workspace_vec_string")] + #[serde(deserialize_with = "maybe_workspace_vec_string")] categories: Option>>, license: Option>, license_file: Option>, diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index 072203bd2ec..b0365f4e708 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -1706,6 +1706,30 @@ Caused by: .run(); } +#[cargo_test] +fn cargo_metadata_with_invalid_authors_field() { + let p = project() + .file("src/foo.rs", "") + .file( + "Cargo.toml", + r#" + [package] + authors = "" + "#, + ) + .build(); + + p.cargo("metadata") + .with_status(101) + .with_stderr( + r#"[ERROR] failed to parse manifest at `[..]` + +Caused by: + invalid type: string "", expected vector of strings for key `package.authors`"#, + ) + .run(); +} + const MANIFEST_OUTPUT: &str = r#" { "packages": [{