Files
resume-haness/tests/test_cli.py
T

223 lines
6.9 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
import pytest
from resume_harness.cli import main
from resume_harness.io import InputError, load_mapping
ROOT = Path(__file__).resolve().parents[1]
def test_validate_examples_without_exposing_contact(capsys: pytest.CaptureFixture[str]) -> None:
exit_code = main(
[
"validate",
"--candidate",
str(ROOT / "examples/candidate.sample.yaml"),
"--job",
str(ROOT / "examples/job.sample.yaml"),
"--config",
str(ROOT / "examples/config.sample.yaml"),
]
)
captured = capsys.readouterr()
payload = json.loads(captured.out)
assert exit_code == 0
assert payload["status"] == "valid"
assert payload["evidence_count"] == 8
assert "haneul.kim@example.com" not in captured.out
assert "010-1234-5678" not in captured.out
def test_schema_command_emits_json_schema(capsys: pytest.CaptureFixture[str]) -> None:
assert main(["schema", "candidate"]) == 0
payload = json.loads(capsys.readouterr().out)
assert payload["title"] == "CandidateProfile"
def test_render_emits_only_quality_gated_markdown(
capsys: pytest.CaptureFixture[str],
) -> None:
exit_code = main(
[
"render",
"--candidate",
str(ROOT / "examples/candidate.sample.yaml"),
"--job",
str(ROOT / "examples/job.sample.yaml"),
"--draft",
str(ROOT / "examples/draft.sample.yaml"),
"--config",
str(ROOT / "examples/config.sample.yaml"),
"--analysis",
str(ROOT / "examples/job-analysis.sample.yaml"),
"--evidence-map",
str(ROOT / "examples/evidence-map.sample.yaml"),
"--content-plan",
str(ROOT / "examples/content-plan.sample.yaml"),
"--quality-report",
str(ROOT / "examples/quality-report.sample.yaml"),
]
)
output = capsys.readouterr().out
assert exit_code == 0
assert output.startswith("# 김하늘\n")
assert "## 경력" in output
assert "근거 ID" not in output
def test_render_rejects_stale_quality_report_after_draft_changes(
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
) -> None:
draft = load_mapping(ROOT / "examples/draft.sample.yaml")
draft["sections"][0]["claims"][0]["text"] += " 변경"
changed_draft = tmp_path / "changed-draft.json"
changed_draft.write_text(
json.dumps(
draft,
ensure_ascii=False,
default=lambda value: value.isoformat(),
),
encoding="utf-8",
)
exit_code = main(
[
"render",
"--candidate",
str(ROOT / "examples/candidate.sample.yaml"),
"--job",
str(ROOT / "examples/job.sample.yaml"),
"--draft",
str(changed_draft),
"--config",
str(ROOT / "examples/config.sample.yaml"),
"--analysis",
str(ROOT / "examples/job-analysis.sample.yaml"),
"--evidence-map",
str(ROOT / "examples/evidence-map.sample.yaml"),
"--content-plan",
str(ROOT / "examples/content-plan.sample.yaml"),
"--quality-report",
str(ROOT / "examples/quality-report.sample.yaml"),
]
)
captured = capsys.readouterr()
assert exit_code == 2
assert "현재 초안 내용과 일치하지 않습니다" in captured.err
assert captured.out == ""
def test_render_rejects_quality_report_when_analysis_context_changes(
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
) -> None:
analysis = load_mapping(ROOT / "examples/job-analysis.sample.yaml")
analysis["summary"] = "내용은 같아 보여도 다른 평가 컨텍스트"
changed_analysis = tmp_path / "changed-analysis.json"
# YAML timestamps are loaded as datetime objects; serialise them exactly as
# the CLI's JSON input contract expects.
changed_analysis.write_text(
json.dumps(
analysis,
ensure_ascii=False,
default=lambda value: value.isoformat(),
),
encoding="utf-8",
)
exit_code = main(
[
"render",
"--candidate",
str(ROOT / "examples/candidate.sample.yaml"),
"--job",
str(ROOT / "examples/job.sample.yaml"),
"--draft",
str(ROOT / "examples/draft.sample.yaml"),
"--config",
str(ROOT / "examples/config.sample.yaml"),
"--analysis",
str(changed_analysis),
"--evidence-map",
str(ROOT / "examples/evidence-map.sample.yaml"),
"--content-plan",
str(ROOT / "examples/content-plan.sample.yaml"),
"--quality-report",
str(ROOT / "examples/quality-report.sample.yaml"),
]
)
captured = capsys.readouterr()
assert exit_code == 2
assert "평가 컨텍스트와 일치하지 않습니다" in captured.err
assert captured.out == ""
def test_render_rejects_quality_report_when_candidate_context_changes(
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
) -> None:
candidate = load_mapping(ROOT / "examples/candidate.sample.yaml")
candidate["headline"] = "평가 이후에 변경된 프로필 정보"
changed_candidate = tmp_path / "changed-candidate.json"
changed_candidate.write_text(
json.dumps(
candidate,
ensure_ascii=False,
default=lambda value: value.isoformat(),
),
encoding="utf-8",
)
exit_code = main(
[
"render",
"--candidate",
str(changed_candidate),
"--job",
str(ROOT / "examples/job.sample.yaml"),
"--draft",
str(ROOT / "examples/draft.sample.yaml"),
"--config",
str(ROOT / "examples/config.sample.yaml"),
"--analysis",
str(ROOT / "examples/job-analysis.sample.yaml"),
"--evidence-map",
str(ROOT / "examples/evidence-map.sample.yaml"),
"--content-plan",
str(ROOT / "examples/content-plan.sample.yaml"),
"--quality-report",
str(ROOT / "examples/quality-report.sample.yaml"),
]
)
captured = capsys.readouterr()
assert exit_code == 2
assert "평가 컨텍스트와 일치하지 않습니다" in captured.err
assert captured.out == ""
def test_load_mapping_rejects_non_mapping(tmp_path: Path) -> None:
path = tmp_path / "input.yaml"
path.write_text("- item\n", encoding="utf-8")
with pytest.raises(InputError, match="mapping"):
load_mapping(path)
def test_load_mapping_rejects_unknown_extension(tmp_path: Path) -> None:
path = tmp_path / "input.txt"
path.write_text("value: 1\n", encoding="utf-8")
with pytest.raises(InputError, match="지원 형식"):
load_mapping(path)