use std::path::{Path, PathBuf};
use vareffect::{FastaReader, TranscriptStore, VarEffect};
fn open_var_effect() -> VarEffect {
let path = std::env::var("FASTA_PATH").expect(
"FASTA_PATH env var must point to a GRCh38 genome binary (.bin) \
with its .bin.idx sidecar. Run `vareffect-cli setup` first, then \
set FASTA_PATH=data/vareffect/GRCh38.bin.",
);
let path_buf = PathBuf::from(path);
let fasta =
FastaReader::open(Path::new(&path_buf)).expect("opening the reference genome binary");
let transcripts = TranscriptStore::from_transcripts(Vec::new());
VarEffect::new(transcripts, fasta)
}
#[test]
#[ignore]
fn snv_passthrough() {
let ve = open_var_effect();
let result = ve
.left_align_indel("chr17", 7_676_154, "C", "T")
.expect("left_align_indel should not error on SNV");
assert_eq!(result, None, "SNV should pass through unchanged");
}
#[test]
#[ignore]
fn mnv_passthrough() {
let ve = open_var_effect();
let result = ve
.left_align_indel("chr17", 7_676_154, "CC", "TG")
.expect("left_align_indel should not error on MNV");
assert_eq!(result, None, "MNV should pass through unchanged");
}
#[test]
#[ignore]
fn already_leftmost_deletion() {
let ve = open_var_effect();
let result = ve
.left_align_indel("chr7", 117_559_590, "ATCT", "A")
.expect("left_align_indel should not error");
assert_eq!(result, None, "non-repeat deletion should be unchanged");
}
#[test]
#[ignore]
fn homopolymer_deletion_shifts_left() {
let ve = open_var_effect();
let result_right = ve
.left_align_indel("chr13", 32_340_301, "GA", "G")
.expect("left_align_indel should not error");
let result_left = ve
.left_align_indel("chr13", 32_340_300, "AG", "A")
.expect("left_align_indel should not error");
let norm_right = result_right.unwrap_or((32_340_301, "GA".to_string(), "G".to_string()));
let norm_left = result_left.unwrap_or((32_340_300, "AG".to_string(), "A".to_string()));
assert_eq!(
norm_right, norm_left,
"two representations of the same deletion must normalize identically"
);
}
#[test]
#[ignore]
fn homopolymer_insertion_shifts_left() {
let ve = open_var_effect();
let result_a = ve
.left_align_indel("chr13", 32_340_301, "G", "GA")
.expect("left_align_indel should not error");
let result_b = ve
.left_align_indel("chr13", 32_340_300, "A", "AG")
.expect("left_align_indel should not error");
let norm_a = result_a.unwrap_or((32_340_301, "G".to_string(), "GA".to_string()));
let norm_b = result_b.unwrap_or((32_340_300, "A".to_string(), "AG".to_string()));
assert_eq!(
norm_a, norm_b,
"two representations of the same insertion must normalize identically"
);
}
#[test]
#[ignore]
fn complex_becomes_deletion_after_shift() {
let ve = open_var_effect();
let result = ve.left_align_indel("chr17", 7_676_154, "CCC", "CC");
assert!(result.is_ok(), "should not error on complex-becomes-indel");
}
#[test]
#[ignore]
fn idempotent() {
let ve = open_var_effect();
let first = ve
.left_align_indel("chr13", 32_340_301, "GA", "G")
.expect("first pass should not error");
if let Some((pos, ref_a, alt_a)) = first {
let second = ve
.left_align_indel("chr13", pos, &ref_a, &alt_a)
.expect("second pass should not error");
assert_eq!(
second, None,
"already-normalized variant should return None on second pass"
);
}
}
#[test]
#[ignore]
fn position_one_boundary() {
let ve = open_var_effect();
let result = ve.left_align_indel("chr1", 1, "NN", "N");
assert!(
result.is_ok(),
"position 1 should not cause underflow: {:?}",
result
);
}
#[test]
#[ignore]
fn vcf_anchor_preserved() {
let ve = open_var_effect();
let result = ve
.left_align_indel("chr13", 32_340_301, "GA", "G")
.expect("should not error");
if let Some((_, ref ref_a, ref alt_a)) = result {
assert!(
!ref_a.is_empty() && !alt_a.is_empty(),
"both alleles must have at least one base (VCF anchor): ref={ref_a}, alt={alt_a}"
);
let shorter = ref_a.len().min(alt_a.len());
assert!(shorter >= 1, "shorter allele must be >= 1 base");
}
}