fn parse_cli(args: Vec<&'static str>) -> Result<Cli, clap::error::Error> {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(move || Cli::try_parse_from(args))
.expect("spawn thread")
.join()
.expect("join thread")
}
#[test]
fn test_cli_parsing_valid() {
use clap::CommandFactory;
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| Cli::command().debug_assert())
.expect("spawn")
.join()
.expect("join");
}
#[test]
fn test_parse_code_model_after_prompt_is_honoured() {
let args = vec!["apr", "code", "-p", "hi", "--model", "/tmp/named.gguf"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Code {
model,
prompt,
print,
..
} => {
assert!(print, "-p must still set print");
assert_eq!(
model,
Some(PathBuf::from("/tmp/named.gguf")),
"--model written after the prompt must be honoured, not swallowed"
);
assert_eq!(
prompt,
vec!["hi".to_string()],
"the prompt must not absorb the option"
);
}
_ => panic!("Expected Code command"),
}
}
#[test]
fn test_parse_code_unknown_option_after_prompt_is_rejected() {
let args = vec!["apr", "code", "-p", "hi", "--totally-bogus-flag-xyz"];
let err = parse_cli(args)
.expect_err("an unknown option after the prompt must fail to parse");
assert_eq!(
err.kind(),
clap::error::ErrorKind::UnknownArgument,
"expected UnknownArgument, got {:?}",
err.kind()
);
}
#[test]
fn test_parse_code_multiword_prompt_still_collects() {
let args = vec!["apr", "code", "-p", "fix", "the", "auth", "bug"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Code { prompt, .. } => {
assert_eq!(prompt, vec!["fix", "the", "auth", "bug"]);
}
_ => panic!("Expected Code command"),
}
}
#[test]
fn test_parse_inspect_command() {
let args = vec!["apr", "inspect", "model.apr"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Inspect { file, .. } => {
assert_eq!(file, PathBuf::from("model.apr"));
}
_ => panic!("Expected Inspect command"),
}
}
#[test]
fn test_parse_inspect_with_flags() {
let args = vec!["apr", "inspect", "model.apr", "--vocab", "--json"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Inspect {
file, vocab, json, ..
} => {
assert_eq!(file, PathBuf::from("model.apr"));
assert!(vocab);
assert!(json);
}
_ => panic!("Expected Inspect command"),
}
}
#[test]
fn test_parse_serve_command() {
let args = vec!["apr", "serve", "run", "model.apr", "--port", "3000"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Serve {
command: ServeCommands::Run { ref file, port, .. },
} => {
assert_eq!(*file, PathBuf::from("model.apr"));
assert_eq!(port, 3000);
}
_ => panic!("Expected Serve Run command"),
}
}
#[test]
fn test_parse_run_command() {
let args = vec![
"apr",
"run",
"hf://openai/whisper-tiny",
"--prompt",
"Hello",
"--max-tokens",
"64",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Run {
source,
prompt,
max_tokens,
..
} => {
assert_eq!(source, "hf://openai/whisper-tiny");
assert_eq!(prompt, Some("Hello".to_string()));
assert_eq!(max_tokens, 64);
}
_ => panic!("Expected Run command"),
}
}
#[test]
fn test_parse_run_stream_flag() {
let args = vec!["apr", "run", "model.gguf", "--prompt", "Hi", "--stream"];
let cli = parse_cli(args).expect("Failed to parse --stream");
match *cli.command {
Commands::Run {
source,
stream,
..
} => {
assert_eq!(source, "model.gguf");
assert!(stream, "--stream must set stream=true");
}
_ => panic!("Expected Run command"),
}
}
#[test]
fn test_parse_run_stream_default_false() {
let args = vec!["apr", "run", "model.gguf", "--prompt", "Hi"];
let cli = parse_cli(args).expect("Failed to parse default");
match *cli.command {
Commands::Run { stream, .. } => assert!(!stream, "--stream defaults to false"),
_ => panic!("Expected Run command"),
}
}
#[test]
fn test_parse_chat_command() {
let args = vec![
"apr",
"chat",
"model.gguf",
"--temperature",
"0.5",
"--top-p",
"0.95",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Chat {
file,
temperature,
top_p,
..
}) => {
assert_eq!(file, PathBuf::from("model.gguf"));
assert!((temperature - 0.5).abs() < f32::EPSILON);
assert!((top_p - 0.95).abs() < f32::EPSILON);
}
_ => panic!("Expected Chat command"),
}
}
#[test]
fn test_parse_validate_with_quality() {
let args = vec!["apr", "validate", "model.apr", "--quality", "--strict"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Validate {
file,
quality,
strict,
..
} => {
assert_eq!(file, PathBuf::from("model.apr"));
assert!(quality);
assert!(strict);
}
_ => panic!("Expected Validate command"),
}
}
#[test]
fn test_parse_diff_command() {
let args = vec!["apr", "diff", "model1.apr", "model2.apr", "--weights"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Diff {
file1,
file2,
weights,
..
} => {
assert_eq!(file1, PathBuf::from("model1.apr"));
assert_eq!(file2, PathBuf::from("model2.apr"));
assert!(weights);
}
_ => panic!("Expected Diff command"),
}
}
#[test]
fn test_parse_bench_command() {
let args = vec![
"apr",
"bench",
"model.gguf",
"--warmup",
"5",
"--iterations",
"10",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Bench {
file,
warmup,
iterations,
..
}) => {
assert_eq!(file, PathBuf::from("model.gguf"));
assert_eq!(warmup, 5);
assert_eq!(iterations, 10);
}
_ => panic!("Expected Bench command"),
}
}
#[test]
fn test_parse_cbtop_ci_mode() {
let args = vec![
"apr",
"cbtop",
"--headless",
"--ci",
"--throughput",
"100.0",
"--brick-score",
"90",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Cbtop {
headless,
ci,
throughput,
brick_score,
..
}) => {
assert!(headless);
assert!(ci);
assert_eq!(throughput, Some(100.0));
assert_eq!(brick_score, Some(90));
}
_ => panic!("Expected Cbtop command"),
}
}
#[test]
fn test_parse_cbtop_rejects_zero_iterations() {
let args = vec![
"apr",
"cbtop",
"--headless",
"--simulated",
"--ci",
"--iterations",
"0",
];
assert!(
parse_cli(args).is_err(),
"cbtop accepted --iterations 0 at parse time"
);
let ok = vec!["apr", "cbtop", "--headless", "--iterations", "1"];
let cli = parse_cli(ok).expect("--iterations 1 should parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Cbtop { iterations, .. }) => {
assert_eq!(iterations, 1);
}
_ => panic!("Expected Cbtop command"),
}
}
#[test]
fn test_parse_cbtop_json_requires_headless() {
assert!(
parse_cli(vec!["apr", "cbtop", "--json"]).is_err(),
"cbtop --json was accepted without --headless"
);
assert!(
parse_cli(vec!["apr", "cbtop", "--output", "r.json"]).is_err(),
"cbtop --output was accepted without --headless"
);
let cli = parse_cli(vec!["apr", "cbtop", "--headless", "--json"])
.expect("--json --headless should parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Cbtop { headless, json, .. }) => {
assert!(headless);
assert!(json);
}
_ => panic!("Expected Cbtop command"),
}
}
#[test]
fn test_parse_qa_command() {
let args = vec![
"apr",
"qa",
"model.gguf",
"--assert-tps",
"50.0",
"--skip-ollama",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Qa {
file,
assert_tps,
skip_ollama,
..
}) => {
assert_eq!(file, PathBuf::from("model.gguf"));
assert_eq!(assert_tps, Some(50.0));
assert!(skip_ollama);
}
_ => panic!("Expected Qa command"),
}
}
#[test]
fn test_global_verbose_flag() {
let args = vec!["apr", "--verbose", "inspect", "model.apr"];
let cli = parse_cli(args).expect("Failed to parse");
assert!(cli.verbose);
}
#[test]
fn test_global_json_flag() {
let args = vec!["apr", "--json", "inspect", "model.apr"];
let cli = parse_cli(args).expect("Failed to parse");
assert!(cli.json);
}
#[test]
fn test_parse_list_command() {
let args = vec!["apr", "list"];
let cli = parse_cli(args).expect("Failed to parse");
assert!(matches!(*cli.command, Commands::List));
}
#[test]
fn test_parse_ls_alias() {
let args = vec!["apr", "ls"];
let cli = parse_cli(args).expect("Failed to parse");
assert!(matches!(*cli.command, Commands::List));
}
#[test]
fn test_parse_rm_command() {
let args = vec!["apr", "rm", "model-name"];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Rm { model_ref } => {
assert_eq!(model_ref, "model-name");
}
_ => panic!("Expected Rm command"),
}
}
#[test]
fn test_invalid_command() {
let args = vec!["apr", "invalid-command"];
let result = parse_cli(args);
assert!(result.is_err());
}
#[test]
fn test_missing_required_arg() {
let args = vec!["apr", "inspect"]; let result = parse_cli(args);
assert!(result.is_err());
}
#[test]
fn test_parse_merge_command() {
let args = vec![
"apr",
"merge",
"model1.apr",
"model2.apr",
"--strategy",
"weighted",
"--weights",
"0.7,0.3",
"-o",
"merged.apr",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Merge {
files,
strategy,
output,
weights,
..
} => {
assert_eq!(files.len(), 2);
assert_eq!(strategy, "weighted");
assert_eq!(output, Some(PathBuf::from("merged.apr")));
assert_eq!(weights, Some(vec![0.7, 0.3]));
}
_ => panic!("Expected Merge command"),
}
}
#[test]
fn test_parse_showcase_command() {
let args = vec![
"apr",
"showcase",
"--tier",
"medium",
"--gpu",
"--auto-verify",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Tools(ToolCommands::Showcase {
tier,
gpu,
auto_verify,
..
})) => {
assert_eq!(tier, "medium");
assert!(gpu);
assert!(auto_verify);
}
_ => panic!("Expected Showcase command"),
}
}
#[test]
fn test_parse_profile_command() {
let args = vec![
"apr",
"profile",
"model.apr",
"--granular",
"--detect-naive",
"--fail-on-naive",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Profile {
file,
granular,
detect_naive,
fail_on_naive,
..
}) => {
assert_eq!(file, PathBuf::from("model.apr"));
assert!(granular);
assert!(detect_naive);
assert!(fail_on_naive);
}
_ => panic!("Expected Profile command"),
}
}
#[test]
fn test_parse_profile_ci_mode() {
let args = vec![
"apr",
"profile",
"model.gguf",
"--ci",
"--assert-throughput",
"100",
"--assert-p99",
"50",
"--format",
"json",
];
let cli = parse_cli(args).expect("Failed to parse");
match *cli.command {
Commands::Extended(ExtendedCommands::Profile {
file,
ci,
assert_throughput,
assert_p99,
format,
..
}) => {
assert_eq!(file, PathBuf::from("model.gguf"));
assert!(ci);
assert_eq!(assert_throughput, Some(100.0));
assert_eq!(assert_p99, Some(50.0));
assert_eq!(format, "json");
}
_ => panic!("Expected Profile command"),
}
}
#[test]
fn every_lint_command_documents_its_flags() {
use clap::CommandFactory;
let offenders = std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut root = Cli::command();
root.build();
let mut bad: Vec<String> = Vec::new();
for sub in root.get_subcommands() {
if !sub.get_name().ends_with("-lint") {
continue;
}
for arg in sub.get_arguments() {
if arg.get_id() == "help" || arg.get_id() == "version" {
continue;
}
let documented = arg
.get_help()
.is_some_and(|h| !h.to_string().trim().is_empty());
if !documented {
bad.push(format!("{} --{}", sub.get_name(), arg.get_id()));
}
}
}
bad
})
.expect("spawn")
.join()
.expect("join");
assert!(
offenders.is_empty(),
"lint commands with an undocumented flag: {offenders:?}"
);
}
#[test]
fn test_tree_rejects_an_unknown_format_value() {
let err = parse_cli(vec!["apr", "tree", "m.apr", "--format", "bogusvalue"])
.expect_err("--format bogusvalue must be rejected");
let msg = err.to_string();
assert!(
msg.contains("bogusvalue"),
"the error must quote the value it rejected, got: {msg}"
);
}
#[test]
fn test_tree_accepts_every_documented_format() {
for value in ["ascii", "text", "dot", "graphviz", "mermaid", "md", "json"] {
let args: Vec<&'static str> = vec!["apr", "tree", "m.apr", "--format", value];
assert!(
parse_cli(args).is_ok(),
"--format {value} is documented and must parse"
);
}
assert!(parse_cli(vec!["apr", "tree", "m.apr"]).is_ok());
}