# Contribuer au projet ## Prérequis Les mêmes que pour le développement (voir [README](README.md)), plus : - PHP 8.1+ avec l'extension `dom` (requise par HTMLPurifier et PHPUnit) ## Lancer les tests ```bash composer install vendor/bin/phpunit ``` Avec rapport de couverture (nécessite Xdebug ou PCOV) : ```bash vendor/bin/phpunit --coverage-text ``` ## Analyse statique (PHPStan) ```bash vendor/bin/phpstan analyse ``` Cette commande utilise `phpstan.neon` qui définit le niveau 8 et les chemins analysés. PDO est nativement connu de PHPStan — aucun stub supplémentaire n'est nécessaire. PHPStan est configuré au niveau 8, le plus strict. L'exécuter avant toute Pull Request garantit la cohérence des types et détecte les erreurs avant l'exécution. ## Suite de tests Les tests sont dans `tests/`, organisés en miroir de `src/`. ### `tests/Auth/` | Fichier | Classe testée | Ce qui est vérifié | |--------------------------------|---------------------------|---------------------| | `AuthServiceTest` | `AuthService` | `createUser()` (normalisation, unicité via exceptions métier, longueur mdp), `authenticate()`, `changePassword()`, `login/logout/isLoggedIn()` | | `AuthServiceRateLimitTest` | `AuthService` | `checkRateLimit()` (IP libre, verrouillée, expirée, minimum 1 minute, `deleteExpired()`), `recordFailure()` (constantes MAX_ATTEMPTS/LOCK_MINUTES), `resetRateLimit()` | | `LoginAttemptRepositoryTest` | `LoginAttemptRepository` | `findByIp()`, `recordFailure()` (INSERT vs UPDATE, compteur, seuil exact, fenêtre temporelle), `resetForIp()`, `deleteExpired()` | | `PasswordResetServiceTest` | `PasswordResetService` | `requestReset()` (email inconnu silencieux, invalidation, création, envoi, URL), `validateToken()` (inexistant, expiré, valide), `resetPassword()` (token invalide, mdp trop court via `WeakPasswordException`, mise à jour + consommation) | | `PasswordResetRepositoryTest` | `PasswordResetRepository` | `create()`, `findActiveByHash()` (filtre `used_at = null`), `invalidateByUserId()` et `markAsUsed()` (jamais de `delete`) | ### `tests/User/` | Fichier | Classe testée | Ce qui est vérifié | |-----------------------|------------------|---------------------| | `UserTest` | `User` | Construction, validation (username, email, hash, rôle), limites min/max, `fromArray()` | | `UserRepositoryTest` | `UserRepository` | `findAll/ById/ByUsername/ByEmail()`, `create()`, `updatePassword()`, `delete()` | ### `tests/Shared/` | Fichier | Classe testée | Ce qui est vérifié | |-----------------------|------------------|---------------------| | `SessionManagerTest` | `SessionManager` / `SessionManagerInterface` | `isAuthenticated()`, `getUserId()`, rôles, écriture `$_SESSION`, `destroy()` | | `HtmlSanitizerTest` | `HtmlSanitizer` | Balises autorisées conservées, XSS supprimé (`