# ============================================================================== # Author: Simon-Pierre Boucher # File: tests/test_sitefinder.py # Desc: Connecteur site-finder (découverte des sites web via l'API Serper # /maps) — croisement HORS LIGNE de fiches Google Maps réelles # (payloads captés le 2026-08-23) : nom + distance GPS <= 400 m, # ambigu = ignoré ; nettoyage/classification des URLs (utm_* retirés, # réseaux sociaux et plateformes de livraison rejetés, réservation # séparée). # ============================================================================== from restoka.connectors.sitefinder import (classify_website, clean_website, match_place, _dist_m) # Réponses RÉELLES de l'API Serper /maps (2026-08-23), abrégées aux champs lus. _AMOS_PLACES = [ {"title": "Pizzéria Amos Inc", "address": "341 6e Rue O, Amos, QC J9T 2V5, Canada", "latitude": 48.568842, "longitude": -78.1315157, "website": "http://pizzeriaamos.com/", "phoneNumber": "+1 819-732-4398", "cid": "9963617425105215735"}, {"title": "Pizza Salvatoré", # à ~350 m : nom différent -> jamais croisé "address": "12 Rte 111 Ouest, Amos, Quebec J9T 2X6, Canada", "latitude": 48.5720841, "longitude": -78.1315975, "website": "https://salvatore.com/fr/restaurant/sal-amos" "?utm_id=92&utm_source=google&utm_medium=business-profile", "phoneNumber": "+1 819-834-5555", "cid": "15827771869290584642"}, {"title": "Mia Pasta - Amos", # à ~1,4 km : hors rayon "address": "82 1re Avenue E, Amos, QC J9T 2E7, Canada", "latitude": 48.571788, "longitude": -78.11258169999999, "website": "https://commandeenligne.miapasta.com/commandeenligne/", "phoneNumber": "+1 819-727-2021", "cid": "18357615835954532349"}, ] _TIMS_PLACES = [ {"title": "Tim Hortons", "address": "208 Bd Saint-Raymond, Gatineau, QC J9A 3H6, Canada", "latitude": 45.4367899, "longitude": -75.76653309999999, "website": "https://locations.timhortons.ca/en/qc/gatineau/" "208-boul-st-raymond", "phoneNumber": "+1 819-778-6481", "cid": "5309096764678078556"}, {"title": "Tim Hortons", # autre succursale à ~4 km : hors rayon "address": "200 Prom. du Portage, Gatineau, QC J8X 4B7, Canada", "latitude": 45.4267914, "longitude": -75.71292389999999, "website": "https://locations.timhortons.ca/en/qc/gatineau/" "200-promenade-du-portage", "phoneNumber": "+1 613-293-7168", "cid": "591025576747174253"}, ] def _row(name, address, city, lat, lng): return {"name": name, "address": address, "city": city, "lat": lat, "lng": lng, "phone": ""} def test_match_typo_and_legal_suffix(): # fiche OSM réelle « Pizzaria Amos » (coquille) vs « Pizzéria Amos Inc » row = _row("Pizzaria Amos", "341 6e Rue Ouest", "Amos", 48.5689429, -78.1316743) hit = match_place(row, _AMOS_PLACES) assert hit is not None and hit["cid"] == "9963617425105215735" def test_match_chain_disambiguated_by_distance(): # deux Tim Hortons à Gatineau : seul celui à <400 m est croisé row = _row("Tim Hortons", "208 Boulevard Saint-Raymond", "Gatineau", 45.4367943, -75.7665445) hit = match_place(row, _TIMS_PLACES) assert hit is not None and hit["cid"] == "5309096764678078556" def test_no_match_far_or_different_name(): # un resto au nom sans rapport, même s'il est proche, n'est pas croisé row = _row("Sushi Miko", "339 6e Rue Ouest", "Amos", 48.5689429, -78.1316743) assert match_place(row, _AMOS_PLACES) is None def test_ambiguous_two_distinct_places(): # deux fiches distinctes (cid) qui matchent toutes deux -> on s'abstient near = dict(_TIMS_PLACES[1], latitude=45.4368, longitude=-75.7666) row = _row("Tim Hortons", "208 Boulevard Saint-Raymond", "Gatineau", 45.4367943, -75.7665445) assert match_place(row, [_TIMS_PLACES[0], near]) is None def test_dist_m_scale(): assert _dist_m(45.5, -73.5, 45.5, -73.5) == 0.0 assert 340 < _dist_m(48.5689429, -78.1316743, 48.5720841, -78.1315975) < 400 def test_clean_website_strips_tracking(): url = _AMOS_PLACES[1]["website"] assert clean_website(url) == "https://salvatore.com/fr/restaurant/sal-amos" assert clean_website("javascript:alert(1)") == "" assert clean_website("") == "" def test_classify_website(): assert classify_website("http://pizzeriaamos.com/") == \ ("site", "http://pizzeriaamos.com/") # une page Facebook n'est pas « le site du resto » kind, _ = classify_website("https://www.facebook.com/cafeologueduquartier/") assert kind == "rejected" # un lien de livraison contaminerait le pipeline dine-in de site-resto assert classify_website("https://www.ubereats.com/ca/store/x")[0] == "rejected" # plateforme de réservation -> details.reservation_url assert classify_website("https://www.opentable.ca/r/toque-montreal")[0] == \ "reservation" # la plateforme de commande en ligne du resto lui-même reste un site valide assert classify_website( "https://commandeenligne.miapasta.com/commandeenligne/")[0] == "site"