""" Pytest Configuration and Shared Fixtures Provides shared test fixtures for unit and integration tests """ import pytest import tempfile import shutil from pathlib import Path from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from fastapi.testclient import TestClient from src.database.models import Base from src.core.storage import LocalStorage from config.settings import settings # ============================================================================= # DATABASE FIXTURES # ============================================================================= @pytest.fixture(scope="session") def test_db_engine(): """ Create test database engine Uses in-memory SQLite for fast tests """ # Use SQLite in-memory for tests engine = create_engine("sqlite:///:memory:", echo=False) # Create all tables Base.metadata.create_all(engine) yield engine # Cleanup Base.metadata.drop_all(engine) engine.dispose() @pytest.fixture def db_session(test_db_engine): """ Database session fixture Creates a new session for each test and rolls back after """ Session = sessionmaker(bind=test_db_engine) session = Session() yield session session.rollback() session.close() # ============================================================================= # STORAGE FIXTURES # ============================================================================= @pytest.fixture def temp_storage_dir(): """ Temporary storage directory Creates a temp dir and cleans up after test """ temp_dir = tempfile.mkdtemp(prefix="giglez_test_") yield Path(temp_dir) # Cleanup shutil.rmtree(temp_dir, ignore_errors=True) @pytest.fixture def test_storage(temp_storage_dir): """ Test storage backend (LocalStorage) Uses temporary directory """ return LocalStorage(base_path=str(temp_storage_dir)) # ============================================================================= # API FIXTURES # ============================================================================= @pytest.fixture def test_client(): """ FastAPI test client Provides TestClient for API endpoint testing """ from src.api.main import app client = TestClient(app) return client # ============================================================================= # SAMPLE DATA FIXTURES # ============================================================================= @pytest.fixture def sample_sub_file_key(): """Sample .sub file content (KEY format)""" return """Filetype: Flipper SubGhz Key File Version: 1 Frequency: 433920000 Preset: FuriHalSubGhzPresetOok270Async Protocol: Princeton Bit: 24 Key: 00 00 00 00 00 95 D5 D4 TE: 400 """ @pytest.fixture def sample_sub_file_raw(): """Sample .sub file content (RAW format)""" return """Filetype: Flipper SubGhz RAW File Version: 1 Frequency: 315000000 Preset: FuriHalSubGhzPresetOok650Async Protocol: RAW RAW_Data: 2980 -240 520 -980 520 -980 1000 -500 480 -1020 """ @pytest.fixture def sample_manifest(): """Sample upload manifest""" return { "session_uuid": "test-session-001", "captures": [ { "filename": "test.sub", "latitude": 40.7128, "longitude": -74.0060, "accuracy": 5.0, "altitude": 10.5, "timestamp": "2026-01-12T10:00:00Z" } ] } @pytest.fixture def sample_gps_coordinates(): """Sample GPS coordinates (valid)""" return [ (40.7128, -74.0060, 5.0, "NYC"), (51.5074, -0.1278, 8.0, "London"), (35.6762, 139.6503, 3.0, "Tokyo"), (-33.8688, 151.2093, 10.0, "Sydney"), ] @pytest.fixture def invalid_gps_coordinates(): """Invalid GPS coordinates for testing""" return [ (91.0, 0.0, 5.0, "Latitude > 90"), (-91.0, 0.0, 5.0, "Latitude < -90"), (0.0, 181.0, 5.0, "Longitude > 180"), (0.0, -181.0, 5.0, "Longitude < -180"), (0.0, 0.0, 5.0, "Null Island"), (40.7128, -74.0060, 100.0, "Poor accuracy"), ] # ============================================================================= # PYTEST MARKERS # ============================================================================= def pytest_configure(config): """Register custom pytest markers""" config.addinivalue_line("markers", "unit: Unit tests (fast, no external dependencies)") config.addinivalue_line("markers", "integration: Integration tests (database, API)") config.addinivalue_line("markers", "manual: Manual tests (human verification required)") config.addinivalue_line("markers", "slow: Slow tests (skip in CI)")