createMock(UserRepositoryInterface::class); $repo->method('countAdmins')->willReturn(2); $guard = new AdminHeadcountGuard($repo); $user = new User(); $user->setUsername('alice'); // Aucune exception ne doit etre levee $guard->ensureAtLeastOneAdminRemainsAfterDemotion($user); $this->addToAssertionCount(1); } /** * Bloque la demote quand il ne reste exactement qu'un admin. */ public function testBlocksDemotionWhenExactlyOneAdmin(): void { $repo = $this->createMock(UserRepositoryInterface::class); $repo->method('countAdmins')->willReturn(1); $guard = new AdminHeadcountGuard($repo); $user = new User(); $user->setUsername('alice'); $this->expectException(LastAdminProtectionException::class); $guard->ensureAtLeastOneAdminRemainsAfterDemotion($user); } /** * Bloque la demote de facon defensive si le compteur est a 0 (etat incoherent). */ public function testBlocksDemotionDefensivelyWhenZeroAdmin(): void { $repo = $this->createMock(UserRepositoryInterface::class); $repo->method('countAdmins')->willReturn(0); $guard = new AdminHeadcountGuard($repo); $user = new User(); $user->setUsername('alice'); $this->expectException(LastAdminProtectionException::class); $guard->ensureAtLeastOneAdminRemainsAfterDemotion($user); } // --------------------------------------------------------------- // Deletion (suppression de l'utilisateur) // --------------------------------------------------------------- /** * Autorise la suppression quand il reste plus d'un admin (cas nominal). */ public function testAllowsDeletionWhenMoreThanOneAdmin(): void { $repo = $this->createMock(UserRepositoryInterface::class); $repo->method('countAdmins')->willReturn(2); $guard = new AdminHeadcountGuard($repo); $user = new User(); $user->setUsername('bob'); // Aucune exception ne doit etre levee $guard->ensureAtLeastOneAdminRemainsAfterDeletion($user); $this->addToAssertionCount(1); } /** * Bloque la suppression quand il ne reste exactement qu'un admin. */ public function testBlocksDeletionWhenExactlyOneAdmin(): void { $repo = $this->createMock(UserRepositoryInterface::class); $repo->method('countAdmins')->willReturn(1); $guard = new AdminHeadcountGuard($repo); $user = new User(); $user->setUsername('bob'); $this->expectException(LastAdminProtectionException::class); $guard->ensureAtLeastOneAdminRemainsAfterDeletion($user); } /** * Bloque la suppression de facon defensive si le compteur est a 0 (etat incoherent). */ public function testBlocksDeletionDefensivelyWhenZeroAdmin(): void { $repo = $this->createMock(UserRepositoryInterface::class); $repo->method('countAdmins')->willReturn(0); $guard = new AdminHeadcountGuard($repo); $user = new User(); $user->setUsername('bob'); $this->expectException(LastAdminProtectionException::class); $guard->ensureAtLeastOneAdminRemainsAfterDeletion($user); } }