Skip to content

Commit

Permalink
fix: checks strand equality before performing liftover
Browse files Browse the repository at this point in the history
  • Loading branch information
claymcleod committed Sep 9, 2023
1 parent 42f72eb commit bd4d7c2
Showing 1 changed file with 173 additions and 0 deletions.
173 changes: 173 additions & 0 deletions src/liftover/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl Machine {
let results = entry
.find(start, stop)
.map(|e| e.val.clone())
.filter(|i| i.reference().strand() == interval.strand())
.map(|pair| pair.clamp(interval).unwrap())
.collect::<Vec<_>>();

Expand All @@ -75,3 +76,175 @@ impl Machine {
}
}
}

#[cfg(test)]
mod tests {
use crate::core::Coordinate;
use crate::core::Interval;
use crate::core::Position;
use crate::core::Strand;
use crate::liftover::machine;
use crate::Reader;

#[test]
pub fn test_valid_positive_strand_liftover() -> Result<(), Box<dyn std::error::Error>> {
let data = b"chain 0 seq0 10 + 0 10 seq1 10 + 0 10 0\n10";
let reader = Reader::new(&data[..]);
let machine = machine::Builder::default().try_build_from(reader)?;

let from = Coordinate::try_new("seq0", 1, Strand::Positive)?;
let to = Coordinate::try_new("seq0", 7, Strand::Positive)?;

let interval = Interval::try_new(from, to)?;
let mut results = machine.liftover(&interval).unwrap();

assert_eq!(results.len(), 1);

let result = results.pop().unwrap();

assert_eq!(result.reference().contig(), "seq0");
assert_eq!(result.reference().start().strand(), &Strand::Positive);
assert_eq!(result.reference().start().position(), &Position::from(1));
assert_eq!(result.reference().end().strand(), &Strand::Positive);
assert_eq!(result.reference().end().position(), &Position::from(7));

assert_eq!(result.query().contig(), "seq1");
assert_eq!(result.query().start().strand(), &Strand::Positive);
assert_eq!(result.query().start().position(), &Position::from(1));
assert_eq!(result.query().end().strand(), &Strand::Positive);
assert_eq!(result.query().end().position(), &Position::from(7));

Ok(())
}

#[test]
pub fn test_valid_negative_strand_liftover() -> Result<(), Box<dyn std::error::Error>> {
let data = b"chain 0 seq0 10 - 0 10 seq1 10 - 0 10 0\n10";
let reader = Reader::new(&data[..]);
let machine = machine::Builder::default().try_build_from(reader)?;

let from = Coordinate::try_new("seq0", 7, Strand::Negative)?;
let to = Coordinate::try_new("seq0", 1, Strand::Negative)?;

let interval = Interval::try_new(from, to)?;
let mut results = machine.liftover(&interval).unwrap();

assert_eq!(results.len(), 1);

let result = results.pop().unwrap();

assert_eq!(result.reference().contig(), "seq0");
assert_eq!(result.reference().start().strand(), &Strand::Negative);
assert_eq!(result.reference().start().position(), &Position::from(7));
assert_eq!(result.reference().end().strand(), &Strand::Negative);
assert_eq!(result.reference().end().position(), &Position::from(1));

assert_eq!(result.query().contig(), "seq1");
assert_eq!(result.query().start().strand(), &Strand::Negative);
assert_eq!(result.query().start().position(), &Position::from(7));
assert_eq!(result.query().end().strand(), &Strand::Negative);
assert_eq!(result.query().end().position(), &Position::from(1));

Ok(())
}

#[test]
pub fn test_valid_positive_to_negative_strand_liftover(
) -> Result<(), Box<dyn std::error::Error>> {
let data = b"chain 0 seq0 10 + 0 10 seq1 10 - 0 10 0\n10";
let reader = Reader::new(&data[..]);
let machine = machine::Builder::default().try_build_from(reader)?;

let from = Coordinate::try_new("seq0", 1, Strand::Positive)?;
let to = Coordinate::try_new("seq0", 7, Strand::Positive)?;

let interval = Interval::try_new(from, to)?;
let mut results = machine.liftover(&interval).unwrap();

assert_eq!(results.len(), 1);

let result = results.pop().unwrap();

assert_eq!(result.reference().contig(), "seq0");
assert_eq!(result.reference().start().strand(), &Strand::Positive);
assert_eq!(result.reference().start().position(), &Position::from(1));
assert_eq!(result.reference().end().strand(), &Strand::Positive);
assert_eq!(result.reference().end().position(), &Position::from(7));

assert_eq!(result.query().contig(), "seq1");
assert_eq!(result.query().start().strand(), &Strand::Negative);
assert_eq!(result.query().start().position(), &Position::from(8));
assert_eq!(result.query().end().strand(), &Strand::Negative);
assert_eq!(result.query().end().position(), &Position::from(2));

Ok(())
}

#[test]
pub fn test_valid_negative_to_positive_strand_liftover(
) -> Result<(), Box<dyn std::error::Error>> {
let data = b"chain 0 seq0 10 - 0 10 seq1 10 + 0 10 0\n10";
let reader = Reader::new(&data[..]);
let machine = machine::Builder::default().try_build_from(reader)?;

let from = Coordinate::try_new("seq0", 7, Strand::Negative)?;
let to = Coordinate::try_new("seq0", 1, Strand::Negative)?;

let interval = Interval::try_new(from, to)?;
let mut results = machine.liftover(&interval).unwrap();

assert_eq!(results.len(), 1);

let result = results.pop().unwrap();

assert_eq!(result.reference().contig(), "seq0");
assert_eq!(result.reference().start().strand(), &Strand::Negative);
assert_eq!(result.reference().start().position(), &Position::from(7));
assert_eq!(result.reference().end().strand(), &Strand::Negative);
assert_eq!(result.reference().end().position(), &Position::from(1));

assert_eq!(result.query().contig(), "seq1");
assert_eq!(result.query().start().strand(), &Strand::Positive);
assert_eq!(result.query().start().position(), &Position::from(2));
assert_eq!(result.query().end().strand(), &Strand::Positive);
assert_eq!(result.query().end().position(), &Position::from(8));

Ok(())
}

#[test]
pub fn test_nonexistent_positive_strand_interval_liftover(
) -> Result<(), Box<dyn std::error::Error>> {
let data = b"chain 0 seq0 10 - 0 10 seq1 10 - 0 10 0\n10";
let reader = Reader::new(&data[..]);
let machine = machine::Builder::default().try_build_from(reader)?;

let from = Coordinate::try_new("seq0", 1, Strand::Positive)?;
let to = Coordinate::try_new("seq0", 7, Strand::Positive)?;

let interval = Interval::try_new(from, to)?;
let results = machine.liftover(&interval);

assert_eq!(results, None);

Ok(())
}

#[test]
pub fn test_nonexistent_negative_strand_interval_liftover(
) -> Result<(), Box<dyn std::error::Error>> {
let data = b"chain 0 seq0 10 + 0 10 seq1 10 + 0 10 0\n10";
let reader = Reader::new(&data[..]);
let machine = machine::Builder::default().try_build_from(reader)?;

let from = Coordinate::try_new("seq0", 7, Strand::Negative)?;
let to = Coordinate::try_new("seq0", 1, Strand::Negative)?;

let interval = Interval::try_new(from, to)?;
let results = machine.liftover(&interval);

assert_eq!(results, None);

Ok(())
}
}

0 comments on commit bd4d7c2

Please sign in to comment.