""" Unit tests for flares.py - Core fNIRS analysis functionality. Covers: - Color mapping utilities - Quality metric directions - Basic signal processing validation - Data structure handling """ import os import sys import pytest import numpy as np from pathlib import Path class TestColorMapping: """Test PRIMARY_COLORS and color mapping functions.""" def test_get_category_color_single_failure(self): """Verify single failure categories return expected colors.""" # Import here to avoid dependency issues in terminal context try: from flares import get_category_color, PRIMARY_COLORS # Test specific categories assert get_category_color("SCI only") == "skyblue" assert get_category_color("SNR only") == "lightgreen" assert get_category_color("Noise only") == "plum" assert get_category_color("Multiple") == "orangered" except ImportError: pytest.skip("PySide6 not available in test environment") def test_get_category_color_unknown(self): """Verify unknown categories return gray (combination color).""" try: from flares import get_category_color, COMBINATION_COLOR # Unknown category should return default assert get_category_color("Unknown Category") == COMBINATION_COLOR except ImportError: pytest.skip("PySide6 not available in test environment") def test_primary_colors_has_all_categories(self): """Verify all expected quality check categories have colors.""" try: from flares import PRIMARY_COLORS expected_categories = [ "SCI only", "SNR only", "PSP only", "Coeff_var only", "Range only", "Noise only", "Disp. only", "Multiple" ] for category in expected_categories: assert category in PRIMARY_COLORS, f"Missing color for {category}" except ImportError: pytest.skip("PySide6 not available in test environment") class TestQualityMetricConfiguration: """Test quality metric configuration and directions.""" def test_qc_metric_directions_defined(self): """Verify all expected QC metrics have direction defined.""" try: from flares import QC_METRIC_DIRECTIONS # Lower-is-better metrics (True) assert QC_METRIC_DIRECTIONS["n_bad_channels_total"] is True assert QC_METRIC_DIRECTIONS["pct_bad_channels"] is True # Higher-is-better metrics (False) assert QC_METRIC_DIRECTIONS["n_epochs_final"] is False except ImportError: pytest.skip("PySide6 not available in test environment") def test_qc_metric_labels_defined(self): """Verify all expected QC metrics have human-readable labels.""" try: from flares import QC_METRIC_LABELS # Check a few important ones assert "n_bad_channels_total" in QC_METRIC_LABELS assert "pct_bad_channels" in QC_METRIC_LABELS assert "final_hr_bpm" in QC_METRIC_LABELS except ImportError: pytest.skip("PySide6 not available in test environment") def test_deviation_based_metrics(self): """Verify deviation-based metrics are identified.""" try: from flares import QC_METRIC_DEVIATION_BASED # Heart rate is colored by deviation, not direction assert "final_hr_bpm" in QC_METRIC_DEVIATION_BASED except ImportError: pytest.skip("PySide6 not available in test environment") class TestDataValidation: """Test data validation utilities from flares.py.""" def test_numpy_array_creation(self): """Verify basic numpy operations work correctly.""" # Test that numpy is properly imported and usable arr = np.array([1, 2, 3, 4, 5]) assert len(arr) == 5 assert np.mean(arr) == 3.0 def test_zscore_calculation_basic(self): """Test z-score calculation is available.""" from scipy.stats import zscore data = np.array([1, 2, 3, 4, 5]) scores = zscore(data) # Check normalization properties assert np.isclose(np.mean(scores), 0, atol=1e-6) assert np.isclose(np.std(scores), 1.0, atol=1e-6) def test_pearson_correlation_basic(self): """Test Pearson correlation is available.""" from scipy.stats import pearsonr x = np.array([1, 2, 3, 4, 5]) y = np.array([2, 4, 6, 8, 10]) # Perfect linear relationship r, p = pearsonr(x, y) assert np.isclose(r, 1.0) assert p < 0.05 class TestFilterParameters: """Test filter configuration parameters.""" def test_filter_constants_defined(self): """Verify filter-related global constants exist.""" try: # These are defined as module-level variables from flares import ( FILTER, FILTER_ALGORITHM, L_FREQ, H_FREQ, IIR_ORDER, FIR_DESIGN ) # Just verify they exist (values may vary based on config) assert hasattr(sys.modules['flares'], 'FILTER') except ImportError: pytest.skip("PySide6 not available in test environment") def test_hrf_model_constant(self): """Verify HRF model parameter exists.""" try: from flares import HRF_MODEL # Just verify it exists assert HRF_MODEL is not None or HRF_MODEL == "" # May be empty string default except ImportError: pytest.skip("PySide6 not available in test environment") class TestMultiprocessingConfiguration: """Test multiprocessing setup for parallel processing.""" def test_n_jobs_parameter_defined(self): """Verify N_JOBS parameter exists for parallel processing.""" try: from flares import N_JOBS, MAX_WORKERS # These control parallelism in analysis assert isinstance(N_JOBS, int) or N_JOBS == 0 except ImportError: pytest.skip("PySide6 not available in test environment") class TestHeartRateParameters: """Test heart rate monitoring configuration.""" def test_hr_parameters_defined(self): """Verify HR-related parameters exist.""" try: from flares import ( HEART_RATE, HR_LOW_FREQ, HR_HIGH_FREQ, HR_SEARCH_MIN, HR_SEARCH_MAX ) # Verify ranges make sense if HEART_RATE: assert HR_LOW_FREQ < HR_HIGH_FREQ assert HR_SEARCH_MIN < HR_SEARCH_MAX except ImportError: pytest.skip("PySide6 not available in test environment") class TestDefaultValues: """Test default parameter values.""" def test_default_age_is_reasonable(self): """Verify default age is set to reasonable value (25).""" try: from flares import AGE assert AGE == 25 assert isinstance(AGE, int) assert 18 <= AGE <= 65 # Reasonable adult range except ImportError: pytest.skip("PySide6 not available in test environment") def test_default_group_is_set(self): """Verify default group parameter.""" try: from flares import GROUP assert GROUP == "Default" or GROUP is not None except ImportError: pytest.skip("PySide6 not available in test environment") class TestMetricRegistry: """Test METRIC_REGISTRY from shareddata integration.""" def test_metric_registry_importable(self): """Verify METRIC_REGISTRY can be imported and used.""" try: from flares import METRIC_REGISTRY # Should exist even if empty assert METRIC_REGISTRY is not None or isinstance(METRIC_REGISTRY, (dict, list)) except ImportError: pytest.skip("PySide6 not available in test environment") class TestPathHandling: """Test path handling utilities.""" def test_resource_path_function_exists(self): """Verify resource_path function from shareddata is available.""" try: from flares import resource_path assert callable(resource_path) except ImportError: pytest.skip("PySide6 not available in test environment") def test_get_app_dir_function_exists(self): """Verify get_app_dir function from shareddata is available.""" try: from flares import get_app_dir assert callable(get_app_dir) result = get_app_dir() assert isinstance(result, Path) or os.path.isdir(str(result)) except ImportError: pytest.skip("PySide6 not available in test environment") if __name__ == "__main__": pytest.main([__file__, "-v"])