use crate::cli::Cli;
use clap::{CommandFactory, Parser};
use parking_lot::Mutex;
static ENV_MUTEX: Mutex<()> = Mutex::new(());
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{AnalyzeCommands, Commands};
use std::env;
#[test]
fn test_derive_parser_propagation() {
let cmd = Cli::command();
assert_eq!(cmd.get_name(), "pmat");
assert!(cmd.get_about().is_some());
assert!(cmd.get_version().is_some());
}
#[test]
fn test_binary_name_detection() {
let cmd = Cli::command();
assert_eq!(cmd.get_name(), "pmat");
let cmd_with_name = cmd.clone().name("pmat");
assert_eq!(cmd_with_name.get_name(), "pmat");
}
#[test]
fn test_global_args_accessible() {
let cli = Cli::try_parse_from(["pmat", "--verbose", "analyze", "complexity"]);
assert!(cli.is_ok());
let cli = cli.unwrap();
assert!(cli.verbose);
assert!(!cli.debug);
assert!(!cli.trace);
let cli = Cli::try_parse_from(["pmat", "--debug", "generate", "makefile", "rust"]);
assert!(cli.is_ok());
let cli = cli.unwrap();
assert!(cli.debug);
}
#[test]
fn test_subcommand_hierarchy() {
let cmd = Cli::command();
let subcommands: Vec<_> = cmd.get_subcommands().map(|sc| sc.get_name()).collect();
assert!(subcommands.contains(&"generate"));
assert!(subcommands.contains(&"analyze"));
assert!(subcommands.contains(&"demo"));
assert!(subcommands.contains(&"scaffold"));
assert!(subcommands.contains(&"list"));
assert!(subcommands.contains(&"search"));
assert!(subcommands.contains(&"validate"));
assert!(subcommands.contains(&"context"));
assert!(subcommands.contains(&"serve"));
let analyze_cmd = cmd.find_subcommand("analyze").unwrap();
let analyze_subs: Vec<_> = analyze_cmd
.get_subcommands()
.map(|sc| sc.get_name())
.collect();
assert!(analyze_subs.contains(&"churn"));
assert!(analyze_subs.contains(&"complexity"));
assert!(analyze_subs.contains(&"dag"));
assert!(analyze_subs.contains(&"dead-code"));
assert!(analyze_subs.contains(&"deep-context"));
assert!(analyze_subs.contains(&"satd"));
}
#[test]
fn test_propagate_version() {
let cmd = Cli::command();
assert!(cmd.get_version().is_some());
let analyze_cmd = cmd.find_subcommand("analyze");
assert!(analyze_cmd.is_some());
}
#[test]
fn test_help_generation() {
let cmd = Cli::command();
let mut help_output = Vec::new();
let _ = cmd.clone().write_help(&mut help_output);
assert!(!help_output.is_empty());
let mut long_help_output = Vec::new();
let _ = cmd.clone().write_long_help(&mut long_help_output);
assert!(!long_help_output.is_empty());
let help_str = String::from_utf8_lossy(&help_output);
assert!(!help_str.is_empty(), "Help output should not be empty");
assert!(
help_str.contains("Usage:"),
"Help should contain Usage section"
);
}
#[test]
fn test_env_var_support() {
let _guard = ENV_MUTEX.lock();
unsafe {
env::set_var("RUST_LOG", "debug");
}
let cli = Cli::try_parse_from(["pmat", "list"]);
assert!(cli.is_ok());
let cli = cli.unwrap();
assert_eq!(cli.trace_filter, Some("debug".to_string()));
unsafe {
env::remove_var("RUST_LOG");
}
}
#[test]
fn test_command_aliases() {
let cli = Cli::try_parse_from(["pmat", "gen", "makefile", "rust"]);
match cli {
Ok(parsed) => {
match parsed.command {
Commands::Generate { .. } => {
}
_ => panic!("Expected Generate command"),
}
}
Err(_) => {
}
}
}
#[test]
fn test_required_args_validation() {
let result = Cli::try_parse_from(["pmat", "generate"]);
assert!(result.is_err(), "Generate should require template type");
let result = Cli::try_parse_from(["pmat", "generate", "makefile", "rust"]);
assert!(
result.is_ok(),
"Generate with all required args should succeed"
);
}
#[test]
fn test_global_flags_precedence() {
let variations = vec![
vec!["pmat", "--verbose", "list"],
vec!["pmat", "list", "--verbose"],
vec!["pmat", "--debug", "analyze", "complexity", "--verbose"],
];
for args in variations {
let result = Cli::try_parse_from(args.clone());
assert!(result.is_ok(), "Failed to parse: {args:?}");
}
}
#[test]
fn test_subcommand_specific_args() {
let cli = Cli::try_parse_from([
"pmat",
"analyze",
"complexity",
"--top-files",
"10",
"--format",
"json",
]);
assert!(cli.is_ok());
if let Ok(parsed) = cli {
match parsed.command {
Commands::Analyze(AnalyzeCommands::Complexity {
top_files, format, ..
}) => {
assert_eq!(top_files, 10);
let _ = format;
}
_ => panic!("Expected Analyze::Complexity command"),
}
}
}
#[test]
fn test_value_enum_parsing() {
let cli = Cli::try_parse_from(["pmat", "--mode", "cli", "list"]);
assert!(cli.is_ok());
let cli = Cli::try_parse_from(["pmat", "--mode", "invalid", "list"]);
assert!(cli.is_err());
}
#[test]
fn test_command_error_suggestions() {
let result = Cli::try_parse_from(["pmat", "analize", "complexity"]);
if let Err(e) = result {
let error_str = e.to_string();
assert!(
error_str.contains("unrecognized")
|| error_str.contains("unknown")
|| error_str.contains("analyze")
|| error_str.contains("did you mean"),
"Error should be helpful: {error_str}"
);
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod clap_derive_completeness_tests {
use super::*;
#[test]
fn test_all_commands_have_help() {
let cmd = Cli::command();
fn check_command_help(cmd: &clap::Command) {
assert!(
cmd.get_about().is_some() || cmd.get_long_about().is_some(),
"Command '{}' missing help text",
cmd.get_name()
);
for subcmd in cmd.get_subcommands() {
check_command_help(subcmd);
}
}
check_command_help(&cmd);
}
#[test]
fn test_all_args_have_help() {
let cmd = Cli::command();
fn check_args_help(cmd: &clap::Command) {
for arg in cmd.get_arguments() {
if arg.get_id() == "help" || arg.get_id() == "version" {
continue;
}
assert!(
arg.get_help().is_some() || arg.get_long_help().is_some(),
"Argument '{}' in command '{}' missing help text",
arg.get_id(),
cmd.get_name()
);
}
for subcmd in cmd.get_subcommands() {
check_args_help(subcmd);
}
}
check_args_help(&cmd);
}
#[test]
fn test_conflicting_args() {
let cli = Cli::try_parse_from(["pmat", "--verbose", "--debug", "list"]);
assert!(cli.is_ok());
let cli = cli.unwrap();
assert!(cli.verbose);
assert!(cli.debug);
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod clap_output_validation_tests {
use super::*;
#[test]
fn test_help_output_format() {
let cmd = Cli::command();
let mut help = Vec::new();
let _ = cmd.clone().write_help(&mut help);
let help_str = String::from_utf8_lossy(&help);
assert!(help_str.contains("Usage:"));
assert!(help_str.contains("Commands:"));
assert!(help_str.contains("Options:"));
assert!(!help_str.is_empty(), "Help should not be empty");
}
#[test]
fn test_error_output_format() {
let result = Cli::try_parse_from(["pmat", "--unknown-flag"]);
assert!(result.is_err());
if let Err(e) = result {
let error_str = e.to_string();
assert!(error_str.contains("unknown") || error_str.contains("unexpected"));
}
}
}