Files
srbhr--resume-matcher/apps/backend/tests/unit/test_verify_diffs.py
T
wehub-resource-sync 5bdf4cc89a
Publish Docker Image / publish (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:36 +08:00

224 lines
11 KiB
Python

"""Unit tests for verify_diff_result() — local quality checks."""
import copy
import pytest
from app.schemas.models import ResumeChange
from app.services.improver import verify_diff_result
class TestVerifyNoWarnings:
"""Tests that pass cleanly with no warnings."""
def test_clean_result_no_warnings(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["summary"] = "Updated summary."
applied = [
ResumeChange(
path="summary",
action="replace",
original=sample_resume["summary"],
value="Updated summary.",
reason="test",
)
]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert len(warnings) == 0
class TestVerifyEmptyChanges:
"""Check 1: No changes applied."""
def test_warns_on_empty_applied_changes(self, sample_resume, sample_job_keywords):
warnings = verify_diff_result(sample_resume, sample_resume, [], sample_job_keywords)
assert len(warnings) == 1
assert "no changes" in warnings[0].lower()
def test_returns_early_on_empty(self, sample_resume, sample_job_keywords):
"""When no changes applied, skip other checks."""
warnings = verify_diff_result(sample_resume, sample_resume, [], sample_job_keywords)
# Should only have the "no changes" warning, not section count etc.
assert len(warnings) == 1
class TestVerifySectionCounts:
"""Check 2: Section counts preserved."""
def test_warns_on_dropped_work_experience(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["workExperience"] = result["workExperience"][:1] # Drop one
applied = [ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("work experience" in w.lower() for w in warnings)
def test_warns_on_dropped_education(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["education"] = []
applied = [ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("education" in w.lower() for w in warnings)
def test_warns_on_dropped_projects(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["personalProjects"] = []
applied = [ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("project" in w.lower() for w in warnings)
def test_no_warning_when_counts_match(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["summary"] = "Changed."
applied = [ResumeChange(path="summary", action="replace", original="x", value="Changed.", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
section_warnings = [w for w in warnings if "section count" in w.lower()]
assert len(section_warnings) == 0
class TestVerifyIdentityFields:
"""Check 3: Identity fields unchanged."""
def test_warns_on_company_change(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["workExperience"][0]["company"] = "Different Corp"
applied = [ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("company" in w.lower() or "identity" in w.lower() for w in warnings)
def test_warns_on_title_change(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["workExperience"][0]["title"] = "VP of Engineering"
applied = [ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("title" in w.lower() or "identity" in w.lower() for w in warnings)
def test_warns_on_institution_change(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
result["education"][0]["institution"] = "Stanford"
applied = [ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("institution" in w.lower() or "identity" in w.lower() for w in warnings)
class TestVerifyWordCount:
"""Check 4: Word count ratio."""
def test_warns_on_word_count_explosion(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
# Make descriptions very long
long_text = "word " * 200
result["workExperience"][0]["description"] = [long_text] * 5
result["workExperience"][1]["description"] = [long_text] * 5
applied = [ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("word count" in w.lower() for w in warnings)
def test_no_warning_on_normal_growth(self, sample_resume, sample_job_keywords):
result = copy.deepcopy(sample_resume)
# Add one bullet — modest growth
result["workExperience"][0]["description"].append("One extra bullet point here")
applied = [
ResumeChange(
path="workExperience[0].description",
action="append",
original=None,
value="One extra bullet point here",
reason="z",
)
]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
word_warnings = [w for w in warnings if "word count" in w.lower()]
assert len(word_warnings) == 0
class TestVerifyInventedMetrics:
"""Check 5: Invented metrics detection."""
def test_warns_on_invented_percentage(self, sample_resume, sample_job_keywords):
applied = [
ResumeChange(
path="workExperience[0].description[0]",
action="replace",
original="Built REST APIs",
value="Built REST APIs improving throughput by 40%",
reason="Added metric",
)
]
result = copy.deepcopy(sample_resume)
result["workExperience"][0]["description"][0] = "Built REST APIs improving throughput by 40%"
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("metric" in w.lower() or "40%" in w for w in warnings)
def test_no_warning_on_preserved_metric(self, sample_resume, sample_job_keywords):
"""If the original already had the metric, no warning."""
applied = [
ResumeChange(
path="workExperience[0].description[0]",
action="replace",
original="Built REST APIs serving 50K requests/day using Python and FastAPI",
value="Designed REST APIs serving 50K requests/day with Python and FastAPI",
reason="Rephrased",
)
]
result = copy.deepcopy(sample_resume)
result["workExperience"][0]["description"][0] = applied[0].value
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
metric_warnings = [w for w in warnings if "metric" in w.lower()]
assert len(metric_warnings) == 0
def test_warns_on_invented_dollar_amount(self, sample_resume, sample_job_keywords):
applied = [
ResumeChange(
path="workExperience[1].description[0]",
action="replace",
original="Developed payment processing system handling $2M monthly",
value="Developed payment processing system handling $5M monthly",
reason="Inflated",
)
]
result = copy.deepcopy(sample_resume)
result["workExperience"][1]["description"][0] = applied[0].value
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
assert any("$5M" in w or "metric" in w.lower() for w in warnings)
class TestVerifyMultipleWarnings:
"""Edge case: multiple warnings from a single verification run."""
def test_multiple_warnings_all_reported(self, sample_resume, sample_job_keywords):
"""A result with section count drift AND identity change should produce both warnings."""
result = copy.deepcopy(sample_resume)
# Trigger section count warning: drop a work experience entry
result["workExperience"] = result["workExperience"][:1]
# Trigger identity field warning: change company name on remaining entry
result["workExperience"][0]["company"] = "Different Corp"
applied = [
ResumeChange(path="summary", action="replace", original="x", value="y", reason="z")
]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
section_warnings = [w for w in warnings if "section count" in w.lower() or "work experience" in w.lower()]
identity_warnings = [w for w in warnings if "identity" in w.lower() or "company" in w.lower()]
assert len(section_warnings) >= 1
assert len(identity_warnings) >= 1
assert len(warnings) >= 2
def test_metric_warning_plus_word_count_warning(self, sample_resume, sample_job_keywords):
"""Invented metric and word count explosion in the same result."""
result = copy.deepcopy(sample_resume)
long_text = "Improved revenue by 99% " + ("extra words " * 200)
result["workExperience"][0]["description"] = [long_text] * 5
result["workExperience"][1]["description"] = [long_text] * 5
applied = [
ResumeChange(
path="workExperience[0].description[0]",
action="replace",
original="Built REST APIs serving 50K requests/day using Python and FastAPI",
value=long_text,
reason="over-elaborate",
)
]
warnings = verify_diff_result(sample_resume, result, applied, sample_job_keywords)
has_metric = any("metric" in w.lower() or "99%" in w for w in warnings)
has_word_count = any("word count" in w.lower() for w in warnings)
assert has_metric
assert has_word_count