File size: 4,863 Bytes
cd0c7a9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""
Unit tests for BLAST parameter resolution and sequence-aware validation.

Pure logic — no external API calls.
"""

import pytest


class TestValidateFastaNucleotide:
    def test_protein_fasta_still_valid(self):
        from app.services.validators import validate_fasta

        res = validate_fasta(">p53\nMEEPQSDPSVEPPLSQETFSDLWKLLPENN", "blast")
        assert res.valid
        assert len(res.sequences) == 1

    def test_dna_sequence_now_valid(self):
        from app.services.validators import validate_fasta

        res = validate_fasta(">seq\nATGGCGACCGGCGCTCCCGCCGGGATCGCCATG", "blast")
        assert res.valid
        assert len(res.sequences) == 1

    def test_plain_dna_valid(self):
        from app.services.validators import validate_fasta

        res = validate_fasta("ATGGCGACCGGCGCTCCCGCCGGGATCGCCATG", "blast")
        assert res.valid

    def test_rna_sequence_valid(self):
        from app.services.validators import validate_fasta

        res = validate_fasta("AUGGCGACCGGCGCUCCCGCCGGGAUCGCCAUG", "blast")
        assert res.valid

    def test_protein_invalid_chars_rejected(self):
        from app.services.validators import validate_fasta

        # FASTA path keeps every char, so digits are caught (plain path strips them)
        res = validate_fasta(">query\nMEEPQSDPSVEPPLSQET12345", "blast")
        assert not res.valid

    def test_protein_with_ambiguity_codes_accepted(self):
        from app.services.validators import validate_fasta

        res = validate_fasta("MEEPQSDPSVEPPLSQETBZXOUJ", "blast")
        assert res.valid

    def test_short_sequence_rejected(self):
        from app.services.validators import validate_fasta

        res = validate_fasta("ATG", "blast")
        assert not res.valid
        assert "short" in res.error.lower()


class TestResolveBlastParams:
    def test_protein_defaults(self):
        from app.services.blast_config import resolve_blast_params

        program, database, seq_type = resolve_blast_params("TTCCPSIVARSNFNVCRLPG")
        assert program == "blastp"
        assert database == "nr"
        assert seq_type == "protein"

    def test_dna_defaults(self):
        from app.services.blast_config import resolve_blast_params

        program, database, seq_type = resolve_blast_params("ATGGCGACCGGCGCTCCCGCCGGGATCGCCATG")
        assert program == "blastn"
        assert database == "nt"
        assert seq_type == "dna"

    def test_fast_mode_switches_to_swissprot(self):
        from app.services.blast_config import resolve_blast_params

        program, database, seq_type = resolve_blast_params(
            "TTCCPSIVARSNFNVCRLPG", fast_mode=True
        )
        assert database == "swissprot"

    def test_explicit_program_and_db_respected(self):
        from app.services.blast_config import resolve_blast_params

        program, database, seq_type = resolve_blast_params(
            "TTCCPSIVARSNFNVCRLPG",
            program="blastp",
            database="pdbaa",
        )
        assert program == "blastp"
        assert database == "pdbaa"

    def test_dna_blastx_allowed(self):
        from app.services.blast_config import resolve_blast_params

        program, database, seq_type = resolve_blast_params(
            "ATGGCGACCGGCGCTCCCGCCGGGATCGCCATG",
            program="blastx",
            database="nr",
        )
        assert program == "blastx"
        assert database == "nr"

    def test_protein_rejects_nucleotide_program(self):
        from app.services.blast_config import resolve_blast_params

        with pytest.raises(ValueError):
            resolve_blast_params("TTCCPSIVARSNFNVCRLPG", program="blastn")

    def test_incompatible_db_falls_back(self):
        from app.services.blast_config import resolve_blast_params

        # nr is a protein db — sending it with blastn must not error
        program, database, seq_type = resolve_blast_params(
            "ATGGCGACCGGCGCTCCCGCCGGGATCGCCATG",
            program="blastn",
            database="nr",
        )
        assert database == "nt"

    def test_dna_fast_mode_falls_back_to_refseq_rna(self):
        from app.services.blast_config import resolve_blast_params

        program, database, seq_type = resolve_blast_params(
            "ATGGCGACCGGCGCTCCCGCCGGGATCGCCATG",
            database="swissprot",  # protein db with a DNA query
            fast_mode=True,
        )
        assert database == "refseq_rna"

    def test_unsupported_program_rejected(self):
        from app.services.blast_config import resolve_blast_params

        with pytest.raises(ValueError):
            resolve_blast_params("TTCCPSIVARSNFNVCRLPG", program="megablast")

    def test_unknown_sequence_rejected(self):
        from app.services.blast_config import resolve_blast_params

        with pytest.raises(ValueError):
            resolve_blast_params("1234567890")