use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "tcproxy")]
#[command(about = "A TCP proxy for PostgreSQL connections with SSH tunnel support")]
#[command(version = "0.1.0")]
pub struct Cli {
#[arg(short, long, default_value = "config.yaml")]
pub config: PathBuf,
#[arg(short, long, default_value = "info")]
pub log_level: String,
#[arg(long)]
pub json_logs: bool,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand)]
pub enum Commands {
Start {
#[arg(short, long)]
target: String,
#[arg(short, long)]
port: Option<u16>,
#[arg(long)]
host: Option<String>,
},
InitConfig {
#[arg(short, long, default_value = "config.yaml")]
output: PathBuf,
#[arg(long)]
force: bool,
},
ValidateConfig,
ShowConfig,
ListTargets,
HealthCheck {
#[arg(short, long)]
target: Option<String>,
},
}
impl Cli {
pub fn parse_args() -> Self {
Self::parse()
}
}
#[cfg(test)]
mod tests {
use super::*;
use clap::Parser;
#[test]
fn test_cli_default_values() {
let cli = Cli::try_parse_from(&["tcproxy", "start", "--target", "local"]).unwrap();
assert_eq!(cli.config, PathBuf::from("config.yaml"));
assert_eq!(cli.log_level, "info");
assert!(!cli.json_logs);
if let Some(Commands::Start { target, port, host }) = cli.command {
assert_eq!(target, "local");
assert!(port.is_none());
assert!(host.is_none());
} else {
panic!("Expected Start command");
}
}
#[test]
fn test_cli_custom_values() {
let cli = Cli::try_parse_from(&[
"tcproxy",
"--config",
"custom.yaml",
"--log-level",
"debug",
"--json-logs",
"start",
"--target",
"production",
"--port",
"5434",
"--host",
"0.0.0.0",
])
.unwrap();
assert_eq!(cli.config, PathBuf::from("custom.yaml"));
assert_eq!(cli.log_level, "debug");
assert!(cli.json_logs);
if let Some(Commands::Start { target, port, host }) = cli.command {
assert_eq!(target, "production");
assert_eq!(port, Some(5434));
assert_eq!(host, Some("0.0.0.0".to_string()));
} else {
panic!("Expected Start command");
}
}
#[test]
fn test_init_config_command() {
let cli =
Cli::try_parse_from(&["tcproxy", "init-config", "--output", "test.yaml", "--force"])
.unwrap();
if let Some(Commands::InitConfig { output, force }) = cli.command {
assert_eq!(output, PathBuf::from("test.yaml"));
assert!(force);
} else {
panic!("Expected InitConfig command");
}
}
#[test]
fn test_health_check_command() {
let cli = Cli::try_parse_from(&["tcproxy", "health-check", "--target", "local"]).unwrap();
if let Some(Commands::HealthCheck { target }) = cli.command {
assert_eq!(target, Some("local".to_string()));
} else {
panic!("Expected HealthCheck command");
}
}
#[test]
fn test_validate_config_command() {
let cli = Cli::try_parse_from(&["tcproxy", "validate-config"]).unwrap();
if let Some(Commands::ValidateConfig) = cli.command {
} else {
panic!("Expected ValidateConfig command");
}
}
#[test]
fn test_show_config_command() {
let cli = Cli::try_parse_from(&["tcproxy", "show-config"]).unwrap();
if let Some(Commands::ShowConfig) = cli.command {
} else {
panic!("Expected ShowConfig command");
}
}
#[test]
fn test_list_targets_command() {
let cli = Cli::try_parse_from(&["tcproxy", "list-targets"]).unwrap();
if let Some(Commands::ListTargets) = cli.command {
} else {
panic!("Expected ListTargets command");
}
}
#[test]
fn test_missing_target_for_start() {
let result = Cli::try_parse_from(&["tcproxy", "start"]);
assert!(result.is_err());
}
}