95 lines
4.4 KiB
Python
95 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from claridoc.lint import lint_document
|
|
from claridoc.models import ProviderSpec, Severity, SourcePack
|
|
from claridoc.prompts import drafting_prompt
|
|
from claridoc.providers.base import ProviderRequest
|
|
from claridoc.providers.mock import MockProvider
|
|
from claridoc.structures import create_outline
|
|
from tests.helpers import make_brief, make_sources
|
|
|
|
|
|
class LintTests(unittest.TestCase):
|
|
def test_mock_document_meets_structural_gate(self) -> None:
|
|
brief = make_brief()
|
|
sources = make_sources()
|
|
outline = create_outline(brief, sources)
|
|
provider = MockProvider(ProviderSpec(provider="mock"))
|
|
response = provider.generate(ProviderRequest("draft", drafting_prompt(brief, outline, sources), Path.cwd()))
|
|
report = lint_document(response.text, brief, outline, sources)
|
|
material = [issue for issue in report.issues if issue.severity in {Severity.BLOCKER, Severity.ERROR}]
|
|
self.assertEqual(material, [])
|
|
self.assertGreaterEqual(report.score, 75)
|
|
|
|
def test_unclosed_fence_and_destructive_command_are_blockers(self) -> None:
|
|
brief = make_brief()
|
|
sources = make_sources()
|
|
outline = create_outline(brief, sources)
|
|
text = "# Wrong\n\n```bash\nrm -rf /tmp/example\n"
|
|
report = lint_document(text, brief, outline, sources)
|
|
codes = {issue.code for issue in report.issues if issue.severity == Severity.BLOCKER}
|
|
self.assertIn("MD001", codes)
|
|
self.assertIn("SAFE001", codes)
|
|
|
|
def test_unknown_source_marker_is_error(self) -> None:
|
|
brief = make_brief()
|
|
sources = make_sources()
|
|
outline = create_outline(brief, sources)
|
|
provider = MockProvider(ProviderSpec(provider="mock"))
|
|
text = provider.generate(ProviderRequest("draft", drafting_prompt(brief, outline, sources), Path.cwd())).text
|
|
report = lint_document(text.replace("[S1]", "[S404]"), brief, outline, sources)
|
|
self.assertIn("EVD001", {issue.code for issue in report.issues})
|
|
|
|
def test_non_s_prefixed_source_id_is_recognized(self) -> None:
|
|
brief = make_brief()
|
|
sources = SourcePack.from_dict({
|
|
"sources": [{
|
|
"id": "RFC9110",
|
|
"title": "HTTP Semantics",
|
|
"url": "https://example.com/rfc9110",
|
|
"facts": ["The example fact is bounded."],
|
|
}]
|
|
})
|
|
outline = create_outline(brief, sources)
|
|
provider = MockProvider(ProviderSpec(provider="mock"))
|
|
text = provider.generate(ProviderRequest("draft", drafting_prompt(brief, outline, sources), Path.cwd())).text
|
|
report = lint_document(text, brief, outline, sources)
|
|
codes = {issue.code for issue in report.issues}
|
|
self.assertNotIn("EVD001", codes)
|
|
self.assertNotIn("EVD003", codes)
|
|
|
|
def test_required_h2_must_appear_exactly_once(self) -> None:
|
|
brief = make_brief()
|
|
sources = make_sources()
|
|
outline = create_outline(brief, sources)
|
|
provider = MockProvider(ProviderSpec(provider="mock"))
|
|
text = provider.generate(ProviderRequest("draft", drafting_prompt(brief, outline, sources), Path.cwd())).text
|
|
text += f"\n## {outline.sections[0].title}\n\nDuplicate section.\n"
|
|
report = lint_document(text, brief, outline, sources)
|
|
self.assertIn("STR009", {issue.code for issue in report.issues if issue.severity == Severity.ERROR})
|
|
|
|
def test_destructive_command_requires_all_safety_controls(self) -> None:
|
|
brief = make_brief()
|
|
sources = make_sources()
|
|
outline = create_outline(brief, sources)
|
|
warning_only = "# A precise technical document\n\nWarning: this is destructive.\n\n```bash\nrm -rf /tmp/example\n```\n"
|
|
report = lint_document(warning_only, brief, outline, sources)
|
|
self.assertIn("SAFE001", {issue.code for issue in report.issues})
|
|
|
|
controlled = (
|
|
"# A precise technical document\n\n"
|
|
"Warning: this removes the test directory. Create a backup checkpoint first. "
|
|
"Expected result: the directory is absent; verify with a read-only listing. "
|
|
"Rollback by restoring the backup.\n\n"
|
|
"```bash\nrm -rf /tmp/example\n```\n"
|
|
)
|
|
controlled_report = lint_document(controlled, brief, outline, sources)
|
|
self.assertNotIn("SAFE001", {issue.code for issue in controlled_report.issues})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|