import warnings
import pytest
import ferro_hgvs
GOOD = "NC_000017.11:g.50198002C>T"
BAD = "totally not a variant"
BAD_NORMALIZED = "NM_000088.3:c.4C>G"
def _projector() -> ferro_hgvs.VariantProjector:
with warnings.catch_warnings():
warnings.simplefilter("ignore", UserWarning)
return ferro_hgvs.VariantProjector()
class TestProjectManyDefault:
def test_default_aborts_and_raises_on_bad_input(self) -> None:
proj = _projector()
with pytest.raises(ferro_hgvs.ProjectionError):
proj.project_many([GOOD, BAD, GOOD])
def test_default_returns_list_of_lists_when_all_good(self) -> None:
proj = _projector()
out = proj.project_many([GOOD, GOOD])
assert isinstance(out, list)
assert all(isinstance(inner, list) for inner in out)
class TestProjectManyReturnExceptions:
def test_isolates_failures_in_order(self) -> None:
proj = _projector()
out = proj.project_many([GOOD, BAD, GOOD], return_exceptions=True)
assert len(out) == 3
assert isinstance(out[0], list)
assert isinstance(out[1], ferro_hgvs.ProjectionError)
assert isinstance(out[2], list)
def test_returned_exception_is_typed_and_backcompat(self) -> None:
proj = _projector()
out = proj.project_many([BAD], return_exceptions=True)
exc = out[0]
assert isinstance(exc, ferro_hgvs.ProjectionError)
assert isinstance(exc, RuntimeError)
assert isinstance(exc, ferro_hgvs.FerroError)
assert "input[0]" in str(exc)
def test_returned_exception_preserves_structured_payload(self) -> None:
proj = _projector()
exc = proj.project_many([BAD], return_exceptions=True)[0]
assert isinstance(exc, ferro_hgvs.ProjectionError)
assert isinstance(exc.mutalyzer_codes, tuple)
assert exc.code is None or (isinstance(exc.code, str) and exc.code.startswith(("E", "W")))
def test_all_good_returns_no_exceptions(self) -> None:
proj = _projector()
out = proj.project_many([GOOD, GOOD], return_exceptions=True)
assert all(isinstance(inner, list) for inner in out)
def test_all_fail_batch_isolates_every_input(self) -> None:
proj = _projector()
out = proj.project_many([BAD, BAD, BAD], return_exceptions=True)
assert len(out) == 3
assert all(isinstance(item, ferro_hgvs.ProjectionError) for item in out)
assert [f"input[{i}]" in str(item) for i, item in enumerate(out)] == [True, True, True]
def test_empty_batch_returns_empty_list(self) -> None:
proj = _projector()
assert proj.project_many([], return_exceptions=True) == []
assert proj.project_many([]) == []
class TestProjectNormalizedManyReturnExceptions:
def test_default_returns_list_of_lists(self) -> None:
proj = _projector()
variant = ferro_hgvs.parse(GOOD)
out = proj.project_normalized_many([variant])
assert isinstance(out, list)
assert all(isinstance(inner, list) for inner in out)
def test_return_exceptions_isolates(self) -> None:
proj = _projector()
variant = ferro_hgvs.parse(GOOD)
out = proj.project_normalized_many([variant], return_exceptions=True)
assert len(out) == 1
assert isinstance(out[0], list)
def test_return_exceptions_isolates_a_real_failure_in_order(self) -> None:
proj = _projector()
good = ferro_hgvs.parse(GOOD)
bad = ferro_hgvs.parse(BAD_NORMALIZED)
out = proj.project_normalized_many([good, bad, good], return_exceptions=True)
assert len(out) == 3
assert isinstance(out[0], list)
assert isinstance(out[1], ferro_hgvs.ProjectionError)
assert "input[1]" in str(out[1])
assert isinstance(out[2], list)
def test_default_aborts_and_raises_on_bad_input(self) -> None:
proj = _projector()
good = ferro_hgvs.parse(GOOD)
bad = ferro_hgvs.parse(BAD_NORMALIZED)
with pytest.raises(ferro_hgvs.ProjectionError):
proj.project_normalized_many([good, bad])