use super::*;
#[test]
fn falsify_eg2l_001_exact_arch_match_only() {
assert!(is_embedding_gemma2("gemma-embedding2"));
assert!(is_embedding_gemma2("Gemma-Embedding2"));
for not_it in [
"gemma",
"gemma2",
"gemma3",
"gemma-embedding",
"gemma-embedding3",
"gemma-embedding2x",
"embeddinggemma2",
"",
] {
assert!(
!is_embedding_gemma2(not_it),
"{not_it} must not be admitted as EmbeddingGemma 2"
);
assert_eq!(
model_kind(not_it, Some(false)),
Ok(ModelKind::Generative),
"{not_it}"
);
}
}
#[test]
fn falsify_eg2l_001_kind_and_causal_flag() {
assert_eq!(
model_kind("gemma-embedding2", Some(false)),
Ok(ModelKind::Embedding)
);
assert_eq!(
model_kind("gemma-embedding2", None),
Ok(ModelKind::Embedding)
);
let err = model_kind("gemma-embedding2", Some(true))
.expect_err("causal embedding file must be refused");
assert!(err.contains("attention.causal = true"), "{err}");
}
#[test]
fn falsify_eg2l_002_kv_heads_array_read_per_layer() {
let layers: Vec<GGUFValue> = (0..24u32)
.map(|i| GGUFValue::UInt32(if i % 6 == 5 { 1 } else { 2 }))
.collect();
let got = per_layer_kv_heads(&GGUFValue::Array(layers), 24).expect("24-long array");
assert_eq!(got.len(), 24);
assert_eq!(got.iter().filter(|&&k| k == 1).count(), 4);
assert_eq!(got[5], 1);
assert_eq!(got[0], 2);
}
#[test]
fn falsify_eg2l_002_kv_heads_follow_the_file_not_a_pattern() {
let vals = [3u32, 1, 4, 1, 5];
let arr = GGUFValue::Array(vals.iter().map(|&v| GGUFValue::Int32(v as i32)).collect());
assert_eq!(per_layer_kv_heads(&arr, 5), Ok(vec![3, 1, 4, 1, 5]));
}
#[test]
fn falsify_eg2l_002_kv_heads_scalar_broadcasts() {
assert_eq!(
per_layer_kv_heads(&GGUFValue::UInt32(8), 3),
Ok(vec![8, 8, 8])
);
assert_eq!(per_layer_kv_heads(&GGUFValue::UInt64(2), 2), Ok(vec![2, 2]));
assert_eq!(per_layer_kv_heads(&GGUFValue::UInt8(1), 1), Ok(vec![1]));
assert_eq!(per_layer_kv_heads(&GGUFValue::UInt16(4), 1), Ok(vec![4]));
}
#[test]
fn falsify_eg2l_002_kv_heads_refusals() {
let short = GGUFValue::Array(vec![GGUFValue::UInt32(1); 23]);
let err = per_layer_kv_heads(&short, 24).expect_err("length mismatch");
assert!(err.contains("23 entries for 24 blocks"), "{err}");
assert!(
per_layer_kv_heads(&GGUFValue::UInt32(0), 2).is_err(),
"zero heads"
);
assert!(
per_layer_kv_heads(&GGUFValue::Int32(-1), 2).is_err(),
"negative heads"
);
assert!(
per_layer_kv_heads(&GGUFValue::Float32(2.0), 2).is_err(),
"float heads"
);
assert!(
per_layer_kv_heads(&GGUFValue::String("2".into()), 2).is_err(),
"string heads"
);
let bad_entry = GGUFValue::Array(vec![GGUFValue::UInt32(1), GGUFValue::Bool(true)]);
assert!(
per_layer_kv_heads(&bad_entry, 2).is_err(),
"non-integer entry"
);
}
#[test]
fn falsify_eg2l_003_layer_kind_from_shapes() {
let widths: Vec<usize> = (0..24)
.map(|i| {
if [5, 11, 17, 23].contains(&i) {
2048
} else {
1024
}
})
.collect();
let kinds = layer_attention_kinds(&widths).expect("two widths");
let globals: Vec<usize> = kinds
.iter()
.enumerate()
.filter(|(_, k)| **k == LayerAttention::Global)
.map(|(i, _)| i)
.collect();
assert_eq!(globals, vec![5, 11, 17, 23]);
}
#[test]
fn falsify_eg2l_003_swapped_shapes_swap_kinds() {
let widths = [2048, 1024, 1024, 2048, 1024];
let kinds = layer_attention_kinds(&widths).expect("two widths");
use LayerAttention::{Global, Local};
assert_eq!(kinds, vec![Global, Local, Local, Global, Local]);
}
#[test]
fn falsify_eg2l_003_layer_kind_refusals() {
assert!(layer_attention_kinds(&[]).is_err(), "no layers");
let err = layer_attention_kinds(&[1024, 1024]).expect_err("single width");
assert!(err.contains("no local/global split"), "{err}");
assert!(layer_attention_kinds(&[0, 1024]).is_err(), "zero width");
}
fn kv_fixture(kv: Option<&[i32]>, scalar: Option<u32>, layers: u32) -> Vec<u8> {
use crate::gguf::test_factory::GGUFBuilder;
let mut b = GGUFBuilder::new()
.architecture("llama")
.hidden_dim("llama", 64)
.num_layers("llama", layers)
.num_heads("llama", 4)
.add_f32_tensor("token_embd.weight", &[8, 64], &[0.0f32; 512]);
if let Some(arr) = kv {
b = b.add_i32_array("llama.attention.head_count_kv", arr);
}
if let Some(k) = scalar {
b = b.num_kv_heads("llama", k);
}
b.build()
}
fn config_of(data: &[u8]) -> crate::error::Result<crate::gguf::GGUFConfig> {
let model = crate::gguf::GGUFModel::from_bytes(data).expect("fixture parses");
crate::gguf::GGUFConfig::from_gguf(&model)
}
#[test]
fn falsify_eg2l_006_scalar_kv_heads_unchanged() {
let cfg = config_of(&kv_fixture(None, Some(2), 3)).expect("scalar loads");
assert_eq!(cfg.num_kv_heads, 2);
let cfg = config_of(&kv_fixture(None, None, 3)).expect("absent loads");
assert_eq!(
cfg.num_kv_heads, 4,
"absent key keeps the num_heads default"
);
}
#[test]
fn falsify_eg2l_006_uniform_kv_array_gives_its_value() {
let cfg = config_of(&kv_fixture(Some(&[2, 2, 2]), None, 3)).expect("uniform array loads");
assert_eq!(
cfg.num_kv_heads, 2,
"a uniform array must not collapse to num_heads (4)"
);
}
#[test]
fn falsify_eg2l_006_non_uniform_kv_array_refused() {
let err =
config_of(&kv_fixture(Some(&[2, 1, 2]), None, 3)).expect_err("non-uniform must be refused");
let msg = err.to_string();
assert!(msg.contains("per-layer"), "{msg}");
let err =
config_of(&kv_fixture(Some(&[2, 2]), None, 3)).expect_err("wrong length must be refused");
assert!(err.to_string().contains("2 entries for 3 blocks"), "{err}");
}
#[test]
fn falsify_eg2l_006_metadata_exposes_per_layer_values() {
let data = kv_fixture(Some(&[2, 1, 2]), None, 3);
let model = crate::gguf::GGUFModel::from_bytes(&data).expect("fixture parses");
assert_eq!(num_kv_heads_per_layer(&model), Some(Ok(vec![2, 1, 2])));
let data = kv_fixture(None, None, 3);
let model = crate::gguf::GGUFModel::from_bytes(&data).expect("fixture parses");
assert_eq!(num_kv_heads_per_layer(&model), None);
}
#[test]
fn uniform_kv_heads_cases() {
assert_eq!(uniform_kv_heads(&[3, 3]), Ok(3));
assert!(uniform_kv_heads(&[3, 1])
.expect_err("mixed")
.contains("per-layer"));
assert!(uniform_kv_heads(&[]).is_err());
}