Spaces:
Running
Running
Download tests/test_structured_placement.py from saitejatirunagari/JAA-ATS-Tool: direct link, hf CLI and curl.
- Browser
- Download file 6.15 kB
-
https://huggingface.co/spaces/saitejatirunagari/JAA-ATS-Tool/resolve/428497b907b395f24268a2d573a3d9e546730d9d/tests/test_structured_placement.py
- Command line
-
hf download hf://spaces/saitejatirunagari/JAA-ATS-Tool@428497b907b395f24268a2d573a3d9e546730d9d/tests/test_structured_placement.py
-
curl -L -o test_structured_placement.py https://huggingface.co/spaces/saitejatirunagari/JAA-ATS-Tool/resolve/428497b907b395f24268a2d573a3d9e546730d9d/tests/test_structured_placement.py
6.15 kB
| """Phase 9 (R22): structured keyword placement into the hardcoded resume. | |
| RETIRED — this validated the mechanical keyword-cycling injector (25-30 terms | |
| crammed per bullet). That behaviour was removed from every V1 résumé path in the | |
| evidence-gating correction: V1 now preserves the résumé and inserts NOTHING | |
| without résumé evidence (see tests/test_ats_safety.py). The injector functions | |
| still exist only as internal V2 fallbacks, so these count-based assertions no | |
| longer describe supported behaviour. Skipped rather than deleted to preserve | |
| history and the rationale. | |
| """ | |
| import os | |
| import re | |
| import pytest | |
| pytestmark = pytest.mark.skip( | |
| reason="mechanical keyword-cycling injection retired; V1 is now evidence-gated " | |
| "(see test_ats_safety.py). No keyword is inserted without résumé evidence." | |
| ) | |
| from src.latex_resume import inject_keywords, place_keywords_structured | |
| def _resume() -> str: | |
| try: | |
| from src.default_resume import DEFAULT_RESUME_LATEX | |
| if DEFAULT_RESUME_LATEX.strip(): | |
| return DEFAULT_RESUME_LATEX | |
| except Exception: | |
| pass | |
| p = os.path.join( | |
| ".planning", "phases", "09-hardcoded-resume-keyword-placement", | |
| "resume-source.tex", | |
| ) | |
| if os.path.exists(p): | |
| with open(p, encoding="utf-8") as f: | |
| txt = f.read() | |
| if txt.strip(): | |
| return txt | |
| pytest.skip("resume source not available") | |
| KWS = [f"kw{i:03d}" for i in range(120)] | |
| def _items_in(block: str): | |
| """Return the list of tagged-item term-strings found in `block`.""" | |
| return re.findall(r"\\resumeItem\{([^\n]*?)\}\s*% ats-item", block) | |
| def test_summary_slot_15_to_20(): | |
| out, _ = inject_keywords(_resume(), KWS) | |
| m = re.search(r"Additional areas: (.+?)\.\s*% ===== end", out, re.S) | |
| assert m, "summary injection block missing" | |
| n = len([t for t in m.group(1).split(",") if t.strip()]) | |
| assert 15 <= n <= 20, f"summary has {n} terms (want 15-20)" | |
| def test_byjus_psm_25_to_30(): | |
| out, _ = inject_keywords(_resume(), KWS) | |
| # The tagged item inside the Asst PSM block. | |
| seg = out[out.find("Asst. Product Success Manager"):] | |
| seg = seg[: seg.find("\\resumeItemListEnd") + 20] | |
| items = _items_in(seg) | |
| assert items, "no tagged item in PSM block" | |
| n = len([t for t in items[-1].split(",") if t.strip()]) | |
| assert 25 <= n <= 30, f"PSM has {n} terms (want 25-30)" | |
| def test_byjus_ps_25_to_30(): | |
| out, _ = inject_keywords(_resume(), KWS) | |
| seg = out[out.find("Product Specialist -- User Experience"):] | |
| seg = seg[: seg.find("\\resumeItemListEnd") + 20] | |
| items = _items_in(seg) | |
| assert items, "no tagged item in Product Specialist block" | |
| n = len([t for t in items[-1].split(",") if t.strip()]) | |
| assert 25 <= n <= 30, f"PS has {n} terms (want 25-30)" | |
| def test_ml_edutech_8_to_12(): | |
| out, _ = inject_keywords(_resume(), KWS) | |
| seg = out[out.find("ML Edutech"):] | |
| seg = seg[: seg.find("\\resumeItemListEnd") + 20] | |
| items = _items_in(seg) | |
| assert items, "no tagged item in ML Edutech block" | |
| n = len([t for t in items[-1].split(",") if t.strip()]) | |
| assert 8 <= n <= 12, f"ML Edutech has {n} terms (want 8-12)" | |
| def test_skills_other_row_present(): | |
| out, _ = inject_keywords(_resume(), KWS) | |
| m = re.search(r"\\textbf\{Other\}\{: (.+?)\}\s*% ats-skills-other", out) | |
| assert m, "Skills Other row missing" | |
| n = len([t for t in m.group(1).split(",") if t.strip()]) | |
| assert n >= 15, f"Skills Other has {n} terms (want >=15 once filled)" | |
| def test_anchor_before_list_end(): | |
| out, _ = inject_keywords(_resume(), KWS) | |
| assert re.search(r"% ats-item[^\n]*\n\s*\\resumeItemListEnd", out), \ | |
| "tagged item not anchored immediately before a \\resumeItemListEnd" | |
| def test_append_only_original_bullets_intact(): | |
| src = _resume() | |
| out, _ = inject_keywords(src, KWS) | |
| for original in [ | |
| "Increased user retention by 8", | |
| "Managed", | |
| "Launched an EdTech app portfolio", | |
| "Led end-to-end revamp of the", | |
| ]: | |
| assert original in out, f"original bullet text lost: {original!r}" | |
| def test_idempotent(): | |
| src = _resume() | |
| o1, _ = inject_keywords(src, KWS) | |
| o2, _ = inject_keywords(o1, KWS) | |
| assert o1 == o2, "placement is not idempotent (injected lines stacked)" | |
| def test_dedupe_skips_present_terms(): | |
| # A term already in the resume must not be re-added. | |
| out, placed = place_keywords_structured(_resume(), ["Roadmap Planning", "kwX1", "kwX2"]) | |
| assert "Roadmap Planning" not in placed | |
| assert "kwX1" in placed | |
| def test_tectonic_asset_matches_sanitizer(): | |
| """assets/default_resume.tectonic.tex (compiled in the Docker warmup) must equal | |
| _sanitize_for_tectonic(default) so the warmed packages match the runtime compile.""" | |
| p = os.path.join("assets", "default_resume.tectonic.tex") | |
| if not os.path.exists(p): | |
| pytest.skip("assets/default_resume.tectonic.tex not present") | |
| from src.default_resume import DEFAULT_RESUME_LATEX | |
| from src.latex_resume import _sanitize_for_tectonic | |
| with open(p, encoding="utf-8") as f: | |
| asset = f.read() | |
| assert asset.strip() == _sanitize_for_tectonic(DEFAULT_RESUME_LATEX).strip(), \ | |
| "assets/default_resume.tectonic.tex drifted from _sanitize_for_tectonic(default)" | |
| # And the sanitized asset must NOT contain the crash sources. | |
| assert "fontawesome5" not in asset and "{FiraMono}" not in asset | |
| assert "\\faPhone" not in asset and "\\faRupeeSign" not in asset | |
| def test_assets_tex_matches_python_source(): | |
| """assets/default_resume.tex (used for the Docker Tectonic warmup) must stay | |
| byte-identical to the Python default so the warmed packages match what users | |
| actually compile.""" | |
| p = os.path.join("assets", "default_resume.tex") | |
| if not os.path.exists(p): | |
| pytest.skip("assets/default_resume.tex not present") | |
| from src.default_resume import DEFAULT_RESUME_LATEX | |
| with open(p, encoding="utf-8") as f: | |
| asset = f.read() | |
| assert asset.strip() == DEFAULT_RESUME_LATEX.strip(), \ | |
| "assets/default_resume.tex drifted from src/default_resume.py" | |