Spaces:
Running
Running
File size: 4,410 Bytes
44c4b80 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | """
Tests for 3d ScanProsite raw-sequence motif scanning:
- scan_prosite_sequence parses the verified ScanProsite JSON contract
- short sequences return a clear error
- empty matchset -> count 0
- POST /api/domains/scan router: success + 400 on short sequence
Network calls are mocked; these run fully offline.
"""
import pytest
from fastapi import HTTPException
from app.tools import domain_analysis as da
from app.routers import domains as domains_router
from app.routers.domains import ScanPrositeRequest, scan_prosite
class FakeResp:
def __init__(self, status_code, json_data):
self.status_code = status_code
self._json = json_data
def json(self):
return self._json
class FakeClient:
def __init__(self, *args, **kwargs):
self.calls = []
async def __aenter__(self):
return self
async def __aexit__(self, *args):
return None
async def post(self, url, data=None, **kwargs):
self.calls.append((url, data))
return FakeResp(200, {
"n_match": 1,
"n_seq": 1,
"matchset": [
{"sequence_ac": "USERSEQ1", "start": 237, "stop": 249,
"signature_ac": "PS00348", "level_tag": "(0)"},
],
})
class TestScanPrositeSequence:
@pytest.mark.asyncio
async def test_parses_json_contract(self, monkeypatch):
fake = FakeClient()
monkeypatch.setattr(da.httpx, "AsyncClient", lambda *a, **k: fake)
monkeypatch.setattr(da, "_prosite_signature_name",
lambda sig: _fake_name(sig))
seq = "M" * 250
result = await da.scan_prosite_sequence(seq)
assert result["sequence_length"] == 250
assert result["count"] == 1
m = result["matches"][0]
assert m["signature_ac"] == "PS00348"
assert m["start"] == 237 and m["stop"] == 249
assert m["name"] == "p53 family signature"
@pytest.mark.asyncio
async def test_empty_matchset(self, monkeypatch):
class FakeClientEmpty(FakeClient):
async def post(self, url, data=None, **kwargs):
self.calls.append((url, data))
return FakeResp(200, {"n_match": 0, "n_seq": 1})
monkeypatch.setattr(da.httpx, "AsyncClient", lambda *a, **k: FakeClientEmpty())
result = await da.scan_prosite_sequence("M" * 50)
assert result["count"] == 0
assert result["matches"] == []
@pytest.mark.asyncio
async def test_short_sequence_rejected(self):
result = await da.scan_prosite_sequence("MEEPQ")
assert "error" in result
assert "too short" in result["error"]
@pytest.mark.asyncio
async def test_http_error(self, monkeypatch):
class FakeClientFail(FakeClient):
async def post(self, url, data=None, **kwargs):
return FakeResp(500, {})
monkeypatch.setattr(da.httpx, "AsyncClient", lambda *a, **k: FakeClientFail())
result = await da.scan_prosite_sequence("M" * 50)
assert "error" in result
assert "HTTP 500" in result["error"]
class TestScanPrositeEndpoint:
@pytest.mark.asyncio
async def test_success(self, monkeypatch):
async def fake_scan(sequence, email=""):
assert email == "bioflow@example.com"
return {"sequence_length": 10, "count": 1, "matches": [
{"signature_ac": "PS00001", "name": "N-glycosylation site",
"start": 2, "stop": 5, "level_tag": "(0)"},
]}
monkeypatch.setattr(domains_router, "scan_prosite_sequence", fake_scan)
resp = await scan_prosite(ScanPrositeRequest(sequence="MEEPQSDPSV"))
assert resp.sequence_length == 10
assert resp.count == 1
assert resp.matches[0].name == "N-glycosylation site"
@pytest.mark.asyncio
async def test_short_sequence_400(self, monkeypatch):
async def fake_scan(sequence, email=""):
return {"error": "Sequence too short (min 10 amino acids)"}
monkeypatch.setattr(domains_router, "scan_prosite_sequence", fake_scan)
with pytest.raises(HTTPException) as exc:
await scan_prosite(ScanPrositeRequest(sequence="MEEPQ"))
assert exc.value.status_code == 400
assert "too short" in exc.value.detail
async def _fake_name(sig: str) -> str:
return "p53 family signature"
|