""" Pytest configuration and fixtures for PIF Compiler tests. This file contains shared fixtures and configuration for all tests. """ import pytest import sys from pathlib import Path # Add src to Python path for imports src_path = Path(__file__).parent.parent / "src" sys.path.insert(0, str(src_path)) # Sample data fixtures @pytest.fixture def sample_cas_numbers(): """Real CAS numbers for testing common cosmetic ingredients.""" return { "water": "7732-18-5", "glycerin": "56-81-5", "sodium_hyaluronate": "9067-32-7", "niacinamide": "98-92-0", "ascorbic_acid": "50-81-7", "retinol": "68-26-8", "lanolin": "85507-69-3", "sodium_chloride": "7647-14-5", "propylene_glycol": "57-55-6", "butylene_glycol": "107-88-0", "salicylic_acid": "69-72-7", "tocopherol": "59-02-9", "caffeine": "58-08-2", "citric_acid": "77-92-9", "hyaluronic_acid": "9004-61-9", "sodium_hyaluronate_crosspolymer": "63148-62-9", "zinc_oxide": "1314-13-2", "titanium_dioxide": "13463-67-7", "lactic_acid": "50-21-5", "lanolin_oil": "8006-54-0", } @pytest.fixture def sample_cosing_response(): """Sample COSING API response for testing.""" return { "inciName": ["WATER"], "casNo": ["7732-18-5"], "ecNo": ["231-791-2"], "substanceId": ["12345"], "itemType": ["Ingredient"], "functionName": ["Solvent"], "chemicalName": ["Dihydrogen monoxide"], "nameOfCommonIngredientsGlossary": ["Water"], "sccsOpinion": [], "sccsOpinionUrls": [], "otherRestrictions": [], "identifiedIngredient": [], "annexNo": [], "otherRegulations": [], "refNo": ["REF123"], "phEurName": [], "innName": [] } @pytest.fixture def sample_ingredient_data(): """Sample ingredient data for Pydantic model testing.""" return { "inci_name": "WATER", "cas": "7732-18-5", "quantity": 70.0, "mol_weight": 18, "dap": 0.5, } @pytest.fixture def sample_pif_data(): """Sample PIF data for testing.""" return { "company": "Beauty Corp", "product_name": "Face Cream", "type": "MOISTURIZER", "physical_form": "CREMA", "CNCP": 123456, "production_company": { "prod_company_name": "Manufacturer Inc", "prod_vat": 12345678, "prod_address": "123 Main St, City, Country" }, "ingredients": [ { "inci_name": "WATER", "cas": "7732-18-5", "quantity": 70.0, "dap": 0.5 }, { "inci_name": "GLYCERIN", "cas": "56-81-5", "quantity": 10.0, "dap": 0.5 } ] } @pytest.fixture def sample_echa_substance_response(): """Sample ECHA substance search API response for glycerin.""" return { "items": [{ "substanceIndex": { "rmlId": "100.029.181", "rmlName": "glycerol", "rmlCas": "56-81-5", "rmlEc": "200-289-5" } }] } @pytest.fixture def sample_echa_substance_response_water(): """Sample ECHA substance search API response for water.""" return { "items": [{ "substanceIndex": { "rmlId": "100.028.902", "rmlName": "water", "rmlCas": "7732-18-5", "rmlEc": "231-791-2" } }] } @pytest.fixture def sample_echa_substance_response_niacinamide(): """Sample ECHA substance search API response for niacinamide.""" return { "items": [{ "substanceIndex": { "rmlId": "100.002.530", "rmlName": "nicotinamide", "rmlCas": "98-92-0", "rmlEc": "202-713-4" } }] } @pytest.fixture def sample_echa_dossier_response(): """Sample ECHA dossier list API response.""" return { "items": [{ "assetExternalId": "abc123def456", "rootKey": "key123", "lastUpdatedDate": "2024-01-15T10:30:00Z" }] } @pytest.fixture def sample_echa_index_html_full(): """Sample ECHA index.html with all toxicology sections.""" return """
No toxicology information available
""" # Skip markers def pytest_configure(config): """Configure custom markers.""" config.addinivalue_line( "markers", "unit: mark test as a unit test (fast, no external deps)" ) config.addinivalue_line( "markers", "integration: mark test as integration test (may use real APIs)" ) config.addinivalue_line( "markers", "slow: mark test as slow (skip by default)" ) config.addinivalue_line( "markers", "database: mark test as requiring database" ) def pytest_collection_modifyitems(config, items): """Modify test collection to skip slow/integration tests by default.""" skip_slow = pytest.mark.skip(reason="Slow test (use -m slow to run)") skip_integration = pytest.mark.skip(reason="Integration test (use -m integration to run)") # Only skip if not explicitly requested run_slow = config.getoption("-m") == "slow" run_integration = config.getoption("-m") == "integration" for item in items: if "slow" in item.keywords and not run_slow: item.add_marker(skip_slow) if "integration" in item.keywords and not run_integration: item.add_marker(skip_integration)