pub(crate) use super::*;
pub(crate) use std::collections::BTreeMap;
#[test]
fn test_hf_to_gguf_name_q_proj_weight() {
assert_eq!(
hf_to_gguf_name("model.layers.0.self_attn.q_proj.weight"),
"blk.0.attn_q.weight"
);
}
#[test]
fn test_hf_to_gguf_name_q_proj_bias() {
assert_eq!(
hf_to_gguf_name("model.layers.5.self_attn.q_proj.bias"),
"blk.5.attn_q.bias"
);
}
#[test]
fn test_hf_to_gguf_name_k_proj_weight() {
assert_eq!(
hf_to_gguf_name("model.layers.3.self_attn.k_proj.weight"),
"blk.3.attn_k.weight"
);
}
#[test]
fn test_hf_to_gguf_name_k_proj_bias() {
assert_eq!(
hf_to_gguf_name("model.layers.11.self_attn.k_proj.bias"),
"blk.11.attn_k.bias"
);
}
#[test]
fn test_hf_to_gguf_name_v_proj_weight() {
assert_eq!(
hf_to_gguf_name("model.layers.7.self_attn.v_proj.weight"),
"blk.7.attn_v.weight"
);
}
#[test]
fn test_hf_to_gguf_name_v_proj_bias() {
assert_eq!(
hf_to_gguf_name("model.layers.0.self_attn.v_proj.bias"),
"blk.0.attn_v.bias"
);
}
#[test]
fn test_hf_to_gguf_name_o_proj_weight() {
assert_eq!(
hf_to_gguf_name("model.layers.2.self_attn.o_proj.weight"),
"blk.2.attn_output.weight"
);
}
#[test]
fn test_hf_to_gguf_name_o_proj_bias() {
assert_eq!(
hf_to_gguf_name("model.layers.31.self_attn.o_proj.bias"),
"blk.31.attn_output.bias"
);
}
#[test]
fn test_hf_to_gguf_name_qkv_proj_weight() {
assert_eq!(
hf_to_gguf_name("model.layers.0.self_attn.qkv_proj.weight"),
"blk.0.attn_qkv.weight"
);
}
#[test]
fn test_hf_to_gguf_name_qkv_proj_bias() {
assert_eq!(
hf_to_gguf_name("model.layers.4.self_attn.qkv_proj.bias"),
"blk.4.attn_qkv.bias"
);
}
#[test]
fn test_hf_to_gguf_name_gate_proj() {
assert_eq!(
hf_to_gguf_name("model.layers.1.mlp.gate_proj.weight"),
"blk.1.ffn_gate.weight"
);
}
#[test]
fn test_hf_to_gguf_name_up_proj() {
assert_eq!(
hf_to_gguf_name("model.layers.10.mlp.up_proj.weight"),
"blk.10.ffn_up.weight"
);
}
#[test]
fn test_hf_to_gguf_name_down_proj() {
assert_eq!(
hf_to_gguf_name("model.layers.23.mlp.down_proj.weight"),
"blk.23.ffn_down.weight"
);
}
#[test]
fn test_hf_to_gguf_name_input_layernorm() {
assert_eq!(
hf_to_gguf_name("model.layers.0.input_layernorm.weight"),
"blk.0.attn_norm.weight"
);
}
#[test]
fn test_hf_to_gguf_name_post_attention_layernorm() {
assert_eq!(
hf_to_gguf_name("model.layers.15.post_attention_layernorm.weight"),
"blk.15.ffn_norm.weight"
);
}
#[test]
fn test_hf_to_gguf_name_embed_tokens() {
assert_eq!(
hf_to_gguf_name("model.embed_tokens.weight"),
"token_embd.weight"
);
}
#[test]
fn test_hf_to_gguf_name_lm_head() {
assert_eq!(hf_to_gguf_name("lm_head.weight"), "output.weight");
}
#[test]
fn test_hf_to_gguf_name_output_norm() {
assert_eq!(hf_to_gguf_name("model.norm.weight"), "output_norm.weight");
}
#[test]
fn test_hf_to_gguf_name_unknown_passthrough() {
assert_eq!(hf_to_gguf_name("some.custom.tensor"), "some.custom.tensor");
}
#[test]
fn test_hf_to_gguf_name_unknown_layer_suffix_passthrough() {
assert_eq!(
hf_to_gguf_name("model.layers.0.some_unknown_suffix.weight"),
"model.layers.0.some_unknown_suffix.weight"
);
}
#[test]
fn test_hf_to_gguf_name_empty_string() {
assert_eq!(hf_to_gguf_name(""), "");
}
#[test]
fn test_hf_to_gguf_name_high_layer_index() {
assert_eq!(
hf_to_gguf_name("model.layers.79.self_attn.q_proj.weight"),
"blk.79.attn_q.weight"
);
}
#[test]
fn test_hf_to_gguf_name_three_digit_layer_index() {
assert_eq!(
hf_to_gguf_name("model.layers.127.mlp.gate_proj.weight"),
"blk.127.ffn_gate.weight"
);
}
#[test]
fn test_hf_to_gguf_name_all_layer_suffixes_mapped() {
let suffixes = [
"self_attn.q_proj.weight",
"self_attn.k_proj.weight",
"self_attn.v_proj.weight",
"self_attn.o_proj.weight",
"mlp.gate_proj.weight",
"mlp.up_proj.weight",
"mlp.down_proj.weight",
"input_layernorm.weight",
"post_attention_layernorm.weight",
];
let mut gguf_names: Vec<String> = suffixes
.iter()
.map(|s| hf_to_gguf_name(&format!("model.layers.0.{s}")))
.collect();
let count_before = gguf_names.len();
gguf_names.sort();
gguf_names.dedup();
assert_eq!(
gguf_names.len(),
count_before,
"Name collision detected in hf_to_gguf_name mapping"
);
}
#[test]
fn test_hf_to_gguf_name_qk_norm_gh279() {
assert_eq!(
hf_to_gguf_name("model.layers.0.self_attn.q_norm.weight"),
"blk.0.attn_q_norm.weight"
);
assert_eq!(
hf_to_gguf_name("model.layers.0.self_attn.k_norm.weight"),
"blk.0.attn_k_norm.weight"
);
assert_eq!(
hf_to_gguf_name("model.layers.35.self_attn.q_norm.weight"),
"blk.35.attn_q_norm.weight"
);
assert_eq!(
hf_to_gguf_name("model.layers.35.self_attn.k_norm.weight"),
"blk.35.attn_k_norm.weight"
);
}
#[test]
fn test_qk_norm_roundtrip_import_export_gh279() {
let gguf_q = "blk.5.attn_q_norm.weight";
let gguf_k = "blk.5.attn_k_norm.weight";
let apr_q = Architecture::Qwen3.map_name(gguf_q);
let apr_k = Architecture::Qwen3.map_name(gguf_k);
assert_eq!(apr_q, "model.layers.5.self_attn.q_norm.weight");
assert_eq!(apr_k, "model.layers.5.self_attn.k_norm.weight");
assert_eq!(hf_to_gguf_name(&apr_q), gguf_q);
assert_eq!(hf_to_gguf_name(&apr_k), gguf_k);
}
#[test]
fn test_infer_vocab_hidden_from_embed_tokens() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"model.embed_tokens.weight".to_string(),
(vec![0.0; 151936 * 896], vec![151936, 896]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 151936);
assert_eq!(hidden, 896);
}
#[test]
fn test_infer_vocab_hidden_from_token_embd() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"token_embd.weight".to_string(),
(vec![0.0; 32000 * 4096], vec![32000, 4096]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 32000);
assert_eq!(hidden, 4096);
}
#[test]
fn test_infer_vocab_hidden_fallback_to_lm_head() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"lm_head.weight".to_string(),
(vec![0.0; 32000 * 4096], vec![32000, 4096]),
);
tensors.insert(
"model.layers.0.self_attn.q_proj.weight".to_string(),
(vec![0.0; 4096 * 4096], vec![4096, 4096]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 32000);
assert_eq!(hidden, 4096);
}
#[test]
fn test_infer_vocab_hidden_fallback_to_output_weight() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"output.weight".to_string(),
(vec![0.0; 128256 * 4096], vec![128256, 4096]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 128256);
assert_eq!(hidden, 4096);
}
#[test]
fn test_infer_vocab_hidden_hidden_from_q_proj() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"model.layers.0.self_attn.q_proj.weight".to_string(),
(vec![0.0; 4096 * 4096], vec![4096, 4096]),
);
tensors.insert(
"model.layers.0.mlp.gate_proj.weight".to_string(),
(vec![0.0; 11008 * 4096], vec![11008, 4096]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 0);
assert_eq!(hidden, 4096);
}
#[test]
fn test_infer_vocab_hidden_empty_tensors() {
let tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 0);
assert_eq!(hidden, 0);
}
#[test]
fn test_infer_vocab_hidden_ignores_1d_embedding() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"model.embed_tokens.weight".to_string(),
(vec![0.0; 4096], vec![4096]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 0);
assert_eq!(hidden, 0);
}
#[test]
fn test_infer_vocab_hidden_ignores_1d_lm_head() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"lm_head.weight".to_string(),
(vec![0.0; 32000], vec![32000]),
);
tensors.insert(
"model.layers.0.self_attn.q_proj.weight".to_string(),
(vec![0.0; 2048 * 2048], vec![2048, 2048]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 0); assert_eq!(hidden, 2048); }
#[test]
fn test_infer_vocab_hidden_embedding_priority_over_lm_head() {
let mut tensors: BTreeMap<String, (Vec<f32>, Vec<usize>)> = BTreeMap::new();
tensors.insert(
"lm_head.weight".to_string(),
(vec![0.0; 32000 * 4096], vec![32000, 4096]),
);
tensors.insert(
"model.embed_tokens.weight".to_string(),
(vec![0.0; 151936 * 896], vec![151936, 896]),
);
let (vocab, hidden) = infer_vocab_hidden(&tensors);
assert_eq!(vocab, 151936);
assert_eq!(hidden, 896);
}
#[test]
fn test_falsify_rope_theta_defaults_match_yaml_contract() {
let expected: &[(&str, f32)] = &[
("qwen2", 1_000_000.0),
("qwen3", 1_000_000.0),
("llama", 10_000.0),
("mistral", 10_000.0),
("gemma", 10_000.0),
("deepseek", 10_000.0),
("phi", 10_000.0),
];
for &(arch, want) in expected {
let got = default_rope_theta_for_architecture(arch);
assert!(
(got - want).abs() < 1.0,
"FALSIFY: default_rope_theta_for_architecture(\"{arch}\") = {got}, \
expected {want} (model-metadata-bounds-v1.yaml)"
);
}
}
include!("export_tests_include_01.rs");