use super::*;
use std::sync::Arc;
fn h(scan_start: usize, profile: Vec<f32>) -> Hill {
let n = profile.len();
Hill {
hill_id: 0,
mz: 500.0,
mz_std: 0.0,
mz_se: 0.0,
rt: 0.5,
rt_start: 0.0,
rt_end: 1.0,
rt_width: 1.0,
im: 0.0,
im_std: 0.0,
scan_start,
scan_apex: scan_start + n / 2,
scan_end: scan_start + n.saturating_sub(1),
n_scans: n,
skipped_scans: 0,
intensity_sum: profile.iter().map(|&x| x as f64).sum(),
intensity_max: profile.iter().copied().fold(0.0f32, f32::max) as f64,
hill_score: 1.0,
intensity_profile: Arc::from(profile.as_slice()),
isolation_window: None,
faims_cv: None,
}
}
const OV: usize = 3;
#[test]
fn identical_profiles_score_one() {
let p = vec![1.0, 5.0, 10.0, 5.0, 1.0];
let cos = cosine_similarity(&h(10, p.clone()), &h(10, p.clone()), OV);
assert!((cos - 1.0).abs() < 1e-9, "expected ~1.0, got {cos}");
}
#[test]
fn disjoint_hills_score_zero() {
let h1 = h(10, vec![1.0, 5.0, 1.0]);
let h2 = h(20, vec![1.0, 5.0, 1.0]);
assert_eq!(cosine_similarity(&h1, &h2, OV), 0.0);
}
#[test]
fn two_scan_overlap_fails_default_gate() {
let h1 = h(10, vec![1.0, 2.0, 10.0, 5.0, 1.0]);
let h2 = h(13, vec![5.0, 10.0, 2.0, 1.0, 0.5]);
assert_eq!(cosine_similarity(&h1, &h2, 3), 0.0);
}
#[test]
fn two_scan_overlap_passes_when_gate_lowered() {
let h1 = h(10, vec![1.0, 2.0, 10.0, 5.0, 1.0]);
let h2 = h(13, vec![5.0, 10.0, 2.0, 1.0, 0.5]);
let cos = cosine_similarity(&h1, &h2, 2);
assert!(
cos > 0.0,
"expected non-zero cosine at min_overlap=2, got {cos}"
);
assert!(cos <= 1.0);
}
#[test]
fn three_scan_overlap_passes_gate() {
let h1 = h(10, vec![1.0, 2.0, 10.0, 5.0, 1.0]);
let h2 = h(12, vec![10.0, 5.0, 1.0, 0.5, 0.1]);
let cos = cosine_similarity(&h1, &h2, OV);
assert!(cos > 0.0, "expected non-zero cosine, got {cos}");
assert!(cos <= 1.0);
}
#[test]
fn offset_peaks_score_low() {
let h1 = h(10, vec![1.0, 1.0, 10.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]);
let h2 = h(10, vec![1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 10.0, 1.0, 1.0]);
let cos = cosine_similarity(&h1, &h2, OV);
assert!(cos < 0.6, "expected low cosine for offset peaks, got {cos}");
}