# ============================================================================== # Author: Simon-Pierre Boucher # File: tests/test_normalize.py # Desc: Tests de normalisation — handles, URLs canoniques, niches, régions, # compteurs d'abonnés, taille d'audience # ============================================================================== from creaka.normalize import ( audience_tier, canonical_url, clean_handle, map_niche, map_region, parse_count, platform_from_url, ) def test_clean_handle(): assert clean_handle("@Enola.Bedard") == "enola.bedard" assert clean_handle("https://www.instagram.com/enola.bedard/") == "enola.bedard" assert clean_handle(" @Nom_Scene ") == "nom_scene" assert clean_handle(None) == "" def test_youtube_channel_id(): # ID de chaîne : casse préservée + forme /channel/ (jamais @ucxxx minuscule) cid = "UCtH1VriJJmhYkGSbq_7Jhra"[:24] assert clean_handle(cid) == cid assert canonical_url("youtube", cid) == f"https://www.youtube.com/channel/{cid}" def test_canonical_url(): assert canonical_url("instagram", "nom") == "https://www.instagram.com/nom/" assert canonical_url("tiktok", "@Nom") == "https://www.tiktok.com/@nom" assert canonical_url("substack", "infolettre") == "https://infolettre.substack.com" assert canonical_url("onlyfans", "nom") == "https://onlyfans.com/nom" # pas de forme canonique → repli sur l'URL source assert canonical_url("site-web", "x", fallback="https://exemple.com") == \ "https://exemple.com" def test_platform_from_url(): assert platform_from_url("https://www.tiktok.com/@nom") == ("tiktok", "nom") assert platform_from_url("https://twitter.com/nom") == ("x", "nom") assert platform_from_url("https://mono.substack.com") == ("substack", "mono") # pages génériques ≠ handles assert platform_from_url("https://www.instagram.com/p/abc123/") is None assert platform_from_url("https://www.youtube.com/watch?v=x") is None assert platform_from_url("https://exemple.com/page") is None def test_map_niche(): assert map_niche("food") == "bouffe-resto" assert map_niche("Beauté") == "beaute" assert map_niche("fitness") == "sport-fitness" assert map_niche("entrepreneur") == "finance-affaires" assert map_niche("catégorie-inconnue") == "autre" def test_map_region_prudence(): # « Québec » seul = la PROVINCE → jamais de région inférée (§7) assert map_region("Québec") == (None, None) assert map_region("Québec (ville)") == ("Capitale-Nationale", "Québec") assert map_region("Montréal, QC")[0] == "Montréal" assert map_region("Blainville, Québec")[0] == "Laurentides" assert map_region("Los Angeles (originaire du Québec)") == (None, None) assert map_region(None) == (None, None) def test_parse_count(): assert parse_count("1,2 M") == 1_200_000 assert parse_count("12.3k") == 12_300 assert parse_count("4 567 abonnés") == 4_567 assert parse_count("1,234,567") == 1_234_567 assert parse_count(2600000) == 2_600_000 assert parse_count(None) is None # un handle n'est JAMAIS un compteur (bug réel : « @chandrayoga-tw5bu » → 5 G) assert parse_count("@chandrayoga-tw5bu") is None assert parse_count("@nom123") is None def test_audience_tier(): assert audience_tier(5_000) == "nano" assert audience_tier(50_000) == "micro" assert audience_tier(500_000) == "macro" assert audience_tier(2_000_000) == "mega" assert audience_tier(None) == "nano"