""" Unit tests for JSONL Knowledge Graph export and validation. """ import os import tempfile import unittest from src.graph.guideline_kg import GuidelineKnowledgeGraph from src.graph.jsonl_exporter import JSONLKGExporter from src.validation.jsonl_validator import JSONLKGValidator class TestJSONLExportAndValidation(unittest.TestCase): def setUp(self): self.exporter = JSONLKGExporter() self.validator = JSONLKGValidator() def test_export_and_validate_roundtrip(self): kg = GuidelineKnowledgeGraph("RCOG-GTG-45", "Birth After Previous Caesarean Birth", "RCOG") kg.add_guideline_version_node(2, "2015-10") prov = { "source_file": "gtg_45.md", "file_sha256": "abc123hash", "page_number": 2, "verbatim_statement": "Planned VBAC is contraindicated in uterine rupture.", "raw_text": "Planned VBAC is contraindicated in uterine rupture. **D**", "revision_tag": "New 2015", "extractor_models": { "ner": "gliner-snomed-biomed:v2.0", "linker": "sapbert-snomed-loinc-rxnorm:v2.0", }, } rec_id = kg.add_recommendation_node( block_id="REC_0001", edition=2, clinical_question="Contraindications?", statement="Planned VBAC is contraindicated in uterine rupture.", evidence_grade="Grade D", modality="CONTRAINDICATED", section_title="Suitability", valid_from="2015-10", valid_to=None, status="Active", provenance=prov, ) c1 = kg.add_concept_node( concept_id="441097003", preferred_term="Trial of labour after caesarean delivery", vocabulary="SNOMED-CT", category="PROCEDURE", ) c2 = kg.add_concept_node( concept_id="34430009", preferred_term="Rupture of uterus", vocabulary="SNOMED-CT", category="DISORDER", ) kg.link_recommendation_to_concept(rec_id, c1, "CONTRAINDICATES_PROCEDURE", "Planned VBAC") kg.link_recommendation_to_concept(rec_id, c2, "CONTRAINDICATED_IN", "uterine rupture", negated=True) with tempfile.NamedTemporaryFile(suffix=".jsonl", delete=False) as tmp: tmp_path = tmp.name try: triplets = self.exporter.export_from_graph(kg, tmp_path) self.assertGreater(len(triplets), 0) # Validate generated JSONL file report = self.validator.validate_file(tmp_path) self.assertTrue(report.is_valid) self.assertEqual(report.invalid_lines, 0) self.assertEqual(report.provenance_completeness_rate, 100.0) self.assertIn("SNOMED-CT", report.vocabulary_breakdown) self.assertIn("CONTRAINDICATED", report.modality_breakdown) finally: if os.path.exists(tmp_path): os.remove(tmp_path) if __name__ == "__main__": unittest.main()