#[test]
fn test_tensor_entry_element_count_1d() {
let entry = TensorEntry {
name: "vec".to_string(),
dtype: "F32".to_string(),
shape: vec![10],
offset: 0,
size: 40,
};
assert_eq!(entry.element_count(), 10);
}
#[test]
fn test_tensor_entry_element_count_3d() {
let entry = TensorEntry {
name: "3d".to_string(),
dtype: "F32".to_string(),
shape: vec![2, 3, 4],
offset: 0,
size: 96,
};
assert_eq!(entry.element_count(), 24);
}
#[test]
fn test_dequantize_f16_odd_bytes() {
let bytes = vec![0x00, 0x3C, 0x00]; let result = crate::apr::dequantize_f16(&bytes, 2);
assert_eq!(result.len(), 1); }
#[test]
fn test_detect_format_bin() {
assert_eq!(detect_format("/path/model.bin"), "unknown");
}
#[test]
fn test_detect_format_pt() {
assert_eq!(detect_format("/path/model.pt"), "unknown");
}
#[test]
fn test_detect_format_no_extension() {
assert_eq!(detect_format("/path/model"), "unknown");
}
#[test]
fn test_detect_format_hidden_file() {
assert_eq!(detect_format("/path/.hidden"), "unknown");
}
#[test]
fn test_dequantize_q8_0_fewer_than_block() {
let mut bytes = vec![0u8; 34];
bytes[0] = 0x00;
bytes[1] = 0x3C; for i in 0..32 {
bytes[2 + i] = (i + 1) as u8; }
let result = crate::apr::dequantize_q8_0(&bytes, 10);
assert_eq!(result.len(), 10);
assert!((result[0] - 1.0).abs() < 0.5);
}
#[test]
fn test_dequantize_q8_0_multiple_blocks() {
let mut bytes = vec![0u8; 68];
bytes[0] = 0x00;
bytes[1] = 0x3C; bytes[34] = 0x00;
bytes[35] = 0x3C;
let result = crate::apr::dequantize_q8_0(&bytes, 64);
assert_eq!(result.len(), 64);
}
#[test]
fn test_dequantize_q4_k_fewer_than_superblock() {
let mut bytes = vec![0u8; 144];
bytes[0] = 0x00;
bytes[1] = 0x3C;
let result = crate::apr::dequantize_q4_k(&bytes, 100);
assert_eq!(result.len(), 100);
}
#[test]
fn test_dequantize_q4_k_multiple_superblocks() {
let mut bytes = vec![0u8; 288];
bytes[0] = 0x00;
bytes[1] = 0x3C;
bytes[144] = 0x00;
bytes[145] = 0x3C;
let result = crate::apr::dequantize_q4_k(&bytes, 512);
assert_eq!(result.len(), 512);
}
#[test]
fn test_dequantize_q6_k_fewer_than_superblock() {
let mut bytes = vec![0u8; 210];
bytes[208] = 0x00;
bytes[209] = 0x3C;
let result = crate::apr::dequantize_q6_k(&bytes, 50);
assert_eq!(result.len(), 50);
}
#[test]
fn test_dequantize_q6_k_multiple_superblocks() {
let mut bytes = vec![0u8; 420];
bytes[208] = 0x00;
bytes[209] = 0x3C;
bytes[418] = 0x00;
bytes[419] = 0x3C;
let result = crate::apr::dequantize_q6_k(&bytes, 512);
assert_eq!(result.len(), 512);
}
#[test]
fn test_bpe_tokenizer_encode_empty() {
let tokenizer = BpeTokenizer {
token_to_id: HashMap::new(),
id_to_token: vec![],
merge_rules: vec![],
bos_id: None,
eos_id: None,
special_tokens: HashMap::new(),
};
let encoded = tokenizer.encode("");
assert!(encoded.is_empty());
}
#[test]
fn test_bpe_tokenizer_encode_with_merges() {
let mut token_to_id = HashMap::new();
token_to_id.insert("a".to_string(), 0);
token_to_id.insert("b".to_string(), 1);
token_to_id.insert("ab".to_string(), 2);
let tokenizer = BpeTokenizer {
token_to_id,
id_to_token: vec!["a".to_string(), "b".to_string(), "ab".to_string()],
merge_rules: vec![("a".to_string(), "b".to_string())],
bos_id: None,
eos_id: None,
special_tokens: HashMap::new(),
};
let encoded = tokenizer.encode("ab");
assert!(!encoded.is_empty());
}
#[test]
fn test_apr_v2_model_tensor_count() {
let data = create_test_apr_model();
let model = AprV2Model::from_bytes(data).expect("APR operation failed");
assert_eq!(model.tensor_count(), 1);
}
#[test]
fn test_apr_v2_model_total_parameters() {
let data = create_test_apr_model();
let model = AprV2Model::from_bytes(data).expect("APR operation failed");
assert!(model.estimated_parameters() > 0);
}
#[test]
fn test_apr_metadata_to_json() {
let meta = AprMetadata {
hidden_size: Some(256),
num_layers: Some(4),
num_heads: Some(8),
vocab_size: Some(32000),
..Default::default()
};
let json = serde_json::to_string(&meta).expect("invalid UTF-8");
assert!(json.contains("256"));
assert!(json.contains("hidden_size"));
}
#[test]
fn test_apr_metadata_roundtrip() {
let meta = AprMetadata {
hidden_size: Some(1024),
num_layers: Some(12),
num_heads: Some(16),
vocab_size: Some(50000),
model_type: Some("llama".to_string()),
..Default::default()
};
let json = serde_json::to_string(&meta).expect("invalid UTF-8");
let parsed: AprMetadata = serde_json::from_str(&json).expect("parse failed");
assert_eq!(parsed.hidden_size, Some(1024));
assert_eq!(parsed.model_type, Some("llama".to_string()));
}
#[test]
fn test_tensor_entry_5d_shape() {
let entry = TensorEntry {
name: "5d".to_string(),
dtype: "F32".to_string(),
shape: vec![2, 3, 4, 5, 6],
offset: 0,
size: 2880,
};
assert_eq!(entry.element_count(), 720);
}
#[test]
fn test_tensor_entry_single_element() {
let entry = TensorEntry {
name: "single".to_string(),
dtype: "F32".to_string(),
shape: vec![1],
offset: 0,
size: 4,
};
assert_eq!(entry.element_count(), 1);
}
#[test]
fn test_is_apr_file_nonexistent_path() {
assert!(!is_apr_file("/nonexistent/path/model.apr"));
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn test_is_apr_file_with_apr_magic() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp = NamedTempFile::new().expect("create temp file");
temp.write_all(&MAGIC).expect("write magic");
temp.write_all(&[0u8; 60]).expect("write padding");
assert!(is_apr_file(temp.path()));
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn test_is_apr_file_without_magic() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp = NamedTempFile::new().expect("create temp file");
temp.write_all(b"GGUF").expect("write wrong magic");
temp.write_all(&[0u8; 60]).expect("write padding");
assert!(!is_apr_file(temp.path()));
}
#[test]
fn test_rms_norm_large() {
let x: Vec<f32> = (0..64).map(|i| i as f32).collect();
let weight: Vec<f32> = vec![1.0; 64];
let eps = 1e-6;
let result = crate::apr::rms_norm(&x, &weight, eps);
assert_eq!(result.len(), 64);
}
#[test]
fn test_rms_norm_negative_values() {
let x = vec![-1.0, -2.0, -3.0, -4.0];
let weight = vec![1.0, 1.0, 1.0, 1.0];
let eps = 1e-6;
let result = crate::apr::rms_norm(&x, &weight, eps);
assert_eq!(result.len(), 4);
assert!(result[0] < 0.0);
}
#[test]
fn test_matmul_zeros() {
let x = vec![0.0; 4];
let w = vec![1.0; 4];
let result = crate::apr::matmul(&x, &w, 2, 2, 2);
assert_eq!(result.len(), 4);
for v in &result {
assert!(v.abs() < 1e-6);
}
}
#[test]
fn test_matmul_scaling() {
let x = vec![2.0, 2.0];
let w = vec![1.0, 1.0];
let result = crate::apr::matmul(&x, &w, 1, 2, 1);
assert_eq!(result.len(), 1);
assert!((result[0] - 4.0).abs() < 1e-6);
}
fn create_test_apr_model_with_dtype(dtype: u8, data_bytes: &[u8]) -> Vec<u8> {
let metadata = r#"{"architecture":"test"}"#;
let metadata_bytes = metadata.as_bytes();
let metadata_padded_size = metadata_bytes.len().div_ceil(64) * 64;
let tensor_entry =
create_binary_tensor_entry("typed.weight", dtype, &[4], 0, data_bytes.len() as u64);
let tensor_index_offset = HEADER_SIZE as u64 + metadata_padded_size as u64;
let data_offset = tensor_index_offset + tensor_entry.len() as u64;
let total_size = data_offset as usize + data_bytes.len();
let mut data = vec![0u8; total_size];
data[0..4].copy_from_slice(&MAGIC);
data[4] = 2; data[5] = 0; data[6..8].copy_from_slice(&0u16.to_le_bytes()); data[8..12].copy_from_slice(&1u32.to_le_bytes()); data[12..20].copy_from_slice(&(HEADER_SIZE as u64).to_le_bytes()); data[20..24].copy_from_slice(&(metadata_bytes.len() as u32).to_le_bytes()); data[24..32].copy_from_slice(&tensor_index_offset.to_le_bytes()); data[32..40].copy_from_slice(&data_offset.to_le_bytes());
data[HEADER_SIZE..HEADER_SIZE + metadata_bytes.len()].copy_from_slice(metadata_bytes);
let idx_start = tensor_index_offset as usize;
data[idx_start..idx_start + tensor_entry.len()].copy_from_slice(&tensor_entry);
let data_start = data_offset as usize;
data[data_start..data_start + data_bytes.len()].copy_from_slice(data_bytes);
data
}
#[test]
fn test_get_tensor_f32_f16_dtype() {
let f16_data = vec![
0x00, 0x3C, 0x00, 0x40, 0x00, 0x3C, 0x00, 0x40, ];
let model_data = create_test_apr_model_with_dtype(1, &f16_data);
let model = AprV2Model::from_bytes(model_data).expect("should load");
let result = model.get_tensor_f32("typed.weight");
assert!(result.is_ok());
let floats = result.expect("APR operation failed");
assert_eq!(floats.len(), 4);
assert!((floats[0] - 1.0).abs() < 0.1);
assert!((floats[1] - 2.0).abs() < 0.1);
}