Spaces:
Running
Running
| """Unit tests for the cloning simulator (dee/core/cloning.py).""" | |
| import pytest | |
| from dee.core import cloning as C | |
| # ββ Gibson / overlap assembly βββββββββββββββββββββββββββββββββββββββββββββββ | |
| def test_gibson_native_overlaps_circular(): | |
| # three fragments sharing 20-bp overlaps, arranged head-to-tail in a circle. | |
| o1 = "ACGTACGTACGTACGTACGT" # AβB overlap | |
| o2 = "TTTTGGGGCCCCAAAATTTT" # BβC overlap | |
| o3 = "GGGGCCCCAAAATTTTGGGG" # CβA overlap | |
| A = o3 + "AAAAAAAAAAAA" + o1 | |
| B = o1 + "CCCCCCCCCCCC" + o2 | |
| Cc = o2 + "GGGGGGGGGGGG" + o3 | |
| out = C.gibson([{"name": "A", "seq": A}, {"name": "B", "seq": B}, {"name": "C", "seq": Cc}]) | |
| assert out["ok"] is True | |
| assert out["topology"] == "circular" | |
| assert all(j["kind"] == "native" for j in out["junctions"]) | |
| assert out["length"] == len(A) + len(B) + len(Cc) - 60 # minus three 20-bp overlaps | |
| def test_gibson_auto_orders_fragments(): | |
| o1 = "ACGTACGTACGTACGTACGT" | |
| o2 = "TTTTGGGGCCCCAAAATTTT" | |
| A = "AAAAAAAA" + o1 | |
| B = o1 + "CCCCCCCC" + o2 | |
| Cc = o2 + "GGGGGGGG" | |
| out = C.gibson([{"name": "C", "seq": Cc}, {"name": "A", "seq": A}, {"name": "B", "seq": B}], | |
| circular=False) | |
| assert out["ok"] is True | |
| assert out["order"] == ["A", "B", "C"] | |
| assert out["length"] == len(A) + len(B) + len(Cc) - 40 | |
| def test_gibson_designs_overlaps_and_primers_for_bare_fragments(): | |
| A = "ATGGTGAGCAAGGGCGAGGAGCTGTTCACC" | |
| B = "GACGAGCTGTACAAGTAACTCGAGCTAGCAT" | |
| out = C.gibson([{"name": "A", "seq": A}, {"name": "B", "seq": B}], circular=False) | |
| assert out["ok"] is True | |
| assert any(j["kind"] == "designed" for j in out["junctions"]) | |
| assert out["length"] == len(A) + len(B) | |
| prim = {p["fragment"]: p for p in out["primers"]} | |
| assert prim["B"]["forward_tail"] > 0 | |
| assert prim["B"]["forward"].startswith(A[-25:]) | |
| def test_gibson_needs_two_fragments(): | |
| assert C.gibson([{"name": "x", "seq": "ACGT"}])["ok"] is False | |
| # ββ Golden Gate ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _bsa_part(left_oh, body, right_oh): | |
| return "GAATT" + "GGTCTC" + "T" + left_oh + body + right_oh + "T" + "GAGACC" + "TTAAG" | |
| def test_excise_part_reads_overhangs(): | |
| p = C._excise_part(_bsa_part("AAAA", "GCTAGCGGGG", "CCCC"), "BsaI") | |
| assert p["left_oh"] == "AAAA" | |
| assert p["right_oh"] == "CCCC" | |
| assert p["inner"] == "AAAA" + "GCTAGCGGGG" + "CCCC" | |
| def test_golden_gate_assembles_circle(): | |
| p1 = _bsa_part("AAAA", "GCTAGCAAAA", "CCCC") | |
| p2 = _bsa_part("CCCC", "TTGGCCAATT", "AAAA") | |
| out = C.golden_gate([{"name": "P1", "seq": p1}, {"name": "P2", "seq": p2}], enzyme="BsaI") | |
| assert out["ok"] is True | |
| assert out["topology"] == "circular" | |
| assert out["length"] == (4 + len("GCTAGCAAAA")) + (4 + len("TTGGCCAATT")) | |
| assert out["order"] == ["P1", "P2"] | |
| def test_golden_gate_rejects_mismatched_overhangs(): | |
| p1 = _bsa_part("AAAA", "GCTAGCAAAA", "CCCC") | |
| p2 = _bsa_part("GGGG", "TTGGCCAATT", "AAAA") | |
| out = C.golden_gate([{"name": "P1", "seq": p1}, {"name": "P2", "seq": p2}], enzyme="BsaI") | |
| assert out["ok"] is False | |
| def test_golden_gate_rejects_non_cassette(): | |
| out = C.golden_gate([{"name": "P1", "seq": "ACGTACGTACGT"}, {"name": "P2", "seq": "TTTTGGGG"}]) | |
| assert out["ok"] is False | |
| # ββ restriction cut-and-ligate ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def test_restriction_clone_single_enzyme(): | |
| vector = "AAAACCCC" + "GAATTC" + "TTTTGGGGCCCCAAAA" | |
| insert = "CC" + "GAATTC" + "ATGCATGCATGCATGC" + "GAATTC" + "GG" | |
| out = C.restriction_clone(vector, insert, "EcoRI", vector_topology="circular") | |
| assert out["ok"] is True | |
| assert out["topology"] == "circular" | |
| assert "ATGCATGCATGCATGC" in out["assembled"] | |
| assert out["length"] > len(vector) | |
| def test_restriction_clone_requires_unique_vector_site(): | |
| vector = "GAATTCAAAAGAATTC" | |
| insert = "GAATTCATGCGAATTC" | |
| out = C.restriction_clone(vector, insert, "EcoRI", vector_topology="linear") | |
| assert out["ok"] is False | |
| def test_restriction_clone_requires_flanked_insert(): | |
| vector = "AAAAGAATTCTTTT" | |
| insert = "ATGCATGCATGC" | |
| out = C.restriction_clone(vector, insert, "EcoRI") | |
| assert out["ok"] is False | |