help-probe 0.1.0

CLI tool discovery and automation framework that extracts structured information from command help text
Documentation
use help_probe::completion::{Shell, generate_shell_completion};
use help_probe::model::{ArgumentSpec, ArgumentType, OptionSpec, ProbeResult, SubcommandSpec};

fn create_test_result() -> ProbeResult {
    ProbeResult {
        command: "mytool".to_string(),
        args: vec!["--help".to_string()],
        exit_code: Some(0),
        timed_out: false,
        help_flag_detected: true,
        usage_blocks: vec!["Usage: mytool [OPTIONS] <FILE>".to_string()],
        options: vec![
            OptionSpec {
                short_flags: vec!["-h".to_string(), "-v".to_string()],
                long_flags: vec!["--help".to_string(), "--verbose".to_string()],
                description: Some("Show help".to_string()),
                option_type: help_probe::model::OptionType::Boolean,
                required: false,
                default_value: None,
                takes_argument: false,
                argument_name: None,
                choices: vec![],
            },
            OptionSpec {
                short_flags: vec![],
                long_flags: vec!["--file".to_string()],
                description: Some("Input file".to_string()),
                option_type: help_probe::model::OptionType::Path,
                required: false,
                default_value: None,
                takes_argument: true,
                argument_name: Some("FILE".to_string()),
                choices: vec![],
            },
        ],
        subcommands: vec![
            SubcommandSpec {
                name: "build".to_string(),
                description: Some("Build the project".to_string()),
                full_path: "build".to_string(),
                parent: None,
                options: Vec::new(),
                arguments: Vec::new(),
                subcommands: Vec::new(),
            },
            SubcommandSpec {
                name: "run".to_string(),
                description: Some("Run the project".to_string()),
                full_path: "run".to_string(),
                parent: None,
                options: Vec::new(),
                arguments: Vec::new(),
                subcommands: Vec::new(),
            },
        ],
        arguments: vec![ArgumentSpec {
            name: "FILE".to_string(),
            description: Some("Input file".to_string()),
            required: true,
            variadic: false,
            arg_type: Some(ArgumentType::Path),
            placeholder: Some("<FILE>".to_string()),
        }],
        examples: vec![],
        environment_variables: vec![],
        validation_rules: vec![],
        raw_stdout: "Usage: mytool [OPTIONS] <FILE>".to_string(),
        raw_stderr: String::new(),
    }
}

#[test]
fn generate_bash_completion() {
    let result = create_test_result();
    let bash_completion = generate_shell_completion(&result, Shell::Bash);

    // Check that it contains expected elements
    assert!(bash_completion.contains("mytool"));
    assert!(bash_completion.contains("--help"));
    assert!(bash_completion.contains("--verbose"));
    assert!(bash_completion.contains("build"));
    assert!(bash_completion.contains("run"));
    assert!(bash_completion.contains("complete -F"));
}

#[test]
fn generate_zsh_completion() {
    let result = create_test_result();
    let zsh_completion = generate_shell_completion(&result, Shell::Zsh);

    // Verify basic structure
    assert!(zsh_completion.contains("#compdef mytool"));
    assert!(zsh_completion.contains("--help"));

    // Verify function wrapper is present (to prevent history issues when sourcing)
    assert!(zsh_completion.contains("_mytool_completion()"));
    assert!(zsh_completion.contains("local -a opts="));
    assert!(zsh_completion.contains("_arguments"));

    // Verify function is called at the end
    assert!(zsh_completion.contains("_mytool_completion"));

    // Verify subcommands are included
    assert!(zsh_completion.contains("build"));
    assert!(zsh_completion.contains("run"));
}

#[test]
fn generate_fish_completion() {
    let result = create_test_result();
    let fish_completion = generate_shell_completion(&result, Shell::Fish);

    assert!(fish_completion.contains("complete -c mytool"));
    assert!(fish_completion.contains("-l help"));
}

#[test]
fn generate_powershell_completion() {
    let result = create_test_result();
    let pwsh_completion = generate_shell_completion(&result, Shell::PowerShell);

    assert!(pwsh_completion.contains("Register-ArgumentCompleter"));
    assert!(pwsh_completion.contains("mytool"));
}

#[test]
fn generate_nushell_completion() {
    let result = create_test_result();
    let nushell_completion = generate_shell_completion(&result, Shell::NuShell);

    // Check that it contains expected elements
    assert!(nushell_completion.contains("extern mytool"));
    assert!(nushell_completion.contains("--help"));
    assert!(nushell_completion.contains("--verbose"));
    assert!(nushell_completion.contains("--file"));
    assert!(nushell_completion.contains("subcommand"));
    assert!(nushell_completion.contains("build"));
    assert!(nushell_completion.contains("run"));
}

#[test]
fn shell_from_str() {
    use help_probe::completion::Shell;

    assert_eq!(Shell::from_str("bash"), Some(Shell::Bash));
    assert_eq!(Shell::from_str("BASH"), Some(Shell::Bash));
    assert_eq!(Shell::from_str("zsh"), Some(Shell::Zsh));
    assert_eq!(Shell::from_str("fish"), Some(Shell::Fish));
    assert_eq!(Shell::from_str("powershell"), Some(Shell::PowerShell));
    assert_eq!(Shell::from_str("pwsh"), Some(Shell::PowerShell));
    assert_eq!(Shell::from_str("nushell"), Some(Shell::NuShell));
    assert_eq!(Shell::from_str("nu"), Some(Shell::NuShell));
    assert_eq!(Shell::from_str("NuShell"), Some(Shell::NuShell));
    assert_eq!(Shell::from_str("invalid"), None);
}