use super::*;
use crate::agent::driver::validate::is_valid_model_file;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};
const APR_MAGIC: [u8; 4] = [0x41, 0x50, 0x52, 0x00];
const GGUF_MAGIC: [u8; 4] = [0x47, 0x47, 0x55, 0x46];
fn write_valid_apr(path: &std::path::Path) {
let mut data = Vec::new();
data.extend_from_slice(&APR_MAGIC);
data.extend_from_slice(br#"{"tokenizer.merges":["a b"],"tokenizer.vocabulary":["hi"]}"#);
std::fs::write(path, &data).expect("write APR");
}
fn write_invalid_apr(path: &std::path::Path) {
let mut data = Vec::new();
data.extend_from_slice(&APR_MAGIC);
data.extend_from_slice(br#"{"architecture":"qwen2","vocab_size":151936}"#);
std::fs::write(path, &data).expect("write invalid APR");
}
fn write_valid_gguf(path: &std::path::Path) {
let mut data = Vec::new();
data.extend_from_slice(&GGUF_MAGIC);
data.extend_from_slice(&[3, 0, 0, 0]); data.extend_from_slice(&[0u8; 100]);
std::fs::write(path, &data).expect("write GGUF");
}
fn set_mtime(path: &std::path::Path, time: SystemTime) {
let ft = filetime::FileTime::from_system_time(time);
filetime::set_file_mtime(path, ft).expect("set mtime");
}
#[test]
fn falsify_disc_101_valid_apr_passes() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("model.apr");
write_valid_apr(&path);
assert!(is_valid_model_file(&path), "FALSIFY-DISC-101: valid APR with tokenizer must pass");
}
#[test]
fn falsify_disc_102_invalid_apr_fails() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("model.apr");
write_invalid_apr(&path);
assert!(!is_valid_model_file(&path), "FALSIFY-DISC-102: APR without tokenizer must fail");
}
#[test]
fn falsify_disc_103_valid_gguf_passes() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("model.gguf");
write_valid_gguf(&path);
assert!(is_valid_model_file(&path), "FALSIFY-DISC-103: valid GGUF must pass");
}
#[test]
fn falsify_disc_104_mtime_beats_format_real_files() {
let dir = tempfile::tempdir().unwrap();
let apr_path = dir.path().join("old.apr");
let gguf_path = dir.path().join("new.gguf");
write_valid_apr(&apr_path);
write_valid_gguf(&gguf_path);
let now = SystemTime::now();
let yesterday = now - Duration::from_secs(86400);
set_mtime(&apr_path, yesterday);
set_mtime(&gguf_path, now);
let mut candidates = vec![
(apr_path.clone(), yesterday, true, is_valid_model_file(&apr_path)),
(gguf_path.clone(), now, false, is_valid_model_file(&gguf_path)),
];
ModelConfig::sort_candidates(&mut candidates);
assert_eq!(
candidates[0].0.file_name().unwrap().to_str().unwrap(),
"new.gguf",
"FALSIFY-DISC-104: newer GGUF must beat older APR"
);
}
#[test]
fn falsify_disc_105_apr_tiebreak_real_files() {
let dir = tempfile::tempdir().unwrap();
let apr_path = dir.path().join("model.apr");
let gguf_path = dir.path().join("model.gguf");
write_valid_apr(&apr_path);
write_valid_gguf(&gguf_path);
let now = SystemTime::now();
set_mtime(&apr_path, now);
set_mtime(&gguf_path, now);
let mut candidates =
vec![(gguf_path.clone(), now, false, true), (apr_path.clone(), now, true, true)];
ModelConfig::sort_candidates(&mut candidates);
assert_eq!(
candidates[0].0.file_name().unwrap().to_str().unwrap(),
"model.apr",
"FALSIFY-DISC-105: APR preferred at same mtime"
);
}
#[test]
fn falsify_disc_106_jidoka_real_files() {
let dir = tempfile::tempdir().unwrap();
let apr_path = dir.path().join("broken.apr");
let gguf_path = dir.path().join("valid.gguf");
write_invalid_apr(&apr_path); write_valid_gguf(&gguf_path);
let now = SystemTime::now();
let yesterday = now - Duration::from_secs(86400);
set_mtime(&apr_path, now);
set_mtime(&gguf_path, yesterday);
let mut candidates = vec![
(apr_path.clone(), now, true, is_valid_model_file(&apr_path)),
(gguf_path.clone(), yesterday, false, is_valid_model_file(&gguf_path)),
];
ModelConfig::sort_candidates(&mut candidates);
assert_eq!(
candidates[0].0.file_name().unwrap().to_str().unwrap(),
"valid.gguf",
"FALSIFY-DISC-106: valid GGUF must beat NEWER invalid APR (Jidoka)"
);
assert!(!candidates[1].3, "FALSIFY-DISC-106: broken APR marked invalid");
}
#[test]
fn falsify_disc_107_four_way_sort() {
let dir = tempfile::tempdir().unwrap();
let now = SystemTime::now();
let files: Vec<(&str, bool, SystemTime)> = vec![
("valid_old.apr", true, now - Duration::from_secs(7200)),
("valid_new.gguf", true, now - Duration::from_secs(60)),
("broken_newest.apr", false, now),
("valid_oldest.gguf", true, now - Duration::from_secs(86400)),
];
let mut candidates: Vec<(PathBuf, SystemTime, bool, bool)> = files
.iter()
.map(|(name, make_valid, mtime)| {
let path = dir.path().join(name);
if name.ends_with(".apr") {
if *make_valid {
write_valid_apr(&path);
} else {
write_invalid_apr(&path);
}
} else {
write_valid_gguf(&path);
}
set_mtime(&path, *mtime);
let is_apr = name.ends_with(".apr");
let is_valid = is_valid_model_file(&path);
(path, *mtime, is_apr, is_valid)
})
.collect();
ModelConfig::sort_candidates(&mut candidates);
assert_eq!(
candidates[0].0.file_name().unwrap().to_str().unwrap(),
"valid_new.gguf",
"FALSIFY-DISC-107: valid+newest wins"
);
assert_eq!(
candidates[3].0.file_name().unwrap().to_str().unwrap(),
"broken_newest.apr",
"FALSIFY-DISC-107: invalid APR sorted last"
);
}
#[test]
fn falsify_disc_108_nonexistent_path() {
assert!(
!is_valid_model_file(std::path::Path::new("/nonexistent/model.apr")),
"FALSIFY-DISC-108: nonexistent path must return false"
);
}
#[test]
fn falsify_disc_109_format_detection() {
let dir = tempfile::tempdir().unwrap();
let apr = dir.path().join("model.apr");
let gguf = dir.path().join("model.gguf");
write_valid_apr(&apr);
write_valid_gguf(&gguf);
assert!(is_valid_model_file(&apr), "FALSIFY-DISC-109: APR accepted");
assert!(is_valid_model_file(&gguf), "FALSIFY-DISC-109: GGUF accepted");
let ext_apr = apr.extension().unwrap().to_str().unwrap();
let ext_gguf = gguf.extension().unwrap().to_str().unwrap();
assert_eq!(ext_apr, "apr", "FALSIFY-DISC-109: APR extension");
assert_eq!(ext_gguf, "gguf", "FALSIFY-DISC-109: GGUF extension");
}
#[test]
fn preferred_default_recognises_qwen3_coder_30b_a3b() {
use super::is_preferred_default_model;
let cases = &[
"Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf",
"qwen3-coder-30b-a3b-instruct-q4_k_m.gguf",
"Qwen3-Coder-30B-A3B-Instruct-BF16.gguf",
];
for name in cases {
let path = PathBuf::from(format!("/home/u/.apr/models/{name}"));
assert!(
is_preferred_default_model(&path),
"must recognise preferred default model: {name}"
);
}
}
#[test]
fn preferred_default_rejects_small_fallbacks() {
use super::is_preferred_default_model;
let cases = &[
"Qwen3-1.7B-Q4_K_M.gguf",
"tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf",
"qwen2.5-coder-1.5b-q4k.apr",
"qwen2.5-coder-7b-instruct-q4_k_m.gguf",
];
for name in cases {
let path = PathBuf::from(format!("/home/u/.apr/models/{name}"));
assert!(
!is_preferred_default_model(&path),
"must NOT mark small fallback as preferred default: {name}"
);
}
}
#[test]
fn sort_candidates_promotes_preferred_over_newer() {
let small_newer = (
PathBuf::from("/m/Qwen3-1.7B-Q4_K_M.gguf"),
SystemTime::UNIX_EPOCH + Duration::from_secs(2_000),
false,
true,
);
let preferred_older = (
PathBuf::from("/m/Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf"),
SystemTime::UNIX_EPOCH + Duration::from_secs(1_000),
false,
true,
);
let mut cands = vec![small_newer, preferred_older.clone()];
ModelConfig::sort_candidates(&mut cands);
assert_eq!(
cands[0].0, preferred_older.0,
"preferred-name model must outrank a newer-but-smaller one"
);
}
#[test]
fn sort_candidates_newer_preferred_beats_older_preferred() {
let preferred_newer = (
PathBuf::from("/m/Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf"),
SystemTime::UNIX_EPOCH + Duration::from_secs(2_000),
false,
true,
);
let preferred_older = (
PathBuf::from("/m/Qwen2.5-Coder-32B-Instruct-Q4_K_M.gguf"),
SystemTime::UNIX_EPOCH + Duration::from_secs(1_000),
false,
true,
);
let mut cands = vec![preferred_older, preferred_newer.clone()];
ModelConfig::sort_candidates(&mut cands);
assert_eq!(
cands[0].0, preferred_newer.0,
"newer preferred model wins over older preferred model"
);
}
#[test]
fn sort_candidates_validity_outranks_preference() {
let invalid_preferred = (
PathBuf::from("/m/Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf"),
SystemTime::UNIX_EPOCH + Duration::from_secs(2_000),
false,
false,
);
let valid_small = (
PathBuf::from("/m/Qwen3-1.7B-Q4_K_M.gguf"),
SystemTime::UNIX_EPOCH + Duration::from_secs(1_000),
false,
true,
);
let mut cands = vec![invalid_preferred, valid_small.clone()];
ModelConfig::sort_candidates(&mut cands);
assert_eq!(
cands[0].0, valid_small.0,
"valid model must outrank invalid even if invalid is preferred-name"
);
}