annotate COBRAxy/src/test/test_marea.py @ 540:7d5b35c715e8 draft

Uploaded
author francesco_lapi
date Sat, 25 Oct 2025 15:08:19 +0000
parents 2fb97466e404
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
539
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
1 """
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
2 Unit tests for MAREA, flux_simulation, and related visualization modules.
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
3
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
4 Run with: python -m pytest test_marea.py -v
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
5 Or: python test_marea.py
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
6 """
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
7
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
8 import sys
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
9 import os
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
10 import pandas as pd
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
11 import numpy as np
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
12 import tempfile
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
13 from pathlib import Path
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
14
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
15 # Try to import pytest, but don't fail if not available
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
16 try:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
17 import pytest
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
18 HAS_PYTEST = True
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
19 except ImportError:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
20 HAS_PYTEST = False
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
21 class _DummyPytest:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
22 class raises:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
23 def __init__(self, *args, **kwargs):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
24 self.expected_exceptions = args
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
25 def __enter__(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
26 return self
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
27 def __exit__(self, exc_type, exc_val, exc_tb):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
28 if exc_type is None:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
29 raise AssertionError("Expected an exception but none was raised")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
30 if not any(issubclass(exc_type, e) for e in self.expected_exceptions):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
31 return False
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
32 return True
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
33 pytest = _DummyPytest()
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
34
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
35 # Add parent directory to path
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
36 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
37
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
38 import marea
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
39 import flux_simulation
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
40 import flux_to_map
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
41 import ras_to_bounds
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
42 import utils.general_utils as utils
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
43
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
44 # Get the tool directory
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
45 TOOL_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
46
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
47
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
48 class TestMAREA:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
49 """Tests for marea module"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
50
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
51 def test_process_args(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
52 """Test argument processing for MAREA"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
53 # Create minimal args for testing
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
54 with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
55 f.write("reaction_id,value\n")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
56 f.write("r1,1.5\n")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
57 temp_file = f.name
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
58
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
59 try:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
60 args = marea.process_args([
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
61 '-td', TOOL_DIR,
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
62 '--tool_dir', TOOL_DIR
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
63 ])
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
64 assert hasattr(args, 'tool_dir')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
65 assert args.tool_dir == TOOL_DIR
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
66 finally:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
67 if os.path.exists(temp_file):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
68 os.unlink(temp_file)
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
69
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
70 def test_comparison_types(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
71 """Test that comparison type enum exists and is correct"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
72 # Check that the ComparisonType enum has expected values
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
73 assert hasattr(marea, 'ComparisonType') or hasattr(marea, 'GroupingCriterion')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
74
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
75 def test_ras_transformation(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
76 """Test RAS transformation logic"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
77 # Create sample RAS data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
78 ras_data = pd.DataFrame({
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
79 'reaction': ['r1', 'r2', 'r3'],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
80 'value': [1.5, 0.5, 2.0]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
81 })
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
82
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
83 # Test that data can be processed
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
84 assert len(ras_data) == 3
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
85 assert ras_data['value'].max() == 2.0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
86
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
87
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
88 class TestFluxSimulation:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
89 """Tests for flux_simulation module"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
90
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
91 def test_process_args(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
92 """Test argument processing for flux simulation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
93 args = flux_simulation.process_args([
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
94 '-td', TOOL_DIR
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
95 ])
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
96 assert hasattr(args, 'tool_dir')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
97
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
98 def test_flux_balance_setup(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
99 """Test that FBA setup functions exist"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
100 # Check that key functions exist
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
101 assert hasattr(flux_simulation, 'process_args')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
102 assert hasattr(flux_simulation, 'main')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
103
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
104
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
105 class TestFluxToMap:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
106 """Tests for flux_to_map module"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
107
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
108 def test_process_args(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
109 """Test argument processing for flux to map"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
110 args = flux_to_map.process_args([
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
111 '-td', TOOL_DIR
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
112 ])
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
113 assert hasattr(args, 'tool_dir')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
114
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
115 def test_color_map_options(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
116 """Test that color map options are available"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
117 # The module should have color map functionality
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
118 assert hasattr(flux_to_map, 'process_args')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
119
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
120
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
121 class TestRasToBounds:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
122 """Tests for ras_to_bounds module"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
123
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
124 def test_process_args(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
125 """Test argument processing for RAS to bounds"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
126 args = ras_to_bounds.process_args([
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
127 '-td', TOOL_DIR
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
128 ])
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
129 assert hasattr(args, 'tool_dir')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
130
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
131 def test_bounds_conversion(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
132 """Test that bounds conversion logic exists"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
133 # Create sample RAS data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
134 ras_data = {
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
135 'r1': 1.5,
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
136 'r2': 0.5,
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
137 'r3': 2.0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
138 }
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
139
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
140 # Test basic transformation logic
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
141 # Reactions with higher RAS should have higher bounds
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
142 assert ras_data['r3'] > ras_data['r1'] > ras_data['r2']
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
143
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
144
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
145 class TestModelConversion:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
146 """Tests for model conversion tools"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
147
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
148 def test_tabular_to_model(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
149 """Test tabular to model conversion"""
540
7d5b35c715e8 Uploaded
francesco_lapi
parents: 539
diff changeset
150 import COBRAxy.src.exportMetabolicModel as exportMetabolicModel
539
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
151
540
7d5b35c715e8 Uploaded
francesco_lapi
parents: 539
diff changeset
152 args = exportMetabolicModel.process_args([])
539
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
153 assert hasattr(args, 'tool_dir')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
154
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
155 def test_model_to_tabular(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
156 """Test model to tabular conversion"""
540
7d5b35c715e8 Uploaded
francesco_lapi
parents: 539
diff changeset
157 import COBRAxy.src.importMetabolicModel as importMetabolicModel
539
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
158
540
7d5b35c715e8 Uploaded
francesco_lapi
parents: 539
diff changeset
159 args = importMetabolicModel.process_args([])
539
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
160 assert hasattr(args, 'tool_dir')
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
161
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
162
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
163 class TestDataProcessing:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
164 """Tests for data processing utilities used across tools"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
165
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
166 def test_ras_data_format(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
167 """Test RAS data format validation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
168 # Create valid RAS data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
169 ras_df = pd.DataFrame({
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
170 'reaction_id': ['r1', 'r2', 'r3'],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
171 'group1': [1.5, 0.5, 2.0],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
172 'group2': [1.8, 0.3, 2.2]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
173 })
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
174
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
175 assert 'reaction_id' in ras_df.columns
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
176 assert len(ras_df) > 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
177
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
178 def test_rps_data_format(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
179 """Test RPS data format validation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
180 # Create valid RPS data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
181 rps_df = pd.DataFrame({
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
182 'reaction_id': ['r1', 'r2', 'r3'],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
183 'sample1': [100.5, 50.3, 200.1],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
184 'sample2': [150.2, 30.8, 250.5]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
185 })
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
186
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
187 assert 'reaction_id' in rps_df.columns
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
188 assert len(rps_df) > 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
189
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
190 def test_flux_data_format(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
191 """Test flux data format validation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
192 # Create valid flux data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
193 flux_df = pd.DataFrame({
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
194 'reaction_id': ['r1', 'r2', 'r3'],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
195 'flux': [1.5, -0.5, 2.0],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
196 'lower_bound': [-10, -10, 0],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
197 'upper_bound': [10, 10, 10]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
198 })
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
199
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
200 assert 'reaction_id' in flux_df.columns
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
201 assert 'flux' in flux_df.columns
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
202
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
203
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
204 class TestStatistics:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
205 """Tests for statistical operations in MAREA"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
206
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
207 def test_fold_change_calculation(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
208 """Test fold change calculation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
209 # Simple fold change test
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
210 group1_mean = 2.0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
211 group2_mean = 4.0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
212 fold_change = group2_mean / group1_mean
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
213
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
214 assert fold_change == 2.0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
215
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
216 def test_log_fold_change(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
217 """Test log fold change calculation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
218 group1_mean = 2.0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
219 group2_mean = 8.0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
220 log_fc = np.log2(group2_mean / group1_mean)
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
221
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
222 assert log_fc == 2.0 # log2(8/2) = log2(4) = 2
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
223
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
224 def test_pvalue_correction(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
225 """Test that statistical functions handle edge cases"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
226 # Test with identical values (should give p-value close to 1)
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
227 group1 = [1.0, 1.0, 1.0]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
228 group2 = [1.0, 1.0, 1.0]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
229
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
230 from scipy import stats
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
231 t_stat, p_value = stats.ttest_ind(group1, group2)
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
232
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
233 # p-value should be NaN or close to 1 for identical groups
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
234 assert np.isnan(p_value) or p_value > 0.9
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
235
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
236
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
237 class TestMapVisualization:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
238 """Tests for SVG map visualization"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
239
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
240 def test_svg_maps_exist(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
241 """Test that SVG maps exist"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
242 map_dir = os.path.join(TOOL_DIR, "local", "svg metabolic maps")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
243 assert os.path.exists(map_dir)
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
244
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
245 # Check for at least one map
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
246 maps = [f for f in os.listdir(map_dir) if f.endswith('.svg')]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
247 assert len(maps) > 0, "No SVG maps found"
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
248
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
249 def test_model_has_map(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
250 """Test that models have associated maps"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
251 # ENGRO2 should have a map
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
252 engro2_map = os.path.join(TOOL_DIR, "local", "svg metabolic maps", "ENGRO2_map.svg")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
253 if os.path.exists(engro2_map):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
254 assert os.path.getsize(engro2_map) > 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
255
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
256 def test_color_gradient(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
257 """Test color gradient generation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
258 # Test that we can generate colors for a range of values
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
259 values = [-2.0, -1.0, 0.0, 1.0, 2.0]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
260
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
261 # All values should be processable
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
262 for val in values:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
263 # Simple color mapping test
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
264 if val < 0:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
265 # Negative values should map to one color scheme
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
266 assert val < 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
267 elif val > 0:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
268 # Positive values should map to another
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
269 assert val > 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
270 else:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
271 # Zero should be neutral
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
272 assert val == 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
273
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
274
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
275 class TestIntegration:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
276 """Integration tests for complete workflows"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
277
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
278 def test_ras_to_marea_workflow(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
279 """Test that RAS data can flow into MAREA"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
280 # Create sample RAS data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
281 ras_data = pd.DataFrame({
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
282 'reaction_id': ['r1', 'r2', 'r3'],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
283 'control': [1.5, 0.8, 1.2],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
284 'treatment': [2.0, 0.5, 1.8]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
285 })
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
286
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
287 # Calculate fold changes
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
288 ras_data['fold_change'] = ras_data['treatment'] / ras_data['control']
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
289
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
290 assert 'fold_change' in ras_data.columns
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
291 assert len(ras_data) == 3
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
292
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
293 def test_rps_to_flux_workflow(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
294 """Test that RPS data can be used for flux simulation"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
295 # Create sample RPS data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
296 rps_data = pd.DataFrame({
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
297 'reaction_id': ['r1', 'r2', 'r3'],
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
298 'rps': [100.0, 50.0, 200.0]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
299 })
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
300
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
301 # RPS can be used to set bounds
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
302 rps_data['upper_bound'] = rps_data['rps'] / 10
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
303
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
304 assert 'upper_bound' in rps_data.columns
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
305
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
306
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
307 class TestErrorHandling:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
308 """Tests for error handling across modules"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
309
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
310 def test_invalid_model_name(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
311 """Test handling of invalid model names"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
312 with pytest.raises((ValueError, KeyError, AttributeError)):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
313 utils.Model("INVALID_MODEL")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
314
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
315 def test_missing_required_column(self):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
316 """Test handling of missing required columns"""
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
317 # Create incomplete data
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
318 incomplete_data = pd.DataFrame({
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
319 'wrong_column': [1, 2, 3]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
320 })
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
321
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
322 # Should fail when looking for required columns
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
323 with pytest.raises(KeyError):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
324 value = incomplete_data['reaction_id']
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
325
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
326
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
327 if __name__ == "__main__":
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
328 # Run tests with pytest if available
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
329 if HAS_PYTEST:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
330 pytest.main([__file__, "-v"])
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
331 else:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
332 print("pytest not available, running basic tests...")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
333
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
334 test_classes = [
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
335 TestMAREA(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
336 TestFluxSimulation(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
337 TestFluxToMap(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
338 TestRasToBounds(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
339 TestModelConversion(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
340 TestDataProcessing(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
341 TestStatistics(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
342 TestMapVisualization(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
343 TestIntegration(),
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
344 TestErrorHandling()
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
345 ]
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
346
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
347 failed = 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
348 passed = 0
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
349
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
350 for test_class in test_classes:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
351 class_name = test_class.__class__.__name__
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
352 print(f"\n{class_name}:")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
353
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
354 for method_name in dir(test_class):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
355 if method_name.startswith("test_"):
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
356 try:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
357 method = getattr(test_class, method_name)
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
358 method()
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
359 print(f" ✓ {method_name}")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
360 passed += 1
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
361 except Exception as e:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
362 print(f" ✗ {method_name}: {str(e)}")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
363 import traceback
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
364 traceback.print_exc()
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
365 failed += 1
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
366
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
367 print(f"\n{'='*60}")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
368 print(f"Results: {passed} passed, {failed} failed")
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
369 if failed > 0:
2fb97466e404 Uploaded
francesco_lapi
parents:
diff changeset
370 sys.exit(1)