Probleme: PHPUnit 13 genere des notices quand createMock() est utilise sans expects(), et des deprecations pour \$this->any() et ->with() sans expects(). Corrections: - tests/Service/AppLoggerServiceTest.php: suppression du setUp() partage, chaque test cree ses propres stubs/mocks selon ses besoins (bus createMock avec expects dans les tests log, createStub dans verify) - tests/EventSubscriber/CsrfProtectionSubscriberTest.php: csrfTokenManager change de createMock a createStub (aucun expects utilise) - tests/EventSubscriber/MessengerFailureSubscriberTest.php: em et mailer changes de createMock a createStub (aucun expects utilise) - tests/EventListener/AdminLogListenerTest.php: testLogThrowsDoesNotBlock cree son propre stub local au lieu d'utiliser le mock du setUp, attribut #[AllowMockObjectsWithoutExpectations] ajoute pour le mock du setUp qui reste instancie mais non utilise dans ce test - tests/Controller/SmallControllersTest.php: mocks sans expects remplaces par createStub via script automatise - tests/Controller/MainControllersTest.php: idem - tests/Controller/Admin/ClientsControllerTest.php: idem - tests/MessageHandler/AnalyticsMessageHandlerTest.php: idem - tests/EventListener/ExceptionListenerTest.php: idem Resultat: 262 tests, 454 assertions, 0 failures, 0 deprecations, 0 notices Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
218 lines
8.6 KiB
PHP
218 lines
8.6 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Controller;
|
|
|
|
use App\Controller\AnalyticsController;
|
|
use App\Controller\CspReportController;
|
|
use App\Controller\EmailTrackingController;
|
|
use App\Controller\ExternalRedirectController;
|
|
use App\Controller\SonarBadgeController;
|
|
use App\Entity\EmailTracking;
|
|
use App\Repository\EmailTrackingRepository;
|
|
use App\Service\AnalyticsCryptoService;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Mailer\MailerInterface;
|
|
use Symfony\Component\Messenger\Envelope;
|
|
use Symfony\Component\Messenger\MessageBusInterface;
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
use Symfony\Contracts\HttpClient\ResponseInterface as HttpClientResponseInterface;
|
|
use Twig\Environment;
|
|
|
|
class SmallControllersTest extends TestCase
|
|
{
|
|
private string $tempDir;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->tempDir = sys_get_temp_dir() . '/small_ctrl_test_' . uniqid();
|
|
mkdir($this->tempDir);
|
|
mkdir($this->tempDir . '/public');
|
|
touch($this->tempDir . '/public/logo_facture.png');
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
$this->removeDir($this->tempDir);
|
|
}
|
|
|
|
private function removeDir(string $dir): void
|
|
{
|
|
if (!is_dir($dir)) return;
|
|
$files = array_diff(scandir($dir), ['.', '..']);
|
|
foreach ($files as $file) {
|
|
$path = $dir . '/' . $file;
|
|
is_dir($path) ? $this->removeDir($path) : unlink($path);
|
|
}
|
|
rmdir($dir);
|
|
}
|
|
|
|
private function createContainer(array $services = []): ContainerInterface
|
|
{
|
|
$container = $this->createStub(ContainerInterface::class);
|
|
$container->method('has')->willReturnCallback(fn($id) => isset($services[$id]) || $id === 'parameter_bag' || $id === 'twig' || $id === 'router');
|
|
$container->method('get')->willReturnCallback(fn($id) => $services[$id] ?? null);
|
|
return $container;
|
|
}
|
|
|
|
// --- SonarBadgeController ---
|
|
|
|
public function testSonarBadgeSuccess(): void
|
|
{
|
|
$client = $this->createMock(HttpClientInterface::class);
|
|
$resp = $this->createStub(HttpClientResponseInterface::class);
|
|
$resp->method('getContent')->willReturn('<svg>badge</svg>');
|
|
$client->expects($this->once())->method('request')->willReturn($resp);
|
|
|
|
$controller = new SonarBadgeController();
|
|
$response = $controller->badge('coverage', $client, 'http://sonar', 'project', 'token');
|
|
|
|
$this->assertSame(200, $response->getStatusCode());
|
|
$this->assertSame('<svg>badge</svg>', $response->getContent());
|
|
}
|
|
|
|
// --- CspReportController ---
|
|
|
|
public function testCspReportInvalidJson(): void
|
|
{
|
|
$request = new Request([], [], [], [], [], [], 'invalid');
|
|
$mailer = $this->createStub(MailerInterface::class);
|
|
$logger = $this->createMock(LoggerInterface::class);
|
|
$logger->expects($this->once())->method('error');
|
|
|
|
$controller = new CspReportController();
|
|
$response = $controller->report($request, $mailer, $logger);
|
|
$this->assertSame(400, $response->getStatusCode());
|
|
}
|
|
|
|
public function testCspReportIgnoredViolation(): void
|
|
{
|
|
$payload = json_encode(['csp-report' => ['source-file' => 'chrome-extension://abc']]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$mailer = $this->createStub(MailerInterface::class);
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$controller = new CspReportController();
|
|
$response = $controller->report($request, $mailer, $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
$this->assertSame('Report ignored', $response->getContent());
|
|
}
|
|
|
|
public function testCspReportSuccess(): void
|
|
{
|
|
$payload = json_encode(['csp-report' => [
|
|
'source-file' => 'http://evil.com/script.js',
|
|
'document-uri' => 'http://site.fr',
|
|
'violated-directive' => 'script-src',
|
|
'blocked-uri' => 'http://evil.com'
|
|
]]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$mailer = $this->createMock(MailerInterface::class);
|
|
$mailer->expects($this->once())->method('send');
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$bag = $this->createStub(ParameterBagInterface::class);
|
|
$bag->method('get')->willReturn('admin@test.com');
|
|
|
|
$container = $this->createContainer(['parameter_bag' => $bag]);
|
|
|
|
$controller = new CspReportController();
|
|
$controller->setContainer($container);
|
|
$response = $controller->report($request, $mailer, $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
// --- EmailTrackingController ---
|
|
|
|
public function testEmailViewSuccess(): void
|
|
{
|
|
$repo = $this->createStub(EmailTrackingRepository::class);
|
|
$tracking = new EmailTracking('id', 'r', 's', '<html><body></body></html>', [['name' => 'att.pdf', 'path' => '/tmp/att.pdf']]);
|
|
$repo->method('findOneBy')->willReturn($tracking);
|
|
|
|
$router = $this->createStub(\Symfony\Component\Routing\RouterInterface::class);
|
|
$router->method('generate')->willReturn('/download');
|
|
|
|
$container = $this->createContainer(['router' => $router]);
|
|
$controller = new EmailTrackingController();
|
|
$controller->setContainer($container);
|
|
|
|
$response = $controller->view('id', $repo);
|
|
$this->assertSame(200, $response->getStatusCode());
|
|
$this->assertStringContainsString('/download', $response->getContent());
|
|
}
|
|
|
|
public function testEmailAttachmentSuccess(): void
|
|
{
|
|
$filePath = $this->tempDir . '/test.pdf';
|
|
file_put_contents($filePath, 'PDF CONTENT');
|
|
|
|
$repo = $this->createStub(EmailTrackingRepository::class);
|
|
$tracking = new EmailTracking('id', 'r', 's', null, [['name' => 'test.pdf', 'path' => $filePath]]);
|
|
$repo->method('findOneBy')->willReturn($tracking);
|
|
|
|
$controller = new EmailTrackingController();
|
|
$response = $controller->attachment('id', 0, $repo);
|
|
$this->assertSame(200, $response->getStatusCode());
|
|
}
|
|
|
|
// --- AnalyticsController ---
|
|
|
|
public function testAnalyticsTrackInvalidToken(): void
|
|
{
|
|
$crypto = $this->createStub(AnalyticsCryptoService::class);
|
|
$em = $this->createStub(EntityManagerInterface::class);
|
|
$bus = $this->createStub(MessageBusInterface::class);
|
|
$request = new Request([], [], [], [], [], [], json_encode(['d' => 'data']));
|
|
|
|
$controller = new AnalyticsController();
|
|
$response = $controller->track('invalid', 'secret', $request, $crypto, $em, $bus);
|
|
$this->assertSame(404, $response->getStatusCode());
|
|
}
|
|
|
|
public function testAnalyticsTrackInvalidHash(): void
|
|
{
|
|
$secret = 'secret';
|
|
$token = substr(hash('sha256', $secret.'_endpoint'), 0, 8);
|
|
|
|
$crypto = $this->createStub(AnalyticsCryptoService::class);
|
|
$crypto->method('decrypt')->willReturn(['uid' => 'uid-123', 'h' => 'bad-hash']);
|
|
$crypto->method('verifyVisitorHash')->willReturn(false);
|
|
|
|
$em = $this->createStub(EntityManagerInterface::class);
|
|
$bus = $this->createStub(MessageBusInterface::class);
|
|
$request = new Request([], [], [], [], [], [], json_encode(['d' => 'data']));
|
|
|
|
$controller = new AnalyticsController();
|
|
$response = $controller->track($token, $secret, $request, $crypto, $em, $bus);
|
|
|
|
$this->assertSame(403, $response->getStatusCode());
|
|
}
|
|
|
|
public function testAnalyticsTrackPageView(): void
|
|
{
|
|
$secret = 'secret';
|
|
$token = substr(hash('sha256', $secret.'_endpoint'), 0, 8);
|
|
|
|
$crypto = $this->createStub(AnalyticsCryptoService::class);
|
|
$crypto->method('decrypt')->willReturn(['uid' => 'uid-123', 'h' => 'hash', 'u' => '/home']);
|
|
$crypto->method('verifyVisitorHash')->willReturn(true);
|
|
|
|
$em = $this->createStub(EntityManagerInterface::class);
|
|
$bus = $this->createMock(MessageBusInterface::class);
|
|
$bus->expects($this->once())->method('dispatch')->willReturn(new Envelope(new \stdClass()));
|
|
|
|
$request = new Request([], [], [], [], [], [], json_encode(['d' => 'data']));
|
|
|
|
$controller = new AnalyticsController();
|
|
$response = $controller->track($token, $secret, $request, $crypto, $em, $bus);
|
|
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
}
|