use clap::{Parser, Subcommand};
use ortho_config::{OrthoConfig, ResultIntoFigment, SubcmdConfigMerge};
use serde::{Deserialize, Serialize};
#[derive(Debug, Parser)]
struct Cli {
#[command(subcommand)]
cmd: Commands,
}
#[derive(Debug, Subcommand)]
enum Commands {
Run(RunArgs),
}
#[derive(Debug, Deserialize, Serialize, Parser, OrthoConfig, Default)]
#[command(name = "run")]
#[ortho_config(prefix = "APP_")]
struct RunArgs {
#[arg(long)]
option: Option<String>,
#[arg(long)]
count: Option<u32>,
}
#[test]
fn merge_works_for_subcommand() {
figment::Jail::expect_with(|j| {
j.create_file(".app.toml", "[cmds.run]\noption = \"file\"")?;
let cli = Cli::parse_from(["prog", "run", "--option", "cli"]);
let Commands::Run(args) = cli.cmd;
let cfg = args.load_and_merge().to_figment()?;
assert_eq!(cfg.option.as_deref(), Some("cli"));
Ok(())
});
}
#[test]
fn merge_falls_back_to_env_when_cli_none() {
figment::Jail::expect_with(|j| {
j.set_env("APP_CMDS_RUN_OPTION", "env");
let cli = Cli::parse_from(["prog", "run"]);
let Commands::Run(args) = cli.cmd;
let cfg = args.load_and_merge().to_figment()?;
assert_eq!(cfg.option.as_deref(), Some("env"));
Ok(())
});
}
#[test]
fn merge_falls_back_to_file_when_cli_none() {
figment::Jail::expect_with(|j| {
j.clear_env();
j.create_file(".app.toml", "[cmds.run]\noption = \"file\"")?;
let cli = Cli::parse_from(["prog", "run"]);
let Commands::Run(args) = cli.cmd;
let cfg = args.load_and_merge().to_figment()?;
assert_eq!(cfg.option.as_deref(), Some("file"));
Ok(())
});
}
#[test]
fn merge_errors_on_invalid_file() {
figment::Jail::expect_with(|j| {
j.create_file(".app.toml", "[cmds.run]\noption = 5")?;
let cli = Cli::parse_from(["prog", "run"]);
let Commands::Run(args) = cli.cmd;
assert!(args.load_and_merge().is_err());
Ok(())
});
}
#[test]
fn merge_errors_on_invalid_env() {
figment::Jail::expect_with(|j| {
j.set_env("APP_CMDS_RUN_COUNT", "not-a-number");
let cli = Cli::parse_from(["prog", "run"]);
let Commands::Run(args) = cli.cmd;
assert!(args.load_and_merge().is_err());
Ok(())
});
}