-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
131 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
|
||
import pytest | ||
from micall.tests.utils import MockAligner, MockAlignment | ||
|
||
def test_basic_mapping(): | ||
|
||
aligner = MockAligner('acgt' + 'a' * 20 + 'acgt') | ||
|
||
alignment = list(aligner.map('a' * 10)) | ||
|
||
assert len(alignment) == 5 | ||
|
||
alignment = alignment[0] | ||
|
||
assert isinstance(alignment, MockAlignment) | ||
assert alignment.mapq == 60 | ||
assert alignment.is_rev == False | ||
assert alignment.r_st == 4 | ||
assert alignment.r_en == 14 | ||
assert alignment.q_st == 0 | ||
assert alignment.q_en == 10 | ||
|
||
|
||
def test_exact_match(): | ||
aligner = MockAligner("abcdefg") | ||
alignments = list(aligner.map("abc")) | ||
assert len(alignments) == 1 | ||
assert alignments[0].r_st == 0 | ||
assert alignments[0].r_en == 3 | ||
|
||
|
||
def test_no_match(): | ||
aligner = MockAligner("abcdefg") | ||
alignments = list(aligner.map("xyz")) | ||
assert len(alignments) == 0 | ||
|
||
|
||
def test_partial_match(): | ||
aligner = MockAligner("abcdefg") | ||
alignments = list(aligner.map("abxyabc")) | ||
assert len(alignments) == 1 | ||
assert alignments[0].r_st == 0 | ||
assert alignments[0].r_en == 3 | ||
|
||
|
||
def test_multiple_matches(): | ||
aligner = MockAligner("A" * 40) | ||
alignments = list(aligner.map("A" * 20)) | ||
assert len(alignments) == 5 | ||
assert alignments[0].r_st == 0 | ||
assert alignments[0].r_en == 20 | ||
assert alignments[1].r_st == 0 | ||
assert alignments[1].r_en == 19 | ||
|
||
|
||
def test_multiple_matches_bigger_query(): | ||
aligner = MockAligner("A" * 40) | ||
alignments = list(aligner.map("A" * 50)) | ||
assert len(alignments) == 5 | ||
assert alignments[0].r_st == 0 | ||
assert alignments[0].r_en == 40 | ||
assert alignments[1].r_st == 0 | ||
assert alignments[1].r_en == 40 | ||
|
||
|
||
def test_empty_reference(): | ||
aligner = MockAligner("A" * 0) | ||
alignments = list(aligner.map("A" * 20)) | ||
assert len(alignments) == 0 | ||
|
||
|
||
def test_empty_query(): | ||
aligner = MockAligner("A" * 40) | ||
alignments = list(aligner.map("A" * 0)) | ||
assert len(alignments) == 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from dataclasses import dataclass | ||
from math import floor, ceil | ||
|
||
from micall.utils.consensus_aligner import CigarActions | ||
|
||
|
||
@dataclass | ||
class MockAlignment: | ||
is_rev: bool | ||
mapq: int | ||
cigar: list | ||
cigar_str: str | ||
q_st: int | ||
q_en: int | ||
r_st: int | ||
r_en: int | ||
|
||
|
||
class MockAligner: | ||
""" | ||
Mock for the mappy's aligner class. | ||
Only reports exact matches. | ||
""" | ||
|
||
def __init__(self, seq, *args, **kwargs): | ||
self.seq = seq | ||
self.max_matches = 5 | ||
self.min_length = 3 | ||
|
||
|
||
def map(self, seq): | ||
max_matches = self.max_matches | ||
returned = set() | ||
for length in range(len(seq), self.min_length - 2, -1): | ||
for start in range(len(seq) - length): | ||
end = start + length | ||
substring = seq[start:end+1] | ||
if substring not in self.seq: | ||
continue | ||
|
||
mapq = 60 | ||
is_rev = False # Doesn't handle reverse complements in this mock. | ||
r_st = self.seq.index(substring) | ||
r_en = r_st + len(substring) | ||
q_st = start | ||
q_en = end + 1 | ||
cigar = [[q_en - q_st, CigarActions.MATCH]] | ||
cigar_str = f'{(q_en - q_st)}M' | ||
al = MockAlignment(is_rev, mapq, cigar, cigar_str, q_st, q_en, r_st, r_en) | ||
if (q_st, q_en, r_st, r_en) not in returned: | ||
returned.add((q_st, q_en, r_st, r_en)) | ||
yield MockAlignment(is_rev, mapq, cigar, cigar_str, q_st, q_en, r_st, r_en) | ||
|
||
max_matches -= 1 | ||
if max_matches < 1: | ||
return |