use minibwa::test_util::{synthetic_reference, write_fasta};
use minibwa::{Aligner, Index, Meth, Opts, ThreadBuf};
#[test]
fn primary_flag_unique_read() {
let dir = std::env::temp_dir().join(format!("minibwa_sf_primary_{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let seq = synthetic_reference(5000, 42);
let fa = write_fasta(&dir, "chr1", &seq);
let prefix = dir.join("idx");
Index::build_from_fasta(&fa, &prefix, false, 1).unwrap();
let idx = Index::load(&prefix, false).unwrap();
let opts = Opts::new();
let aligner = Aligner::new(&idx, &opts);
let mut buf = ThreadBuf::new();
let query = &seq[2000..2150];
let hits = aligner
.map(&mut buf, b"primary_read", query, Meth::None)
.unwrap();
println!("[case1] hit count: {}", hits.len());
for (i, h) in hits.iter().enumerate() {
println!(
" hit[{i}] contig={:?} ref={}-{} primary={} secondary={} supplementary={}",
h.contig, h.ref_start, h.ref_end, h.is_primary, h.is_secondary, h.is_supplementary
);
}
assert_eq!(hits.len(), 1, "unique read should produce exactly one hit");
assert!(hits[0].is_primary, "the single hit must be primary");
assert!(
!hits[0].is_secondary,
"the single hit must not be secondary"
);
assert!(
!hits[0].is_supplementary,
"the single hit must not be supplementary"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn secondary_flag_duplicated_region() {
let dir = std::env::temp_dir().join(format!("minibwa_sf_secondary_{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let flank_a = synthetic_reference(2000, 11);
let dup = synthetic_reference(250, 77); let flank_b = synthetic_reference(2000, 31);
let mut refseq = Vec::with_capacity(flank_a.len() + dup.len() + flank_b.len() + dup.len());
refseq.extend_from_slice(&flank_a);
refseq.extend_from_slice(&dup);
refseq.extend_from_slice(&flank_b);
refseq.extend_from_slice(&dup);
let fa = write_fasta(&dir, "chr1", &refseq);
let prefix = dir.join("idx");
Index::build_from_fasta(&fa, &prefix, false, 1).unwrap();
let idx = Index::load(&prefix, false).unwrap();
let opts = Opts::new().set_out_n(5);
let aligner = Aligner::new(&idx, &opts);
let mut buf = ThreadBuf::new();
let query = &dup[25..225];
let hits = aligner
.map(&mut buf, b"dup_read", query, Meth::None)
.unwrap();
println!("[case2] hit count: {}", hits.len());
for (i, h) in hits.iter().enumerate() {
println!(
" hit[{i}] contig={:?} ref={}-{} primary={} secondary={} supplementary={}",
h.contig, h.ref_start, h.ref_end, h.is_primary, h.is_secondary, h.is_supplementary
);
}
assert!(
!hits.is_empty(),
"duplicated-region read must produce at least one hit"
);
let primary_count = hits.iter().filter(|h| h.is_primary).count();
assert_eq!(
primary_count, 1,
"exactly one hit must be primary; got {primary_count}"
);
for (i, h) in hits.iter().enumerate() {
assert!(
!(h.is_primary && h.is_secondary),
"hit[{i}] is both primary and secondary — impossible"
);
}
for (i, h) in hits.iter().enumerate() {
if !h.is_primary {
assert!(
h.is_secondary,
"hit[{i}] is non-primary but not secondary (supplementary={})",
h.is_supplementary
);
}
}
let secondary_count = hits.iter().filter(|h| h.is_secondary).count();
println!(
"[case2] primaries={primary_count} secondaries={secondary_count} total={}",
hits.len()
);
std::fs::remove_dir_all(&dir).ok();
}