Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<!--
SPDX-FileCopyrightText: 2025 Adam Poulemanos <89049923+bashandbone@users.noreply.github.com>

SPDX-License-Identifier: LicenseRef-PlainMIT OR MIT
-->

# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Expand Down
42 changes: 37 additions & 5 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
SerializableBranch::from_str(&s)
SerializableBranch::from_gitmodules(&s)
.map_err(|_| serde::de::Error::custom(format!("invalid branch value: {s}")))
}
}
Expand Down Expand Up @@ -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);
}
Expand All @@ -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<SerializableBranch, toml::de::Error> =
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<SerializableBranch, toml::de::Error> =
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<Branch> for SerializableBranch {
type Error = ();

Expand Down