176 lines
6.0 KiB
PHP
176 lines
6.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Functional;
|
|
|
|
use App\DataFixtures\SignalFixtures;
|
|
use App\Entity\Signal;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Doctrine\ORM\Tools\SchemaTool;
|
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class SignalControllerTest extends WebTestCase
|
|
{
|
|
private KernelBrowser $client;
|
|
|
|
private EntityManagerInterface $entityManager;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->client = static::createClient();
|
|
$entityManager = $this->client->getContainer()->get(EntityManagerInterface::class);
|
|
self::assertInstanceOf(EntityManagerInterface::class, $entityManager);
|
|
$this->entityManager = $entityManager;
|
|
|
|
$metadata = $this->entityManager->getMetadataFactory()->getAllMetadata();
|
|
$schemaTool = new SchemaTool($this->entityManager);
|
|
$schemaTool->dropDatabase();
|
|
if ($metadata !== []) {
|
|
$schemaTool->createSchema($metadata);
|
|
}
|
|
|
|
new SignalFixtures()->load($this->entityManager);
|
|
}
|
|
|
|
#[\Override]
|
|
protected function tearDown(): void
|
|
{
|
|
parent::tearDown();
|
|
|
|
if (isset($this->entityManager)) {
|
|
$this->entityManager->close();
|
|
unset($this->entityManager);
|
|
}
|
|
}
|
|
|
|
public function testIndexReturnsRecentSignals(): void
|
|
{
|
|
$this->client->request('GET', '/api/signals', server: [
|
|
'HTTP_ACCEPT' => 'application/json',
|
|
]);
|
|
|
|
self::assertResponseIsSuccessful();
|
|
|
|
$content = $this->client->getResponse()->getContent();
|
|
self::assertIsString($content);
|
|
$payload = json_decode($content, true, 512, JSON_THROW_ON_ERROR);
|
|
|
|
self::assertSame(substr(hash('sha256', '127.0.0.1'), 0, 12), $payload['clientKey']);
|
|
self::assertCount(3, $payload['points']);
|
|
self::assertSame(3, $payload['totals']['points']);
|
|
self::assertSame(2, $payload['totals']['contributors']);
|
|
self::assertSame(-11.6852, $payload['points'][0]['signalLocation']['lat']);
|
|
self::assertArrayNotHasKey('userLocation', $payload['points'][0]);
|
|
}
|
|
|
|
public function testIndexRespectsLimitQueryParameter(): void
|
|
{
|
|
$this->client->request('GET', '/api/signals?limit=1', server: [
|
|
'HTTP_ACCEPT' => 'application/json',
|
|
]);
|
|
|
|
self::assertResponseIsSuccessful();
|
|
|
|
$content = $this->client->getResponse()->getContent();
|
|
self::assertIsString($content);
|
|
$payload = json_decode($content, true, 512, JSON_THROW_ON_ERROR);
|
|
|
|
self::assertCount(1, $payload['points']);
|
|
self::assertSame(1, $payload['totals']['points']);
|
|
}
|
|
|
|
public function testStorePersistsNewSignal(): void
|
|
{
|
|
$body = [
|
|
'signalLocation' => [
|
|
'lat' => -11.6901,
|
|
'lng' => 27.4959,
|
|
],
|
|
'userLocation' => [
|
|
'lat' => -11.6899,
|
|
'lng' => 27.4962,
|
|
],
|
|
];
|
|
|
|
$this->client->request('POST', '/api/signals', server: [
|
|
'CONTENT_TYPE' => 'application/json',
|
|
'HTTP_ACCEPT' => 'application/json',
|
|
], content: json_encode($body, JSON_THROW_ON_ERROR));
|
|
|
|
self::assertResponseStatusCodeSame(Response::HTTP_CREATED);
|
|
|
|
$content = $this->client->getResponse()->getContent();
|
|
self::assertIsString($content);
|
|
$payload = json_decode($content, true, 512, JSON_THROW_ON_ERROR);
|
|
self::assertSame('stored', $payload['status']);
|
|
self::assertSame($body['signalLocation']['lat'], $payload['point']['signalLocation']['lat']);
|
|
self::assertSame($body['signalLocation']['lng'], $payload['point']['signalLocation']['lng']);
|
|
self::assertArrayNotHasKey('userLocation', $payload['point']);
|
|
|
|
$repository = $this->entityManager->getRepository(Signal::class);
|
|
$signals = $repository->findAll();
|
|
self::assertCount(4, $signals);
|
|
}
|
|
|
|
public function testStoreRejectsInvalidCoordinates(): void
|
|
{
|
|
$body = [
|
|
'signalLocation' => [
|
|
'lat' => 181,
|
|
'lng' => 10,
|
|
],
|
|
'userLocation' => [
|
|
'lat' => 10,
|
|
'lng' => 10,
|
|
],
|
|
];
|
|
|
|
$this->client->request('POST', '/api/signals', server: [
|
|
'CONTENT_TYPE' => 'application/json',
|
|
'HTTP_ACCEPT' => 'application/json',
|
|
], content: json_encode($body, JSON_THROW_ON_ERROR));
|
|
|
|
self::assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
|
|
$response = $this->client->getResponse();
|
|
self::assertSame('invalid_coordinates', $response->headers->get('x-error-code'));
|
|
|
|
$content = $response->getContent();
|
|
self::assertIsString($content);
|
|
$payload = json_decode($content, true, 512, JSON_THROW_ON_ERROR);
|
|
self::assertSame('Latitude 181.000000 is out of bounds.', $payload['detail'] ?? null);
|
|
}
|
|
|
|
public function testStoreRejectsPointTooFar(): void
|
|
{
|
|
$body = [
|
|
'signalLocation' => [
|
|
'lat' => -11.6901,
|
|
'lng' => 27.4959,
|
|
],
|
|
'userLocation' => [
|
|
'lat' => -11.7005,
|
|
'lng' => 27.4804,
|
|
],
|
|
];
|
|
|
|
$this->client->request('POST', '/api/signals', server: [
|
|
'CONTENT_TYPE' => 'application/json',
|
|
'HTTP_ACCEPT' => 'application/json',
|
|
], content: json_encode($body, JSON_THROW_ON_ERROR));
|
|
|
|
self::assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
|
|
$response = $this->client->getResponse();
|
|
self::assertSame('point_too_far', $response->headers->get('x-error-code'));
|
|
|
|
$content = $response->getContent();
|
|
self::assertIsString($content);
|
|
$payload = json_decode($content, true, 512, JSON_THROW_ON_ERROR);
|
|
self::assertSame('The submitted point must be within 1.00km of your location.', $payload['detail'] ?? null);
|
|
}
|
|
}
|