Files
slim-blog/tests/Auth/AccountControllerTest.php
2026-03-16 01:47:07 +01:00

208 lines
7.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Auth;
use App\Auth\AccountController;
use App\Auth\AuthServiceInterface;
use App\Shared\Http\FlashServiceInterface;
use App\Shared\Http\SessionManagerInterface;
use App\User\Exception\WeakPasswordException;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\ControllerTestCase;
/**
* Tests unitaires pour AccountController.
*
* Couvre showChangePassword() et changePassword() :
* mots de passe non identiques, mot de passe faible, mot de passe actuel
* incorrect, erreur inattendue et succès.
*/
final class AccountControllerTest extends ControllerTestCase
{
/** @var \Slim\Views\Twig&MockObject */
private \Slim\Views\Twig $view;
/** @var AuthServiceInterface&MockObject */
private AuthServiceInterface $authService;
/** @var FlashServiceInterface&MockObject */
private FlashServiceInterface $flash;
/** @var SessionManagerInterface&MockObject */
private SessionManagerInterface $sessionManager;
private AccountController $controller;
protected function setUp(): void
{
$this->view = $this->makeTwigMock();
$this->authService = $this->createMock(AuthServiceInterface::class);
$this->flash = $this->createMock(FlashServiceInterface::class);
$this->sessionManager = $this->createMock(SessionManagerInterface::class);
$this->controller = new AccountController(
$this->view,
$this->authService,
$this->flash,
$this->sessionManager,
);
}
// ── showChangePassword ───────────────────────────────────────────
/**
* showChangePassword() doit rendre le formulaire de changement de mot de passe.
*/
public function testShowChangePasswordRendersForm(): void
{
$this->view->expects($this->once())
->method('render')
->with($this->anything(), 'pages/account/password-change.twig', $this->anything())
->willReturnArgument(0);
$res = $this->controller->showChangePassword($this->makeGet('/account/password'), $this->makeResponse());
$this->assertStatus($res, 200);
}
// ── changePassword ───────────────────────────────────────────────
/**
* changePassword() doit rediriger avec une erreur si les mots de passe ne correspondent pas.
*/
public function testChangePasswordRedirectsWhenPasswordMismatch(): void
{
$this->flash->expects($this->once())->method('set')
->with('password_error', 'Les mots de passe ne correspondent pas');
$req = $this->makePost('/account/password', [
'current_password' => 'oldpass',
'new_password' => 'newpass1',
'new_password_confirm' => 'newpass2',
]);
$res = $this->controller->changePassword($req, $this->makeResponse());
$this->assertRedirectTo($res, '/account/password');
}
/**
* changePassword() ne doit pas appeler authService si les mots de passe ne correspondent pas.
*/
public function testChangePasswordDoesNotCallServiceOnMismatch(): void
{
$this->authService->expects($this->never())->method('changePassword');
$req = $this->makePost('/account/password', [
'current_password' => 'old',
'new_password' => 'aaa',
'new_password_confirm' => 'bbb',
]);
$this->controller->changePassword($req, $this->makeResponse());
}
/**
* changePassword() doit afficher une erreur si le nouveau mot de passe est trop court.
*/
public function testChangePasswordRedirectsOnWeakPassword(): void
{
$this->sessionManager->method('getUserId')->willReturn(1);
$this->authService->method('changePassword')->willThrowException(new WeakPasswordException());
$this->flash->expects($this->once())->method('set')
->with('password_error', $this->stringContains('8 caractères'));
$req = $this->makePost('/account/password', [
'current_password' => 'old',
'new_password' => 'short',
'new_password_confirm' => 'short',
]);
$res = $this->controller->changePassword($req, $this->makeResponse());
$this->assertRedirectTo($res, '/account/password');
}
/**
* changePassword() doit afficher une erreur si le mot de passe actuel est incorrect.
*/
public function testChangePasswordRedirectsOnWrongCurrentPassword(): void
{
$this->sessionManager->method('getUserId')->willReturn(1);
$this->authService->method('changePassword')
->willThrowException(new \InvalidArgumentException('Mot de passe actuel incorrect'));
$this->flash->expects($this->once())->method('set')
->with('password_error', 'Le mot de passe actuel est incorrect');
$req = $this->makePost('/account/password', [
'current_password' => 'wrong',
'new_password' => 'newpassword',
'new_password_confirm' => 'newpassword',
]);
$res = $this->controller->changePassword($req, $this->makeResponse());
$this->assertRedirectTo($res, '/account/password');
}
/**
* changePassword() doit afficher une erreur générique en cas d'exception inattendue.
*/
public function testChangePasswordRedirectsOnUnexpectedError(): void
{
$this->sessionManager->method('getUserId')->willReturn(1);
$this->authService->method('changePassword')
->willThrowException(new \RuntimeException('DB error'));
$this->flash->expects($this->once())->method('set')
->with('password_error', $this->stringContains('inattendue'));
$req = $this->makePost('/account/password', [
'current_password' => 'old',
'new_password' => 'newpassword',
'new_password_confirm' => 'newpassword',
]);
$res = $this->controller->changePassword($req, $this->makeResponse());
$this->assertRedirectTo($res, '/account/password');
}
/**
* changePassword() doit afficher un message de succès et rediriger en cas de succès.
*/
public function testChangePasswordRedirectsWithSuccessFlash(): void
{
$this->sessionManager->method('getUserId')->willReturn(1);
$this->flash->expects($this->once())->method('set')
->with('password_success', $this->stringContains('Mot de passe modifié'));
$req = $this->makePost('/account/password', [
'current_password' => 'oldpass123',
'new_password' => 'newpass123',
'new_password_confirm' => 'newpass123',
]);
$res = $this->controller->changePassword($req, $this->makeResponse());
$this->assertRedirectTo($res, '/account/password');
}
/**
* changePassword() doit utiliser 0 comme userId de repli si la session est vide.
*/
public function testChangePasswordUsesZeroAsUserIdFallback(): void
{
$this->sessionManager->method('getUserId')->willReturn(null);
$this->authService->expects($this->once())
->method('changePassword')
->with(0, $this->anything(), $this->anything());
$req = $this->makePost('/account/password', [
'current_password' => 'old',
'new_password' => 'newpassword',
'new_password_confirm' => 'newpassword',
]);
$this->controller->changePassword($req, $this->makeResponse());
}
}