Module sites (#8)
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s

| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|                  |                 |

## Description de la PR

## Modification du .env

## Check list

- [x] Pas de régression
- [x] TU/TI/TF rédigée
- [x] TU/TI/TF OK
- [ ] CHANGELOG modifié

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #8
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #8.
This commit is contained in:
2026-04-20 15:31:58 +00:00
committed by Autin
parent 6b4868b261
commit 6cf5ef4cfc
77 changed files with 7739 additions and 80 deletions

View File

@@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
namespace App\Tests\Module\Sites\Infrastructure\ApiPlatform\State\Processor;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Post;
use ApiPlatform\State\ProcessorInterface;
use App\Module\Sites\Application\Service\CurrentSiteProviderInterface;
use App\Module\Sites\Domain\Entity\Site;
use App\Module\Sites\Infrastructure\ApiPlatform\State\Processor\SiteAwareInjectionProcessor;
use App\Shared\Domain\Contract\SiteAwareInterface;
use App\Shared\Domain\Contract\SiteInterface;
use PHPUnit\Framework\TestCase;
use stdClass;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* Tests unitaires du SiteAwareInjectionProcessor.
*
* Mocks isoles : le processor decore, donc on verifie (a) les mutations
* appliquees sur $data avant delegation, (b) que inner->process est
* toujours invoque sauf en cas de throw, (c) le throw 400 explicite si
* $data SiteAware sans site + provider null.
*
* @internal
*/
final class SiteAwareInjectionProcessorTest extends TestCase
{
public function testInjectsCurrentSiteOnSiteAwareEntityWithoutSite(): void
{
$currentSite = new Site('Chatellerault', 'Rue', null, '86100', 'Chatellerault', '#056CF2');
$data = $this->makeSiteAwareStub(null);
$inner = $this->createMock(ProcessorInterface::class);
$inner->expects(self::once())
->method('process')
->willReturnArgument(0)
;
$processor = $this->makeProcessor($inner, $currentSite);
$processor->process($data, $this->makeOperation());
self::assertSame($currentSite, $data->getSite());
}
public function testDoesNotOverrideExistingSite(): void
{
$existingSite = new Site('Existing', 'Rue', null, '12345', 'Ville', '#000000');
$currentSite = new Site('Chatellerault', 'Rue', null, '86100', 'Chatellerault', '#056CF2');
$data = $this->makeSiteAwareStub($existingSite);
$inner = $this->createMock(ProcessorInterface::class);
$inner->expects(self::once())->method('process');
$processor = $this->makeProcessor($inner, $currentSite);
$processor->process($data, $this->makeOperation());
self::assertSame(
$existingSite,
$data->getSite(),
'Un site deja positionne doit etre preserve, pas ecrase par le currentSite.',
);
}
public function testSkipsNonSiteAwareData(): void
{
$nonSiteAware = new stdClass();
$inner = $this->createMock(ProcessorInterface::class);
$inner->expects(self::once())
->method('process')
->with($nonSiteAware)
;
$processor = $this->makeProcessor(
$inner,
new Site('Any', 'Rue', null, '12345', 'Ville', '#000000'),
);
$processor->process($nonSiteAware, $this->makeOperation());
}
public function testThrowsBadRequestIfSiteAwareAndNoCurrentSite(): void
{
$data = $this->makeSiteAwareStub(null);
$inner = $this->createMock(ProcessorInterface::class);
$inner->expects(self::never())
->method('process')
;
$processor = $this->makeProcessor($inner, currentSite: null);
$this->expectException(BadRequestHttpException::class);
$this->expectExceptionMessage('aucun site selectionne');
$processor->process($data, $this->makeOperation());
}
public function testDelegatesToInnerProcessorAlwaysWhenNoThrow(): void
{
$data = new stdClass();
$inner = $this->createMock(ProcessorInterface::class);
$inner->expects(self::once())
->method('process')
->willReturn('delegated-result')
;
$processor = $this->makeProcessor(
$inner,
new Site('Any', 'Rue', null, '12345', 'Ville', '#000000'),
);
$result = $processor->process($data, $this->makeOperation());
self::assertSame('delegated-result', $result);
}
private function makeProcessor(
ProcessorInterface $inner,
?Site $currentSite,
): SiteAwareInjectionProcessor {
// createStub : on n'a besoin que de fixer la valeur de retour, pas
// d'attentes sur le nombre d'appels. Evite la notice PHPUnit
// "No expectations were configured for the mock object".
$provider = $this->createStub(CurrentSiteProviderInterface::class);
$provider->method('get')->willReturn($currentSite);
// Stub Security : bypass_scope = true par defaut pour preserver le
// comportement des tests historiques (pas de validation cross-site).
// Les tests dedies a la validation cross-site instancient leur propre
// Security via un helper dedie.
$security = $this->createStub(Security::class);
$security->method('isGranted')->willReturn(true);
return new SiteAwareInjectionProcessor($inner, $provider, $security);
}
private function makeSiteAwareStub(?Site $initialSite): SiteAwareInterface
{
return new class($initialSite) implements SiteAwareInterface {
public function __construct(private ?SiteInterface $site) {}
public function getSite(): ?SiteInterface
{
return $this->site;
}
public function setSite(SiteInterface $site): void
{
$this->site = $site;
}
};
}
private function makeOperation(): Operation
{
return new Post();
}
}