Skip to content

Commit d27c20b

Browse files
KSXGitHubclaudeCopilot
authored
test: prevent duplicated aliases from idiots (#365)
* fix(usage_md): detect and reject visible aliases that duplicate their own flag name A visible_alias matching the argument's own --long name (or a visible_short_alias matching its -short flag) is a coding mistake that produces redundant output in USAGE.md. The new validation runs at the start of render_usage_md() and exits with code 1 if any such redundancy is found. https://claude.ai/code/session_01TSnvxN1HBwwzhxfFShWAQ5 * refactor(usage_md): return custom error type instead of calling process::exit Define a non-exhaustive `RenderUsageMdError` enum with `derive_more::{Display, Error}` and make `render_usage_md` return `Result<String, RenderUsageMdError>`. The callsites in cli/usage_md.rs and tests/sync_usage_md.rs now handle the error appropriately. https://claude.ai/code/session_01TSnvxN1HBwwzhxfFShWAQ5 * refactor(usage_md): address review feedback on error type and callsites - Split RedundantVisibleAlias into RedundantVisibleLongAlias(String) and RedundantVisibleShortAlias(char), moving message into #[display] - Rename validate_no_redundant_visible_aliases to check_visible_aliases - Use if-let-Err pattern in cli/usage_md.rs to match lib.rs style - Simplify test to use .unwrap() instead of .expect() - Fix doc comment to use plain English instead of backtick-wrapped flags https://claude.ai/code/session_01TSnvxN1HBwwzhxfFShWAQ5 * refactor(usage_md): rename to reject_redundant_aliases, use pipe-trait, revert to match - Rename check_visible_aliases to reject_redundant_aliases - Use pipe-trait to flatten nested constructor and Err calls - Revert cli/usage_md.rs back to match pattern https://claude.ai/code/session_01TSnvxN1HBwwzhxfFShWAQ5 * refactor(usage_md): return ExitCode instead of calling process::exit https://claude.ai/code/session_01TSnvxN1HBwwzhxfFShWAQ5 * docs: improve error message Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 618b701 commit d27c20b

3 files changed

Lines changed: 64 additions & 5 deletions

File tree

cli/usage_md.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
use parallel_disk_usage::usage_md::render_usage_md;
2+
use std::process::ExitCode;
23

3-
fn main() {
4-
println!("{}", render_usage_md().trim_end());
4+
fn main() -> ExitCode {
5+
match render_usage_md() {
6+
Ok(content) => {
7+
println!("{}", content.trim_end());
8+
ExitCode::SUCCESS
9+
}
10+
Err(error) => {
11+
eprintln!("error: {error}");
12+
ExitCode::FAILURE
13+
}
14+
}
515
}

src/usage_md.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
use crate::args::Args;
22
use clap::builder::PossibleValue;
33
use clap::{Arg, ArgAction, Command, CommandFactory};
4+
use derive_more::{Display, Error};
45
use itertools::Itertools;
6+
use pipe_trait::Pipe;
57
use std::borrow::Cow;
68

9+
/// Error produced when generating the usage Markdown.
10+
#[derive(Debug, Display, Error)]
11+
#[non_exhaustive]
12+
pub enum RenderUsageMdError {
13+
/// A `visible_alias` duplicates the argument's own long flag name.
14+
#[display("--{_0} has a visible_alias that duplicates its own flag name")]
15+
RedundantVisibleLongAlias(#[error(not(source))] String),
16+
/// A `visible_short_alias` duplicates the argument's own short flag name.
17+
#[display("-{_0} has a visible_short_alias that duplicates its own flag name")]
18+
RedundantVisibleShortAlias(#[error(not(source))] char),
19+
}
20+
721
/// Renders a Markdown reference page for `pdu`'s CLI.
8-
pub fn render_usage_md() -> String {
22+
pub fn render_usage_md() -> Result<String, RenderUsageMdError> {
923
let mut command: Command = Args::command();
24+
reject_redundant_aliases(&command)?;
1025
let mut out = String::new();
1126

1227
let usage = command.render_usage().to_string();
@@ -59,7 +74,7 @@ pub fn render_usage_md() -> String {
5974
}
6075
}
6176

62-
out
77+
Ok(out)
6378
}
6479

6580
fn render_argument(out: &mut String, arg: &Arg) {
@@ -232,3 +247,35 @@ fn ensure_ends_with_punctuation(line: &str) -> Cow<'_, str> {
232247
Cow::Owned(format!("{line}."))
233248
}
234249
}
250+
251+
/// Rejects any argument whose visible alias duplicates its own primary flag name.
252+
///
253+
/// A visible alias matching the argument's own long name, or a visible short alias
254+
/// matching its own short flag, is a coding mistake that produces redundant output in
255+
/// USAGE.md.
256+
fn reject_redundant_aliases(command: &Command) -> Result<(), RenderUsageMdError> {
257+
for arg in command.get_arguments() {
258+
if let Some(primary_long) = arg.get_long() {
259+
for alias in arg.get_visible_aliases().unwrap_or_default() {
260+
if alias == primary_long {
261+
return primary_long
262+
.to_owned()
263+
.pipe(RenderUsageMdError::RedundantVisibleLongAlias)
264+
.pipe(Err);
265+
}
266+
}
267+
}
268+
269+
if let Some(primary_short) = arg.get_short() {
270+
for alias in arg.get_visible_short_aliases().unwrap_or_default() {
271+
if alias == primary_short {
272+
return primary_short
273+
.pipe(RenderUsageMdError::RedundantVisibleShortAlias)
274+
.pipe(Err);
275+
}
276+
}
277+
}
278+
}
279+
280+
Ok(())
281+
}

tests/sync_usage_md.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use parallel_disk_usage::usage_md::render_usage_md;
1111

1212
#[test]
1313
fn usage_md() {
14-
let actual = render_usage_md();
14+
let actual = render_usage_md().unwrap_or_else(|error| {
15+
panic!("failed to render usage markdown: {error}");
16+
});
1517
let expected = include_str!("../USAGE.md");
1618
assert!(
1719
actual.trim_end() == expected.trim_end(),

0 commit comments

Comments
 (0)