#[test]
fn test_f_tune_002_missing_model() {
apr()
.args(["tune", "/nonexistent/model.gguf", "--plan"])
.assert()
.failure()
.stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such file"))
.or(predicate::str::contains("Failed")),
);
}
#[test]
fn test_f_qa_001_help() {
apr()
.args(["qa", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("qa").or(predicate::str::contains("QA")));
}
#[test]
fn test_f_qa_002_missing_model() {
apr()
.args(["qa", "/nonexistent/model.gguf"])
.assert()
.failure()
.stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such file"))
.or(predicate::str::contains("Failed")),
);
}
#[test]
fn test_f_convert_001_rosetta_help() {
apr()
.args(["rosetta", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("convert").or(predicate::str::contains("Convert")));
}
#[test]
fn test_f_convert_002_missing_model() {
apr()
.args([
"rosetta",
"convert",
"/nonexistent/model.gguf",
"/tmp/out.apr",
])
.assert()
.failure()
.stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such file"))
.or(predicate::str::contains("Failed"))
.or(predicate::str::contains("does not exist")),
);
}
#[test]
fn test_f_profile_ci_001_help_shows_ci_options() {
apr()
.args(["profile", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("--ci"))
.stdout(predicate::str::contains("--assert-throughput"))
.stdout(predicate::str::contains("--assert-p99"));
}
#[test]
fn test_f_profile_ci_002_missing_model_error() {
apr()
.args(["profile", "/nonexistent/model.gguf"])
.assert()
.failure()
.stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such file"))
.or(predicate::str::contains("Failed"))
.or(predicate::str::contains("does not exist")),
);
}
#[test]
fn test_f_profile_ci_003_ci_mode_missing_model() {
apr()
.args([
"profile",
"/nonexistent/model.gguf",
"--ci",
"--assert-throughput",
"100",
])
.assert()
.failure()
.stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such file"))
.or(predicate::str::contains("Failed"))
.or(predicate::str::contains("does not exist")),
);
}
#[test]
fn test_f_profile_ci_004_format_json_accepted() {
apr()
.args(["profile", "/nonexistent/model.gguf", "--format", "json"])
.assert()
.failure(); }
#[test]
fn test_f_profile_ci_005_warmup_measure_accepted() {
apr()
.args([
"profile",
"/nonexistent/model.gguf",
"--warmup",
"5",
"--measure",
"20",
])
.assert()
.failure(); }
#[test]
fn test_f_profile_ci_006_assert_p50_accepted() {
apr()
.args([
"profile",
"/nonexistent/model.gguf",
"--ci",
"--assert-p50",
"25",
])
.assert()
.failure(); }
#[test]
fn test_f_profile_exit_001_help_documents_exit_codes() {
apr()
.args(["profile", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("--ci"))
.stdout(predicate::str::contains("--assert-throughput"));
}
#[test]
fn test_f_profile_exit_002_nonexistent_model_fails() {
apr()
.args([
"profile",
"/nonexistent/path/to/model.gguf",
"--ci",
"--assert-throughput",
"1.0",
])
.assert()
.failure()
.code(predicate::ne(0)); }
#[test]
#[ignore = "requires model download - run with: cargo test -- --ignored"]
fn test_f_profile_exit_003_impossible_threshold_fails() {
apr()
.args([
"profile",
"test-model.gguf", "--ci",
"--assert-throughput",
"999999999.0",
"--warmup",
"1",
"--measure",
"1",
])
.assert()
.failure()
.code(predicate::eq(1)); }
#[test]
fn test_f_convert_quant_001_help_shows_q4k() {
apr()
.args(["convert", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("q4k").or(predicate::str::contains("q4_k")));
}
#[test]
fn test_f_convert_quant_002_q4k_option_accepted() {
apr()
.args([
"convert",
"/nonexistent/model.gguf",
"/tmp/out.apr",
"--quantize",
"q4k",
])
.assert()
.failure(); }
#[test]
fn test_f_export_companion_001_help_shows_formats() {
apr()
.args(["export", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("safetensors"))
.stdout(predicate::str::contains("gguf"));
}
#[test]
fn test_f_export_companion_002_safetensors_accepted() {
apr()
.args([
"export",
"/nonexistent/model.apr",
"--format",
"safetensors",
"/tmp/out.safetensors",
])
.assert()
.failure(); }
#[test]
fn test_f_validate_gguf_001_help_shows_options() {
apr()
.args(["validate", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("quality").or(predicate::str::contains("strict")));
}
#[test]
fn test_f_validate_gguf_002_magic_error_message() {
use std::io::Write;
let mut file = NamedTempFile::new().expect("create temp file");
file.write_all(b"BADM1234567890123456789012345678").unwrap();
apr()
.args(["validate", file.path().to_str().unwrap()])
.assert()
.failure()
.stderr(
predicate::str::contains("Invalid")
.or(predicate::str::contains("magic"))
.or(predicate::str::contains("Unknown")),
);
}
#[test]
fn test_f_validate_gguf_003_accepts_gguf_magic() {
use std::io::Write;
let mut file = NamedTempFile::new().expect("create temp file");
file.write_all(b"GGUF").unwrap(); file.write_all(&3u32.to_le_bytes()).unwrap(); file.write_all(&0u64.to_le_bytes()).unwrap(); file.write_all(&0u64.to_le_bytes()).unwrap(); file.write_all(&[0u8; 8]).unwrap();
let output = apr()
.args(["validate", file.path().to_str().unwrap()])
.output()
.expect("run command");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!stdout.contains("Invalid magic"),
"GGUF magic should be accepted: {stdout}"
);
}
fn create_test_gguf_file() -> NamedTempFile {
let file = NamedTempFile::with_suffix(".gguf").expect("create temp file");
let mut data = Vec::new();
data.extend_from_slice(b"GGUF");
data.extend_from_slice(&3u32.to_le_bytes()); data.extend_from_slice(&0u64.to_le_bytes()); data.extend_from_slice(&0u64.to_le_bytes()); data.extend_from_slice(&[0u8; 8]);
std::fs::write(file.path(), data).expect("write file");
file
}
fn create_test_safetensors_file() -> NamedTempFile {
let file = NamedTempFile::with_suffix(".safetensors").expect("create temp file");
let header = b"{}";
let header_len = header.len() as u64;
let mut data = Vec::new();
data.extend_from_slice(&header_len.to_le_bytes());
data.extend_from_slice(header);
std::fs::write(file.path(), data).expect("write file");
file
}
#[test]
fn test_f_format_dispatch_001_inspect_all_formats() {
let gguf = create_test_gguf_file();
let output = apr()
.args(["inspect", gguf.path().to_str().unwrap()])
.output()
.expect("run inspect on GGUF");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("not supported") && !stderr.contains("Only GGUF"),
"GGUF inspect should not skip: {stderr}"
);
let apr_file = create_test_apr_file();
let output = apr()
.args(["inspect", apr_file.path().to_str().unwrap()])
.output()
.expect("run inspect on APR");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("not supported") && !stderr.contains("Only GGUF"),
"APR inspect should not skip: {stderr}"
);
let st = create_test_safetensors_file();
let output = apr()
.args(["inspect", st.path().to_str().unwrap()])
.output()
.expect("run inspect on SafeTensors");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("not supported") && !stderr.contains("Only GGUF"),
"SafeTensors inspect should not skip: {stderr}"
);
}
#[test]
fn test_f_format_dispatch_002_validate_all_formats() {
for (name, file) in [
("GGUF", create_test_gguf_file()),
("APR", create_test_apr_file()),
("SafeTensors", create_test_safetensors_file()),
] {
let output = apr()
.args(["validate", file.path().to_str().unwrap()])
.output()
.expect(&format!("run validate on {name}"));
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("not supported") && !stderr.contains("Only GGUF"),
"{name} validate should not skip: {stderr}"
);
}
}