import pytest from app.modules.design.domain.entities import ( Capability, Entity, Module, TraceabilityLink, ) from app.modules.design.domain.services import DesignValidationService from app.modules.design.domain.value_objects import FileStatus class TestFileStatusDetermination: def test_empty_content_is_missing(self): assert DesignValidationService.determine_file_status("", "test.csv") == FileStatus.MISSING def test_csv_header_only_is_sparse(self): assert DesignValidationService.determine_file_status("id,name\n", "test.csv") == FileStatus.SPARSE def test_csv_with_data_is_ok(self): content = "id,name\n1,foo\n2,bar\n" assert DesignValidationService.determine_file_status(content, "test.csv") == FileStatus.OK def test_md_too_short_is_sparse(self): assert DesignValidationService.determine_file_status("# Title\n\nShort.\n", "test.md") == FileStatus.SPARSE def test_template_residue_detected(self): content = "id,name\nTODO,\nreal,data\n" assert DesignValidationService.determine_file_status(content, "test.csv") == FileStatus.TEMPLATE_RESIDUE def test_placeholder_heavy(self): content = "id,name,desc\nTODO,TODO,TODO\nTODO,TODO,TODO\n" assert DesignValidationService.determine_file_status(content, "test.csv") == FileStatus.PLACEHOLDER_HEAVY def test_ok_md_file(self): content = "---\ndoc_id: DOC-01\ntitle: Test\n---\n\n# Title\n\nThis is a real document with enough content.\nLine 4.\nLine 5.\nLine 6.\n" assert DesignValidationService.determine_file_status(content, "test.md") == FileStatus.OK class TestConstraintValidation: def _make_cap(self, cap_id: str) -> Capability: return Capability(cap_id, "n", "d", "must", "MVP", []) def _make_mod(self, mod_id: str) -> Module: return Module(mod_id, "n", "backend", "d", "MVP", [], []) def _make_ent(self, ent_id: str, owner: str) -> Entity: return Entity(ent_id, "n", "d", owner, "d", "MVP", "f.csv") def _make_link(self, trace_id: str, cap: str, mod: str, ents: list[str]) -> TraceabilityLink: return TraceabilityLink(trace_id, cap, mod, ents, [], "") def test_capability_without_module_link_is_violation(self): caps = [self._make_cap("CAP-01")] links = [] violations = DesignValidationService.check_capability_module_linkage(caps, links) assert len(violations) == 1 def test_entity_without_owner_is_violation(self): entities = [self._make_ent("ENT-01", "")] violations = DesignValidationService.check_entity_owner(entities) assert len(violations) == 1 def test_valid_traceability_passes(self): caps = [self._make_cap("CAP-01")] mods = [self._make_mod("MOD-01")] ents = [self._make_ent("ENT-01", "MOD-01")] links = [self._make_link("TR-01", "CAP-01", "MOD-01", ["ENT-01"])] violations = DesignValidationService.check_traceability_references(links, caps, mods, ents) assert len(violations) == 0 def test_broken_traceability_reference_is_violation(self): caps = [self._make_cap("CAP-01")] mods = [self._make_mod("MOD-01")] ents = [self._make_ent("ENT-01", "MOD-01")] links = [self._make_link("TR-01", "CAP-MISSING", "MOD-01", ["ENT-01"])] violations = DesignValidationService.check_traceability_references(links, caps, mods, ents) assert len(violations) >= 1