Files
bin/projekt-matching/tests/test_rules.py

97 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import datetime as dt
from projektmatch import rules
TODAY = dt.date(2026, 7, 9)
def geo_munich(place):
return (48.137, 11.575) # ~40 km from Sauerlach
def geo_hamburg(place):
return (53.551, 9.994) # ~600 km
def geo_fail(place):
raise OSError("network down")
def misc(**kw):
base = {"miscType": "other", "startDate": None, "workloadPercent": None,
"remotePercent": None, "onsiteLocation": None}
base.update(kw)
return base
def test_security_is_always_no():
assert rules.eval_misc(misc(miscType="security"), TODAY) == rules.NO
def test_start_within_8_weeks_yes_after_no_missing_unknown():
assert rules.eval_misc(misc(miscType="start", startDate="2026-08-01"), TODAY) == rules.YES
assert rules.eval_misc(misc(miscType="start", startDate="2026-12-01"), TODAY) == rules.NO
assert rules.eval_misc(misc(miscType="start"), TODAY) == rules.UNKNOWN
assert rules.eval_misc(misc(miscType="start", startDate="asap"), TODAY) == rules.UNKNOWN
def test_workload():
assert rules.eval_misc(misc(miscType="workload", workloadPercent=100), TODAY) == rules.YES
assert rules.eval_misc(misc(miscType="workload", workloadPercent=50), TODAY) == rules.UNKNOWN
assert rules.eval_misc(misc(miscType="workload"), TODAY) == rules.UNKNOWN
def test_duration_always_yes():
assert rules.eval_misc(misc(miscType="duration"), TODAY) == rules.YES
def test_location_rules():
full_remote = misc(miscType="location", remotePercent=100)
assert rules.eval_misc(full_remote, TODAY) == rules.YES
hybrid_near = misc(miscType="location", remotePercent=60, onsiteLocation="München")
assert rules.eval_misc(hybrid_near, TODAY, geocode_fn=geo_munich) == rules.YES
hybrid_far = misc(miscType="location", remotePercent=60, onsiteLocation="Hamburg")
assert rules.eval_misc(hybrid_far, TODAY, geocode_fn=geo_hamburg) == rules.NO
unclear = misc(miscType="location")
assert rules.eval_misc(unclear, TODAY) == rules.NO
geo_broken = misc(miscType="location", remotePercent=40, onsiteLocation="Xyzstadt")
assert rules.eval_misc(geo_broken, TODAY, geocode_fn=geo_fail) == rules.UNKNOWN
def test_calc_match_and_rounding():
rows = [{"kat": "Must", "rating": "yes", "text": "a"},
{"kat": "Must", "rating": "yes", "text": "b"},
{"kat": "Must", "rating": "unknown", "text": "c"},
{"kat": "Nice", "rating": "no", "text": "d"},
{"kat": "Misc", "rating": "yes", "text": "e"}]
assert rules.calc_match(rows, "Must") == 75 # (100+100+25)/3
assert rules.calc_match(rows, "Nice") == 0
assert rules.calc_match([], "Nice") is None
# commercial rounding, half up (not banker's): (100+25)/2 = 62.5 -> 63
two = [{"kat": "Must", "rating": "yes", "text": "a"},
{"kat": "Must", "rating": "unknown", "text": "b"}]
assert rules.calc_match(two, "Must") == 63
def test_build_description_exact_format():
rows = [{"kat": "Misc", "rating": "yes", "text": "Hybrid: 60 % remote"},
{"kat": "Must", "rating": "no", "text": "Mehrjährige LLM-Plattform-Erfahrung"},
{"kat": "Must", "rating": "yes", "text": "RAG-Systeme"},
{"kat": "Nice", "rating": "yes", "text": "vLLM"}]
text = rules.build_description(rules.order_rows(rows))
assert text == (
"Must-have-Match: 50 % · Nice-to-have-Match: 100 %\n"
"\n"
"| Nr. | Kat. | ❔ | Anforderung |\n"
"|---|---|---|---|\n"
"| 1 | Must | ❌ | Mehrjährige LLM-Plattform-Erfahrung |\n"
"| 2 | Must | ✅ | RAG-Systeme |\n"
"| 3 | Nice | ✅ | vLLM |\n"
"| 4 | Misc | ✅ | Hybrid: 60 % remote |")
def test_empty_category_dash():
rows = [{"kat": "Must", "rating": "yes", "text": "a"}]
assert rules.build_description(rows).startswith(
"Must-have-Match: 100 % · Nice-to-have-Match: ")