Toutes les sorties et tous les événements du Québec, un seul endroit — 7 connecteurs, fiches SSR, design Groupe KA.
HTML 82.9%
Python 15.2%
TypeScript 0.9%
JavaScript 0.7%
1# ==============================================================================2# Author: Simon-Pierre Boucher <contact@spboucher.ai>3# File: tests/test_normalize.py4# Desc: Tests de la couche de normalisation (dates, prix, catégories, régions)5# ==============================================================================6from __future__ import annotations78from sortika.normalize import (artists_from_title, clean_city, clean_text,9 map_categories, parse_date_iso, parse_latlng,10 parse_price, parse_time, utc_to_local)11from sortika.regions import region_from_city, region_from_tourist12from sortika.schema import Event131415def test_parse_date_iso():16 assert parse_date_iso("2026-09-11T00:00:00") == "2026-09-11"17 assert parse_date_iso("2026-09-11") == "2026-09-11"18 assert parse_date_iso("") is None19 assert parse_date_iso("demain") is None20 assert parse_date_iso("0001-99-99") is None212223def test_parse_time():24 assert parse_time("17 août 2026, 20h00") == "20:00"25 assert parse_time("19h30") == "19:30"26 assert parse_time("15 h 00") == "15:00"27 assert parse_time("19:30:00") == "19:30"28 assert parse_time("2026-09-11T19:30:00") == "19:30"29 assert parse_time("17 août 2026") is None30 assert parse_time("") is None31 assert parse_time(None) is None323334def test_utc_to_local():35 # hiver (UTC-5) et été (UTC-4), vérifiés sur les flux Laval/Sherbrooke36 assert utc_to_local("2025-02-13T23:30:00") == ("2025-02-13", "18:30")37 assert utc_to_local("2026-08-01T22:30:00Z") == ("2026-08-01", "18:30")38 # minuit local = placeholder « toute la journée » → pas d'heure39 assert utc_to_local("2026-07-10T04:00:00Z") == ("2026-07-10", None)40 assert utc_to_local(None) == (None, None)414243def test_artists_from_title():44 # patron sûr : suffixe = salle connue de l'événement45 assert artists_from_title("Les Cowboys Fringants - Club Soda",46 "Club Soda") == ["Les Cowboys Fringants"]47 # patron sûr : « X en concert / en spectacle »48 assert artists_from_title("Marc Dupré en spectacle", "") == ["Marc Dupré"]49 # ambigu ou événement → jamais d'artiste inventé50 assert artists_from_title("Festival d'été de Québec", "") == []51 assert artists_from_title("Soirée humour - Club Soda", "Club Soda") == []52 assert artists_from_title("Un artiste - Une autre salle", "Club Soda") == []53 assert artists_from_title("", "") == []545556def test_parse_price():57 assert parse_price("Gratuit") == (True, None, "Gratuit")58 assert parse_price("Entrée libre") == (True, None, "Entrée libre")59 free, amt, _ = parse_price("Adulte 25 $, enfant 12,50 $")60 assert free is False and amt == 12.5061 assert parse_price("Payant")[0] is False62 assert parse_price("")[0] is None636465def test_map_categories():66 assert map_categories(["Festival"]) == ["festival"]67 assert map_categories(["Manifestation sportive"]) == ["sport"]68 assert map_categories(["Chanson", "Sports et plein air"]) == ["musique", "sport"]69 assert map_categories(["Conseil et comité"]) == ["communautaire"]70 assert map_categories(["Zzz-inconnu"]) == ["autre"]71 assert map_categories([]) == ["autre"]727374def test_regions():75 assert region_from_tourist("Cantons-de-l'Est") == "Estrie"76 assert region_from_tourist("Charlevoix") == "Capitale-Nationale"77 assert region_from_tourist("Québec") == "Capitale-Nationale"78 assert region_from_city("Lévis") == "Chaudière-Appalaches"79 assert region_from_city("Gatineau") == "Outaouais"80 assert region_from_city("Ville-Inconnue") == ""818283def test_clean():84 assert clean_city("Montréal (Québec)") == "Montréal"85 assert clean_text("a <b>b</b> c") == "a b c"868788def test_parse_latlng():89 assert parse_latlng("45.5", "-73.5") == (45.5, -73.5)90 assert parse_latlng("0", "0") == (None, None)91 assert parse_latlng(None, None) == (None, None)929394def test_event_finalize_and_dedup():95 a = Event(source="sitq", external_id="X1", url="https://a",96 title=" Festival d'été ", city="Québec (Québec)",97 tourist_region="Québec", raw_categories=["Festival"],98 start_date="2026-07-01T00:00:00", price_label="Gratuit").finalize()99 b = Event(source="montreal", external_id="Y2", url="https://b",100 title="Festival d'été", city="Québec",101 start_date="2026-07-01").finalize()102 assert a.title == "Festival d'été"103 assert a.region == "Capitale-Nationale"104 assert a.categories == ["festival"]105 assert a.is_free is True106 assert a.end_date == "2026-07-01"107 assert a.dedup_key() == b.dedup_key()108109110def test_canonical_city_mamh():111 """Phase 2 : les graphies sans accents des sources sont ramenées au nom112 officiel du Répertoire MAMH (facettes ville unifiées)."""113 from sortika.normalize import canonical_city114 assert canonical_city("Montreal") == "Montréal"115 assert canonical_city("Quebec") == "Québec"116 assert canonical_city("Levis") == "Lévis"117 assert canonical_city("Trois-Rivieres") == "Trois-Rivières"118 assert canonical_city("MONTRÉAL") == "Montréal"119 assert canonical_city("Toronto") == "Toronto" # hors répertoire : intact120 assert clean_city("Montreal, Québec") == "Montréal"121122123def test_normalize_status():124 from sortika.schema import normalize_status125 assert normalize_status("cancelled") == "cancelled"126 assert normalize_status("ANNULÉ") == "cancelled"127 assert normalize_status("sold_out") == "soldout"128 assert normalize_status("postponed") == "postponed"129 assert normalize_status("rescheduled") == "postponed"130 assert normalize_status("buy_now") == ""131 assert normalize_status("") == ""132 assert normalize_status(None) == ""133