- Backend: Refactored tasks.py to directly invoke run_single_fna_pipeline.py for consistency. - Backend: Changed output format to ZIP and added auto-cleanup of intermediate files. - Backend: Fixed language parameter passing in API and tasks. - Frontend: Removed CRISPR Fusion UI elements from Submit and Monitor views. - Frontend: Implemented simulated progress bar for better UX. - Frontend: Restored One-click load button and added result file structure documentation. - Docker: Fixed critical Restarting loop by removing incorrect image directive in docker-compose.yml. - Docker: Optimized Dockerfile to correct .pixi environment path issues and prevent accidental deletion of frontend assets.
94 lines
2.8 KiB
Python
94 lines
2.8 KiB
Python
import pytest
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
# Add project root to path to allow importing modules
|
|
sys.path.insert(0, str(Path(__file__).parents[2]))
|
|
|
|
from crispr_cas.scripts.fusion_analysis import calculate_distance, perform_fusion_analysis
|
|
|
|
def test_calculate_distance():
|
|
"""Test genomic distance calculation"""
|
|
# Same contig, no overlap
|
|
# Range1: 100-200, Range2: 300-400 -> Dist 100
|
|
assert calculate_distance("c1:100-200", "c1:300-400") == 100
|
|
|
|
# Same contig, overlap
|
|
# Range1: 100-300, Range2: 200-400 -> Dist 0
|
|
assert calculate_distance("c1:100-300", "c1:200-400") == 0
|
|
|
|
# Different contig
|
|
assert calculate_distance("c1:100-200", "c2:300-400") == -1
|
|
|
|
# Invalid format
|
|
assert calculate_distance("invalid", "c1:100-200") == -1
|
|
|
|
def test_fusion_analysis_logic(tmp_path):
|
|
"""Test main analysis logic with mock data"""
|
|
|
|
# Mock CRISPR data
|
|
crispr_data = {
|
|
"strain_id": "test_strain",
|
|
"arrays": [
|
|
{
|
|
"id": "A1",
|
|
"contig": "contig_1",
|
|
"start": 1000,
|
|
"end": 2000,
|
|
"spacers": [{"sequence": "ATGC"}]
|
|
}
|
|
]
|
|
}
|
|
|
|
# Mock toxin file (just a placeholder for path)
|
|
toxin_file = tmp_path / "toxins.txt"
|
|
toxin_file.touch()
|
|
|
|
# Run analysis in mock mode
|
|
# In mock mode, the script generates its own toxin list:
|
|
# {"name": "Cry1Ac1", "position": "contig_1:10000-12000"}
|
|
# Distance: 10000 - 2000 = 8000 (< 10000 threshold) -> Should match
|
|
|
|
results = perform_fusion_analysis(crispr_data, toxin_file, mock=True)
|
|
|
|
assert results["strain_id"] == "test_strain"
|
|
assert len(results["associations"]) > 0
|
|
|
|
# Check for proximity match
|
|
proximity_matches = [a for a in results["associations"] if a["type"] == "proximity"]
|
|
assert len(proximity_matches) > 0
|
|
assert proximity_matches[0]["distance"] == 8000
|
|
|
|
def test_script_execution(tmp_path):
|
|
"""Test full script execution via subprocess"""
|
|
|
|
# Create input files
|
|
crispr_file = tmp_path / "crispr.json"
|
|
with open(crispr_file, 'w') as f:
|
|
json.dump({"strain_id": "test", "arrays": []}, f)
|
|
|
|
toxin_file = tmp_path / "toxins.txt"
|
|
toxin_file.touch()
|
|
|
|
genome_file = tmp_path / "genome.fna"
|
|
genome_file.touch()
|
|
|
|
output_file = tmp_path / "output.json"
|
|
|
|
script_path = Path("crispr_cas/scripts/fusion_analysis.py").absolute()
|
|
|
|
import subprocess
|
|
cmd = [
|
|
"python3", str(script_path),
|
|
"--crispr-results", str(crispr_file),
|
|
"--toxin-results", str(toxin_file),
|
|
"--genome", str(genome_file),
|
|
"--output", str(output_file),
|
|
"--mock"
|
|
]
|
|
|
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
assert result.returncode == 0
|
|
assert output_file.exists()
|