diff --git a/CLAUDE.md b/CLAUDE.md index e2860d3..efa544d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,3 +1,9 @@ + + # CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. diff --git a/src/options.rs b/src/options.rs index 9fb7a8f..5eaeb5e 100644 --- a/src/options.rs +++ b/src/options.rs @@ -402,13 +402,14 @@ impl Serialize for SerializableBranch { } impl<'de> Deserialize<'de> for SerializableBranch { - /// Deserialize from a plain string using the same logic as [`FromStr`]. + /// Deserialize from a plain string, delegating to [`from_gitmodules`](GitmodulesConvert::from_gitmodules). /// Accepts `"."`, `"current"`, `"current-in-super-project"`, `"superproject"`, or `"super"` - /// as [`CurrentInSuperproject`](SerializableBranch::CurrentInSuperproject); all other strings - /// become [`Name`](SerializableBranch::Name). + /// as [`CurrentInSuperproject`](SerializableBranch::CurrentInSuperproject); all other + /// non-empty, non-whitespace strings become [`Name`](SerializableBranch::Name). + /// Empty or whitespace-only strings are rejected with a deserialization error. fn deserialize>(deserializer: D) -> Result { let s = String::deserialize(deserializer)?; - SerializableBranch::from_str(&s) + SerializableBranch::from_gitmodules(&s) .map_err(|_| serde::de::Error::custom(format!("invalid branch value: {s}"))) } } @@ -446,7 +447,10 @@ impl GitmodulesConvert for SerializableBranch { || options == "current-in-super-project" || options == "superproject" || options == "super" - || options == SerializableBranch::current_in_superproject().unwrap_or_default() + || SerializableBranch::current_in_superproject() + .ok() + .as_deref() + .map_or(false, |cur| cur == options) { return Ok(SerializableBranch::CurrentInSuperproject); } @@ -464,6 +468,34 @@ impl GitmodulesConvert for SerializableBranch { } } +#[cfg(test)] +mod tests { + use super::SerializableBranch; + + #[test] + fn test_branch_deserialize_from_toml_rejects_empty_and_whitespace() { + // Empty string should be rejected + let res_empty: Result = + toml::from_str(r#"branch = """"#); + assert!(res_empty.is_err(), "expected error for empty branch value"); + let err_empty = res_empty.unwrap_err().to_string(); + assert!( + err_empty.contains("invalid branch value"), + "error for empty branch value should contain context, got: {err_empty}" + ); + + // Whitespace-only string should be rejected + let res_ws: Result = + toml::from_str(r#"branch = " ""#); + assert!(res_ws.is_err(), "expected error for whitespace-only branch value"); + let err_ws = res_ws.unwrap_err().to_string(); + assert!( + err_ws.contains("invalid branch value"), + "error for whitespace-only branch value should contain context, got: {err_ws}" + ); + } +} + impl TryFrom for SerializableBranch { type Error = ();