#![allow(dead_code)]
use facet::Facet;
use facet_args as args;
#[derive(Facet, Debug)]
struct SimpleArgs {
#[facet(args::named, args::short = 'v')]
verbose: bool,
#[facet(args::named, args::short = 'j')]
jobs: Option<usize>,
#[facet(args::positional)]
input: String,
#[facet(default, args::positional)]
output: Option<String>,
}
#[test]
fn test_help_simple_struct() {
let config = facet_args::HelpConfig {
program_name: Some("myapp".to_string()),
version: Some("1.0.0".to_string()),
..Default::default()
};
let help = facet_args::generate_help::<SimpleArgs>(&config);
insta::assert_snapshot!(help);
}
#[derive(Facet, Debug)]
struct GitArgs {
#[facet(args::named)]
version: bool,
#[facet(args::subcommand)]
command: GitCommand,
}
#[derive(Facet, Debug)]
#[repr(u8)]
enum GitCommand {
Clone {
#[facet(args::positional)]
url: String,
#[facet(default, args::positional)]
directory: Option<String>,
},
Log {
#[facet(args::named, args::short = 'n')]
count: Option<usize>,
#[facet(args::named)]
oneline: bool,
},
Remote {
#[facet(args::subcommand)]
action: RemoteAction,
},
}
#[derive(Facet, Debug)]
#[repr(u8)]
enum RemoteAction {
Add {
#[facet(args::positional)]
name: String,
#[facet(args::positional)]
url: String,
},
#[facet(rename = "rm")]
Remove {
#[facet(args::positional)]
name: String,
},
#[facet(rename = "ls")]
List {
#[facet(args::named, args::short = 'v')]
verbose: bool,
},
}
#[test]
fn test_help_with_subcommands() {
let config = facet_args::HelpConfig {
program_name: Some("git".to_string()),
version: Some("2.40.0".to_string()),
..Default::default()
};
let help = facet_args::generate_help::<GitArgs>(&config);
insta::assert_snapshot!(help);
}
#[test]
fn test_help_enum_only() {
let config = facet_args::HelpConfig {
program_name: Some("git".to_string()),
..Default::default()
};
let help = facet_args::generate_help::<GitCommand>(&config);
insta::assert_snapshot!(help);
}
#[test]
fn test_auto_help_long_flag() {
let result = facet_args::from_slice::<SimpleArgs>(&["--help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
assert!(err.help_text().is_some());
let help = err.help_text().unwrap();
assert!(help.contains("USAGE"));
assert!(help.contains("--verbose"));
}
#[test]
fn test_auto_help_short_flag() {
let result = facet_args::from_slice::<SimpleArgs>(&["-h"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
}
#[test]
fn test_auto_help_single_dash() {
let result = facet_args::from_slice::<SimpleArgs>(&["-help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
}
#[test]
fn test_auto_help_windows_style() {
let result = facet_args::from_slice::<SimpleArgs>(&["/?"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
}
#[test]
fn test_auto_help_with_custom_config() {
let config = facet_args::HelpConfig {
program_name: Some("myapp".to_string()),
version: Some("2.0.0".to_string()),
..Default::default()
};
let result = facet_args::from_slice_with_config::<SimpleArgs>(&["--help"], &config);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
let help = err.help_text().unwrap();
assert!(help.contains("myapp 2.0.0"));
}
#[test]
fn test_auto_help_display() {
let result = facet_args::from_slice::<SimpleArgs>(&["--help"]);
let err = result.unwrap_err();
let display = format!("{}", err);
assert!(display.contains("USAGE"));
}
#[test]
fn test_help_not_triggered_with_other_args() {
let result = facet_args::from_slice::<SimpleArgs>(&["input.txt", "--help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(!err.is_help_request());
}
#[test]
fn test_subcommand_help_long_flag() {
let result = facet_args::from_slice::<GitArgs>(&["clone", "--help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
let help = err.help_text().unwrap();
assert!(help.contains("clone"));
}
#[test]
fn test_subcommand_help_short_flag() {
let result = facet_args::from_slice::<GitArgs>(&["log", "-h"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
let help = err.help_text().unwrap();
assert!(help.contains("log"));
}
#[test]
fn test_nested_subcommand_help() {
let result = facet_args::from_slice::<GitArgs>(&["remote", "add", "--help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
let help = err.help_text().unwrap();
assert!(help.contains("add"));
}
#[test]
fn test_missing_required_subcommand_error() {
let result = facet_args::from_slice::<GitArgs>(&[]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(!err.is_help_request());
let display = format!("{}", err);
assert!(display.contains("expected a subcommand"));
assert!(display.contains("clone") || display.contains("log") || display.contains("remote"));
}
#[test]
fn test_unknown_subcommand_error() {
let result = facet_args::from_slice::<GitArgs>(&["notacommand"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(!err.is_help_request());
let display = format!("{}", err);
assert!(display.contains("notacommand") || display.contains("unknown"));
assert!(display.contains("clone") || display.contains("log") || display.contains("remote"));
}
#[test]
fn test_subcommand_help_colored_snapshot() {
let result = facet_args::from_slice::<GitArgs>(&["clone", "--help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
let help = err.help_text().unwrap();
assert!(help.contains("USAGE") || help.contains("ARGUMENTS"));
insta::assert_snapshot!(help);
}
#[test]
fn test_nested_subcommand_help_colored_snapshot() {
let result = facet_args::from_slice::<GitArgs>(&["remote", "add", "--help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
let help = err.help_text().unwrap();
assert!(help.contains("remote") && help.contains("add"));
insta::assert_snapshot!(help);
}
#[test]
fn test_tuple_variant_subcommand_help_flattening() {
#[derive(Facet, Debug)]
struct BuildArgs {
#[facet(args::named, args::short = 'r')]
release: bool,
#[facet(args::named)]
no_spawn: bool,
#[facet(args::named)]
no_tui: bool,
}
#[derive(Facet, Debug)]
#[repr(u8)]
enum Command {
Build(BuildArgs),
Test {
#[facet(args::named, args::short = 'v')]
verbose: bool,
},
}
#[derive(Facet, Debug)]
struct Args {
#[facet(args::subcommand)]
command: Command,
}
let config = facet_args::HelpConfig {
program_name: Some("myapp".to_string()),
..Default::default()
};
let help = facet_args::generate_help::<Args>(&config);
insta::assert_snapshot!("tuple_variant_main_help", help);
let result = facet_args::from_slice::<Args>(&["build", "--help"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.is_help_request());
let help = err.help_text().unwrap();
assert!(
!help.contains("--0"),
"Help should not show --0 for tuple variant fields. Got:\n{help}"
);
assert!(
help.contains("--release") || help.contains("-r"),
"Help should show --release flag. Got:\n{help}"
);
assert!(
help.contains("--no-spawn"),
"Help should show --no-spawn flag. Got:\n{help}"
);
assert!(
help.contains("--no-tui"),
"Help should show --no-tui flag. Got:\n{help}"
);
insta::assert_snapshot!("tuple_variant_subcommand_help", help);
}