"""Regression tests for CLI/reporting helper utilities.""" from pathlib import Path import pytest import yaml from sentinel.models import ( CancerRiskAssessment, ContributingFactor, ContributionStrength, DxRecommendation, InitialAssessment, RiskFactor, RiskFactorCategory, ) from sentinel.reporting import generate_excel_report, generate_pdf_report from sentinel.user_input import ( AlcoholConsumption, Anthropometrics, CancerType, Demographics, Ethnicity, FamilyMemberCancer, FamilyRelation, FamilySide, Lifestyle, PersonalMedicalHistory, RelationshipDegree, Sex, SmokingHistory, SmokingStatus, UserInput, ) from sentinel.utils import load_user_file def test_load_user_file_yaml(tmp_path): """Ensure YAML user profiles load into a ``UserInput`` instance. Args: tmp_path: Pytest-managed temporary directory path. """ data = { "demographics": { "age_years": 30, "sex": "male", "anthropometrics": {"height_cm": 175, "weight_kg": 70}, }, "lifestyle": { "smoking": {"status": "never"}, "alcohol_consumption": "none", }, "personal_medical_history": {}, "family_history": [], } path = tmp_path / "user.yaml" path.write_text(yaml.dump(data)) user = load_user_file(str(path)) assert isinstance(user, UserInput) assert user.demographics.age_years == 30 assert user.lifestyle.smoking.status == SmokingStatus.NEVER assert user.symptoms == [] @pytest.mark.parametrize("save_files", [True, False]) def test_generate_reports(tmp_path, save_files): """Generate PDF and Excel reports and assert the outputs exist. Args: tmp_path: Pytest-managed temporary directory path. save_files: Whether to write outputs to repo path or temporary path. """ # 1. Create mock UserInput data with all fields user = UserInput( demographics=Demographics( age_years=45, sex=Sex.FEMALE, ethnicity=Ethnicity.WHITE, anthropometrics=Anthropometrics(height_cm=165, weight_kg=70), ), lifestyle=Lifestyle( smoking=SmokingHistory( status=SmokingStatus.FORMER, pack_years=10, ), alcohol_consumption=AlcoholConsumption.LIGHT, ), personal_medical_history=PersonalMedicalHistory( previous_cancers=[CancerType.MELANOMA], ), family_history=[ FamilyMemberCancer( relation=FamilyRelation.MOTHER, cancer_type=CancerType.BREAST, age_at_diagnosis=50, degree=RelationshipDegree.FIRST, side=FamilySide.MATERNAL, ) ], ) # 2. Create mock InitialAssessment data assessment = InitialAssessment( response="This is a summary response.", thinking="The user is a 45-year-old female with a BRCA2 mutation...", reasoning="1. Assessed breast cancer risk as high due to BRCA2...", overall_summary="This assessment indicates a significant and immediate need...", overall_risk_score=68, identified_risk_factors=[ RiskFactor( description="Positive for BRCA2 genetic mutation", category=RiskFactorCategory.PERSONAL_MEDICAL, ), RiskFactor( description="Personal history of Skin Cancer", category=RiskFactorCategory.PERSONAL_MEDICAL, ), RiskFactor( description="First-degree relative (Mother) with Breast Cancer", category=RiskFactorCategory.FAMILY_HISTORY, ), RiskFactor( description="Age of 45", category=RiskFactorCategory.DEMOGRAPHICS ), RiskFactor( description="Former smoker (10 pack-years)", category=RiskFactorCategory.LIFESTYLE, ), ], llm_risk_interpretations=[ CancerRiskAssessment( cancer_type="Breast Cancer", risk_level=4, explanation="Risk is high due to the combination of a known BRCA2 mutation and a first-degree relative with breast cancer.", recommended_steps=[ "Annual mammogram", "Annual breast MRI", "Consultation with a high-risk breast specialist", ], contributing_factors=[ ContributingFactor( description="Positive for BRCA2 genetic mutation", category=RiskFactorCategory.PERSONAL_MEDICAL, strength=ContributionStrength.MAJOR, ), ContributingFactor( description="First-degree relative (Mother) with Breast Cancer", category=RiskFactorCategory.FAMILY_HISTORY, strength=ContributionStrength.MAJOR, ), ContributingFactor( description="Age of 45", category=RiskFactorCategory.DEMOGRAPHICS, strength=ContributionStrength.MINOR, ), ], ), CancerRiskAssessment( cancer_type="Ovarian Cancer", risk_level=4, explanation="Risk is significantly elevated due to the known BRCA2 mutation.", recommended_steps=[ "Consider risk-reducing surgery", "Transvaginal ultrasound and CA-125 blood test for surveillance", ], contributing_factors=[ ContributingFactor( description="Positive for BRCA2 genetic mutation", category=RiskFactorCategory.PERSONAL_MEDICAL, strength=ContributionStrength.MAJOR, ) ], ), CancerRiskAssessment( cancer_type="Skin Cancer", risk_level=3, explanation="Risk is moderate-to-high due to a personal history of skin cancer, which is a strong predictor of future risk.", recommended_steps=[ "Annual full-body dermatological examination.", "Vigilant use of broad-spectrum sunscreen.", ], contributing_factors=[ ContributingFactor( description="Personal history of Skin Cancer", category=RiskFactorCategory.PERSONAL_MEDICAL, strength=ContributionStrength.MAJOR, ) ], ), CancerRiskAssessment( cancer_type="Colorectal Cancer", risk_level=3, explanation="Risk is moderate as you have reached the standard screening age. Some studies suggest a minor increased risk with BRCA2 mutations.", recommended_steps=[ "Begin regular colonoscopy screenings as per standard guidelines (age 45)." ], contributing_factors=[ ContributingFactor( description="Age of 45", category=RiskFactorCategory.DEMOGRAPHICS, strength=ContributionStrength.MODERATE, ), ContributingFactor( description="Positive for BRCA2 genetic mutation", category=RiskFactorCategory.PERSONAL_MEDICAL, strength=ContributionStrength.MINOR, ), ], ), CancerRiskAssessment( cancer_type="Lung Cancer", risk_level=2, explanation="A history of smoking, even as a former smoker, confers a residual risk for lung cancer, though it is not high enough to warrant screening at this time.", recommended_steps=["Monitor for symptoms like persistent cough."], lifestyle_advice="Continue to avoid smoking.", contributing_factors=[ ContributingFactor( description="Former smoker (10 pack-years)", category=RiskFactorCategory.LIFESTYLE, strength=ContributionStrength.MODERATE, ) ], ), ], dx_recommendations=[ DxRecommendation( test_name="Mammogram", frequency="Annually", rationale="High risk for breast cancer due to BRCA2 and family history.", recommendation_level=5, ), DxRecommendation( test_name="MRI", # Breast MRI frequency="Annually", rationale="Supplemental screening for high-risk individuals with BRCA mutations.", recommendation_level=5, ), DxRecommendation( test_name="Colonoscopy", frequency="Every 5-10 years", rationale="Standard screening age reached; commence screening.", recommendation_level=4, ), ], ) # 3. Define output path if save_files: output_path = Path("outputs") output_path.mkdir(exist_ok=True) else: output_path = tmp_path # 4. Define output filenames pdf_filename = output_path / "report.pdf" excel_filename = output_path / "report.xlsx" # 5. Generate and check PDF report try: generate_pdf_report(assessment, user, str(pdf_filename)) assert pdf_filename.exists() assert pdf_filename.stat().st_size > 0 # Check file is not empty except Exception as e: # The test environment might not have PDF generation dependencies print(f"PDF generation failed, likely due to missing dependencies: {e}") pytest.fail(f"PDF generation failed with an unexpected error: {e}") # 6. Generate and check Excel report generate_excel_report(assessment, user, str(excel_filename)) assert excel_filename.exists() assert excel_filename.stat().st_size > 0