use super::*;
fn vec_magnitude(v: &[f32]) -> f32 {
v.iter().map(|x| x * x).sum::<f32>().sqrt()
}
#[test]
fn last_token_pool_picks_last_attended_row() {
let hidden = vec![1.0, 1.0, 2.0, 2.0, 9.0, 9.0];
let mask = vec![1, 1, 0];
let pooled = last_token_pool(&hidden, 3, 2, &mask);
assert_eq!(pooled, vec![2.0, 2.0]);
}
#[test]
fn last_token_pool_all_attended_picks_final_row() {
let hidden = vec![1.0, 1.0, 2.0, 2.0, 3.0, 3.0];
let mask = vec![1, 1, 1];
let pooled = last_token_pool(&hidden, 3, 2, &mask);
assert_eq!(pooled, vec![3.0, 3.0]);
}
#[test]
fn last_token_pool_empty_mask_falls_back_to_final_row() {
let hidden = vec![1.0, 1.0, 7.0, 7.0];
let pooled = last_token_pool(&hidden, 2, 2, &[]);
assert_eq!(pooled, vec![7.0, 7.0]);
}
#[test]
fn mrl_slices_to_512_and_normalizes() {
let full: Vec<f32> = (0..1024).map(|i| (i as f32) + 1.0).collect();
let out = mrl_slice_l2norm(&full, QWEN3_DIMS);
assert_eq!(out.len(), QWEN3_DIMS, "must slice to 512 dims");
let mag = vec_magnitude(&out);
assert!((mag - 1.0).abs() < 1e-4, "magnitude = {mag}, expected ~1.0");
assert!(out[0] > 0.0 && out[511] > 0.0);
}
#[test]
fn mrl_zero_pads_short_input() {
let short = vec![3.0, 4.0]; let out = mrl_slice_l2norm(&short, QWEN3_DIMS);
assert_eq!(out.len(), QWEN3_DIMS);
assert!((out[0] - 0.6).abs() < 1e-4);
assert!((out[1] - 0.8).abs() < 1e-4);
assert!(out[2..].iter().all(|&x| x == 0.0));
}
#[tokio::test]
async fn absent_model_degrades_to_mock() {
let p = Qwen3EmbeddingProvider::new("/nonexistent/model_fp16.onnx", "/nonexistent/tok.json");
assert!(!p.is_runtime_available());
assert_eq!(p.dimensions(), QWEN3_DIMS);
assert!(p.model_name().starts_with(QWEN3_MODEL_NAME));
assert!(p.model_name().contains("fallback"));
let v = p.embed("hello world").await.unwrap();
assert_eq!(v.len(), QWEN3_DIMS);
let v2 = p.embed("hello world").await.unwrap();
assert_eq!(v, v2);
}
#[tokio::test]
async fn fallback_query_embeds_without_model() {
let p = Qwen3EmbeddingProvider::new("/nope.onnx", "/nope.json");
let q = p
.embed_query("what is the kernel boot order")
.await
.unwrap();
assert_eq!(q.len(), QWEN3_DIMS);
}
#[tokio::test]
async fn fallback_batch_matches_individual() {
let p = Qwen3EmbeddingProvider::new("/nope.onnx", "/nope.json");
let batch = p.embed_batch(&["a", "b"]).await.unwrap();
let a = p.embed("a").await.unwrap();
assert_eq!(batch.len(), 2);
assert_eq!(batch[0], a);
}
#[test]
fn query_instruction_format_is_official() {
assert!(QUERY_INSTRUCTION.starts_with("Instruct: "));
assert!(QUERY_INSTRUCTION.ends_with("\nQuery: "));
assert!(QUERY_INSTRUCTION.contains("code-search"));
}
#[cfg(feature = "onnx-embeddings")]
fn cosine(a: &[f32], b: &[f32]) -> f32 {
let dot: f32 = a.iter().zip(b).map(|(x, y)| x * y).sum();
let na = vec_magnitude(a);
let nb = vec_magnitude(b);
if na == 0.0 || nb == 0.0 {
0.0
} else {
dot / (na * nb)
}
}
#[cfg(feature = "onnx-embeddings")]
#[tokio::test]
#[ignore = "requires Qwen3 model bundle (~1.2 GB) — ADR-059 follow-up 1"]
async fn qwen3_live_inference_sanity() {
let provider = Qwen3EmbeddingProvider::new(
".weftos/models/Qwen3-Embedding-0.6B/model_fp16.onnx",
".weftos/models/Qwen3-Embedding-0.6B/tokenizer.json",
);
assert!(
provider.is_runtime_available(),
"model bundle not loaded; fetch onnx-community/Qwen3-Embedding-0.6B-ONNX first"
);
let doc = provider
.embed("The kernel boots the process table.")
.await
.unwrap();
assert_eq!(doc.len(), QWEN3_DIMS);
let mag = vec_magnitude(&doc);
assert!((mag - 1.0).abs() < 1e-2, "doc not L2-normalized: {mag}");
let q = provider
.embed_query("how does the kernel boot")
.await
.unwrap();
assert_eq!(q.len(), QWEN3_DIMS);
let a = provider.embed("process table allocation").await.unwrap();
let b = provider
.embed("allocating PIDs in the process table")
.await
.unwrap();
let c = provider
.embed("ocean acoustic sonar propagation")
.await
.unwrap();
assert!(
cosine(&a, &b) > cosine(&a, &c),
"related cosine {} should exceed unrelated cosine {}",
cosine(&a, &b),
cosine(&a, &c)
);
}
#[cfg(feature = "onnx-embeddings")]
#[tokio::test]
#[ignore = "requires Qwen3 model bundle + WEFTOS_QWEN3_PARITY_FIXTURE (ADR-059 1.4)"]
async fn qwen3_parity_vs_lab() {
let Ok(fixture_path) = std::env::var("WEFTOS_QWEN3_PARITY_FIXTURE") else {
eprintln!("WEFTOS_QWEN3_PARITY_FIXTURE unset — skipping parity test");
return;
};
let raw = std::fs::read_to_string(&fixture_path).expect("read fixture");
let fixture: serde_json::Value = serde_json::from_str(&raw).expect("parse fixture");
let items = fixture["items"].as_array().expect("items array");
let provider = Qwen3EmbeddingProvider::new(
".weftos/models/Qwen3-Embedding-0.6B/model_fp16.onnx",
".weftos/models/Qwen3-Embedding-0.6B/tokenizer.json",
);
assert!(provider.is_runtime_available(), "model bundle not loaded");
let mut cosines = Vec::with_capacity(items.len());
for item in items {
let text = item["text"].as_str().unwrap();
let mode = item["mode"].as_str().unwrap_or("doc");
let reference: Vec<f32> = item["vec"]
.as_array()
.unwrap()
.iter()
.map(|x| x.as_f64().unwrap() as f32)
.collect();
let rust = if mode == "query" {
provider.embed_query(text).await.unwrap()
} else {
provider.embed(text).await.unwrap()
};
assert_eq!(rust.len(), reference.len(), "dim mismatch");
cosines.push(cosine(&rust, &reference));
}
let n = cosines.len() as f32;
let mean = cosines.iter().sum::<f32>() / n;
let min = cosines.iter().cloned().fold(f32::INFINITY, f32::min);
let frac_ge = cosines.iter().filter(|&&c| c >= 0.99).count() as f32 / n;
eprintln!(
"Qwen3 Rust↔lab parity (n={}): mean_cos={:.4} min_cos={:.4} frac≥0.99={:.3}",
cosines.len(),
mean,
min,
frac_ge
);
assert!(
mean >= 0.99,
"mean cosine-parity {mean:.4} < 0.99 (ADR-059 gate)"
);
}