use crate::gguf::test_factory::{
build_minimal_llama_gguf, build_minimal_phi2_gguf, create_f16_data, create_q2_k_data,
create_q4_0_data, create_q4_1_data, create_q4_k_data, create_q5_0_data, create_q5_1_data,
create_q5_k_data, create_q6_k_data, create_q8_0_data, GGUFBuilder,
};
use crate::gguf::{GGUFModel, GGUFTransformer};
#[test]
fn test_from_bytes_minimal_empty() {
let data = GGUFBuilder::new().build();
let model = GGUFModel::from_bytes(&data);
assert!(model.is_ok());
let model = model.expect("test value should be present");
assert_eq!(model.tensors.len(), 0);
assert_eq!(model.metadata.len(), 0);
}
#[test]
fn test_from_bytes_with_metadata_only() {
let data = GGUFBuilder::new()
.architecture("test")
.add_u32("test.value", 42)
.add_f32("test.float", 3.14)
.add_string("test.string", "hello")
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert!(model.metadata.len() >= 4);
}
#[test]
fn test_from_bytes_llama_arch() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.architecture(), Some("llama"));
}
#[test]
fn test_from_bytes_phi2_arch() {
let data = build_minimal_phi2_gguf(32, 64, 128, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.architecture(), Some("phi2"));
}
#[test]
fn test_from_bytes_with_q4_0_tensors() {
let q4_data = create_q4_0_data(1024);
let data = GGUFBuilder::new()
.architecture("llama")
.add_q4_0_tensor("test.weight", &[32, 32], &q4_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.tensors.len(), 1);
assert_eq!(model.tensors[0].qtype, 2); }
#[test]
fn test_from_bytes_with_q8_0_tensors() {
let q8_data = create_q8_0_data(1024);
let data = GGUFBuilder::new()
.architecture("llama")
.add_q8_0_tensor("test.weight", &[32, 32], &q8_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.tensors.len(), 1);
assert_eq!(model.tensors[0].qtype, 8); }
#[test]
fn test_from_bytes_with_q4_k_tensors() {
let q4k_data = create_q4_k_data(256);
let data = GGUFBuilder::new()
.architecture("llama")
.add_q4_k_tensor("test.weight", &[16, 16], &q4k_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.tensors.len(), 1);
assert_eq!(model.tensors[0].qtype, 12); }
#[test]
fn test_from_bytes_with_q5_k_tensors() {
let q5k_data = create_q5_k_data(256);
let data = GGUFBuilder::new()
.architecture("llama")
.add_q5_k_tensor("test.weight", &[16, 16], &q5k_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.tensors.len(), 1);
assert_eq!(model.tensors[0].qtype, 13); }
#[test]
fn test_from_bytes_with_q6_k_tensors() {
let q6k_data = create_q6_k_data(256);
let data = GGUFBuilder::new()
.architecture("llama")
.add_q6_k_tensor("test.weight", &[16, 16], &q6k_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.tensors.len(), 1);
assert_eq!(model.tensors[0].qtype, 14); }
#[test]
fn test_from_bytes_with_f32_tensors() {
let f32_data: Vec<f32> = (0..1024).map(|i| i as f32 * 0.001).collect();
let data = GGUFBuilder::new()
.architecture("llama")
.add_f32_tensor("test.weight", &[32, 32], &f32_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.tensors.len(), 1);
assert_eq!(model.tensors[0].qtype, 0); }
#[test]
fn test_metadata_accessors_llama() {
let data = build_minimal_llama_gguf(100, 128, 256, 8, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.architecture(), Some("llama"));
assert_eq!(model.embedding_dim(), Some(128));
assert_eq!(model.num_layers(), Some(1));
assert_eq!(model.num_heads(), Some(8));
assert_eq!(model.num_kv_heads(), Some(4));
assert_eq!(model.context_length(), Some(256));
}
#[test]
fn test_metadata_accessors_phi2() {
let data = build_minimal_phi2_gguf(100, 128, 256, 8);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.architecture(), Some("phi2"));
assert_eq!(model.embedding_dim(), Some(128));
assert_eq!(model.num_heads(), Some(8));
}
#[test]
fn test_rope_freq_base_accessor() {
let data = GGUFBuilder::new()
.architecture("llama")
.rope_freq_base("llama", 10000.0)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let rope_base = model.rope_freq_base();
assert!(rope_base.is_some());
assert!((rope_base.expect("test value should be present") - 10000.0).abs() < 0.01);
}
#[test]
fn test_rms_epsilon_accessor() {
let data = GGUFBuilder::new()
.architecture("llama")
.rms_epsilon("llama", 1e-5)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let eps = model.rms_epsilon();
assert!(eps.is_some());
assert!((eps.expect("test value should be present") - 1e-5).abs() < 1e-10);
}
#[test]
fn test_ffn_hidden_dim_accessor() {
let data = GGUFBuilder::new()
.architecture("llama")
.ffn_hidden_dim("llama", 512)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let val = model.metadata.get("llama.feed_forward_length");
assert!(val.is_some());
}
#[test]
fn test_transformer_from_llama_pygmy() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let transformer = GGUFTransformer::from_gguf(&model, &data);
assert!(
transformer.is_ok(),
"Transformer load failed: {:?}",
transformer.err()
);
let transformer = transformer.expect("test value should be present");
assert_eq!(transformer.config.num_layers, 1);
assert_eq!(transformer.config.hidden_dim, 64);
}
#[test]
fn test_transformer_from_phi2_pygmy() {
let data = build_minimal_phi2_gguf(32, 64, 128, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let transformer = GGUFTransformer::from_gguf(&model, &data);
let _ = transformer;
}
#[test]
fn test_transformer_token_embedding_size() {
let vocab = 64;
let hidden = 32;
let data = build_minimal_llama_gguf(vocab, hidden, 64, 2, 2);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let transformer =
GGUFTransformer::from_gguf(&model, &data).expect("test value should be present");
assert_eq!(transformer.token_embedding.len(), vocab * hidden);
}
#[test]
fn test_get_tensor_f32_from_f32() {
let f32_data: Vec<f32> = (0..64).map(|i| i as f32 * 0.1).collect();
let data = GGUFBuilder::new()
.add_f32_tensor("test.weight", &[8, 8], &f32_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let tensor = model.get_tensor_f32("test.weight", &data);
assert!(tensor.is_ok());
let tensor = tensor.expect("test value should be present");
assert_eq!(tensor.len(), 64);
}
#[test]
fn test_get_tensor_f32_from_q4_0() {
let q4_data = create_q4_0_data(1024);
let data = GGUFBuilder::new()
.add_q4_0_tensor("test.weight", &[32, 32], &q4_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let tensor = model.get_tensor_f32("test.weight", &data);
assert!(tensor.is_ok());
let tensor = tensor.expect("test value should be present");
assert_eq!(tensor.len(), 1024);
}
#[test]
fn test_get_tensor_f32_from_q8_0() {
let q8_data = create_q8_0_data(1024);
let data = GGUFBuilder::new()
.add_q8_0_tensor("test.weight", &[32, 32], &q8_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let tensor = model.get_tensor_f32("test.weight", &data);
assert!(tensor.is_ok());
}
#[test]
fn test_get_tensor_f32_from_q4_k() {
let q4k_data = create_q4_k_data(256);
let data = GGUFBuilder::new()
.add_q4_k_tensor("test.weight", &[16, 16], &q4k_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let tensor = model.get_tensor_f32("test.weight", &data);
assert!(tensor.is_ok());
}
#[test]
fn test_get_tensor_f32_nonexistent() {
let data = GGUFBuilder::new().architecture("llama").build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let tensor = model.get_tensor_f32("nonexistent.tensor", &data);
assert!(tensor.is_err());
}
#[test]
fn test_decode_empty_tokens() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let decoded = model.decode(&[]);
assert_eq!(decoded, "");
}
#[test]
fn test_decode_single_token() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let decoded = model.decode(&[0]);
let _ = decoded;
}
#[test]
fn test_decode_multiple_tokens() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let decoded = model.decode(&[0, 1, 2, 3, 4]);
let _ = decoded;
}
#[test]
fn test_decode_out_of_range_token() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let decoded = model.decode(&[99999]);
let _ = decoded;
}
#[test]
fn test_encode_empty_text() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let encoded = model.encode("");
let _ = encoded;
}
#[test]
fn test_encode_simple_text() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let encoded = model.encode("hello");
let _ = encoded;
}
#[test]
fn test_bos_token_id() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let bos = model.bos_token_id();
let _ = bos;
}
#[test]
fn test_eos_token_id() {
let data = build_minimal_llama_gguf(32, 64, 128, 4, 4);
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
let eos = model.eos_token_id();
let _ = eos;
}
#[test]
fn test_from_bytes_too_small() {
let data = vec![0u8; 4]; let result = GGUFModel::from_bytes(&data);
assert!(result.is_err());
}
#[test]
fn test_from_bytes_invalid_magic() {
let mut data = vec![0u8; 100];
data[0..4].copy_from_slice(b"XXXX");
let result = GGUFModel::from_bytes(&data);
assert!(result.is_err());
}
#[test]
fn test_from_bytes_truncated_header() {
let mut data = vec![0u8; 16];
data[0..4].copy_from_slice(&0x46554747u32.to_le_bytes()); let result = GGUFModel::from_bytes(&data);
assert!(result.is_err());
}
#[test]
fn test_model_with_mixed_tensor_types() {
let f32_data: Vec<f32> = (0..64).map(|i| i as f32 * 0.1).collect();
let q4_data = create_q4_0_data(1024);
let q4k_data = create_q4_k_data(256);
let data = GGUFBuilder::new()
.architecture("llama")
.add_f32_tensor("f32_tensor", &[8, 8], &f32_data)
.add_q4_0_tensor("q4_0_tensor", &[32, 32], &q4_data)
.add_q4_k_tensor("q4_k_tensor", &[16, 16], &q4k_data)
.build();
let model = GGUFModel::from_bytes(&data).expect("test value should be present");
assert_eq!(model.tensors.len(), 3);
let _ = model.get_tensor_f32("f32_tensor", &data);
let _ = model.get_tensor_f32("q4_0_tensor", &data);
let _ = model.get_tensor_f32("q4_k_tensor", &data);
}
include!("vocabulary_accessor.rs");