jobhunt-platform/packages/matching/tests/test_keywords.py

152 lines
No EOL
5.5 KiB
Python

"""Tests for keyword extraction and coverage."""
from __future__ import annotations
from matching.keywords import extract_keywords, coverage
class TestExtractKeywords:
def test_basic_extraction(self):
text = "Python developer with Fast API experience and PostgreSQL database skills."
kws = extract_keywords(text)
assert "python" in kws
assert "fastapi" in kws
assert "postgresql" in kws
def test_stopwords_removed(self):
text = "We are looking for a developer with experience in Python."
kws = extract_keywords(text)
assert "we" not in kws
assert "are" not in kws
assert "for" not in kws
assert "a" not in kws
assert "in" not in kws
assert "python" in kws
assert "developer" in kws
def test_swedish_stopwords_removed(self):
text = "Vi letar efter en Python utvecklare med erfarenhet av Docker."
kws = extract_keywords(text)
assert "vi" not in kws
assert "en" not in kws
assert "av" not in kws
assert "python" in kws
assert "docker" in kws
def test_top_n_limit(self):
text = "python python python docker docker docker kubernetes kubernetes kubernetes react react react"
kws = extract_keywords(text, top_n=2)
assert len(kws) == 2
def test_empty_text(self):
assert extract_keywords("") == []
def test_whitespace_only(self):
assert extract_keywords(" ") == []
def test_multiword_fastapi(self):
text = "Experience with fast api framework for building REST APIs."
kws = extract_keywords(text)
assert "fastapi" in kws
def test_multiword_machine_learning(self):
text = "machine learning models for predictive analytics."
kws = extract_keywords(text)
assert "machine-learning" in kws
def test_frequency_ordering(self):
text = "python python python docker docker kubernetes"
kws = extract_keywords(text, top_n=3)
assert kws[0] == "python"
assert kws[1] == "docker"
assert kws[2] == "kubernetes"
def test_deterministic_tie_breaking(self):
"""Ties in frequency should be broken alphabetically."""
text = "docker kubernetes"
kws = extract_keywords(text)
# Both have frequency 1, so alphabetical: docker < kubernetes
assert kws[0] == "docker"
assert kws[1] == "kubernetes"
def test_min_token_length(self):
text = "x y z aa bb cc developer"
kws = extract_keywords(text)
assert "x" not in kws
assert "y" not in kws
assert "z" not in kws
assert "developer" in kws
def test_tech_terms_preserved(self):
text = "Node.js and React Native for mobile development."
kws = extract_keywords(text)
assert "nodejs" in kws
assert "react-native" in kws
class TestCoverage:
def test_full_coverage(self):
cv = "Python developer with Fast API PostgreSQL Docker AWS Kubernetes"
posting = "Python developer with Fast API PostgreSQL Docker AWS Kubernetes"
result = coverage(cv, posting)
assert result["ratio"] == 1.0
assert len(result["missing"]) == 0
def test_partial_coverage(self):
cv = "Python developer with PostgreSQL and Docker experience"
posting = "Python developer with Fast API PostgreSQL Docker AWS Kubernetes React"
result = coverage(cv, posting)
assert 0.0 < result["ratio"] < 1.0
assert "python" in result["matched"]
assert "postgresql" in result["matched"]
assert "docker" in result["matched"]
assert "fastapi" in result["missing"]
assert "kubernetes" in result["missing"]
def test_zero_coverage(self):
cv = "Chef with experience in French cuisine and menu planning"
posting = "Python developer with Fast API PostgreSQL Docker"
result = coverage(cv, posting)
assert result["ratio"] == 0.0
assert len(result["matched"]) == 0
assert len(result["missing"]) > 0
def test_empty_posting(self):
result = coverage("Python developer", "")
assert result == {"matched": [], "missing": [], "ratio": 0.0}
def test_empty_cv(self):
result = coverage("", "Python developer with Docker")
assert result["ratio"] == 0.0
assert len(result["matched"]) == 0
assert len(result["missing"]) > 0
def test_both_empty(self):
result = coverage("", "")
assert result == {"matched": [], "missing": [], "ratio": 0.0}
def test_ratio_calculation(self):
cv = "python docker postgresql"
posting = "python docker postgresql kubernetes"
result = coverage(cv, posting)
# 3 of 4 matched (approx, depends on stopword filtering).
assert result["ratio"] > 0.5
assert result["ratio"] <= 1.0
def test_matched_and_missing_lists(self):
cv = "python docker"
posting = "python docker kubernetes react"
result = coverage(cv, posting)
assert "python" in result["matched"]
assert "docker" in result["matched"]
assert "kubernetes" in result["missing"]
assert "react" in result["missing"]
def test_coverage_returns_dict_keys(self):
result = coverage("python", "python docker")
assert "matched" in result
assert "missing" in result
assert "ratio" in result
assert isinstance(result["matched"], list)
assert isinstance(result["missing"], list)
assert isinstance(result["ratio"], float)