"""Couche Windows du contrat Systeme — éprouvée depuis macOS par injection. `winsound`, `msvcrt` et `ctypes.windll` n'existent pas sur macOS : c'est pourquoi `SystemeWindows` les reçoit en paramètres injectables (jouer, clavier, verrouiller) plutôt que de les importer en tête de module. Ces tests éprouvent donc la LOGIQUE française de la classe — quel alias pour quel son, quel bit pour quelle touche, comment les chemins et le verrou sont construits — jamais le comportement réel de winsound.PlaySound, GetAsyncKeyState ou msvcrt.locking : aucune machine ici ne peut le vérifier. Seule une vraie machine Windows le peut. """ import os import pytest from systeme.windows import SystemeWindows # --- jouer_son --------------------------------------------------------- def test_jouer_son_start_produit_lalias_systemasterisk(): appels = [] s = SystemeWindows(jouer=appels.append) s.jouer_son("start") assert appels == ["SystemAsterisk"] def test_jouer_son_done_produit_lalias_systemexclamation(): appels = [] s = SystemeWindows(jouer=appels.append) s.jouer_son("done") assert appels == ["SystemExclamation"] def test_jouer_son_error_produit_lalias_systemhand(): appels = [] s = SystemeWindows(jouer=appels.append) s.jouer_son("error") assert appels == ["SystemHand"] def test_jouer_son_nom_inconnu_ne_produit_aucun_appel(): appels = [] s = SystemeWindows(jouer=appels.append) s.jouer_son("inconnu") assert appels == [] def test_jouer_son_qui_echoue_ne_leve_pas(): def echoue(alias): raise OSError("winsound indisponible") s = SystemeWindows(jouer=echoue) s.jouer_son("start") # ne doit jamais lever : le son ne casse pas la dictée # --- modificateurs_enfonces -------------------------------------------- @pytest.mark.parametrize("vk", [0x11, 0x10, 0x12, 0x5B, 0x5C]) def test_modificateurs_enfonces_vrai_pour_chacune_des_cinq_touches(vk): # bit de poids fort posé UNIQUEMENT pour la touche ciblée par ce cas. s = SystemeWindows(clavier=lambda sonde, cible=vk: 0x8000 if sonde == cible else 0) assert s.modificateurs_enfonces() is True def test_modificateurs_enfonces_faux_si_aucun_bit_de_poids_fort_pose(): # une valeur non nulle mais sans le bit 0x8000 ne doit pas compter. s = SystemeWindows(clavier=lambda vk: 0x0001) assert s.modificateurs_enfonces() is False def test_modificateurs_enfonces_faux_si_toutes_les_touches_sont_relachees(): s = SystemeWindows(clavier=lambda vk: 0) assert s.modificateurs_enfonces() is False def test_modificateurs_enfonces_faux_si_la_sonde_leve(): def leve(vk): raise OSError("user32 indisponible") s = SystemeWindows(clavier=leve) assert s.modificateurs_enfonces() is False # --- raccourci_defaut ---------------------------------------------------- def test_raccourci_defaut_est_ctrl_alt_d(): # n'existe pas sur Windows, contrairement à macOS. assert SystemeWindows().raccourci_defaut() == "++d" # --- chemins --------------------------------------------------------------- def test_chemin_log_derive_de_localappdata(monkeypatch, tmp_path): monkeypatch.setenv("LOCALAPPDATA", str(tmp_path)) assert SystemeWindows().chemin_log() == os.path.join(str(tmp_path), "Zonza", "Zonza.log") def test_dossier_donnees_derive_de_localappdata(monkeypatch, tmp_path): monkeypatch.setenv("LOCALAPPDATA", str(tmp_path)) assert SystemeWindows().dossier_donnees() == os.path.join(str(tmp_path), "Zonza") def test_chemin_log_retombe_sur_le_dossier_utilisateur_si_localappdata_absent(monkeypatch): monkeypatch.delenv("LOCALAPPDATA", raising=False) attendu = os.path.join(os.path.expanduser("~"), "Zonza", "Zonza.log") assert SystemeWindows().chemin_log() == attendu # --- verrou d'instance ------------------------------------------------------- def test_le_verrou_rend_un_objet_la_premiere_fois(tmp_path): chemin = str(tmp_path / "sous-dossier" / "z.lock") s = SystemeWindows(verrouiller=lambda f: None) verrou = s.acquerir_verrou_instance(chemin) assert verrou is not None verrou.close() def test_le_verrou_cree_le_dossier_parent_manquant(tmp_path): chemin = str(tmp_path / "sous-dossier" / "z.lock") s = SystemeWindows(verrouiller=lambda f: None) assert not os.path.isdir(os.path.dirname(chemin)) verrou = s.acquerir_verrou_instance(chemin) assert os.path.isdir(os.path.dirname(chemin)) verrou.close() def test_le_verrou_refuse_une_seconde_prise(tmp_path): chemin = str(tmp_path / "z.lock") pris = {"valeur": False} def verrouiller(f): if pris["valeur"]: raise OSError("verrou déjà pris") pris["valeur"] = True s = SystemeWindows(verrouiller=verrouiller) premier = s.acquerir_verrou_instance(chemin) assert premier is not None second = s.acquerir_verrou_instance(chemin) assert second is None premier.close() def test_un_verrou_dont_la_prise_echoue_referme_le_fichier(tmp_path): chemin = str(tmp_path / "z.lock") captures = {} def echoue(f): captures["fichier"] = f raise OSError("verrou pris") s = SystemeWindows(verrouiller=echoue) resultat = s.acquerir_verrou_instance(chemin) assert resultat is None assert captures["fichier"].closed