from __future__ import annotations import tempfile import unittest from pathlib import Path from unittest import mock from docforge.cli import _parser, _run from docforge.errors import DocForgeError from docforge.project import Project class DocForgeOnboardingTests(unittest.TestCase): def test_scaffold_honors_disabled_manual_projection_policy(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) / "disabled-render" root.mkdir() arguments = _parser().parse_args( [ "--project-root", str(root), "--manual-render-policy", "disabled", "onboard", "--scaffold", ] ) with mock.patch( "docforge.cli.RenderService.render", side_effect=AssertionError("disabled onboarding must not render"), ): result = _run(arguments) self.assertEqual("skipped", result["render"]["state"]) self.assertFalse((root / ".docforge/rendered/manual.html").exists()) def test_assessment_detects_multiple_languages_without_writing(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) / "polyglot" (root / "src").mkdir(parents=True) (root / "src/main.rs").write_text("fn main() {}\n", encoding="utf-8") (root / "src/App.java").write_text("class App {}\n", encoding="utf-8") (root / "Cargo.toml").write_text("[package]\nname='polyglot'\n", encoding="utf-8") (root / "pom.xml").write_text("\n", encoding="utf-8") (root / "target/generated").mkdir(parents=True) (root / "target/generated/ignored.rs").write_text("", encoding="utf-8") result = assess = _run(_parser().parse_args(["--project-root", str(root), "onboard"])) self.assertEqual("assessment", result["mode"]) self.assertFalse(result["configured"]) self.assertFalse((root / ".docforge").exists()) languages = {item["id"]: item for item in assess["languages"]} self.assertEqual(1, languages["rust"]["source_files"]) self.assertEqual(["Cargo.toml"], languages["rust"]["build_evidence"]) self.assertEqual(1, languages["java"]["source_files"]) self.assertEqual(["pom.xml"], languages["java"]["build_evidence"]) def test_explicit_language_keeps_zero_source_profile_visible(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) result = _run( _parser().parse_args(["--project-root", str(root), "onboard", "--language", "rust"]) ) self.assertEqual( [ { "id": "rust", "title": "Rust", "source_files": 0, "build_evidence": [], "frontend_status": "adapter_required", } ], result["languages"], ) def test_scaffold_builds_and_renders_a_valid_generic_manual(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) / "ski-game" (root / "src").mkdir(parents=True) (root / "src/lib.rs").write_text("pub fn carve() {}\n", encoding="utf-8") result = _run( _parser().parse_args( [ "--project-root", str(root), "onboard", "--language", "rust", "--scaffold", "--project-id", "awesome-ski-game", "--title", "Awesome Ski Game", ] ) ) self.assertEqual("scaffold", result["mode"]) self.assertEqual("adapter_required", result["source_graph_status"]) self.assertEqual(1, result["build"]["node_count"]) self.assertTrue((root / ".docforge/rendered/manual.html").is_file()) snapshot = Project.open(root).load() self.assertEqual("awesome-ski-game", snapshot.descriptor.project_id) self.assertEqual("architecture.overview", snapshot.nodes[0].node_id) self.assertIn("Rust", snapshot.nodes[0].content) def test_scaffold_refuses_existing_files_and_unsafe_paths(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) (root / ".docforge").mkdir() (root / ".docforge/project.toml").write_text("existing\n", encoding="utf-8") arguments = _parser().parse_args(["--project-root", str(root), "onboard", "--scaffold"]) with self.assertRaisesRegex(DocForgeError, "replace existing"): _run(arguments) self.assertEqual( "existing\n", (root / ".docforge/project.toml").read_text(encoding="utf-8"), ) clean = Path(directory) / "clean" clean.mkdir() escaped = _parser().parse_args( [ "--project-root", str(clean), "onboard", "--scaffold", "--content-root", "../outside", ] ) with self.assertRaisesRegex(DocForgeError, "inside the project root"): _run(escaped) if __name__ == "__main__": unittest.main()