"""Une suite unique, rejouée contre TOUTES les implémentations d'un contrat. Le jour où une implémentation oublie une méthode, c'est ici que ça rougit — y compris pour les plateformes absentes de la machine de développement. """ import inspect import pytest from contrats import Overlay, Systeme, Transcripteur @pytest.mark.parametrize("contrat, methodes", [ (Transcripteur, ["warmup", "transcrire"]), (Overlay, ["show", "hide", "set_level", "set_status", "rearmer_garde"]), (Systeme, ["jouer_son", "modificateurs_enfonces", "raccourci_defaut", "chemin_log", "dossier_donnees", "acquerir_verrou_instance"]), ]) def test_le_contrat_declare_exactement_ses_methodes(contrat, methodes): declarees = [n for n, _ in inspect.getmembers(contrat, inspect.isfunction) if not n.startswith("_")] assert sorted(declarees) == sorted(methodes) # Ce sont les docstrings de MÉTHODE qui portent l'essentiel du contrat # (la plage [0, 1] de set_level, l'affinité thread, la sémantique de # retour) : une docstring vidée ici doit rougir, pas seulement celle # de la classe. for nom in methodes: methode = getattr(contrat, nom) assert methode.__doc__, f"{contrat.__name__}.{nom} doit dire à quoi il sert" def test_les_contrats_sont_documentes(): for contrat in (Transcripteur, Overlay, Systeme): assert contrat.__doc__, f"{contrat.__name__} doit dire à quoi il sert"