SPB Git forge

spb/crea-ka

Public

Créa·Ka — annuaire public cross-plateforme des créateurs de contenu québécois (crea-ka.com)

52commits 1branches 0releases
11.3 MBsize
maindefault branch
19 days agolast push
Python 73.6% HTML 13.2% TypeScript 6% JavaScript 4.5% CSS 1.7% Dockerfile 0.6%
4.5 KB · 99 lines python
Raw Blame History
1# ==============================================================================2# Author: Simon-Pierre Boucher <contact@spboucher.ai>3# File:   tests/test_perimetre_qc.py4# Desc:   Périmètre québécois (§1-2) — garde QC de la boule de neige (les5#         profils reliés IG ramènent des vedettes mondiales sans filtre) et6#         rapprochement par compte identique dans sync_source (anti-doublons)7# ==============================================================================8"""Régressions du 2026-08-20 : vedettes américaines + fiches en double.9101. snowball-ig émettait TOUS les profils reliés Instagram (cristiano,11   selenagomez, ferrari, nasa… — 3 767 fiches hors-périmètre en un passage).122. `_find_existing` exigeait une confiance forte des DEUX côtés : une fiche à13   signal `mention` (0.60) n'était jamais retrouvée → sync_source créait une14   seconde fiche et l'upsert des comptes lui réassignait le compte, laissant15   l'originale orpheline (691 doublons).16"""17from creaka import db18from creaka.connectors.snowball import SnowballConnector19from creaka.identity import account20from creaka.schema import Creator212223def _creator(name, accounts, **kw):24    return Creator(source="test", external_id="", display_name=name,25                   platforms=accounts, **kw).finalize()262728def _source_avec_relies(related):29    acc = account("instagram", "createur.qc", "profil_source").finalize()30    acc.metrics["related_profiles"] = related31    return _creator("Créateur QC", [acc])323334def test_snowball_ecarte_les_vedettes_mondiales():35    src = _source_avec_relies([36        {"username": "cristiano", "full_name": "Cristiano Ronaldo"},37        {"username": "selenagomez", "full_name": "Selena Gomez"},38        {"username": "ferrari", "full_name": "Ferrari"},39        {"username": "nasa", "full_name": "NASA"},40    ])41    assert SnowballConnector().enrich([src]) == []424344def test_marqueur_queb_exige_fin_de_mot():45    # faux positifs constatés le 2026-08-20 : « queb » nu matchait dans46    # « quebra » (portugais) et « jacquebrazil »47    from creaka.connectors.youtube_recherche import is_quebec48    assert not is_quebec("tatiquebrabarraco Tati Quebra Barraco")49    assert not is_quebec("jacquebrazil")50    assert is_quebec("onlyqueb")           # queb en fin de mot51    assert is_quebec("grainsduquebec")     # quebec collé dans un handle52    assert is_quebec("Créatrice québécoise à Montréal")535455def test_snowball_ecarte_les_organismes_qc():56    # revue du 2026-08-20 : villes, tourisme, ministères, partis, festivals…57    # portent des marqueurs QC mais ne sont pas des créateurs58    src = _source_avec_relies([59        {"username": "villequebec", "full_name": "Ville de Québec"},60        {"username": "tourismecharlevoix", "full_name": "Tourisme Charlevoix"},61        {"username": "transports_quebec", "full_name": "Transports Québec"},62        {"username": "justepourrirequebec", "full_name": "Juste pour rire"},63        {"username": "humoriste.mtl", "full_name": "Humoriste MTL"},64    ])65    handles = {c.platforms[0].handle66               for c in SnowballConnector().enrich([src])}67    assert handles == {"humoriste.mtl"}686970def test_snowball_garde_les_profils_marques_qc():71    src = _source_avec_relies([72        {"username": "humoriste.mtl", "full_name": "Humoriste MTL"},73        {"username": "chroniques.quebec", "full_name": "Chroniques"},74        {"username": "katyperry", "full_name": "Katy Perry"},75    ])76    handles = {c.platforms[0].handle77               for c in SnowballConnector().enrich([src])}78    assert handles == {"humoriste.mtl", "chroniques.quebec"}798081def test_compte_identique_fusionne_jamais_de_doublon(tmp_path):82    con = db.connect(tmp_path / "t.db")83    faible = _creator("misslavoie",84                      [account("instagram", "misslavoie", "mention")])85    s1 = db.sync_source(con, "snowball-ig", [faible])86    assert s1["added"] == 187    # ré-observation du MÊME compte avec signal fort (ex. enrichissement) :88    # la fiche existante est réutilisée, jamais de seconde fiche89    fort = _creator("Jade Lavoie",90                    [account("instagram", "misslavoie", "profil_source")])91    s2 = db.sync_source(con, "autre-source", [fort])92    assert s2["added"] == 0 and s2["updated"] == 193    assert con.execute("SELECT count(*) FROM creators").fetchone()[0] == 194    # aucun orphelin : chaque fiche possède encore son compte95    orphans = con.execute(96        "SELECT count(*) FROM creators WHERE id NOT IN "97        "(SELECT creator_id FROM accounts)").fetchone()[0]98    assert orphans == 099