115 lines
4.8 KiB
Python
115 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from docforge.cli import _parser, _run
|
|
from docforge.errors import DocForgeError
|
|
from docforge.project import Project
|
|
|
|
|
|
class DocForgeOnboardingTests(unittest.TestCase):
|
|
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("<project/>\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()
|