SPB Git

spb/job-ka

Public
5.8 KB · 179 lines python
1# =============================================================================2# Job·Ka — Groupe KA3# Auteur  : Simon-Pierre Boucher4# Contact : contact@spboucher.ai5# Fichier : tests/test_normalize.py6# Rôle    : Tests unitaires de la couche de normalisation (salaires, dates,7#           mode/type d'emploi, lieux, catégories)8# Créé    : 2026-08-17   Modifié : 2026-08-179# =============================================================================10import datetime as dt1112from jobka.normalize import (13    categorize,14    clean_html,15    is_quebec_location,16    parse_date,17    parse_employment_type,18    parse_location,19    parse_salary,20    parse_work_mode,21    salary_to_hourly,22    salary_to_yearly,23)2425TODAY = dt.date(2026, 8, 17)262728# --- salaires ----------------------------------------------------------------2930def test_salary_hourly_range():31    assert parse_salary("25,00 $ à 30,00 $ de l'heure") == (25.0, 30.0, "hour")323334def test_salary_hourly_english():35    assert parse_salary("$22.50 - $27.75 per hour") == (22.5, 27.75, "hour")363738def test_salary_yearly_thousands():39    assert parse_salary("70 000 $ à 90 000 $ par année") == (70000.0, 90000.0, "year")404142def test_salary_yearly_english_commas():43    assert parse_salary("$85,000 - $105,000 annually") == (85000.0, 105000.0, "year")444546def test_salary_k_notation():47    assert parse_salary("80k$ - 100k$ /an") == (80000.0, 100000.0, "year")484950def test_salary_single_value():51    lo, hi, unit = parse_salary("Salaire : 28,50 $/h")52    assert (lo, hi, unit) == (28.5, 28.5, "hour")535455def test_salary_infers_unit_from_magnitude():56    assert parse_salary("55 000 $")[2] == "year"57    assert parse_salary("26,75 $")[2] == "hour"585960def test_salary_rejects_hours_of_work():61    # « 35 heures/semaine » n'est PAS un salaire62    assert parse_salary("35 heures par semaine") == (None, None, None)636465def test_salary_rejects_empty_and_garbage():66    assert parse_salary("") == (None, None, None)67    assert parse_salary("Salaire concurrentiel") == (None, None, None)686970def test_salary_conversions():71    assert salary_to_yearly(25.0, "hour") == 52000.072    assert salary_to_hourly(52000.0, "year") == 25.073    assert salary_to_yearly(5000.0, "month") == 60000.074    assert salary_to_yearly(None, "hour") is None757677# --- dates ---------------------------------------------------------------------7879def test_date_iso_passthrough():80    assert parse_date("2026-09-01") == "2026-09-01"81    assert parse_date("2026-06-16T05:06:55-04:00") == "2026-06-16"828384def test_date_epoch_ms():85    # Lever : createdAt en millisecondes86    assert parse_date(1755000000000) == dt.date.fromtimestamp(1755000000).isoformat()878889def test_date_french():90    assert parse_date("1er juillet 2026", TODAY) == "2026-07-01"91    assert parse_date("déc. 2026", TODAY) == "2026-12-01"929394def test_date_english():95    assert parse_date("July 1st, 2026", TODAY) == "2026-07-01"969798def test_date_relative():99    assert parse_date("Posted 3 Days Ago", TODAY) == "2026-08-14"100    assert parse_date("il y a 2 semaines", TODAY) == "2026-08-03"101    assert parse_date("Posted Today", TODAY) == "2026-08-17"102    assert parse_date("Posted Yesterday", TODAY) == "2026-08-16"103104105def test_date_never_invented():106    assert parse_date("bientôt") is None107    assert parse_date("") is None108    assert parse_date(None) is None109110111# --- mode / type ---------------------------------------------------------------112113def test_work_mode():114    assert parse_work_mode("Télétravail") == "teletravail"115    assert parse_work_mode("Remote - QC") == "teletravail"116    assert parse_work_mode("Mode hybride (3 jours au bureau)") == "hybride"117    assert parse_work_mode("Sur place") == "presentiel"118    assert parse_work_mode("Montréal") is None119120121def test_work_mode_hybrid_wins():122    assert parse_work_mode("hybride avec télétravail partiel") == "hybride"123124125def test_employment_type():126    assert parse_employment_type("Temps plein") == "temps_plein"127    assert parse_employment_type("Full time") == "temps_plein"128    assert parse_employment_type("Permanent") == "temps_plein"129    assert parse_employment_type("Temps partiel") == "temps_partiel"130    assert parse_employment_type("Contrat 12 mois") == "contractuel"131    assert parse_employment_type("Stage été 2027") == "stage"132    assert parse_employment_type("Emploi saisonnier") == "saisonnier"133    assert parse_employment_type("") is None134135136# --- lieux -----------------------------------------------------------------------137138def test_location_montreal():139    loc = parse_location("Montréal, QC, Canada")140    assert loc["city"] == "Montréal"141    assert loc["region"] == "Québec"142143144def test_location_quebec_city_english():145    assert parse_location("Quebec City, Quebec")["city"] == "Québec"146147148def test_location_postal_code():149    loc = parse_location("1500 rue Exemple, Lévis G6V 4Z2")150    assert loc["postal_code"] == "G6V 4Z2"151    assert loc["city"] == "Lévis"152153154def test_is_quebec_location():155    assert is_quebec_location("Montréal, QC")156    assert is_quebec_location("Saint-Laurent, Quebec, Canada")157    assert is_quebec_location("Sherbrooke")158    assert not is_quebec_location("Toronto, ON")159    assert not is_quebec_location("Richmond, BC")160    assert not is_quebec_location("Paris, IDF, France")161    assert not is_quebec_location("")162163164# --- catégories / HTML ------------------------------------------------------------165166def test_categorize():167    assert categorize("Développeur logiciel senior") == "TI"168    assert categorize("Infirmière clinicienne") == "Santé"169    assert categorize("Conseiller en ressources humaines") == "RH"170    assert categorize("Poste mystère") == ""171172173def test_clean_html():174    html = "<p>Bonjour&nbsp;!</p><ul><li>Point 1</li><li>Point 2</li></ul>"175    txt = clean_html(html)176    assert "Bonjour !" in txt177    assert "Point 1" in txt and "Point 2" in txt178    assert "<" not in txt179
Files · 1604ff9e1a30e9d4ce075746d260ef95616e4516
Menu

Theme