clap_fmt 0.1.1

Serialize a clap arg parser into the command-line arguments.
Documentation
use clap::Parser;
use clap_fmt::FmtArgs;
use serde::Serialize;

// Test different argument positions
#[derive(Parser, Debug, Serialize)]
struct CliWithPositions {
    #[arg(index = 1)]
    first: String,

    #[arg(index = 2)]
    second: String,

    #[arg(long)]
    flag: bool,

    #[arg(index = 3, num_args = 1..)]
    rest: Vec<String>,
}

#[test]
fn test_positional_ordering() {
    let cli = CliWithPositions {
        first: "one".to_string(),
        second: "two".to_string(),
        flag: true,
        rest: vec!["three".to_string(), "four".to_string()],
    };

    let result = cli.to_args();
    assert_eq!(result, vec!["one", "two", "--flag", "three", "four"]);
}

// Test short-only and long-only flags
#[derive(Parser, Debug, Serialize)]
struct CliWithShortLong {
    #[arg(short)]
    short_only: bool,

    #[arg(long)]
    long_only: bool,

    #[arg(short = 'x')]
    custom_short: bool,

    #[arg(long = "custom-long")]
    custom_long: bool,

    #[arg(short, long)]
    both: bool,
}

#[test]
fn test_short_long_flags() {
    let cli = CliWithShortLong {
        short_only: true,
        long_only: true,
        custom_short: true,
        custom_long: true,
        both: true,
    };

    let result = cli.to_args();
    assert_eq!(result, vec!["-s", "--long-only", "-x", "--custom-long", "--both"]);
}

// Test environment variables and other special cases
#[derive(Parser, Debug, Serialize)]
struct CliWithEnv {
    #[arg(long, env = "MY_CONFIG")]
    config: Option<String>,

    #[arg(long, hide = true)]
    hidden: bool,

    #[arg(long, alias = "colour")]
    color: bool,
}

#[test]
fn test_env_and_special() {
    let cli = CliWithEnv {
        config: Some("app.conf".to_string()),
        hidden: true,
        color: true,
    };

    let result = cli.to_args();
    assert_eq!(result, vec!["--config", "app.conf", "--hidden", "--color"]);
}

// Test exclusive and conflicting arguments
#[derive(Parser, Debug, Serialize)]
struct CliWithConflicts {
    #[arg(long, conflicts_with = "json")]
    xml: bool,

    #[arg(long, conflicts_with = "xml")]
    json: bool,

    #[arg(long, required_unless_present = "input")]
    output: Option<String>,

    #[arg(long, required_unless_present = "output")]
    input: Option<String>,
}

#[test]
fn test_conflicts() {
    let cli = CliWithConflicts {
        xml: true,
        json: false,
        output: Some("out.txt".to_string()),
        input: None,
    };

    let result = cli.to_args();
    assert_eq!(result, vec!["--xml", "--output", "out.txt"]);
}

// Test value names and help strings (they don't affect output but shouldn't break)
#[derive(Parser, Debug, Serialize)]
struct CliWithMetadata {
    /// This is a help string
    #[arg(short, long, value_name = "FILE", help = "Input file to process")]
    input: String,

    /// Another help string
    #[arg(
        short,
        long,
        value_name = "DIR",
        long_help = "Output directory for results"
    )]
    output: String,
}

#[test]
fn test_metadata_doesnt_break() {
    let cli = CliWithMetadata {
        input: "in.txt".to_string(),
        output: "out/".to_string(),
    };

    let result = cli.to_args();
    assert_eq!(result, vec!["--input", "in.txt", "--output", "out/"]);
}