use super::*;
use aprender::format::v2::{AprV2Metadata, AprV2Writer};
use std::io::Write;
use tempfile::NamedTempFile;
fn known_good_apr_bytes() -> Vec<u8> {
let mut writer = AprV2Writer::new(AprV2Metadata::new("truncation-fixture"));
let weight: Vec<f32> = (0..1024)
.map(|i| ((i % 17) as f32 - 8.0) * 0.031_25)
.collect();
let bias: Vec<f32> = (0..32).map(|i| (i as f32) * 0.01 - 0.15).collect();
writer.add_f32_tensor("layer.0.weight", vec![32, 32], &weight);
writer.add_f32_tensor("layer.0.bias", vec![32], &bias);
writer.write().expect("fixture must serialize")
}
fn apr_file(bytes: &[u8]) -> NamedTempFile {
let mut file = NamedTempFile::with_suffix(".apr").expect("create temp file");
file.write_all(bytes).expect("write fixture");
file.flush().expect("flush fixture");
file
}
fn truncated_apr_file() -> NamedTempFile {
let bytes = known_good_apr_bytes();
apr_file(&bytes[..bytes.len() / 2])
}
fn err_text(result: &Result<(), CliError>) -> String {
match result {
Ok(()) => String::new(),
Err(e) => e.to_string(),
}
}
#[test]
fn truncated_apr_exits_non_zero() {
let file = truncated_apr_file();
let result = run(file.path(), false, false, None, false, false);
assert!(
result.is_err(),
"a truncated .apr must not validate clean — exit 0 here is #2612"
);
let msg = err_text(&result);
assert!(
msg.contains("Truncated APR"),
"the failure must name truncation, not a downstream symptom: {msg}"
);
}
#[test]
fn truncated_apr_exits_non_zero_with_quality_flag() {
let file = truncated_apr_file();
let result = run(file.path(), true, false, None, false, false);
assert!(
result.is_err(),
"`apr validate --quality` on a truncated .apr must exit non-zero"
);
assert!(err_text(&result).contains("Truncated APR"));
}
#[test]
fn truncated_apr_exits_non_zero_with_skip_contract() {
let file = truncated_apr_file();
let result = run(file.path(), false, false, None, false, true);
assert!(
result.is_err(),
"--skip-contract waives the data-quality contract, not the file's own arithmetic"
);
assert!(err_text(&result).contains("Truncated APR"));
}
#[test]
fn truncated_apr_exits_non_zero_as_json() {
let file = truncated_apr_file();
let result = run(file.path(), false, false, None, true, false);
assert!(
result.is_err(),
"the --json consumer reads the exit code too"
);
assert!(err_text(&result).contains("Truncated APR"));
}
#[test]
fn truncated_apr_exits_non_zero_with_skip_contract_and_json() {
let file = truncated_apr_file();
let result = run(file.path(), true, false, None, true, true);
assert!(result.is_err(), "no flag combination waives truncation");
assert!(err_text(&result).contains("Truncated APR"));
}
#[test]
fn intact_apr_is_never_reported_as_truncated() {
let bytes = known_good_apr_bytes();
let file = apr_file(&bytes);
let result = run(file.path(), true, false, None, false, false);
assert!(
!err_text(&result).contains("Truncated APR"),
"intact .apr must not be reported as truncated: {}",
err_text(&result)
);
}
#[test]
fn apr_truncation_is_refused_the_way_gguf_truncation_is() {
let file = truncated_apr_file();
let result = run(file.path(), false, false, None, false, false);
assert!(
matches!(result, Err(CliError::ValidationFailed(_))),
"expected ValidationFailed (the GGUF truncation verdict), got {result:?}"
);
}