#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys from pathlib import Path import pytest def _ensure_scripts_on_path() -> None: scripts_dir = Path(__file__).resolve().parents[2] if str(scripts_dir) not in sys.path: sys.path.insert(0, str(scripts_dir)) def _load_noma_module(): _ensure_scripts_on_path() import data_modules.noma as noma_module return noma_module def test_init_does_not_resolve_existing_project_root(monkeypatch): module = _load_noma_module() called = {} def _fake_run_script(script_name, argv): called["script_name"] = script_name called["argv"] = list(argv) return 0 def _fail_resolve(_explicit_project_root=None): raise AssertionError("init 子命令不应触发 project_root 解析") monkeypatch.setenv("WEBNOVEL_PROJECT_ROOT", r"D:\invalid\root") monkeypatch.setattr(module, "_run_script", _fake_run_script) monkeypatch.setattr(module, "_resolve_root", _fail_resolve) monkeypatch.setattr(sys, "argv", ["noma", "init", "proj-dir", "测试书", "修仙"]) with pytest.raises(SystemExit) as exc: module.main() assert int(exc.value.code or 0) == 0 assert called["script_name"] == "init_project.py" assert called["argv"] == ["proj-dir", "测试书", "修仙"] def test_extract_context_forwards_with_resolved_project_root(monkeypatch, tmp_path): module = _load_noma_module() book_root = (tmp_path / "book").resolve() called = {} def _fake_resolve(explicit_project_root=None): return book_root def _fake_run_script(script_name, argv): called["script_name"] = script_name called["argv"] = list(argv) return 0 monkeypatch.setattr(module, "_resolve_root", _fake_resolve) monkeypatch.setattr(module, "_run_script", _fake_run_script) monkeypatch.setattr( sys, "argv", [ "noma", "--project-root", str(tmp_path), "extract-context", "--chapter", "12", "--format", "json", ], ) with pytest.raises(SystemExit) as exc: module.main() assert int(exc.value.code or 0) == 0 assert called["script_name"] == "extract_chapter_context.py" assert called["argv"] == [ "--project-root", str(book_root), "--chapter", "12", "--format", "json", ] def test_preflight_succeeds_for_valid_project_root(monkeypatch, tmp_path, capsys): module = _load_noma_module() project_root = tmp_path / "book" (project_root / ".noma").mkdir(parents=True, exist_ok=True) (project_root / ".noma" / "state.json").write_text("{}", encoding="utf-8") monkeypatch.setattr(sys, "argv", ["noma", "--project-root", str(project_root), "preflight"]) with pytest.raises(SystemExit) as exc: module.main() captured = capsys.readouterr() assert int(exc.value.code or 0) == 0 assert "OK project_root" in captured.out assert str(project_root.resolve()) in captured.out def test_preflight_fails_when_required_scripts_are_missing(monkeypatch, tmp_path, capsys): module = _load_noma_module() project_root = tmp_path / "book" (project_root / ".noma").mkdir(parents=True, exist_ok=True) (project_root / ".noma" / "state.json").write_text("{}", encoding="utf-8") fake_scripts_dir = tmp_path / "fake-scripts" fake_scripts_dir.mkdir(parents=True, exist_ok=True) monkeypatch.setattr(module, "_scripts_dir", lambda: fake_scripts_dir) monkeypatch.setattr(sys, "argv", ["noma", "--project-root", str(project_root), "preflight", "--format", "json"]) with pytest.raises(SystemExit) as exc: module.main() captured = capsys.readouterr() assert int(exc.value.code or 0) == 1 assert '"ok": false' in captured.out assert '"name": "entry_script"' in captured.out def test_quality_trend_report_writes_to_book_root_when_input_is_workspace_root(tmp_path, monkeypatch): _ensure_scripts_on_path() import quality_trend_report as quality_trend_report_module workspace_root = (tmp_path / "workspace").resolve() book_root = (workspace_root / "凡人资本论").resolve() (workspace_root / ".claude").mkdir(parents=True, exist_ok=True) (workspace_root / ".claude" / ".noma-current-project").write_text(str(book_root), encoding="utf-8") (book_root / ".noma").mkdir(parents=True, exist_ok=True) (book_root / ".noma" / "state.json").write_text("{}", encoding="utf-8") output_path = workspace_root / "report.md" monkeypatch.setattr( sys, "argv", [ "quality_trend_report", "--project-root", str(workspace_root), "--limit", "1", "--output", str(output_path), ], ) quality_trend_report_module.main() assert output_path.is_file() assert (book_root / ".noma" / "index.db").is_file() assert not (workspace_root / ".noma" / "index.db").exists()