Remplace createMock() par createStub() pour tous les collaborateurs sans expectations configurées. Les mocks avec expects() restent des mocks locaux créés dans le test concerné. 0 notices sur 49 tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
181 lines
7.3 KiB
PHP
181 lines
7.3 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Unit\Controller;
|
|
|
|
use App\Controller\FeedbackController;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Container\ContainerInterface;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\RateLimiter\RateLimiterFactory;
|
|
use Symfony\Component\RateLimiter\Storage\InMemoryStorage;
|
|
|
|
class FeedbackControllerTest extends TestCase
|
|
{
|
|
private EntityManagerInterface $em;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->em = $this->createStub(EntityManagerInterface::class);
|
|
}
|
|
|
|
private function makeController(bool $exhaust = false, ?EntityManagerInterface $em = null): FeedbackController
|
|
{
|
|
$storage = new InMemoryStorage();
|
|
$factory = new RateLimiterFactory([
|
|
'id' => 'feedback_test',
|
|
'policy' => 'token_bucket',
|
|
'limit' => 10,
|
|
'rate' => ['interval' => '1 minute'],
|
|
], $storage);
|
|
|
|
if ($exhaust) {
|
|
// Vider les tokens avec la même clé que le controller (l'IP du request)
|
|
$limiter = $factory->create('1.2.3.4');
|
|
for ($i = 0; $i < 11; $i++) {
|
|
$limiter->consume();
|
|
}
|
|
}
|
|
|
|
$controller = new FeedbackController($em ?? $this->em, $factory);
|
|
|
|
$container = $this->createStub(ContainerInterface::class);
|
|
$container->method('has')->willReturn(false);
|
|
$controller->setContainer($container);
|
|
|
|
return $controller;
|
|
}
|
|
|
|
private function makeRequest(string $body, string $ip = '1.2.3.4'): Request
|
|
{
|
|
$request = Request::create('/api/feedback', 'POST', [], [], [], [], $body);
|
|
$request->server->set('REMOTE_ADDR', $ip);
|
|
return $request;
|
|
}
|
|
|
|
// ── Taille de payload ─────────────────────────────────────────────────────
|
|
|
|
public function testBodyTooLargeReturns413(): void
|
|
{
|
|
$body = json_encode(['lat' => 14.65, 'lng' => -61.0, 'hasSeaweed' => true, 'pad' => str_repeat('x', 4100)]);
|
|
self::assertSame(413, $this->makeController()->create($this->makeRequest($body))->getStatusCode());
|
|
}
|
|
|
|
// ── Validation JSON ───────────────────────────────────────────────────────
|
|
|
|
public function testInvalidJsonReturns400(): void
|
|
{
|
|
self::assertSame(400, $this->makeController()->create($this->makeRequest('not-json'))->getStatusCode());
|
|
}
|
|
|
|
// ── Champs obligatoires ───────────────────────────────────────────────────
|
|
|
|
public function testMissingLatReturns422(): void
|
|
{
|
|
self::assertSame(422, $this->makeController()->create(
|
|
$this->makeRequest(json_encode(['lng' => -61.0, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
public function testMissingLngReturns422(): void
|
|
{
|
|
self::assertSame(422, $this->makeController()->create(
|
|
$this->makeRequest(json_encode(['lat' => 14.65, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
public function testMissingHasSeaweedReturns422(): void
|
|
{
|
|
self::assertSame(422, $this->makeController()->create(
|
|
$this->makeRequest(json_encode(['lat' => 14.65, 'lng' => -61.0]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
// ── Validation lat/lng ────────────────────────────────────────────────────
|
|
|
|
public function testInvalidLatStringReturns422(): void
|
|
{
|
|
self::assertSame(422, $this->makeController()->create(
|
|
$this->makeRequest(json_encode(['lat' => 'abc', 'lng' => -61.0, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
public function testLatAboveRangeReturns422(): void
|
|
{
|
|
self::assertSame(422, $this->makeController()->create(
|
|
$this->makeRequest(json_encode(['lat' => 91.0, 'lng' => -61.0, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
public function testLatBelowRangeReturns422(): void
|
|
{
|
|
self::assertSame(422, $this->makeController()->create(
|
|
$this->makeRequest(json_encode(['lat' => -91.0, 'lng' => -61.0, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
public function testLngAboveRangeReturns422(): void
|
|
{
|
|
self::assertSame(422, $this->makeController()->create(
|
|
$this->makeRequest(json_encode(['lat' => 14.65, 'lng' => 181.0, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
// ── Frontières exactes ────────────────────────────────────────────────────
|
|
|
|
public function testExactBoundaryLatLngIsAccepted(): void
|
|
{
|
|
$em = $this->createMock(EntityManagerInterface::class);
|
|
$em->expects(self::once())->method('persist');
|
|
$em->expects(self::once())->method('flush');
|
|
|
|
self::assertSame(201, $this->makeController(em: $em)->create(
|
|
$this->makeRequest(json_encode(['lat' => 90.0, 'lng' => -180.0, 'hasSeaweed' => false]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
// ── Requête valide ────────────────────────────────────────────────────────
|
|
|
|
public function testValidRequestReturns201(): void
|
|
{
|
|
$em = $this->createMock(EntityManagerInterface::class);
|
|
$em->expects(self::once())->method('persist');
|
|
$em->expects(self::once())->method('flush');
|
|
|
|
self::assertSame(201, $this->makeController(em: $em)->create(
|
|
$this->makeRequest(json_encode(['lat' => 14.65, 'lng' => -61.0, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
public function testValidDensityIsAccepted(): void
|
|
{
|
|
$em = $this->createMock(EntityManagerInterface::class);
|
|
$em->expects(self::once())->method('persist');
|
|
$em->expects(self::once())->method('flush');
|
|
|
|
self::assertSame(201, $this->makeController(em: $em)->create(
|
|
$this->makeRequest(json_encode(['lat' => 14.65, 'lng' => -61.0, 'hasSeaweed' => true, 'density' => 'high']))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
public function testInvalidDensityIsIgnoredAndRequestSucceeds(): void
|
|
{
|
|
$em = $this->createMock(EntityManagerInterface::class);
|
|
$em->expects(self::once())->method('persist');
|
|
$em->expects(self::once())->method('flush');
|
|
|
|
self::assertSame(201, $this->makeController(em: $em)->create(
|
|
$this->makeRequest(json_encode(['lat' => 14.65, 'lng' => -61.0, 'hasSeaweed' => true, 'density' => 'extreme']))
|
|
)->getStatusCode());
|
|
}
|
|
|
|
// ── Rate limiting ─────────────────────────────────────────────────────────
|
|
|
|
public function testRateLimitExceededReturns429(): void
|
|
{
|
|
self::assertSame(429, $this->makeController(exhaust: true)->create(
|
|
$this->makeRequest(json_encode(['lat' => 14.65, 'lng' => -61.0, 'hasSeaweed' => true]))
|
|
)->getStatusCode());
|
|
}
|
|
}
|