use crate::hgvs::interval::TxInterval;
pub(crate) fn resolve_tx_start(location: &TxInterval) -> Result<u64, String> {
match location.start.inner() {
Some(pos) if pos.downstream => Err(format!(
"n.*{} lies beyond the transcript's last base and has no transcript \
coordinate: the n. axis numbers only n.1..n.<length> \
(background/numbering.md:52) and a variant outside a transcript's \
boundaries may not be described against that transcript \
(background/numbering.md:54)",
pos.base
)),
Some(pos) => Ok(pos.base as u64),
None => Ok(1),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::hgvs::interval::UncertainBoundary;
use crate::hgvs::location::TxPos;
use crate::hgvs::uncertainty::Mu;
#[test]
fn a_downstream_start_does_not_resolve_to_its_in_transcript_twin() {
let plain = resolve_tx_start(&TxInterval::point(TxPos::new(5)));
let downstream = resolve_tx_start(&TxInterval::point(TxPos::downstream(5)));
assert_eq!(plain, Ok(5), "control: n.5 is transcript coordinate 5");
assert!(
downstream.is_err(),
"n.*5 names a nucleotide past the transcript's last base \
(background/numbering.md:52, :54) and has no transcript coordinate; \
resolution answered {downstream:?} instead of refusing"
);
assert_ne!(
plain, downstream,
"n.5 and n.*5 are different nucleotides and must not resolve alike"
);
}
#[test]
fn every_downstream_start_is_refused_by_name() {
for base in [1, 5, 31, 4000] {
let err = resolve_tx_start(&TxInterval::point(TxPos::downstream(base)))
.expect_err("n.*{base} must be refused");
assert!(
err.contains("n.*"),
"the decline must name the notation it refused, got: {err}"
);
}
}
#[test]
fn a_downstream_start_carrying_an_offset_is_refused() {
assert!(
resolve_tx_start(&TxInterval::point(TxPos::downstream_with_offset(5, 10))).is_err(),
"n.*5+10 must be refused like n.*5"
);
}
#[test]
fn the_two_unread_markers_keep_their_historical_answers() {
assert_eq!(
resolve_tx_start(&TxInterval::point(TxPos::with_offset(5, 10))),
Ok(5),
"an intronic offset is still dropped; changing that is its own change"
);
assert_eq!(
resolve_tx_start(&TxInterval {
start: UncertainBoundary::Single(Mu::Unknown),
end: UncertainBoundary::Single(Mu::Unknown),
}),
Ok(1),
"an absent inner position still substitutes 1"
);
}
}