job-research/tests/test_cli.py
2026-06-05 12:18:31 +02:00

292 lines
7.6 KiB
Python

from subprocess import run
from textwrap import dedent
from typer.testing import CliRunner
from job_research.cli import app
from job_research.storage import load_yaml
def test_installed_cli_help_exposes_build_profile_subcommand() -> None:
result = run(["uv", "run", "job-research", "--help"], capture_output=True, text=True, check=False)
assert result.returncode == 0
assert "build-profile" in result.stdout
assert "Build candidate-profile.yaml from CV and markdown profile." in result.stdout
def test_installed_cli_subcommand_help_works() -> None:
result = run(["uv", "run", "job-research", "build-profile", "--help"], capture_output=True, text=True, check=False)
assert result.returncode == 0
assert "Usage: job-research build-profile" in result.stdout
def test_build_profile_writes_yaml_from_cv_and_profile(tmp_path) -> None:
cv = tmp_path / "cv.txt"
cv.write_text(
dedent(
"""
Tonio Example
Location: France
Languages: French, English
Skills: Python, SQL, Terraform
Years of experience: 3
Data Engineer at Acme
Education: Master of Science at Example University
"""
).strip(),
encoding="utf-8",
)
profile = tmp_path / "profile.md"
profile.write_text(
dedent(
"""
# Candidate Profile
## Summary
Junior data engineer focused on Python and GCP.
## Target Roles
- Data Engineer
## Strengths
- Python
- SQL
## Skills To Emphasize
- GCP
- BigQuery
## Constraints
- CDI only
- France only
## Notes
- Slight preference for French listings.
- Years of experience feels closer to 4.
"""
).strip(),
encoding="utf-8",
)
out = tmp_path / "candidate-profile.yaml"
result = run(
["uv", "run", "job-research", "build-profile", "--cv", str(cv), "--profile", str(profile), "--out", str(out)],
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0
assert f"candidate profile written to {out}" in result.stdout
assert "Warnings included: 1" in result.stdout
payload = load_yaml(out)
assert payload["name"] == "Tonio Example"
assert payload["summary"] == "Junior data engineer focused on Python and GCP."
assert payload["target_roles"] == ["Data Engineer"]
assert payload["skills"] == ["Python", "SQL", "Terraform", "GCP", "BigQuery"]
assert any(item["field"] == "years_of_experience" for item in payload["warnings"])
def test_build_profile_reports_when_no_warnings_are_included(tmp_path) -> None:
cv = tmp_path / "cv.txt"
cv.write_text(
dedent(
"""
Tonio Example
Location: France
Languages: French, English
Skills: Python, SQL
Data Engineer at Acme
Education: Master of Science at Example University
"""
).strip(),
encoding="utf-8",
)
profile = tmp_path / "profile.md"
profile.write_text(
dedent(
"""
# Candidate Profile
## Summary
Junior data engineer focused on Python and GCP.
## Target Roles
- Data Engineer
## Strengths
- Python
- SQL
## Skills To Emphasize
- GCP
- BigQuery
## Constraints
- CDI only
- France only
## Notes
- Slight preference for French listings.
"""
).strip(),
encoding="utf-8",
)
out = tmp_path / "candidate-profile.yaml"
result = run(
["uv", "run", "job-research", "build-profile", "--cv", str(cv), "--profile", str(profile), "--out", str(out)],
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0
assert f"candidate profile written to {out}" in result.stdout
assert "No warnings included." in result.stdout
def test_build_profile_rejects_empty_cv_text_before_writing(tmp_path) -> None:
cv = tmp_path / "cv.txt"
cv.write_text(" \n", encoding="utf-8")
profile = tmp_path / "profile.md"
profile.write_text(
dedent(
"""
# Candidate Profile
## Summary
Junior data engineer.
## Target Roles
- Data Engineer
## Strengths
- Python
## Skills To Emphasize
- BigQuery
## Constraints
- CDI only
## Notes
- Slight preference for French listings.
"""
).strip(),
encoding="utf-8",
)
out = tmp_path / "candidate-profile.yaml"
result = run(
["uv", "run", "job-research", "build-profile", "--cv", str(cv), "--profile", str(profile), "--out", str(out)],
capture_output=True,
text=True,
check=False,
)
assert result.returncode != 0
assert not out.exists()
assert "No readable text found in CV input" in result.stderr
assert "Traceback" not in result.stderr
def test_build_profile_reports_unreadable_pdf_input_cleanly(tmp_path, monkeypatch) -> None:
cv = tmp_path / "cv.pdf"
cv.write_bytes(b"%PDF-1.4\n")
profile = tmp_path / "profile.md"
profile.write_text(
dedent(
"""
# Candidate Profile
## Summary
Junior data engineer.
## Target Roles
- Data Engineer
## Strengths
- Python
## Skills To Emphasize
- BigQuery
## Constraints
- CDI only
## Notes
- Slight preference for French listings.
"""
).strip(),
encoding="utf-8",
)
out = tmp_path / "candidate-profile.yaml"
def broken_extract_pdf_text(path):
raise ValueError("broken pdf")
monkeypatch.setattr("job_research.cli.extract_pdf_text", broken_extract_pdf_text)
result = CliRunner().invoke(app, ["build-profile", "--cv", str(cv), "--profile", str(profile), "--out", str(out)])
assert result.exit_code == 1
assert not out.exists()
assert "CV input not readable" in result.stderr
assert "broken pdf" in result.stderr
assert "Traceback" not in result.stderr
def test_build_profile_reports_malformed_profile_markdown_cleanly(tmp_path) -> None:
cv = tmp_path / "cv.txt"
cv.write_text(
dedent(
"""
Tonio Example
Location: France
Languages: French, English
Skills: Python
"""
).strip(),
encoding="utf-8",
)
profile = tmp_path / "profile.md"
profile.write_text(
dedent(
"""
# Candidate Profile
## Summary
Junior data engineer.
## Target Roles
Data Engineer
## Strengths
- Python
## Skills To Emphasize
- BigQuery
## Constraints
- CDI only
## Notes
- Slight preference for French listings.
"""
).strip(),
encoding="utf-8",
)
out = tmp_path / "candidate-profile.yaml"
result = CliRunner().invoke(app, ["build-profile", "--cv", str(cv), "--profile", str(profile), "--out", str(out)])
assert result.exit_code == 1
assert not out.exists()
assert "profile markdown invalid" in result.stderr
assert "Traceback" not in result.stderr